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 | 1x 1x 1x 1x 1x 1x 1x 1x 18x 18x 18x 18x 18x 18x 4x 63x 63x 8x 8x 8x 55x 49x 6x 6x 16x 16x 96015x 16x 16x 16x 16x 6x 6x 6x 8x 8x 8x 8x 65x 65x 65x 65x 65x 65x | import { ShortChannelId } from "@node-lightning/core";
import { ILogger } from "@node-lightning/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);
}
}
|