UNPKG

@node-dlc/wire

Version:
204 lines (167 loc) 8.36 kB
/* eslint-disable @typescript-eslint/no-explicit-any */ import { ShortChannelId } from '@node-dlc/common'; import { ILogger } from '@node-dlc/logger'; import { expect } from 'chai'; import { GossipError, GossipErrorCode } from '../../lib/gossip/GossipError'; import { GossipQueriesSync, GossipQueriesSyncState, } from '../../lib/gossip/GossipQueriesSync'; import { ReplyChannelRangeMessage } from '../../lib/messages/ReplyChannelRangeMessage'; import { ReplyShortChannelIdsEndMessage } from '../../lib/messages/ReplyShortChannelIdsEndMessage'; import { createFakeLogger, createFakePeer, wait } from '../_test-utils'; describe('GossipQueriesSync', () => { let chainHash: Buffer; let sut: GossipQueriesSync; let peer: any; let logger: ILogger; beforeEach(() => { chainHash = Buffer.alloc(32); peer = createFakePeer(); logger = createFakeLogger(); sut = new GossipQueriesSync(chainHash, peer, logger); }); it('integration - success', async () => { // change the default completion timeout to 50ms (sut as any)._syncWatcher.completeAfterMs = 50; // we should expect to start in the idel posion since we have not yet // execute the query expect(sut.state).to.equal(GossipQueriesSyncState.Idle); // Execute the query. Since this is a promise, we will resolve the test // when the queryRange method resolves successfully. If for some reason // it fails, we will reject with the error and the test will fail const promise = sut.queryRange(); // At this point, the query should have been sent and we will now be // awaiting completion of the channel range state machine. expect(sut.state).to.equal(GossipQueriesSyncState.AwaitingChannelRange); // At this point, we should have sent a query message and we will // reply from the peer with a response message. const replyRangeMsg = new ReplyChannelRangeMessage(); replyRangeMsg.fullInformation = true; replyRangeMsg.firstBlocknum = 0; replyRangeMsg.numberOfBlocks = 0xffffffff; replyRangeMsg.shortChannelIds.push(new ShortChannelId(1, 1, 1)); sut.handleWireMessage(replyRangeMsg); await wait(0); // wait for promise to tick // After the reply, we will validate that the expect(sut.state).to.equal(GossipQueriesSyncState.AwaitingChannels); // At this point, we have sent along our channels query and are waiting // for the channels query result along with const replyChannelsMsg = new ReplyShortChannelIdsEndMessage(); replyChannelsMsg.complete = true; sut.handleWireMessage(replyChannelsMsg); await wait(0); // wait for promise to tick // After this reply, we are just waiting for the final messages to // arrive expect(sut.state).to.equal(GossipQueriesSyncState.AwaitingMessages); // now we just need to wait for things to finalize and we will double // the completion timeout await wait(100); // finally the promise should be resolve or rejected at this await promise; }); it('integration - rejects on range failure', async () => { // we should expect to start in the idel posion since we have not yet // execute the query expect(sut.state).to.equal(GossipQueriesSyncState.Idle); // Execute the query. Since this is a promise, we will resolve the test // when the queryRange method resolves successfully. If for some reason // it fails, we will reject with the error and the test will fail const promise = sut.queryRange(); // At this point, the query should have been sent and we will now be // awaiting completion of the channel range state machine. expect(sut.state).to.equal(GossipQueriesSyncState.AwaitingChannelRange); // At this point, we should have sent a query message and we will // reply from the peer with a response message. const replyRangeMsg = new ReplyChannelRangeMessage(); replyRangeMsg.fullInformation = false; replyRangeMsg.firstBlocknum = 0; replyRangeMsg.numberOfBlocks = 0xffffffff; sut.handleWireMessage(replyRangeMsg); // Wait for the promise to fail return promise.catch((err: GossipError) => { // The state should now be failed expect(sut.state).to.equal(GossipQueriesSyncState.Failed); // The error should be a RangeQuery failure expect(err.code).to.equal(GossipErrorCode.ReplyChannelRangeNoInformation); }); }); it('integration - rejects on channels failure', async () => { // we should expect to start in the idel posion since we have not yet // execute the query expect(sut.state).to.equal(GossipQueriesSyncState.Idle); // Execute the query. Since this is a promise, we will resolve the test // when the queryRange method resolves successfully. If for some reason // it fails, we will reject with the error and the test will fail const promise = sut.queryRange(); // At this point, the query should have been sent and we will now be // awaiting completion of the channel range state machine. expect(sut.state).to.equal(GossipQueriesSyncState.AwaitingChannelRange); // At this point, we should have sent a query message and we will // reply from the peer with a response message. const replyRangeMsg = new ReplyChannelRangeMessage(); replyRangeMsg.fullInformation = true; replyRangeMsg.firstBlocknum = 0; replyRangeMsg.numberOfBlocks = 0xffffffff; replyRangeMsg.shortChannelIds.push(new ShortChannelId(1, 1, 1)); sut.handleWireMessage(replyRangeMsg); await wait(0); // wait for promise to tick // After the reply, we will validate that the expect(sut.state).to.equal(GossipQueriesSyncState.AwaitingChannels); // At this point, we have sent along our channels query and are waiting // for the channels query result along with const replyChannelsMsg = new ReplyShortChannelIdsEndMessage(); replyChannelsMsg.complete = false; sut.handleWireMessage(replyChannelsMsg); // Wait for the promise to fail return promise.catch((err: GossipError) => { // The state should now be failed expect(sut.state).to.equal(GossipQueriesSyncState.Failed); // The error should be a RangeQuery failure expect(err.code).to.equal(GossipErrorCode.ReplyChannelsNoInfo); }); }); it('integration - large reply', async () => { // change the default completion timeout to 50ms (sut as any)._syncWatcher.completeAfterMs = 50; // we should expect to start in the idel posion since we have not yet // execute the query expect(sut.state).to.equal(GossipQueriesSyncState.Idle); // Execute the query. Since this is a promise, we will resolve the test // when the queryRange method resolves successfully. If for some reason // it fails, we will reject with the error and the test will fail const promise = sut.queryRange(); // At this point, the query should have been sent and we will now be // awaiting completion of the channel range state machine. expect(sut.state).to.equal(GossipQueriesSyncState.AwaitingChannelRange); // Let's handle ~96,000 replies split across const messages = 12; for (let i = 0; i < messages; i++) { const scids = []; for (let j = 0; j < 8000; j++) { scids.push(new ShortChannelId(i * 8000 + j, 0, 0)); } const replyRangeMsg = new ReplyChannelRangeMessage(); replyRangeMsg.fullInformation = i === messages - 1; replyRangeMsg.firstBlocknum = i * 8000; replyRangeMsg.numberOfBlocks = 1; replyRangeMsg.shortChannelIds = scids; sut.handleWireMessage(replyRangeMsg); await wait(0); // wait for promise to tick } // After the reply, we will validate that the expect(sut.state).to.equal(GossipQueriesSyncState.AwaitingChannels); // Now we need to wait for each of the sent batches to complete while (sut.state !== GossipQueriesSyncState.AwaitingMessages) { const replyChannelsMsg = new ReplyShortChannelIdsEndMessage(); replyChannelsMsg.complete = true; sut.handleWireMessage(replyChannelsMsg); await wait(0); // wait for promise to tick } // now we just need to wait for things to finalize and we will double // the completion timeout await wait(100); // finally the promise should be resolve or rejected at this await promise; }); });