All files / lib/messages ExtendedChannelAnnouncementMessage.ts

67.8% Statements 40/59
33.33% Branches 1/3
75% Functions 3/4
67.8% Lines 40/59

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 1341x 1x 1x   1x 1x                           1x               50x 50x 50x 50x 50x 50x 50x 50x 50x 50x 50x 50x 50x 50x           1x 1x 1x   1x 1x 1x 1x   1x 1x 1x 1x 1x 1x 1x 1x     1x 1x         1x       1x                           1x                                                                                        
import { HashByteOrder, HashValue, OutPoint } from '@node-dlc/bitcoin';
import { BufferReader, BufferWriter } from '@node-dlc/bufio';
import { BitField, shortChannelIdFromBuffer } from '@node-dlc/common';
 
import { readTlvs } from '../serialize/readTlvs';
import { ChannelAnnouncementMessage } from './ChannelAnnouncementMessage';
 
/**
 * Decorator for the channel_announcement that includes the additional
 * information provided by the on-chain validation. Specifically, the
 * channel_announcement message only has a short_channel_id with block, tx num,
 * and vout num. We need to obtain the txid as well as the outpoint value to
 * determine the value of the channel.
 *
 * This information is stored in this decorator class which can be broadcast
 * and used downstream by clients that need both sets of information. Additionally
 * the use of this decorator allows us to store the on-chain data along side the
 * channel_announcement data if so desired.
 */
export class ExtendedChannelAnnouncementMessage extends ChannelAnnouncementMessage {
  /**
   * Constructs a new ExtendedChannelAnnouncementMessage from the plain-jane
   * ChannelAnnouncementMessage
   */
  public static fromMessage(
    msg: ChannelAnnouncementMessage,
  ): ExtendedChannelAnnouncementMessage {
    const instance = new ExtendedChannelAnnouncementMessage();
    instance.bitcoinKey1 = msg.bitcoinKey1;
    instance.bitcoinKey2 = msg.bitcoinKey2;
    instance.bitcoinSignature1 = msg.bitcoinSignature1;
    instance.bitcoinSignature2 = msg.bitcoinSignature2;
    instance.chainHash = msg.chainHash;
    instance.features = msg.features;
    instance.nodeId1 = msg.nodeId1;
    instance.nodeId2 = msg.nodeId2;
    instance.nodeSignature1 = msg.nodeSignature1;
    instance.nodeSignature2 = msg.nodeSignature2;
    instance.shortChannelId = msg.shortChannelId;
    instance.type = msg.type;
    return instance;
  }
 
  public static deserialize(
    payload: Buffer,
  ): ExtendedChannelAnnouncementMessage {
    const instance = new ExtendedChannelAnnouncementMessage();
    const reader = new BufferReader(payload);
    reader.readUInt16BE(); // read off type
 
    instance.nodeSignature1 = reader.readBytes(64);
    instance.nodeSignature2 = reader.readBytes(64);
    instance.bitcoinSignature1 = reader.readBytes(64);
    instance.bitcoinSignature2 = reader.readBytes(64);
 
    const len = reader.readUInt16BE();
    instance.features = BitField.fromBuffer(reader.readBytes(len));
    instance.chainHash = reader.readBytes(32);
    instance.shortChannelId = shortChannelIdFromBuffer(reader.readBytes(8));
    instance.nodeId1 = reader.readBytes(33);
    instance.nodeId2 = reader.readBytes(33);
    instance.bitcoinKey1 = reader.readBytes(33);
    instance.bitcoinKey2 = reader.readBytes(33);
 
    // read the TLVs for the extended data
    readTlvs(reader, (type: bigint, valueReader: BufferReader) => {
      switch (type) {
        // process the outpoint which is obtained after looking onchain
        // at the funding transaction. This is encoded as a 32-byte txid
        // and a 2 byte uint output index
        case BigInt(16777271): {
          instance.outpoint = new OutPoint(
            HashValue.fromRpc(valueReader.readBytes(32).toString('hex')),
            valueReader.readTUInt16(),
          );
          return true;
        }
        // process the channel capacity which is obtained  after looking
        // onchain at the funding transaction outpoint. This is encoded
        // as a single tuint64 value.
        case BigInt(16777273): {
          instance.capacity = valueReader.readTUInt64();
          return true;
        }
        default:
          return false;
      }
    });
 
    return instance;
  }
 
  /**
   * OutPoint for the channel that includes the transaction identifier as well
   * as the vout index. This information is obtained by finding the transaction
   * in a block based on the short_channel_id.
   */
  public outpoint: OutPoint;
 
  /**
   * Capacity of the funding transaction. This information is obtained from on-chain
   * validation of the transaction.
   */
  public capacity: bigint;
 
  public serialize(): Buffer {
    const chanAnnBuffer = super.serialize();
    const writer = new BufferWriter();
 
    // outpoint value
    let valueWriter = new BufferWriter();
    valueWriter.writeBytes(this.outpoint.txid.serialize(HashByteOrder.RPC));
    valueWriter.writeTUInt16(this.outpoint.outputIndex);
    let value = valueWriter.toBuffer();
 
    // outpoint tlv
    writer.writeBigSize(16777271);
    writer.writeBigSize(value.length);
    writer.writeBytes(value);
 
    // capacity value
    valueWriter = new BufferWriter();
    valueWriter.writeTUInt64(this.capacity);
    value = valueWriter.toBuffer();
 
    // capacity tlv
    writer.writeBigSize(16777273);
    writer.writeBigSize(value.length);
    writer.writeBytes(value);
 
    return Buffer.concat([chanAnnBuffer, writer.toBuffer()]);
  }
}