import { BufferReader , BufferWriter } from "@node-lightning/bufio" ; import { BitField } from "@node-lightning/core" ; import { ShortChannelId } from "@node-lightning/core" ; import { shortChannelIdFromBuffer } from "@node-lightning/core" ; import * as crypto from "@node-lightning/crypto" ; import { ChannelFeatureFlags } from "../flags/ChannelFeatureFlags" ; import { MessageType } from "../MessageType" ; import { IWireMessage } from "./IWireMessage" ; /**
 * Message contains ownership information regarding a channel.
 * It ties each on-chain Bitcoin key to the associated Lightning
 * node key, and vice-versa. Proviing the existance of a channel
 * between node_1 and node_2 requires:
 *   1. proving that the funding pays to bitcoin_key_1 and bitcoin_key_2
 *   2. proving that node_1 owns bitcoin_key_1
 *   3. proving that node_2 owns bitcoin_key_2
 *
 * This also varifies that both nodes want to announce the channel.
 * The required data to perform all of these proofs is available
 * in this message.
 */ export class ChannelAnnouncementMessage implements IWireMessage { /**
     * Deserializes the Buffer into a ChannelAnnouncementMessage.
     */ public static deserialize ( payload ) { const instance = new ChannelAnnouncementMessage ( ) ; const reader = new BufferReader ( payload ) ; reader . readUInt16BE ( ) ; 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 ) ; return instance ; } /**
     * Message hashing is after the first 258 bytes of the message
     * and excludes the type and signatures. It performs a double
     * sha-256 hash of the remaining bytes.
     */ public static hash ( msg ) { const bytes = msg . serialize ( ) . slice ( 258 ) ; return crypto . hash256 ( bytes ) ; } /**
     * Performs validation the message was signed by each node and the
     * the corresponding bitcoin key is owned by the owner of the node.
     *
     * This is accomplished by:
     * 1. verifying the bitcoinSignatures1/2 are validate signatures
     *    from bitcoinKey1/2
     * 2. verifying the nodeSignature1/2 are validate signatures
     *     from nodeId1/2
     */ public static verifySignatures ( msg ) { const hash = ChannelAnnouncementMessage . hash ( msg ) ; return ( crypto . verifySig ( hash , msg . bitcoinSignature1 , msg . bitcoinKey1 ) && crypto . verifySig ( hash , msg . bitcoinSignature2 , msg . bitcoinKey2 ) && crypto . verifySig ( hash , msg . nodeSignature1 , msg . nodeId1 ) && crypto . verifySig ( hash , msg . nodeSignature2 , msg . nodeId2 ) ) ; } /**
     * The message type - 256
     */ public type : MessageType = MessageType . ChannelAnnouncement ; /**
     * Validate signature from node_1 of the hash containing the
     * data: features, chainHash, shortChannelId, nodeId1,
     * nodeId1, bitcoinKey1, and bitcoinKey2.
     */ public nodeSignature1 : Buffer ; /**
     * Validate signature from node_2 of the hash containing the
     * data: features, chainHash, shortChannelId, nodeId1,
     * nodeId1, bitcoinKey1, and bitcoinKey2.
     */ public nodeSignature2 : Buffer ; /**
     * Validate signature from bitcoin_key_1 of the hash containing the
     * data: features, chainHash, shortChannelId, nodeId1,
     * nodeId1, bitcoinKey1, and bitcoinKey2.
     */ public bitcoinSignature1 : Buffer ; /**
     * Validate signature from bitcoin_key_2 of the hash containing the
     * data: features, chainHash, shortChannelId, nodeId1,
     * nodeId1, bitcoinKey1, and bitcoinKey2.
     */ public bitcoinSignature2 : Buffer ; /**
     * The channel features are a bitmask
     */ public features : BitField < ChannelFeatureFlags > ; /**
     * Must set chain_hash to a 32-byte hash that uniquely identifies
     * the chain that the channel opened within.
     */ public chainHash : Buffer ; /**
     * ShortChannelId is a unique reference to the funding output of the
     * channel.
     */ public shortChannelId : ShortChannelId ; /**
     * The 33-byte compressed public key identifying the
     * numerically greater of the two DER-encoded keys
     * sorted in ascending numerical order.
     */ public nodeId1 : Buffer ; /**
     * The 33-byte compressed public key identifying the
     * numerically greater of the two DER-encoded keys
     * sorted in ascending numerical order.
     */ public nodeId2 : Buffer ; /**
     * The 33-byte compressed Bitcoin public key used by
     * node_id_1 to create the funding transaction.
     */ public bitcoinKey1 : Buffer ; /**
     * The 33-byte compressed Bitcoin public key used by
     * node_id_2 to create the funding transaction.
     */ public bitcoinKey2 : Buffer ; /**
     * Serializes the intancee into a Buffer suitable
     * for wire transport
     */ public serialize ( ) { const featuresBuffer = this . features . toBuffer ( ) ; const featuresLen = featuresBuffer . length ; const len = 2 + 64 + 64 + 64 + 64 + 2 + featuresLen + 32 + 8 + 33 + 33 + 33 + 33 ; const writer = new BufferWriter ( Buffer . alloc ( len ) ) ; writer . writeUInt16BE ( this . type ) ; writer . writeBytes ( this . nodeSignature1 ) ; writer . writeBytes ( this . nodeSignature2 ) ; writer . writeBytes ( this . bitcoinSignature1 ) ; writer . writeBytes ( this . bitcoinSignature2 ) ; writer . writeUInt16BE ( featuresLen ) ; if ( featuresLen > 0 ) writer . writeBytes ( featuresBuffer ) ; writer . writeBytes ( this . chainHash ) ; writer . writeBytes ( this . shortChannelId . toBuffer ( ) ) ; writer . writeBytes ( this . nodeId1 ) ; writer . writeBytes ( this . nodeId2 ) ; writer . writeBytes ( this . bitcoinKey1 ) ; writer . writeBytes ( this . bitcoinKey2 ) ; return writer . toBuffer ( ) ; } }