getLocator. optimize height lookup.

This commit is contained in:
Christopher Jeffrey 2016-05-06 03:11:58 -07:00
parent 198aee6560
commit c5181c272b
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
4 changed files with 75 additions and 111 deletions

View File

@ -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;
};

View File

@ -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);
});
});
};

View File

@ -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);

View File

@ -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);
};
/**