getLocator. optimize height lookup.
This commit is contained in:
parent
198aee6560
commit
c5181c272b
@ -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;
|
||||
};
|
||||
|
||||
@ -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);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
Loading…
Reference in New Issue
Block a user