/*! * memblock.js - memblock block object for bcoin * Copyright (c) 2014-2015, Fedor Indutny (MIT License) * Copyright (c) 2014-2016, Christopher Jeffrey (MIT License). * https://github.com/bcoin-org/bcoin */ 'use strict'; module.exports = MemBlock; var utils = require('../utils/utils'); var AbstractBlock = require('./abstractblock'); var Block = require('./block'); var Script = require('../script/script'); var BufferReader = require('../utils/reader'); /** * A block object which is essentially a "placeholder" * for a full {@link Block} object. The v8 garbage * collector's head will explode if there is too much * data on the javascript heap. Blocks can currently * be up to 1mb in size. In the future, they may be * 2mb, 8mb, or maybe 20mb, who knows? A MemBlock * is an optimization in BCoin which defers parsing of * the serialized transactions (the block Buffer) until * the block has passed through the chain queue and * is about to enter the chain. This keeps a lot data * off of the javascript heap for most of the time a * block even exists in memory, and manages to keep a * lot of strain off of the garbage collector. Having * 500mb of blocks on the js heap would not be a good * thing. * @exports MemBlock * @constructor * @param {NakedBlock} options * @property {Boolean} memory - Always true. * @property {Number} coinbaseHeight - The coinbase height which * was extracted by the parser (the coinbase is the only * transaction we parse ahead of time). * @property {Buffer} raw - The raw block data. */ function MemBlock(options) { if (!(this instanceof MemBlock)) return new MemBlock(options); AbstractBlock.call(this, options); this.memory = true; this.coinbaseHeight = -1; this.raw = null; if (options) this.fromOptions(options); } utils.inherits(MemBlock, AbstractBlock); /** * Inject properties from options object. * @private * @param {NakedBlock} options */ MemBlock.prototype.fromOptions = function fromOptions(options) { this.coinbaseHeight = options.coinbaseHeight; this.raw = options.raw; return this; }; /** * Instantiate memblock from options object. * @param {NakedBlock} options * @returns {MemBlock} */ MemBlock.fromOptions = function fromOptions(options) { return new MemBlock().fromOptions(options); }; /** * Get the full block size. * @returns {Number} */ MemBlock.prototype.getSize = function getSize() { return this.raw.length; }; /** * Verify the block headers. * @alias MemBlock#verify * @param {Object?} ret - Return object, may be * set with properties `reason` and `score`. * @returns {Boolean} */ MemBlock.prototype._verify = function _verify(ret) { return this.verifyHeaders(ret); }; /** * Retrieve the coinbase height from the coinbase input script (already * extracted in actuality). * @returns {Number} height (-1 if not present). */ MemBlock.prototype.getCoinbaseHeight = function getCoinbaseHeight() { return this.coinbaseHeight; }; /** * Inject properties from serialized data. * @private * @param {Buffer} data */ MemBlock.prototype.fromRaw = function fromRaw(data) { var p = BufferReader(data, true); var height = -1; var inCount, input; this.version = p.readU32(); // Technically signed this.prevBlock = p.readHash('hex'); this.merkleRoot = p.readHash('hex'); this.ts = p.readU32(); this.bits = p.readU32(); this.nonce = p.readU32(); this.totalTX = p.readVarint(); if (this.version > 1 && this.totalTX > 0) { p.seek(4); inCount = p.readVarint(); if (inCount === 0) { if (p.readU8() !== 0) inCount = p.readVarint(); } if (inCount > 0) { p.seek(36); input = p.readVarBytes(); height = Script.getCoinbaseHeight(input); } } this.coinbaseHeight = height; this.raw = p.data; return this; }; /** * Insantiate a memblock from serialized data. * @param {Buffer} data * @returns {MemBlock} */ MemBlock.fromRaw = function fromRaw(data) { return new MemBlock().fromRaw(data); }; /** * Return serialized block data. * @returns {Buffer} */ MemBlock.prototype.toRaw = function toRaw() { return this.raw; }; /** * Return serialized block data. * @returns {Buffer} */ MemBlock.prototype.toNormal = function toNormal() { return this.raw; }; /** * Parse the serialized block data * and create an actual {@link Block}. * @returns {Block} * @throws Parse error */ MemBlock.prototype.toBlock = function toBlock() { var block = Block.fromRaw(this.raw); block._hash = this._hash; block._cbHeight = this.coinbaseHeight; this.raw = null; return block; }; /** * Test whether an object is a MemBlock. * @param {Object} obj * @returns {Boolean} */ MemBlock.isMemBlock = function isMemBlock(obj) { return obj && obj.memory && typeof obj.toBlock === 'function'; }; /* * Expose */ module.exports = MemBlock;