Page MenuHomePhabricator

D13634.diff
No OneTemporary

D13634.diff

diff --git a/apps/alias-server/index.js b/apps/alias-server/index.js
--- a/apps/alias-server/index.js
+++ b/apps/alias-server/index.js
@@ -24,12 +24,7 @@
polling: true,
});
-async function main(
- chronik,
- telegramBot,
- channelId,
- avalancheCheckWaitInterval,
-) {
+async function main(chronik, telegramBot, channelId, avalancheRpc) {
// Initialize db connection
const db = await initializeDb();
@@ -39,7 +34,7 @@
db,
telegramBot,
channelId,
- avalancheCheckWaitInterval,
+ avalancheRpc,
);
if (aliasWebsocket && aliasWebsocket._subs && aliasWebsocket._subs[0]) {
const subscribedHash160 = aliasWebsocket._subs[0].scriptPayload;
@@ -47,13 +42,7 @@
}
// Get the latest alias information on app startup
- await handleAppStartup(
- chronik,
- db,
- telegramBot,
- channelId,
- avalancheCheckWaitInterval,
- );
+ await handleAppStartup(chronik, db, telegramBot, channelId, avalancheRpc);
// Set up your API endpoints
const app = express();
@@ -81,4 +70,4 @@
app.listen(config.express.port);
}
-main(chronik, telegramBot, channelId, config.avalancheCheckWaitInterval);
+main(chronik, telegramBot, channelId, secrets.avalancheRpc);
diff --git a/apps/alias-server/src/events.js b/apps/alias-server/src/events.js
--- a/apps/alias-server/src/events.js
+++ b/apps/alias-server/src/events.js
@@ -6,6 +6,7 @@
const config = require('../config');
const log = require('./log');
const { wait } = require('./utils');
+const { isFinalBlock } = require('./rpc');
module.exports = {
handleAppStartup: async function (
@@ -13,7 +14,7 @@
db,
telegramBot,
channelId,
- avalancheCheckWaitInterval,
+ avalancheRpc,
) {
log(`Checking for new aliases on startup`);
// If this is app startup, get the latest tipHash and tipHeight by querying the blockchain
@@ -35,7 +36,7 @@
db,
telegramBot,
channelId,
- avalancheCheckWaitInterval,
+ avalancheRpc,
tipHash,
tipHeight,
);
@@ -47,7 +48,7 @@
db,
telegramBot,
channelId,
- avalancheCheckWaitInterval,
+ avalancheRpc,
tipHash,
tipHeight,
) {
@@ -90,10 +91,35 @@
}
}
+ // Initialize isAvalancheFinalized as false. Only set to true if you
+ // prove it so with a node rpc call
+ let isAvalancheFinalized = false;
+
for (let i = 0; i < config.avalancheCheckCount; i += 1) {
- // TODO check isFinalBlock
- wait(avalancheCheckWaitInterval);
- // TODO if isFinalBlock, break loop
+ // Check to see if block tipHash has been finalized by avalanche
+ try {
+ isAvalancheFinalized = await isFinalBlock(
+ avalancheRpc,
+ tipHash,
+ );
+ } catch (err) {
+ log(`Error in isFinalBlock for ${tipHash}`, err);
+ }
+ if (isAvalancheFinalized) {
+ // If isAvalancheFinalized, stop checking
+ break;
+ }
+ wait(config.avalancheCheckWaitInterval);
+ }
+
+ if (!isAvalancheFinalized) {
+ log(
+ `Block ${tipHash} is not avalanche finalized after ${
+ config.avalancheCheckWaitInterval *
+ config.avalancheCheckCount
+ } ms. Exiting handleBlockConnected().`,
+ );
+ return false;
}
// TODO Get the valid aliases already in the db
diff --git a/apps/alias-server/src/websocket.js b/apps/alias-server/src/websocket.js
--- a/apps/alias-server/src/websocket.js
+++ b/apps/alias-server/src/websocket.js
@@ -14,7 +14,7 @@
db,
telegramBot,
channelId,
- avalancheCheckWaitInterval,
+ avalancheRpc,
) {
// Subscribe to chronik websocket
const ws = chronik.ws({
@@ -24,7 +24,7 @@
db,
telegramBot,
channelId,
- avalancheCheckWaitInterval,
+ avalancheRpc,
msg,
);
},
@@ -41,7 +41,7 @@
db,
telegramBot,
channelId,
- avalancheCheckWaitInterval,
+ avalancheRpc,
wsMsg = { type: 'BlockConnected' },
) {
log(`parseWebsocketMessage called on`, wsMsg);
@@ -60,7 +60,7 @@
db,
telegramBot,
channelId,
- avalancheCheckWaitInterval,
+ avalancheRpc,
wsMsg.blockHash,
);
case 'AddedToMempool':
diff --git a/apps/alias-server/test/eventsTests.js b/apps/alias-server/test/eventsTests.js
--- a/apps/alias-server/test/eventsTests.js
+++ b/apps/alias-server/test/eventsTests.js
@@ -4,11 +4,14 @@
'use strict';
const assert = require('assert');
+const mockSecrets = require('../secrets.sample');
const { handleAppStartup } = require('../src/events');
const { MockChronikClient } = require('./mocks/chronikMock');
+const MockAdapter = require('axios-mock-adapter');
+const axios = require('axios');
describe('alias-server events.js', async function () {
- it('handleAppStartup calls handleBlockConnected with tipHeight', async function () {
+ it('handleAppStartup calls handleBlockConnected with tipHeight and completes function if block is avalanche finalized', async function () {
// Initialize chronik mock
const mockedChronik = new MockChronikClient();
@@ -24,17 +27,27 @@
output: mockBlockchaininfoResponse,
});
+ // Mock avalanche RPC call
+ // onNoMatch: 'throwException' helps to debug if mock is not being used
+ const mock = new MockAdapter(axios, { onNoMatch: 'throwException' });
+ // Mock response for rpc return of true for isfinalblock method
+ mock.onPost().reply(200, {
+ result: true,
+ error: null,
+ id: 'isfinalblock',
+ });
+
const db = null;
const telegramBot = null;
const channelId = null;
- const avalancheCheckWaitInterval = 0;
+ const { avalancheRpc } = mockSecrets;
const result = await handleAppStartup(
mockedChronik,
db,
telegramBot,
channelId,
- avalancheCheckWaitInterval,
+ avalancheRpc,
);
assert.deepEqual(
@@ -42,6 +55,47 @@
`Alias registrations updated to block ${mockBlockchaininfoResponse.tipHash} at height ${mockBlockchaininfoResponse.tipHeight}`,
);
});
+ it('handleAppStartup calls handleBlockConnected with tipHeight and returns false if block is not avalanche finalized', async function () {
+ // Initialize chronik mock
+ const mockedChronik = new MockChronikClient();
+
+ const mockBlockchaininfoResponse = {
+ tipHash:
+ '00000000000000000ce690f27bc92c46863337cc9bd5b7c20aec094854db26e3',
+ tipHeight: 786878,
+ };
+
+ // Tell mockedChronik what response we expect
+ mockedChronik.setMock('blockchainInfo', {
+ input: null,
+ output: mockBlockchaininfoResponse,
+ });
+
+ // Mock avalanche RPC call
+ // onNoMatch: 'throwException' helps to debug if mock is not being used
+ const mock = new MockAdapter(axios, { onNoMatch: 'throwException' });
+ // Mock response for rpc return of true for isfinalblock method
+ mock.onPost().reply(200, {
+ result: false,
+ error: null,
+ id: 'isfinalblock',
+ });
+
+ const db = null;
+ const telegramBot = null;
+ const channelId = null;
+ const { avalancheRpc } = mockSecrets;
+
+ const result = await handleAppStartup(
+ mockedChronik,
+ db,
+ telegramBot,
+ channelId,
+ avalancheRpc,
+ );
+
+ assert.deepEqual(result, false);
+ });
it('handleAppStartup returns false on chronik error', async function () {
// Initialize chronik mock
const mockedChronik = new MockChronikClient();
@@ -59,17 +113,19 @@
output: mockBlockchaininfoResponse,
});
+ // Function will not get to RPC call, no need for axios mock
+
const db = null;
const telegramBot = null;
const channelId = null;
- const avalancheCheckWaitInterval = 0;
+ const { avalancheRpc } = mockSecrets;
const result = await handleAppStartup(
mockedChronik,
db,
telegramBot,
channelId,
- avalancheCheckWaitInterval,
+ avalancheRpc,
);
assert.deepEqual(result, false);
diff --git a/apps/alias-server/test/mocks/chronikResponses.js b/apps/alias-server/test/mocks/chronikResponses.js
new file mode 100644
--- /dev/null
+++ b/apps/alias-server/test/mocks/chronikResponses.js
@@ -0,0 +1,11 @@
+// Copyright (c) 2023 The Bitcoin developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+'use strict';
+module.exports = {
+ mockBlock: {
+ blockInfo: {
+ height: 786878,
+ },
+ },
+};
diff --git a/apps/alias-server/test/websocketTests.js b/apps/alias-server/test/websocketTests.js
--- a/apps/alias-server/test/websocketTests.js
+++ b/apps/alias-server/test/websocketTests.js
@@ -10,6 +10,10 @@
parseWebsocketMessage,
} = require('../src/websocket');
const { MockChronikClient } = require('./mocks/chronikMock');
+const { mockBlock } = require('./mocks/chronikResponses');
+const mockSecrets = require('../secrets.sample');
+const MockAdapter = require('axios-mock-adapter');
+const axios = require('axios');
describe('alias-server websocket.js', async function () {
it('initializeWebsocket returns expected websocket object for a p2pkh address', async function () {
@@ -21,7 +25,7 @@
const db = null;
const telegramBot = null;
const channelId = null;
- const avalancheCheckWaitInterval = 0;
+ const { avalancheRpc } = mockSecrets;
const result = await initializeWebsocket(
mockedChronik,
@@ -29,7 +33,7 @@
db,
telegramBot,
channelId,
- avalancheCheckWaitInterval,
+ avalancheRpc,
);
// Confirm websocket opened
@@ -50,7 +54,7 @@
const db = null;
const telegramBot = null;
const channelId = null;
- const avalancheCheckWaitInterval = 0;
+ const { avalancheRpc } = mockSecrets;
const result = await initializeWebsocket(
mockedChronik,
@@ -58,7 +62,7 @@
db,
telegramBot,
channelId,
- avalancheCheckWaitInterval,
+ avalancheRpc,
);
// Confirm websocket opened
@@ -70,13 +74,13 @@
{ scriptType: type, scriptPayload: hash },
]);
});
- it('parseWebsocketMessage correctly processes a chronik websocket BlockConnected message', async function () {
+ it('parseWebsocketMessage correctly processes a chronik websocket BlockConnected message if block is avalanche finalized', async function () {
// Initialize chronik mock
const mockedChronik = new MockChronikClient();
const db = null;
const telegramBot = null;
const channelId = null;
- const avalancheCheckWaitInterval = 0;
+ const { avalancheRpc } = mockSecrets;
const wsMsg = {
type: 'BlockConnected',
blockHash:
@@ -92,12 +96,22 @@
input: wsMsg.blockHash,
output: mockBlock,
});
+
+ // Mock avalanche RPC call
+ // onNoMatch: 'throwException' helps to debug if mock is not being used
+ const mock = new MockAdapter(axios, { onNoMatch: 'throwException' });
+ // Mock response for rpc return of true for isfinalblock method
+ mock.onPost().reply(200, {
+ result: true,
+ error: null,
+ id: 'isfinalblock',
+ });
const result = await parseWebsocketMessage(
mockedChronik,
db,
telegramBot,
channelId,
- avalancheCheckWaitInterval,
+ avalancheRpc,
wsMsg,
);
@@ -106,4 +120,43 @@
`Alias registrations updated to block ${wsMsg.blockHash} at height ${mockBlock.blockInfo.height}`,
);
});
+ it('parseWebsocketMessage calls handleBlockConnected, which exits if block is not avalanche finalized', async function () {
+ // Initialize chronik mock
+ const mockedChronik = new MockChronikClient();
+ const db = null;
+ const telegramBot = null;
+ const channelId = null;
+ const { avalancheRpc } = mockSecrets;
+ const wsMsg = {
+ type: 'BlockConnected',
+ blockHash:
+ '000000000000000015713b0407590ab1481fd7b8430f87e19cf768bec285ad55',
+ };
+
+ // Tell mockedChronik what response we expect
+ mockedChronik.setMock('block', {
+ input: wsMsg.blockHash,
+ output: mockBlock,
+ });
+
+ // Mock avalanche RPC call
+ // onNoMatch: 'throwException' helps to debug if mock is not being used
+ const mock = new MockAdapter(axios, { onNoMatch: 'throwException' });
+ // Mock response for rpc return of true for isfinalblock method
+ mock.onPost().reply(200, {
+ result: false,
+ error: null,
+ id: 'isfinalblock',
+ });
+ const result = await parseWebsocketMessage(
+ mockedChronik,
+ db,
+ telegramBot,
+ channelId,
+ avalancheRpc,
+ wsMsg,
+ );
+
+ assert.deepEqual(result, false);
+ });
});

File Metadata

Mime Type
text/plain
Expires
Fri, Nov 22, 10:03 (20 h, 34 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
4546868
Default Alt Text
D13634.diff (14 KB)

Event Timeline