Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 | 1x 1x 1x 1x 1x 1x 1x 1x 13x 13x 13x 13x 13x 13x 4x 13x 13x 7x 7x 7x 6x 2x 4x 4x 13x 13x 13x 13x 13x 13x 13x 4x 4x 4x 7x 7x 7x 7x 15x 15x 15x 15x 15x 15x | import { ShortChannelId } from '@node-dlc/common';
import { ILogger } from '@node-dlc/logger';
import { QueryShortChannelIdsMessage } from '../messages/QueryShortChannelIdsMessage';
import { ReplyShortChannelIdsEndMessage } from '../messages/ReplyShortChannelIdsEndMessage';
import { IMessageSender } from '../Peer';
import { GossipError, GossipErrorCode } from './GossipError';
export enum ChannelsQueryState {
Idle,
Active,
Complete,
Failed,
}
/**
* This class manages the state machine for executing query_short_channel_ids
* and will resolve as either complete or with an error. This class can accept
* an arbitrarily large number of short channel ids and will chunk the requests
* appropriately.
*/
export class ChannelsQuery {
public chunkSize = 2000;
private _queue: ShortChannelId[] = [];
private _state: ChannelsQueryState;
private _error: GossipError;
private _resolve: () => void;
private _reject: (error: GossipError) => void;
constructor(
readonly chainHash: Buffer,
readonly peer: IMessageSender,
readonly logger: ILogger,
) {
this._state = ChannelsQueryState.Idle;
}
public get state(): ChannelsQueryState {
return this._state;
}
public get error(): Error {
return this._error;
}
public handleReplyShortChannelIdsEnd(
msg: ReplyShortChannelIdsEndMessage,
): void {
this.logger.debug(
'received reply_short_channel_ids_end - complete: %d',
msg.complete,
);
// If we receive a reply with complete=false, the remote peer
// does not maintain up-to-date channel information for the
// requested chain_hash
if (!msg.complete) {
const error = new GossipError(GossipErrorCode.ReplyChannelsNoInfo, msg);
this._transitionFailed(error);
return;
}
// This occurs when the last batch of information has been received
// but there is still more short_channel_ids to request. This scenario
// requires sending another QueryShortIds message
if (this._queue.length > 0) {
this._sendQuery();
} else {
this._transitionSuccess();
return;
}
}
/**
*
* @param scids
*/
public query(...scids: ShortChannelId[]): Promise<void> {
return new Promise((resolve, reject) => {
// enqueue the short ids
for (const scid of scids) {
this._queue.push(scid);
}
// Ensure we are in the active state
this._state = ChannelsQueryState.Active;
// send our query to the peer
this._sendQuery();
// capture the promise method for use when complete
this._resolve = resolve;
this._reject = reject;
});
}
private _transitionSuccess() {
Iif (this._state !== ChannelsQueryState.Active) return;
this._state = ChannelsQueryState.Complete;
this._resolve();
}
private _transitionFailed(error: GossipError) {
Iif (this._state !== ChannelsQueryState.Active) return;
this._state = ChannelsQueryState.Failed;
this._error = error;
this._reject(error);
}
private _sendQuery() {
// splice a chunk of work to do from the suqery
const scids = this._queue.splice(0, this.chunkSize);
const msg = new QueryShortChannelIdsMessage();
msg.chainHash = this.chainHash;
msg.shortChannelIds = scids;
this.logger.debug(
'sending query_short_channel_ids - scid_count:',
scids.length,
);
this.peer.sendMessage(msg);
}
}
|