@node-lightning/graph
Version:
Lightning Network P2P Graph
116 lines • 4.88 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.GraphManager = void 0;
const wire_1 = require("@node-lightning/wire");
const events_1 = require("events");
const channel_from_message_1 = require("./deserialize/channel-from-message");
const channel_settings_from_message_1 = require("./deserialize/channel-settings-from-message");
const graph_1 = require("./graph");
const graph_error_1 = require("./graph-error");
const node_1 = require("./node");
/**
* 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.
*/
class GraphManager extends events_1.EventEmitter {
constructor(gossipManager, graph = new graph_1.Graph()) {
super();
this.graph = graph;
this.gossipEmitter = gossipManager;
this.gossipEmitter.on("message", this._onMessage.bind(this));
}
/**
* Closes channel via the outpoint
* @param outpoint
*/
removeChannel(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;
}
}
}
_onMessage(msg) {
// 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 = channel_from_message_1.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_1.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_1.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 graph_error_1.ChannelNotFoundError(msg.shortChannelId));
return;
}
// construct the settings and update the channel
const settings = channel_settings_from_message_1.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
if (isNodeAnnouncement(msg)) {
let node = this.graph.getNode(msg.nodeId);
if (!node) {
node = new node_1.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);
}
}
}
exports.GraphManager = GraphManager;
function isChannelAnnouncment(msg) {
return msg.type === wire_1.MessageType.ChannelAnnouncement;
}
function isChannelUpdate(msg) {
return msg.type === wire_1.MessageType.ChannelUpdate;
}
function isNodeAnnouncement(msg) {
return msg.type === wire_1.MessageType.NodeAnnouncement;
}
//# sourceMappingURL=graph-manager.js.map