From c5181c272b7abe13ad8eb6c0cc008593993f37e5 Mon Sep 17 00:00:00 2001 From: Christopher Jeffrey Date: Fri, 6 May 2016 03:11:58 -0700 Subject: [PATCH] getLocator. optimize height lookup. --- lib/bcoin/chain.js | 146 +++++++++++++++------------------------- lib/bcoin/chainblock.js | 20 ++++-- lib/bcoin/chaindb.js | 3 + lib/bcoin/mempool.js | 17 +---- 4 files changed, 75 insertions(+), 111 deletions(-) diff --git a/lib/bcoin/chain.js b/lib/bcoin/chain.js index 7b5ba80f..2c6bface 100644 --- a/lib/bcoin/chain.js +++ b/lib/bcoin/chain.js @@ -827,8 +827,6 @@ Chain.prototype._checkInputs = function _checkInputs(block, prev, state, callbac // Check all transactions utils.forEachSerial(block.txs, function(tx, next) { - var hash = tx.hash('hex'); - // Ensure tx is not double spending an output. if (!tx.isCoinbase()) { if (!tx.hasCoins()) { @@ -1598,8 +1596,8 @@ Chain.prototype.add = function add(block, callback, force) { // Take heap snapshot for debugging. if (self.total % 20 === 0) { - bcoin.profiler.snapshot(); utils.gc(); + bcoin.profiler.snapshot(); } utils.nextTick(function() { @@ -1916,9 +1914,8 @@ Chain.prototype.getHashRange = function getHashRange(start, end, callback) { Chain.prototype.getLocator = function getLocator(start, callback, force) { var self = this; var hashes = []; - var top = this.height; var step = 1; - var i; + var height; var unlock = this._lock(getLocator, [start, callback], force); if (!unlock) @@ -1926,67 +1923,67 @@ Chain.prototype.getLocator = function getLocator(start, callback, force) { callback = utils.wrap(callback, unlock); - function build(err, top) { + function getAncestor(entry, height, main, callback) { + if (height === 0) + return callback(null, { hash: network.genesis.hash, height: 0 }); + + if (!main) + return entry.getAncestorByHeight(height, callback); + + return self.db.getHash(height, function(err, hash) { + if (err) + return callback(err); + + if (!hash) + return callback(); + + return callback(null, { hash: hash, height: height }); + }); + } + + if (start == null) + start = this.tip.hash; + + return self.db.get(start, function(err, entry) { if (err) return callback(err); - i = top; - for (;;) { - hashes.push(i); - i = i - step; - if (i <= 0) { - if (i + step !== 0) - hashes.push(network.genesis.hash); - break; - } - if (hashes.length >= 10) - step *= 2; + if (!entry) { + // We could simply return `start` here, + // but there is no standardized "spacing" + // for locator hashes. Pretend this hash + // is our tip. This is useful for + // getheaders. + if (typeof start === 'string') + hashes.push(start); + entry = self.tip; } - utils.forEachSerial(hashes, function(height, next, i) { - if (typeof height === 'string') - return next(); - - self.db.getHash(height, function(err, hash) { - if (err) - return next(err); - - assert(hash); - - hashes[i] = hash; - - next(); - }); - }, function(err) { + entry.isMainChain(function(err, main) { if (err) return callback(err); - return callback(null, hashes); + + (function next(err, entry) { + if (err) + return callback(err); + + if (!entry) + return callback(null, hashes); + + hashes.push(entry.hash); + + if (entry.height === 0) + return callback(null, hashes); + + height = Math.max(entry.height - step, 0); + + if (hashes.length > 10) + step *= 2; + + getAncestor(entry, height, main, next); + })(null, entry); }); - } - - if (typeof start === 'string') { - return self.db.getHeight(start, function(err, top) { - if (err) - return build(err); - - if (top === -1) { - // We could simply `return [start]` here, - // but there is no standardized "spacing" - // for locator hashes. Pretend this hash - // is our tip. This is useful for getheaders - // when not using headers-first. - hashes.push(start); - top = self.height; - } - - return build(null, top); - }); - } - - if (typeof start === 'number') - top = start; - - return build(null, top); + }); }; /** @@ -2507,7 +2504,7 @@ Chain.prototype.getLocks = function getLocks(tx, flags, entry, callback) { */ Chain.prototype.evalLocks = function evalLocks(entry, minHeight, minTime, callback) { - if (minHeight >= entry.height) + if (minHeight >= entry.height + 1) return utils.asyncify(callback)(null, false); if (minTime === -1) @@ -2543,36 +2540,5 @@ Chain.prototype.checkLocks = function checkLocks(tx, flags, entry, callback) { }); }; -/** - * Calculate the difficulty. - * @param {ChainBlock} entry - * @returns {Number} Difficulty. - */ - -Chain.prototype.getDifficulty = function getDifficulty(entry) { - var shift, diff; - - if (!entry) { - if (!this.tip) - return 1.0; - entry = this.tip; - } - - shift = (entry.bits >>> 24) & 0xff; - diff = 0x0000ffff / (entry.bits & 0x00ffffff); - - while (shift < 29) { - diff *= 256.0; - shift++; - } - - while (shift > 29) { - diff /= 256.0; - shift--; - } - - return diff; -}; - return Chain; }; diff --git a/lib/bcoin/chainblock.js b/lib/bcoin/chainblock.js index 1a0d6d36..60399e8a 100644 --- a/lib/bcoin/chainblock.js +++ b/lib/bcoin/chainblock.js @@ -172,22 +172,32 @@ ChainBlock.prototype.isMainChain = function isMainChain(callback) { */ ChainBlock.prototype.getAncestorByHeight = function getAncestorByHeight(height, callback) { + var self = this; + if (height < 0) return utils.nextTick(callback); assert(height >= 0); assert(height <= this.height); - return this.getAncestor(this.height - height, function(err, entry) { + this.isMainChain(function(err, main) { if (err) return callback(err); - if (!entry) - return callback(); + if (main) + return self.chain.db.get(height, callback); - assert(entry.height === height); + return self.getAncestor(self.height - height, function(err, entry) { + if (err) + return callback(err); - return callback(null, entry); + if (!entry) + return callback(); + + assert(entry.height === height); + + return callback(null, entry); + }); }); }; diff --git a/lib/bcoin/chaindb.js b/lib/bcoin/chaindb.js index c3b038d3..51b66a14 100644 --- a/lib/bcoin/chaindb.js +++ b/lib/bcoin/chaindb.js @@ -629,6 +629,9 @@ ChainDB.prototype.isMainChain = function isMainChain(hash, callback) { query = hash; } + if (hash === this.chain.tip.hash || hash === network.genesis.hash) + return utils.asyncify(callback)(null, true); + return this.getHeight(query, function(err, height) { if (err) return callback(err); diff --git a/lib/bcoin/mempool.js b/lib/bcoin/mempool.js index ac4add9a..86512a5e 100644 --- a/lib/bcoin/mempool.js +++ b/lib/bcoin/mempool.js @@ -1240,22 +1240,7 @@ Mempool.prototype.getSnapshot = function getSnapshot(callback) { */ Mempool.prototype.checkLocks = function checkLocks(tx, flags, callback) { - var self = this; - var tip = this.chain.tip; - - var index = new bcoin.chainblock(this.chain, { - hash: constants.NULL_HASH, - version: tip.version, - prevBlock: tip.hash, - merkleRoot: constants.NULL_HASH, - ts: utils.now(), - bits: 0, - nonce: 0, - height: tip.height + 1, - chainwork: tip.chainwork - }); - - return this.chain.checkLocks(tx, flags, index, callback); + return this.chain.checkLocks(tx, flags, this.chain.tip, callback); }; /**