All files / lib/messages InitMessage.ts

100% Statements 36/36
100% Branches 2/2
100% Functions 4/4
100% Lines 36/36

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 1091x 1x     1x 1x                       1x               22x 22x     22x       22x 20x     20x 20x       20x     20x 4x         4x 6x 6x   4x         20x           31x         31x         31x             8x     8x     8x 8x     8x 8x 8x 8x     8x 6x 6x 6x     8x      
import { BufferReader, BufferWriter } from '@node-dlc/bufio';
import { BitField } from '@node-dlc/common';
 
import { InitFeatureFlags } from '../flags/InitFeatureFlags';
import { MessageType } from '../MessageType';
import { readTlvs } from '../serialize/readTlvs';
import { IWireMessage } from './IWireMessage';
 
/**
 * InitMessage is defined in BOLT #1. Once authentication is complete, the first
 * message reveals the features supported or required by the node sending the
 * message. This message is sent even on a reconnection.
 *
 * This message contains two fields; global features and local features, that
 * are used to signal how the message should operate. The values of are defined
 * in the BOLT #9.
 */
export class InitMessage implements IWireMessage {
  /**
   * Processes a buffer containing the message information. This method
   * will capture the arbitrary length global and local
   * features into two internal properties of the newly constructed
   * init message object.
   */
  public static deserialize(buffer: Buffer): InitMessage {
    const instance = new InitMessage();
    const reader = new BufferReader(buffer);
 
    // read the type bytes
    reader.readUInt16BE();
 
    // read the global features and per the specification, the global
    // features should not exceed features greater than 13.
    const gflen = reader.readUInt16BE();
    const gf = BitField.fromBuffer(reader.readBytes(gflen));
 
    // Read the local length and parse into a BN value.
    const lflen = reader.readUInt16BE();
    const lf = BitField.fromBuffer(reader.readBytes(lflen));
 
    // construct a single features object by bitwise or of the global and
    // local features.
    instance.features = new BitField().or(gf).or(lf);
 
    // process TLVs
    readTlvs(reader, (type: bigint, valueReader: BufferReader) => {
      switch (type) {
        // Process networks TLVs which is a series of chain_hash 32
        // byte values. This method will simply read from the stream
        // until every thing has been read
        case BigInt(1): {
          while (!valueReader.eof) {
            const chainHash = valueReader.readBytes(32);
            instance.chainHashes.push(chainHash);
          }
          return true;
        }
      }
    });
 
    return instance;
  }
 
  /**
   * Message type 16
   */
  public type: MessageType = MessageType.Init;
 
  /**
   * BitField containing the features provided in by the local or remote node
   */
  public features: BitField<InitFeatureFlags> = new BitField();
 
  /**
   * Supported chain_hashes for the remote peer
   */
  public chainHashes: Buffer[] = [];
 
  /**
   * Serialize will construct a properly formatted message based on the
   * properties of the configured message.
   */
  public serialize(): Buffer {
    const writer = new BufferWriter();
 
    // write the type
    writer.writeUInt16BE(this.type);
 
    // write gflen
    const gflen = 0;
    writer.writeUInt16BE(gflen);
 
    // write features
    const features = this.features.toBuffer();
    const featuresLen = features.length;
    writer.writeUInt16BE(featuresLen);
    writer.writeBytes(features);
 
    // write chainhash tlv
    if (this.chainHashes.length) {
      writer.writeBigSize(1); // type
      writer.writeBigSize(this.chainHashes.length * 32); // length
      writer.writeBytes(Buffer.concat(this.chainHashes)); // value
    }
 
    return writer.toBuffer();
  }
}