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 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 | 1x 1x 1x 1x 1x 1x 1x 1x 9x 9x 9x 9x 1x 1x 2x 1x 1x 1x 14x 8x 8x 1x 7x 6x 6x 6x 6x 7x 6x 6x 6x 6x 7x 7x 7x 6x 3x 3x 1x 1x 2x 2x 2x 2x 3x 3x 3x 2x 2x 2x 3x 3x 3x 3x 3x 3x 14x 6x 3x | import { OutPoint } from "@node-lightning/core";
import { IGossipEmitter, IWireMessage, MessageType } from "@node-lightning/wire";
import { ChannelAnnouncementMessage } from "@node-lightning/wire";
import { ChannelUpdateMessage } from "@node-lightning/wire";
import { NodeAnnouncementMessage } from "@node-lightning/wire";
import { EventEmitter } from "events";
import { Channel } from "./channel";
import { ChannelSettings } from "./channel-settings";
import { channelFromMessage } from "./deserialize/channel-from-message";
import { channelSettingsFromMessage } from "./deserialize/channel-settings-from-message";
import { Graph } from "./graph";
import { ChannelNotFoundError } from "./graph-error";
import { GraphError } from "./graph-error";
import { Node } from "./node";
// tslint:disable-next-line: interface-name
export declare interface GraphManager {
on(event: "node", fn: (node: Node) => void): this;
on(event: "channel", fn: (channel: Channel) => void): this;
on(event: "channel_update", fn: (channel: Channel, settings: ChannelSettings) => void): this;
on(event: "error", fn: (err: GraphError) => void): this;
}
/**
* GraphManager is a facade around a Graph object. It converts in-bound
* gossip messages from the wire into a graph representation. Channels
* can also be removed by monitoring the block chain via a chainmon object.
*/
export class GraphManager extends EventEmitter {
public graph: Graph;
public gossipEmitter: IGossipEmitter;
constructor(gossipManager: IGossipEmitter, graph = new Graph()) {
super();
this.graph = graph;
this.gossipEmitter = gossipManager;
this.gossipEmitter.on("message", this._onMessage.bind(this));
}
/**
* Closes channel via the outpoint
* @param outpoint
*/
public removeChannel(outpoint: OutPoint) {
const outpointStr = outpoint.toString();
for (const channel of this.graph.channels.values()) {
if (outpointStr === channel?.channelPoint?.toString()) {
this.graph.removeChannel(channel);
this.emit("channel_closed", channel);
return;
}
}
}
private _onMessage(msg: IWireMessage) {
// channel_announcement messages are processed by:
// First ensuring that we don't already have a duplicate channel.
// We then check to see if we need to insert node
// references. Inserting temporary node's is required because we
// may receieve a channel_announcement without ever receiving
// node_announcement messages.
if (isChannelAnnouncment(msg)) {
const channel = channelFromMessage(msg);
// abort processing if the channel already exists
if (this.graph.getChannel(msg.shortChannelId)) {
return;
}
// construct node1 if required
if (!this.graph.getNode(msg.nodeId1)) {
const node1 = new Node();
node1.nodeId = msg.nodeId1;
this.graph.addNode(node1);
this.emit("node", node1);
}
// construct node2 if required
if (!this.graph.getNode(msg.nodeId2)) {
const node2 = new Node();
node2.nodeId = msg.nodeId2;
this.graph.addNode(node2);
this.emit("node", node2);
}
// finally attach the channel
this.graph.addChannel(channel);
this.emit("channel", channel);
return;
}
// channel_update messages are processed by:
// * looking for the existing channel, if it doesn't then an error is thrown.
// * updating the existing channel
// The GossipFilter in Wire should ensure that channel_announcement messages
// are always transmitted prior to channel_update messages being announced.
if (isChannelUpdate(msg)) {
// first validate we have a channel
const channel = this.graph.getChannel(msg.shortChannelId);
if (!channel) {
this.emit("error", new ChannelNotFoundError(msg.shortChannelId));
return;
}
// construct the settings and update the channel
const settings = channelSettingsFromMessage(msg);
channel.updateSettings(settings);
this.emit("channel_update", channel, settings);
return;
}
// node_announcement messages are processed by:
// * finding or creating the node (if it doesn't exist)
// * updating the node with values from the announcement
Eif (isNodeAnnouncement(msg)) {
let node = this.graph.getNode(msg.nodeId);
if (!node) {
node = new Node();
node.nodeId = msg.nodeId;
this.graph.addNode(node);
}
node.features = msg.features;
node.lastUpdate = msg.timestamp;
node.alias = msg.alias;
node.rgbColor = msg.rgbColor;
node.addresses = msg.addresses;
this.emit("node", node);
}
}
}
function isChannelAnnouncment(msg: IWireMessage): msg is ChannelAnnouncementMessage {
return msg.type === MessageType.ChannelAnnouncement;
}
function isChannelUpdate(msg: IWireMessage): msg is ChannelUpdateMessage {
return msg.type === MessageType.ChannelUpdate;
}
function isNodeAnnouncement(msg: IWireMessage): msg is NodeAnnouncementMessage {
return msg.type === MessageType.NodeAnnouncement;
}
|