From 9f56efe0d7d4e3808ca06f9e546fe937257ce74b Mon Sep 17 00:00:00 2001 From: Christopher Jeffrey Date: Tue, 8 Mar 2016 14:25:43 -0800 Subject: [PATCH] more chainblock refactoring. --- lib/bcoin/chain.js | 4 +- lib/bcoin/chainblock.js | 239 +++++++++++++++------------------------- lib/bcoin/chaindb.js | 7 +- 3 files changed, 97 insertions(+), 153 deletions(-) diff --git a/lib/bcoin/chain.js b/lib/bcoin/chain.js index 3411d112..0a4abd52 100644 --- a/lib/bcoin/chain.js +++ b/lib/bcoin/chain.js @@ -1848,7 +1848,7 @@ Chain.prototype.getTarget = function getTarget(last, block) { return powLimit; i = 1; - prev = last.previous; + prev = last.ancestors; while (prev[i] && last.height % network.powDiffInterval !== 0 && last.bits === powLimit) { @@ -1861,7 +1861,7 @@ Chain.prototype.getTarget = function getTarget(last, block) { } // Back 2 weeks - first = last.previous[network.powDiffInterval - 1]; + first = last.ancestors[network.powDiffInterval - 1]; assert(first); diff --git a/lib/bcoin/chainblock.js b/lib/bcoin/chainblock.js index 8285adf9..e76589b5 100644 --- a/lib/bcoin/chainblock.js +++ b/lib/bcoin/chainblock.js @@ -23,6 +23,7 @@ function ChainBlock(chain, data, prev) { return new ChainBlock(chain, data); this.chain = chain; + this.hash = data.hash; this.version = data.version; this.prevBlock = data.prevBlock; @@ -32,14 +33,9 @@ function ChainBlock(chain, data, prev) { this.nonce = data.nonce; this.height = data.height; this.chainwork = data.chainwork || this.getChainwork(prev); - - assert(this.chainwork); - - this.previous = []; + this.ancestors = []; } -ChainBlock.BLOCK_SIZE = 116; - ChainBlock.prototype.getProof = function getProof() { var target = utils.fromCompact(this.bits); if (target.isNeg() || target.cmpn(0) === 0) @@ -55,104 +51,6 @@ ChainBlock.prototype.isGenesis = function isGenesis() { return this.hash === network.genesis.hash; }; -ChainBlock.prototype.toJSON = function toJSON() { - return { - hash: this.hash, - version: this.version, - prevBlock: this.prevBlock, - merkleRoot: this.merkleRoot, - ts: this.ts, - bits: this.bits, - nonce: this.nonce, - height: this.height - }; -}; - -ChainBlock.fromJSON = function fromJSON(chain, json) { - return new ChainBlock(chain, json); -}; - -ChainBlock.prototype.toRaw = function toRaw() { - var res = new Buffer(ChainBlock.BLOCK_SIZE); - - utils.write32(res, this.version, 0); - utils.copy(new Buffer(this.prevBlock, 'hex'), res, 4); - utils.copy(new Buffer(this.merkleRoot, 'hex'), res, 36); - utils.writeU32(res, this.ts, 68); - utils.writeU32(res, this.bits, 72); - utils.writeU32(res, this.nonce, 76); - utils.writeU32(res, this.height, 80); - utils.copy(new Buffer(this.chainwork.toArray('le', 32)), res, 84); - - return res; -}; - -ChainBlock.fromRaw = function fromRaw(chain, p) { - return new ChainBlock(chain, { - hash: utils.toHex(utils.dsha256(p.slice(0, 80))), - version: utils.read32(p, 0), - prevBlock: utils.toHex(p.slice(4, 36)), - merkleRoot: utils.toHex(p.slice(36, 68)), - ts: utils.readU32(p, 68), - bits: utils.readU32(p, 72), - nonce: utils.readU32(p, 76), - height: utils.readU32(p, 80), - chainwork: new bn(p.slice(84, 116), 'le') - }); -}; - -ChainBlock.prototype.getMedianTimeAsync = function getMedianTime(callback) { - var self = this; - var median = []; - var timeSpan = constants.block.medianTimespan; - var i = 0; - - (function next(err, entry) { - if (err) - return callback(err); - - if (!entry || i >= timeSpan) { - median = median.sort(); - return callback(null, median[median.length / 2 | 0]); - } - - median[i] = entry.ts; - i++; - - entry.getPrevious(next); - })(null, this); -}; - -ChainBlock.prototype.isOutdatedAsync = function isOutdated(version, callback) { - return this.isSuperMajority(version, network.block.majorityRejectOutdated, callback); -}; - -ChainBlock.prototype.isUpgradedAsync = function isUpgraded(version, callback) { - return this.isSuperMajority(version, network.block.majorityEnforceUpgrade, callback); -}; - -ChainBlock.prototype.isSuperMajorityAsync = function isSuperMajority(version, required, callback) { - var self = this; - var found = 0; - var majorityWindow = network.block.majorityWindow; - var i = 0; - - (function next(err, entry) { - if (err) - return callback(err); - - if (!entry || i >= majorityWindow || found >= required) - return callback(null, found >= required); - - if (entry.version >= version) - found++; - - i++; - - entry.getPrevious(next); - })(null, this); -}; - ChainBlock.prototype.ensureAncestors = function ensureAncestors(callback) { var majorityWindow = network.block.majorityWindow; var medianTimespan = constants.block.medianTimespan; @@ -161,7 +59,7 @@ ChainBlock.prototype.ensureAncestors = function ensureAncestors(callback) { var max = Math.max(majorityWindow, medianTimespan); if ((this.height + 1) % powDiffInterval === 0 || allowMinDiff) max = Math.max(max, powDiffInterval); - assert(this.previous.length === 0); + assert(this.ancestors.length === 0); return this.alloc(max, callback); }; @@ -169,16 +67,16 @@ ChainBlock.prototype.alloc = function alloc(max, callback) { var self = this; var i; - return this.getAncestors(max, function(err, previous) { + return this.getAncestors(max, function(err, ancestors) { if (err) return callback(err); - assert(previous); + assert(ancestors); - self.previous.length = 0; + self.ancestors.length = 0; - for (i = 0; i < previous.length; i++) - self.previous.push(previous[i]); + for (i = 0; i < ancestors.length; i++) + self.ancestors.push(ancestors[i]); return callback(); }); @@ -187,26 +85,26 @@ ChainBlock.prototype.alloc = function alloc(max, callback) { ChainBlock.prototype.getAncestors = function getAncestors(max, callback) { var self = this; var entry = this; - var previous = this.previous.slice(); + var ancestors = this.ancestors.slice(); if (max === 0) return callback(null, []); - if (previous.length) - entry = previous.pop(); + if (ancestors.length) + entry = ancestors.pop(); assert(utils.isFinite(max)); // Try to do this iteratively and synchronously // so we don't have to wait on nextTicks. for (;;) { - previous.push(entry); + ancestors.push(entry); - if (previous.length >= max) - return callback(null, previous); + if (ancestors.length >= max) + return callback(null, ancestors); if (!this.chain.db.hasCache(entry.prevBlock)) { - previous.pop(); + ancestors.pop(); break; } @@ -218,19 +116,19 @@ ChainBlock.prototype.getAncestors = function getAncestors(max, callback) { return callback(err); if (!entry) - return callback(null, previous); + return callback(null, ancestors); - previous.push(entry); + ancestors.push(entry); - if (previous.length >= max) - return callback(null, previous); + if (ancestors.length >= max) + return callback(null, ancestors); entry.getPrevious(next); })(null, entry); }; ChainBlock.prototype.free = function free() { - this.previous.length = 0; + this.ancestors.length = 0; }; ChainBlock.prototype.isMainChain = function isMainChain(callback) { @@ -264,14 +162,14 @@ ChainBlock.prototype.getAncestorByHeight = function getAncestorByHeight(height, ChainBlock.prototype.getAncestor = function getAncestor(index, callback) { assert(index >= 0); - return this.getAncestors(index + 1, function(err, previous) { + return this.getAncestors(index + 1, function(err, ancestors) { if (err) return callback(err); - if (previous.length !== index + 1) + if (ancestors.length !== index + 1) return callback(); - return callback(null, previous[previous.length - 1]); + return callback(null, ancestors[ancestors.length - 1]); }); }; @@ -292,16 +190,16 @@ ChainBlock.prototype.getNext = function getNext(callback) { }); }; -ChainBlock.prototype.getMedianTime = function getMedianTime(previous) { +ChainBlock.prototype.getMedianTime = function getMedianTime(ancestors) { var entry = this; var median = []; var timeSpan = constants.block.medianTimespan; var i; - if (!previous) - previous = this.previous; + if (!ancestors) + ancestors = this.ancestors; - for (i = 0; i < timeSpan && entry; i++, entry = previous[i]) + for (i = 0; i < timeSpan && entry; i++, entry = ancestors[i]) median.push(entry.ts); median = median.sort(); @@ -309,27 +207,27 @@ ChainBlock.prototype.getMedianTime = function getMedianTime(previous) { return median[median.length / 2 | 0]; }; -ChainBlock.prototype.isOutdated = function isOutdated(version, previous) { - return this.isSuperMajority(version, network.block.majorityRejectOutdated, previous); +ChainBlock.prototype.isOutdated = function isOutdated(version, ancestors) { + return this.isSuperMajority(version, network.block.majorityRejectOutdated, ancestors); }; -ChainBlock.prototype.isUpgraded = function isUpgraded(version, previous) { - return this.isSuperMajority(version, network.block.majorityEnforceUpgrade, previous); +ChainBlock.prototype.isUpgraded = function isUpgraded(version, ancestors) { + return this.isSuperMajority(version, network.block.majorityEnforceUpgrade, ancestors); }; -ChainBlock.prototype.isSuperMajority = function isSuperMajority(version, required, previous) { +ChainBlock.prototype.isSuperMajority = function isSuperMajority(version, required, ancestors) { var entry = this; var found = 0; var majorityWindow = network.block.majorityWindow; var i; - if (!previous) - previous = this.previous; + if (!ancestors) + ancestors = this.ancestors; for (i = 0; i < majorityWindow && found < required && entry; i++) { if (entry.version >= version) found++; - entry = previous[i + 1]; + entry = ancestors[i + 1]; } return found >= required; @@ -338,24 +236,69 @@ ChainBlock.prototype.isSuperMajority = function isSuperMajority(version, require ChainBlock.prototype.getMedianTimeAsync = function getMedianTimeAsync(callback) { var self = this; - return this.getAncestors(constants.block.medianTimespan, function(err, previous) { + return this.getAncestors(constants.block.medianTimespan, function(err, ancestors) { if (err) return callback(err); - return callback(null, self.getMedianTime(previous)); + return callback(null, self.getMedianTime(ancestors)); }); }; +ChainBlock.prototype.toRaw = function toRaw() { + var res = new Buffer(116); + + utils.write32(res, this.version, 0); + utils.copy(new Buffer(this.prevBlock, 'hex'), res, 4); + utils.copy(new Buffer(this.merkleRoot, 'hex'), res, 36); + utils.writeU32(res, this.ts, 68); + utils.writeU32(res, this.bits, 72); + utils.writeU32(res, this.nonce, 76); + utils.writeU32(res, this.height, 80); + utils.copy(new Buffer(this.chainwork.toArray('le', 32)), res, 84); + + return res; +}; + +ChainBlock.fromRaw = function fromRaw(chain, p) { + return new ChainBlock(chain, { + hash: utils.toHex(utils.dsha256(p.slice(0, 80))), + version: utils.read32(p, 0), + prevBlock: utils.toHex(p.slice(4, 36)), + merkleRoot: utils.toHex(p.slice(36, 68)), + ts: utils.readU32(p, 68), + bits: utils.readU32(p, 72), + nonce: utils.readU32(p, 76), + height: utils.readU32(p, 80), + chainwork: new bn(p.slice(84, 116), 'le') + }); +}; + +ChainBlock.prototype.toJSON = function toJSON() { + return { + version: this.version, + hash: utils.revHex(this.hash), + prevBlock: utils.revHex(this.prevBlock), + merkleRoot: utils.revHex(this.merkleRoot), + ts: this.ts, + bits: this.bits, + nonce: this.nonce, + height: this.height, + chainwork: this.chainwork.toString('hex') + }; +}; + +ChainBlock.fromJSON = function fromJSON(chain, json) { + json.hash = utils.revHex(json.hash); + json.prevBlock = utils.revHex(json.prevBlock); + json.merkleRoot = utils.revHex(json.merkleRoot); + json.chainwork = new bn(json.chainwork, 'hex'); + return new ChainBlock(chain, json); +}; + ChainBlock.prototype.inspect = function inspect() { - var copy = new ChainBlock(this.chain, this, null); - copy.__proto__ = null; - copy.hash = utils.revHex(copy.hash); - copy.prevBlock = utils.revHex(copy.prevBlock); - copy.merkleRoot = utils.revHex(copy.merkleRoot); - copy.chainwork = copy.chainwork.toString(10); - delete copy.chain; - copy.previous = this.previous.length; - return copy; + var json = this.toJSON(); + json.ancestors = this.ancestors.length; + return json; }; /** diff --git a/lib/bcoin/chaindb.js b/lib/bcoin/chaindb.js index da542968..1b68cc82 100644 --- a/lib/bcoin/chaindb.js +++ b/lib/bcoin/chaindb.js @@ -96,7 +96,7 @@ ChainDB.prototype._init = function _init() { ChainDB.prototype.load = function load(callback) { var self = this; - var genesis = bcoin.chainblock.fromJSON(this.chain, { + var genesis = new bcoin.chainblock(this.chain, { hash: network.genesis.hash, version: network.genesis.version, prevBlock: network.genesis.prevBlock, @@ -104,8 +104,9 @@ ChainDB.prototype.load = function load(callback) { ts: network.genesis.ts, bits: network.genesis.bits, nonce: network.genesis.nonce, - height: 0 - }); + height: 0, + chainwork: null + }, null); this.loading = true;