All files / lib/gossip GossipMemoryStore.ts

71.7% Statements 38/53
60% Branches 6/10
80.95% Functions 17/21
72.55% Lines 37/51

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 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162    1x       1x             1x 117x 117x 117x 117x 117x     77x       110x       110x           52x 52x 52x 51x         52x 52x       150x                 149x       151x 151x 151x 78x 78x   78x           322x                               317x                           250x                                                         72x       72x 72x       104x 104x       104x         870x       841x       472x    
/* eslint-disable @typescript-eslint/require-await */
import { OutPoint } from '@node-dlc/bitcoin';
import { ShortChannelId, shortChannelIdFromNumber } from '@node-dlc/common';
 
import { ChannelAnnouncementMessage } from '../messages/ChannelAnnouncementMessage';
import { ChannelUpdateMessage } from '../messages/ChannelUpdateMessage';
import { ExtendedChannelAnnouncementMessage } from '../messages/ExtendedChannelAnnouncementMessage';
import { NodeAnnouncementMessage } from '../messages/NodeAnnouncementMessage';
import { IGossipStore } from './GossipStore';
 
/**
 * In-memory implementation of the IGossipStore.
 */
export class GossipMemoryStore implements IGossipStore {
  private _channelAnn = new Map<bigint, ChannelAnnouncementMessage>();
  private _channelByOutPoint = new Map<string, bigint>();
  private _channelUpd = new Map<bigint, ChannelUpdateMessage>();
  private _nodeAnn = new Map<string, NodeAnnouncementMessage>();
  private _nodeChannels = new Map<string, Set<bigint>>();
 
  public get channelAnnouncementCount(): number {
    return this._channelAnn.size;
  }
 
  public get channelUpdateCount(): number {
    return this._channelUpd.size;
  }
 
  public get nodeAnnouncementCount(): number {
    return this._nodeAnn.size;
  }
 
  public async saveChannelAnnouncement(
    msg: ChannelAnnouncementMessage,
  ): Promise<void> {
    const chanKey = getChanKey(msg.shortChannelId);
    this._channelAnn.set(chanKey, msg);
    if (msg instanceof ExtendedChannelAnnouncementMessage) {
      this._channelByOutPoint.set(
        msg.outpoint.toString(),
        msg.shortChannelId.toNumber(),
      );
    }
    await this._saveNodeChannel(msg.nodeId1, chanKey);
    await this._saveNodeChannel(msg.nodeId2, chanKey);
  }
 
  public async saveChannelUpdate(msg: ChannelUpdateMessage): Promise<void> {
    this._channelUpd.set(
      getChanUpdKey(getChanKey(msg.shortChannelId), msg.direction),
      msg,
    );
  }
 
  public async saveNodeAnnouncement(
    msg: NodeAnnouncementMessage,
  ): Promise<void> {
    this._nodeAnn.set(getNodeKey(msg.nodeId), msg);
  }
 
  public async findChannelsForNode(nodeId: Buffer): Promise<ShortChannelId[]> {
    const scidInts = this._nodeChannels.get(getNodeKey(nodeId));
    const results: ShortChannelId[] = [];
    if (!scidInts) return results;
    for (const scidInt of scidInts) {
      results.push(shortChannelIdFromNumber(scidInt));
    }
    return results;
  }
 
  public async findNodeAnnouncement(
    nodeId: Buffer,
  ): Promise<NodeAnnouncementMessage> {
    return this._nodeAnn.get(getNodeKey(nodeId));
  }
 
  public async findNodeAnnouncements(): Promise<NodeAnnouncementMessage[]> {
    return Array.from(this._nodeAnn.values());
  }
 
  public async findChannelAnnouncemnts(): Promise<
    ChannelAnnouncementMessage[]
  > {
    return Array.from(this._channelAnn.values());
  }
 
  public async findChannelAnnouncement(
    scid: ShortChannelId,
  ): Promise<ChannelAnnouncementMessage> {
    return this._channelAnn.get(getChanKey(scid));
  }
 
  public async findChannelAnnouncementByOutpoint(
    outpoint: OutPoint,
  ): Promise<ChannelAnnouncementMessage> {
    const scidNum = this._channelByOutPoint.get(outpoint.toString());
    return this._channelAnn.get(scidNum);
  }
 
  public async findChannelUpdate(
    scid: ShortChannelId,
    dir: number,
  ): Promise<ChannelUpdateMessage> {
    return this._channelUpd.get(getChanUpdKey(getChanKey(scid), dir));
  }
 
  public async deleteChannelAnnouncement(scid: ShortChannelId): Promise<void> {
    const msg = await this.findChannelAnnouncement(scid);
    if (!msg) return;
    const chanKey = getChanKey(scid);
 
    // delete channel
    this._channelAnn.delete(getChanKey(scid));
 
    // delete outpoint link
    if (msg instanceof ExtendedChannelAnnouncementMessage) {
      this._channelByOutPoint.delete(msg.outpoint.toString());
    }
 
    // delete channel_updates
    this._channelUpd.delete(getChanUpdKey(scid.toNumber(), 0));
    this._channelUpd.delete(getChanUpdKey(scid.toNumber(), 0));
 
    // delete node links
    this._nodeChannels.get(getNodeKey(msg.nodeId1)).delete(chanKey);
    this._nodeChannels.get(getNodeKey(msg.nodeId2)).delete(chanKey);
  }
 
  public async deleteChannelUpdate(
    scid: ShortChannelId,
    dir: number,
  ): Promise<void> {
    this._channelUpd.delete(getChanUpdKey(getChanKey(scid), dir));
  }
 
  public async deleteNodeAnnouncement(nodeId: Buffer): Promise<void> {
    this._nodeAnn.delete(getNodeKey(nodeId));
    this._nodeChannels.get(getNodeKey(nodeId));
  }
 
  private async _saveNodeChannel(nodeId: Buffer, chanKey: bigint) {
    const nodeKey = getNodeKey(nodeId);
    this._nodeChannels.set(
      nodeKey,
      this._nodeChannels.get(nodeKey) || new Set<bigint>(),
    );
    this._nodeChannels.get(nodeKey).add(chanKey);
  }
}
 
function getNodeKey(nodeId: Buffer): string {
  return nodeId.toString('hex');
}
 
function getChanKey(scid: ShortChannelId): bigint {
  return scid.toNumber();
}
 
function getChanUpdKey(chanKey: bigint, direction: number): bigint {
  return (chanKey << BigInt(8)) | BigInt(direction);
}