diff --git a/lib/bcoin/chainentry.js b/lib/bcoin/chainentry.js index 79eb6006..f8204609 100644 --- a/lib/bcoin/chainentry.js +++ b/lib/bcoin/chainentry.js @@ -25,7 +25,7 @@ var InvItem = bcoin.packets.InvItem; * @exports ChainEntry * @constructor * @param {Chain} chain - * @param {Object} data + * @param {Object} options * @param {ChainEntry} prev * @property {Hash} hash * @property {Number} version - Transaction version. Note that BCoin reads @@ -41,27 +41,73 @@ var InvItem = bcoin.packets.InvItem; * @property {ReversedHash} rhash - Reversed block hash (uint256le). */ -function ChainEntry(chain, data, prev) { +function ChainEntry(chain, options, prev) { if (!(this instanceof ChainEntry)) - return new ChainEntry(chain, data); + return new ChainEntry(chain, options, prev); this.chain = chain; + this.network = chain ? chain.network : bcoin.network.get(); - this.network = this.chain - ? this.chain.network - : bcoin.network.get(); + this.hash = constants.NULL_HASH; + this.version = 1; + this.prevBlock = constants.NULL_HASH; + this.merkleRoot = constants.NULL_HASH; + this.ts = 0; + this.bits = 0; + this.nonce = 0; + this.height = -1; + this.chainwork = null; - this.hash = data.hash; - this.version = data.version; - this.prevBlock = data.prevBlock; - this.merkleRoot = data.merkleRoot; - this.ts = data.ts; - this.bits = data.bits; - this.nonce = data.nonce; - this.height = data.height; - this.chainwork = data.chainwork || this.getChainwork(prev); + if (options) + this.fromOptions(options, prev); } +/** + * Inject properties from options. + * @private + * @param {Object} options + * @param {ChainEntry} prev - Previous entry. + */ + +ChainEntry.prototype.fromOptions = function fromOptions(options, prev) { + assert(options, 'Block data is required.'); + assert(typeof options.hash === 'string'); + assert(utils.isNumber(options.version)); + assert(typeof options.prevBlock === 'string'); + assert(typeof options.merkleRoot === 'string'); + assert(utils.isNumber(options.ts)); + assert(utils.isNumber(options.bits)); + assert(utils.isNumber(options.nonce)); + assert(!options.chainwork || bn.isBN(options.chainwork)); + + this.hash = options.hash; + this.version = options.version; + this.prevBlock = options.prevBlock; + this.merkleRoot = options.merkleRoot; + this.ts = options.ts; + this.bits = options.bits; + this.nonce = options.nonce; + this.height = options.height; + this.chainwork = options.chainwork; + + if (!this.chainwork) + this.chainwork = this.getChainwork(prev); + + return this; +}; + +/** + * Instantiate chainentry from options. + * @param {Chain} chain + * @param {Object} options + * @param {ChainEntry} prev - Previous entry. + * @returns {ChainEntry} + */ + +ChainEntry.fromOptions = function fromOptions(chain, options, prev) { + return new ChainEntry(chain).fromOptions(options, prev); +}; + /** * The max chainwork (1 << 256). * @const {BN} @@ -401,6 +447,41 @@ ChainEntry.prototype.__defineGetter__('rhash', function() { return utils.revHex(this.hash); }); +/** + * Inject properties from block. + * @private + * @param {Block|MerkleBlock} block + * @param {ChainEntry} prev - Previous entry. + */ + +ChainEntry.prototype.fromBlock = function fromBlock(block, prev) { + assert(block.height !== -1); + + this.hash = block.hash('hex'); + this.version = block.version; + this.prevBlock = block.prevBlock; + this.merkleRoot = block.merkleRoot; + this.ts = block.ts; + this.bits = block.bits; + this.nonce = block.nonce; + this.height = block.height; + this.chainwork = this.getChainwork(prev); + + return this; +}; + +/** + * Instantiate chainentry from block. + * @param {Chain} chain + * @param {Block|MerkleBlock} block + * @param {ChainEntry} prev - Previous entry. + * @returns {ChainEntry} + */ + +ChainEntry.fromBlock = function fromBlock(chain, block, prev) { + return new ChainEntry(chain).fromBlock(block, prev); +}; + /** * Serialize the entry to internal database format. * @returns {Buffer} @@ -425,29 +506,39 @@ ChainEntry.prototype.toRaw = function toRaw(writer) { }; /** - * Deserialize the entry. - * @param {Chain} chain - * @param {Buffer} buf - * @returns {ChainEntry} + * Inject properties from serialized data. + * @private + * @param {Buffer} data */ -ChainEntry.fromRaw = function fromRaw(chain, buf) { - var p = new BufferReader(buf, true); +ChainEntry.prototype.fromRaw = function fromRaw(data) { + var p = new BufferReader(data, true); var hash = utils.hash256(p.readBytes(80)); p.seek(-80); - return new ChainEntry(chain, { - hash: hash.toString('hex'), - version: p.readU32(), // Technically signed - prevBlock: p.readHash('hex'), - merkleRoot: p.readHash('hex'), - ts: p.readU32(), - bits: p.readU32(), - nonce: p.readU32(), - height: p.readU32(), - chainwork: new bn(p.readBytes(32), 'le') - }); + this.hash = hash.toString('hex'); + 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.height = p.readU32(); + this.chainwork = new bn(p.readBytes(32), 'le'); + + return this; +}; + +/** + * Deserialize the entry. + * @param {Chain} chain + * @param {Buffer} data + * @returns {ChainEntry} + */ + +ChainEntry.fromRaw = function fromRaw(chain, data) { + return new ChainEntry(chain).fromRaw(data); }; /** @@ -470,6 +561,36 @@ ChainEntry.prototype.toJSON = function toJSON() { }; }; +/** + * Inject properties from json object. + * @private + * @param {Object} json + */ + +ChainEntry.prototype.fromJSON = function fromJSON(json) { + assert(json, 'Block data is required.'); + assert(typeof json.hash === 'string'); + assert(utils.isNumber(json.version)); + assert(typeof json.prevBlock === 'string'); + assert(typeof json.merkleRoot === 'string'); + assert(utils.isNumber(json.ts)); + assert(utils.isNumber(json.bits)); + assert(utils.isNumber(json.nonce)); + assert(typeof json.chainwork === 'string'); + + this.hash = utils.revHex(json.hash); + this.version = json.version; + this.prevBlock = utils.revHex(json.prevBlock); + this.merkleRoot = utils.revHex(json.merkleRoot); + this.ts = json.ts; + this.bits = json.bits; + this.nonce = json.nonce; + this.height = json.height; + this.chainwork = new bn(json.chainwork, 10); + + return this; +}; + /** * Instantiate block from jsonified object. * @param {Chain} chain @@ -478,17 +599,7 @@ ChainEntry.prototype.toJSON = function toJSON() { */ ChainEntry.fromJSON = function fromJSON(chain, json) { - return new ChainEntry(chain, { - hash: utils.revHex(json.hash), - version: json.version, - prevBlock: utils.revHex(json.prevBlock), - merkleRoot: utils.revHex(json.merkleRoot), - ts: json.ts, - bits: json.bits, - nonce: json.nonce, - height: json.height, - chainwork: new bn(json.chainwork, 10) - }); + return new ChainEntry(chain).fromJSON(json); }; /** @@ -526,7 +637,7 @@ ChainEntry.prototype.inspect = function inspect() { ChainEntry.isChainEntry = function isChainEntry(obj) { return obj - && bn.isBN(obj.chainwork) + && obj.chainwork !== undefined && typeof obj.getMedianTime === 'function'; };