"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.NodeAnnouncementMessage = void 0;
const bufio_1 = require("@node-dlc/bufio");
const common_1 = require("@node-dlc/common");
const crypto = __importStar(require("@node-dlc/crypto"));
const Address_1 = require("../domain/Address");
const MessageType_1 = require("../MessageType");
const getTlv_1 = require("../serialize/getTlv");
/**
 * This gossip message allows a node to indicate extra data associated with it,
 * in addition to its public key. To avoid trivial denial of service attacks,
 * nodes not associated with an already known channel are ignored.
 */
class NodeAnnouncementMessage {
    constructor() {
        /**
         * Type 257
         */
        this.type = MessageType_1.MessageType.NodeAnnouncement;
        /**
         * Addresses that the node allow public network connections
         * on. The type indicates how the address is encoded. Addresses
         * are in order of connectivity preference. Currently
         * supported addresses formats are IPv4, IPv6, Tor2 and Tor3
         */
        this.addresses = [];
    }
    static deserialize(payload) {
        const instance = new NodeAnnouncementMessage();
        const reader = new bufio_1.BufferReader(payload);
        reader.readUInt16BE(); // read off type
        instance.signature = reader.readBytes(64);
        const flen = reader.readUInt16BE();
        instance.features = common_1.BitField.fromBuffer(reader.readBytes(flen));
        instance.timestamp = reader.readUInt32BE();
        instance.nodeId = reader.readBytes(33);
        instance.rgbColor = reader.readBytes(3);
        instance.alias = reader.readBytes(32);
        instance.addresses = [];
        reader.readUInt16BE(); // addr_len
        while (!reader.eof) {
            const address = Address_1.Address.deserialize((0, getTlv_1.getTlv)(reader));
            instance.addresses.push(address);
        }
        return instance;
    }
    /**
     * Message hashing is after the first 66 bytes of the message
     * and excludes the type and signature. It performs a double
     * sha-256 hash of the remaining bytes.
     */
    static hash(msg) {
        const bytes = msg.serialize().slice(66); // type + signature
        return crypto.hash256(bytes);
    }
    /**
     * Verifies the message signature
     */
    static verifySignatures(msg) {
        const hash = NodeAnnouncementMessage.hash(msg);
        return crypto.verifySig(hash, msg.signature, msg.nodeId);
    }
    serialize() {
        const featuresBuffer = this.features.toBuffer();
        const featuresLen = featuresBuffer.length;
        // serialize addresses into buffers so we can obtain the length
        const addressBuffers = [];
        for (const address of this.addresses) {
            addressBuffers.push(address.serialize());
        }
        // obtain total address length
        // eslint-disable-next-line
        const addressBytes = addressBuffers.map(b => b.length).reduce((sum, val) => sum + val, 0); // prettier-ignore
        const len = 2 + // type
            64 + // signature
            2 + // flen
            featuresLen + // features length
            4 + // timestamp
            33 + // node_id
            3 + // rgb_color
            32 + // alias
            2 + // addresses
            addressBytes; // cumulative addr bytes
        const writer = new bufio_1.BufferWriter(Buffer.alloc(len));
        writer.writeUInt16BE(this.type);
        writer.writeBytes(this.signature);
        writer.writeUInt16BE(featuresLen);
        if (featuresLen > 0)
            writer.writeBytes(featuresBuffer);
        writer.writeUInt32BE(this.timestamp);
        writer.writeBytes(this.nodeId);
        writer.writeBytes(this.rgbColor);
        writer.writeBytes(this.alias);
        writer.writeUInt16BE(addressBytes);
        for (const addressBuffer of addressBuffers) {
            writer.writeBytes(addressBuffer);
        }
        return writer.toBuffer();
    }
}
exports.NodeAnnouncementMessage = NodeAnnouncementMessage;
NodeAnnouncementMessage.type = MessageType_1.MessageType.NodeAnnouncement;
//# sourceMappingURL=NodeAnnouncementMessage.js.map