All files / lib/messages ExtendedChannelAnnouncementMessage.ts

98.33% Statements 59/60
66.67% Branches 2/3
100% Functions 4/4
98.33% Lines 59/60

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 1301x 1x 1x 1x 1x 1x                           1x           135x 135x 135x 135x 135x 135x 135x 135x 135x 135x 135x 135x 135x 135x       12x 12x 12x   12x 12x 12x 12x   12x 12x 12x 12x 12x 12x 12x 12x     12x 13x         12x       12x           1x 1x             12x                                 1x 1x     1x 1x 1x 1x     1x 1x 1x     1x 1x 1x     1x 1x 1x   1x      
import { BufferReader, BufferWriter } from "@node-lightning/bufio";
import { BitField, HashByteOrder, HashValue } from "@node-lightning/core";
import { shortChannelIdFromBuffer } from "@node-lightning/core";
import { OutPoint } from "@node-lightning/core";
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) {
        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() {
        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()]);
    }
}