Source: lib/Block.js

'use strict';

const BlockHeader = require('./BlockHeader');
const utils = require("./utils");
const Web3 = require("web3");

/**
 * Block
 */
class Block {
  /**
   * Split transaction data into txBytes, sig1, sig2
   * @param {string} txData hex string of data to split into txBytes, sig1, sig2
   */
  static splitTxData(txData) {
    let rawData = utils.removeHexPrefix(txData);
    let txBytes = utils.addHexPrefix(rawData.slice(0, rawData.length - 130 - 130));
    let sig1 = utils.addHexPrefix(rawData.slice(rawData.length - 130 - 130, rawData.length - 130));
    let sig2 = utils.addHexPrefix(rawData.slice(rawData.length - 130));
    return {
      txBytes,
      sig1,
      sig2,
    }
  }

  /**
   * Create a block
   * @param {number} blockNumber block number
   * @param {string} previousHash hex string of hash of previous block
   * @param {Transaction[]} transactions array of transactions
   */
  constructor(blockNumber, previousHash, transactions) {
    previousHash = utils.addHexPrefix(previousHash);
    let merkleData = [];
    transactions = transactions || [];
    transactions.forEach(tx => {
      //console.log(tx, tx.merkleData);
      if (tx && tx.merkleData) {
        merkleData.push(tx.merkleData());
      } else {
        merkleData.push(tx);
      }
    });
    this.blockHeader = new BlockHeader(blockNumber, previousHash, merkleData);
    this.transactions = transactions.map(tx => tx && tx.data ? tx.data() : tx).filter(tx => tx.length > 0);
    this.hashes = this.transactions.map(tx => Web3.utils.sha3(tx));
    this.confirmations = transactions.map(tx => "").filter(tx => tx.length > 0);
    this.types = transactions.map(tx => tx.type).filter(t => t != null);
  }

  /**
   * Sha3 hash of the hex string representing transactions in this block
   */
  get hash() {
    return Web3.utils.sha3(utils.addHexPrefix(this.toString()));
  }

  /**
   * Convert block to hex string of transactions without the prefix.
   */
  toString() {
    let txsHex = "";
    this.transactions.forEach(tx => txsHex += utils.removeHexPrefix(tx));
    this.types.forEach(tx => txsHex += tx);
    return this.blockHeader.toString(true) + txsHex;
  }

  /**
   * Create a block from json
   * @param {Object} json json string from toJSON()
   */
  static fromJSON(json) {
    let block = new Block(json.blockNumber, json.previousHash);
    block.transactions = json.transactions;
    block.confirmations = json.confirmations;
    block.types = json.types;
    block.hashes = json.hashes;
    block.blockHeader = BlockHeader.fromJSON(json.blockHeader);
    return block;
  }

  /**
   * Get Transaction in block
   */
  getTransactions() {
    let txs = [];
    for (let i = 0; i < this.transactions.length; i++) {
      const txData = this.transactions[i];
      let type = this.types[i] ? this.types[i] : 0;
      const tx = Transaction.fromTxData(txData, type);
      txs.push(tx);
    }
    return txs;
  }

  /**
   * Convert a block to JSON
   */
  toJSON() {
    // console.log(this, this.blockHeader);
    return {
      'blockHeader': this.blockHeader.toJSON(),
      'hashes': this.hashes.filter(tx => tx && tx.length > 0),
      'transactions': this.transactions.filter(tx => tx && tx.length > 0),
      'confirmations': this.confirmations.filter(cf => cf && cf.length > 0),
      'types': this.types.filter(t => t != null),
    }
  }

  /**
   * Returns a simplified json object representing a block
   */
  printBlock() {
    return {
      'blockNumber': this.blockHeader.blockNumber,
      'previousHash': this.blockHeader.previousHash,
      'merkleRoot': this.blockHeader.merkleRoot,
      'signature': utils.addHexPrefix(this.blockHeader.sigR + this.blockHeader.sigS + this.blockHeader.sigV),
      'transactions': this.transactions.filter(tx => tx && tx.length > 0),
      'hashes': this.hashes.filter(tx => tx && tx.length > 0),
      'confirmations': this.confirmations.filter(cf => cf && cf.length > 0),
      'types': this.types.filter(t => t != null),
      'timestamp': this.blockHeader.timestamp,
    };
  }
}

module.exports = Block;