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
|
// Check all transactions
|
||||||
utils.forEachSerial(block.txs, function(tx, next) {
|
utils.forEachSerial(block.txs, function(tx, next) {
|
||||||
var hash = tx.hash('hex');
|
|
||||||
|
|
||||||
// Ensure tx is not double spending an output.
|
// Ensure tx is not double spending an output.
|
||||||
if (!tx.isCoinbase()) {
|
if (!tx.isCoinbase()) {
|
||||||
if (!tx.hasCoins()) {
|
if (!tx.hasCoins()) {
|
||||||
@ -1598,8 +1596,8 @@ Chain.prototype.add = function add(block, callback, force) {
|
|||||||
|
|
||||||
// Take heap snapshot for debugging.
|
// Take heap snapshot for debugging.
|
||||||
if (self.total % 20 === 0) {
|
if (self.total % 20 === 0) {
|
||||||
bcoin.profiler.snapshot();
|
|
||||||
utils.gc();
|
utils.gc();
|
||||||
|
bcoin.profiler.snapshot();
|
||||||
}
|
}
|
||||||
|
|
||||||
utils.nextTick(function() {
|
utils.nextTick(function() {
|
||||||
@ -1916,9 +1914,8 @@ Chain.prototype.getHashRange = function getHashRange(start, end, callback) {
|
|||||||
Chain.prototype.getLocator = function getLocator(start, callback, force) {
|
Chain.prototype.getLocator = function getLocator(start, callback, force) {
|
||||||
var self = this;
|
var self = this;
|
||||||
var hashes = [];
|
var hashes = [];
|
||||||
var top = this.height;
|
|
||||||
var step = 1;
|
var step = 1;
|
||||||
var i;
|
var height;
|
||||||
|
|
||||||
var unlock = this._lock(getLocator, [start, callback], force);
|
var unlock = this._lock(getLocator, [start, callback], force);
|
||||||
if (!unlock)
|
if (!unlock)
|
||||||
@ -1926,67 +1923,67 @@ Chain.prototype.getLocator = function getLocator(start, callback, force) {
|
|||||||
|
|
||||||
callback = utils.wrap(callback, unlock);
|
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)
|
if (err)
|
||||||
return callback(err);
|
return callback(err);
|
||||||
|
|
||||||
i = top;
|
if (!entry) {
|
||||||
for (;;) {
|
// We could simply return `start` here,
|
||||||
hashes.push(i);
|
// but there is no standardized "spacing"
|
||||||
i = i - step;
|
// for locator hashes. Pretend this hash
|
||||||
if (i <= 0) {
|
// is our tip. This is useful for
|
||||||
if (i + step !== 0)
|
// getheaders.
|
||||||
hashes.push(network.genesis.hash);
|
if (typeof start === 'string')
|
||||||
break;
|
hashes.push(start);
|
||||||
}
|
entry = self.tip;
|
||||||
if (hashes.length >= 10)
|
|
||||||
step *= 2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
utils.forEachSerial(hashes, function(height, next, i) {
|
entry.isMainChain(function(err, main) {
|
||||||
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) {
|
|
||||||
if (err)
|
if (err)
|
||||||
return callback(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) {
|
Chain.prototype.evalLocks = function evalLocks(entry, minHeight, minTime, callback) {
|
||||||
if (minHeight >= entry.height)
|
if (minHeight >= entry.height + 1)
|
||||||
return utils.asyncify(callback)(null, false);
|
return utils.asyncify(callback)(null, false);
|
||||||
|
|
||||||
if (minTime === -1)
|
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;
|
return Chain;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -172,22 +172,32 @@ ChainBlock.prototype.isMainChain = function isMainChain(callback) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
ChainBlock.prototype.getAncestorByHeight = function getAncestorByHeight(height, callback) {
|
ChainBlock.prototype.getAncestorByHeight = function getAncestorByHeight(height, callback) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
if (height < 0)
|
if (height < 0)
|
||||||
return utils.nextTick(callback);
|
return utils.nextTick(callback);
|
||||||
|
|
||||||
assert(height >= 0);
|
assert(height >= 0);
|
||||||
assert(height <= this.height);
|
assert(height <= this.height);
|
||||||
|
|
||||||
return this.getAncestor(this.height - height, function(err, entry) {
|
this.isMainChain(function(err, main) {
|
||||||
if (err)
|
if (err)
|
||||||
return callback(err);
|
return callback(err);
|
||||||
|
|
||||||
if (!entry)
|
if (main)
|
||||||
return callback();
|
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;
|
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) {
|
return this.getHeight(query, function(err, height) {
|
||||||
if (err)
|
if (err)
|
||||||
return callback(err);
|
return callback(err);
|
||||||
|
|||||||
@ -1240,22 +1240,7 @@ Mempool.prototype.getSnapshot = function getSnapshot(callback) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Mempool.prototype.checkLocks = function checkLocks(tx, flags, callback) {
|
Mempool.prototype.checkLocks = function checkLocks(tx, flags, callback) {
|
||||||
var self = this;
|
return this.chain.checkLocks(tx, flags, this.chain.tip, callback);
|
||||||
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);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user