Source: primitives/headers.js

/*!
 * headers.js - headers object for bcoin
 * Copyright (c) 2014-2015, Fedor Indutny (MIT License)
 * Copyright (c) 2014-2017, Christopher Jeffrey (MIT License).
 * https://github.com/bcoin-org/bcoin
 */

'use strict';

const bio = require('bufio');
const util = require('../utils/util');
const AbstractBlock = require('./abstractblock');
const {inspectSymbol} = require('../utils');

/**
 * Headers
 * Represents block headers obtained
 * from the network via `headers`.
 * @alias module:primitives.Headers
 * @extends AbstractBlock
 */

class Headers extends AbstractBlock {
  /**
   * Create headers.
   * @constructor
   * @param {Object} options
   */

  constructor(options) {
    super();

    if (options)
      this.parseOptions(options);
  }

  /**
   * Perform non-contextual
   * verification on the headers.
   * @returns {Boolean}
   */

  verifyBody() {
    return true;
  }

  /**
   * Get size of the headers.
   * @returns {Number}
   */

  getSize() {
    return 81;
  }

  /**
   * Serialize the headers to a buffer writer.
   * @param {BufferWriter} bw
   */

  toWriter(bw) {
    this.writeHead(bw);
    bw.writeVarint(0);
    return bw;
  }

  /**
   * Serialize the headers.
   * @returns {Buffer|String}
   */

  toRaw() {
    const size = this.getSize();
    return this.toWriter(bio.write(size)).render();
  }

  /**
   * Inject properties from buffer reader.
   * @private
   * @param {Buffer} data
   */

  fromReader(br) {
    this.readHead(br);
    br.readVarint();
    return this;
  }

  /**
   * Inject properties from serialized data.
   * @private
   * @param {Buffer} data
   */

  fromRaw(data) {
    return this.fromReader(bio.read(data));
  }

  /**
   * Instantiate headers from buffer reader.
   * @param {BufferReader} br
   * @returns {Headers}
   */

  static fromReader(br) {
    return new this().fromReader(br);
  }

  /**
   * Instantiate headers from serialized data.
   * @param {Buffer} data
   * @param {String?} enc - Encoding, can be `'hex'` or null.
   * @returns {Headers}
   */

  static fromRaw(data, enc) {
    if (typeof data === 'string')
      data = Buffer.from(data, enc);
    return new this().fromRaw(data);
  }

  /**
   * Instantiate headers from serialized data.
   * @param {Buffer} data
   * @param {String?} enc - Encoding, can be `'hex'` or null.
   * @returns {Headers}
   */

  static fromHead(data, enc) {
    if (typeof data === 'string')
      data = Buffer.from(data, enc);
    return new this().fromHead(data);
  }

  /**
   * Instantiate headers from a chain entry.
   * @param {ChainEntry} entry
   * @returns {Headers}
   */

  static fromEntry(entry) {
    const headers = new this();
    headers.version = entry.version;
    headers.prevBlock = entry.prevBlock;
    headers.merkleRoot = entry.merkleRoot;
    headers.time = entry.time;
    headers.bits = entry.bits;
    headers.nonce = entry.nonce;
    headers._hash = entry.hash;
    headers._hhash = entry.hash;
    return headers;
  }

  /**
   * Convert the block to a headers object.
   * @returns {Headers}
   */

  toHeaders() {
    return this;
  }

  /**
   * Convert the block to a headers object.
   * @param {Block|MerkleBlock} block
   * @returns {Headers}
   */

  static fromBlock(block) {
    const headers = new this(block);
    headers._hash = block._hash;
    headers._hhash = block._hhash;
    return headers;
  }

  /**
   * Convert the block to an object suitable
   * for JSON serialization.
   * @returns {Object}
   */

  toJSON() {
    return this.getJSON();
  }

  /**
   * Convert the block to an object suitable
   * for JSON serialization. Note that the hashes
   * will be reversed to abide by bitcoind's legacy
   * of little-endian uint256s.
   * @param {Network} network
   * @param {CoinView} view
   * @param {Number} height
   * @returns {Object}
   */

  getJSON(network, view, height) {
    return {
      hash: this.rhash(),
      height: height,
      version: this.version,
      prevBlock: util.revHex(this.prevBlock),
      merkleRoot: util.revHex(this.merkleRoot),
      time: this.time,
      bits: this.bits,
      nonce: this.nonce
    };
  }

  /**
   * Inject properties from json object.
   * @private
   * @param {Object} json
   */

  fromJSON(json) {
    this.parseJSON(json);
    return this;
  }

  /**
   * Instantiate a merkle block from a jsonified block object.
   * @param {Object} json - The jsonified block object.
   * @returns {Headers}
   */

  static fromJSON(json) {
    return new this().fromJSON(json);
  }

  /**
   * Inspect the headers and return a more
   * user-friendly representation of the data.
   * @returns {Object}
   */

  [inspectSymbol]() {
    return this.format();
  }

  /**
   * Inspect the headers and return a more
   * user-friendly representation of the data.
   * @param {CoinView} view
   * @param {Number} height
   * @returns {Object}
   */

  format(view, height) {
    return {
      hash: this.rhash(),
      height: height != null ? height : -1,
      date: util.date(this.time),
      version: this.version.toString(16),
      prevBlock: util.revHex(this.prevBlock),
      merkleRoot: util.revHex(this.merkleRoot),
      time: this.time,
      bits: this.bits,
      nonce: this.nonce
    };
  }

  /**
   * Test an object to see if it is a Headers object.
   * @param {Object} obj
   * @returns {Boolean}
   */

  static isHeaders(obj) {
    return obj instanceof Headers;
  }
}

/*
 * Expose
 */

module.exports = Headers;