drop old caching mechanism.
This commit is contained in:
parent
5fd44dbed8
commit
4d937e642a
@ -468,42 +468,45 @@ Chain.prototype._verify = function _verify(block, prev, callback) {
|
|||||||
var ret = {};
|
var ret = {};
|
||||||
var height, ts, i, tx, medianTime, commitmentHash;
|
var height, ts, i, tx, medianTime, commitmentHash;
|
||||||
|
|
||||||
function done(err, result) {
|
|
||||||
prev.free();
|
|
||||||
callback(err, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!block.verify(ret))
|
if (!block.verify(ret))
|
||||||
return done(new VerifyError(block, 'invalid', ret.reason, ret.score));
|
return callback(new VerifyError(block, 'invalid', ret.reason, ret.score));
|
||||||
|
|
||||||
if (this.options.spv || block.type !== 'block')
|
if (this.options.spv || block.type !== 'block')
|
||||||
return done(null, constants.flags.MANDATORY_VERIFY_FLAGS);
|
return callback(null, constants.flags.MANDATORY_VERIFY_FLAGS);
|
||||||
|
|
||||||
// Skip the genesis block
|
// Skip the genesis block
|
||||||
if (block.isGenesis())
|
if (block.isGenesis())
|
||||||
return done(null, constants.flags.MANDATORY_VERIFY_FLAGS);
|
return callback(null, constants.flags.MANDATORY_VERIFY_FLAGS);
|
||||||
|
|
||||||
// Ensure it's not an orphan
|
// Ensure it's not an orphan
|
||||||
if (!prev)
|
if (!prev)
|
||||||
return done(new VerifyError(block, 'invalid', 'bad-prevblk', 0));
|
return callback(new VerifyError(block, 'invalid', 'bad-prevblk', 0));
|
||||||
|
|
||||||
prev.ensureAncestors(function(err) {
|
prev.getRetargetAncestors(function(err, ancestors) {
|
||||||
if (err)
|
if (err)
|
||||||
return done(err);
|
return callback(err);
|
||||||
|
|
||||||
height = prev.height + 1;
|
height = prev.height + 1;
|
||||||
medianTime = prev.getMedianTime();
|
medianTime = prev.getMedianTime();
|
||||||
|
|
||||||
// Ensure the timestamp is correct
|
// Ensure the timestamp is correct
|
||||||
if (block.ts <= medianTime)
|
if (block.ts <= medianTime) {
|
||||||
return done(new VerifyError(block, 'invalid', 'time-too-old', 0));
|
return callback(new VerifyError(block,
|
||||||
|
'invalid',
|
||||||
|
'time-too-old',
|
||||||
|
0));
|
||||||
|
}
|
||||||
|
|
||||||
if (block.bits !== self.getTarget(prev, block))
|
if (block.bits !== self.getTarget(prev, block, ancestors)) {
|
||||||
return done(new VerifyError(block, 'invalid', 'bad-diffbits', 100));
|
return callback(new VerifyError(block,
|
||||||
|
'invalid',
|
||||||
|
'bad-diffbits',
|
||||||
|
100));
|
||||||
|
}
|
||||||
|
|
||||||
self._checkDeployments(block, prev, function(err, state) {
|
self._checkDeployments(block, prev, ancestors, function(err, state) {
|
||||||
if (err)
|
if (err)
|
||||||
return done(err);
|
return callback(err);
|
||||||
|
|
||||||
// Expose the state of csv and segwit globally.
|
// Expose the state of csv and segwit globally.
|
||||||
self.csvActive = state.csv;
|
self.csvActive = state.csv;
|
||||||
@ -511,12 +514,16 @@ Chain.prototype._verify = function _verify(block, prev, callback) {
|
|||||||
|
|
||||||
// Can't verify any further when merkleblock or headers.
|
// Can't verify any further when merkleblock or headers.
|
||||||
if (block.type !== 'block')
|
if (block.type !== 'block')
|
||||||
return done(null, state.flags);
|
return callback(null, state.flags);
|
||||||
|
|
||||||
// Make sure the height contained in the coinbase is correct.
|
// Make sure the height contained in the coinbase is correct.
|
||||||
if (state.coinbaseHeight) {
|
if (state.coinbaseHeight) {
|
||||||
if (block.getCoinbaseHeight() !== height)
|
if (block.getCoinbaseHeight() !== height) {
|
||||||
return done(new VerifyError(block, 'invalid', 'bad-cb-height', 100));
|
return callback(new VerifyError(block,
|
||||||
|
'invalid',
|
||||||
|
'bad-cb-height',
|
||||||
|
100));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check the commitment hash for segwit.
|
// Check the commitment hash for segwit.
|
||||||
@ -524,13 +531,13 @@ Chain.prototype._verify = function _verify(block, prev, callback) {
|
|||||||
commitmentHash = block.commitmentHash;
|
commitmentHash = block.commitmentHash;
|
||||||
if (commitmentHash) {
|
if (commitmentHash) {
|
||||||
if (!block.witnessNonce) {
|
if (!block.witnessNonce) {
|
||||||
return done(new VerifyError(block,
|
return callback(new VerifyError(block,
|
||||||
'invalid',
|
'invalid',
|
||||||
'bad-witness-merkle-size',
|
'bad-witness-merkle-size',
|
||||||
100));
|
100));
|
||||||
}
|
}
|
||||||
if (commitmentHash !== block.getCommitmentHash('hex')) {
|
if (commitmentHash !== block.getCommitmentHash('hex')) {
|
||||||
return done(new VerifyError(block,
|
return callback(new VerifyError(block,
|
||||||
'invalid',
|
'invalid',
|
||||||
'bad-witness-merkle-match',
|
'bad-witness-merkle-match',
|
||||||
100));
|
100));
|
||||||
@ -542,7 +549,7 @@ Chain.prototype._verify = function _verify(block, prev, callback) {
|
|||||||
// witness data data cannot contain it.
|
// witness data data cannot contain it.
|
||||||
if (!commitmentHash) {
|
if (!commitmentHash) {
|
||||||
if (block.hasWitness()) {
|
if (block.hasWitness()) {
|
||||||
return done(new VerifyError(block,
|
return callback(new VerifyError(block,
|
||||||
'invalid',
|
'invalid',
|
||||||
'unexpected-witness',
|
'unexpected-witness',
|
||||||
100));
|
100));
|
||||||
@ -552,7 +559,7 @@ Chain.prototype._verify = function _verify(block, prev, callback) {
|
|||||||
// Check block cost (different from block size
|
// Check block cost (different from block size
|
||||||
// check in non-contextual verification).
|
// check in non-contextual verification).
|
||||||
if (block.getCost() > constants.block.MAX_COST) {
|
if (block.getCost() > constants.block.MAX_COST) {
|
||||||
return done(new VerifyError(block,
|
return callback(new VerifyError(block,
|
||||||
'invalid',
|
'invalid',
|
||||||
'bad-blk-cost',
|
'bad-blk-cost',
|
||||||
100));
|
100));
|
||||||
@ -570,14 +577,14 @@ Chain.prototype._verify = function _verify(block, prev, callback) {
|
|||||||
// Transactions must be finalized with
|
// Transactions must be finalized with
|
||||||
// regards to nSequence and nLockTime.
|
// regards to nSequence and nLockTime.
|
||||||
if (!tx.isFinal(height, ts)) {
|
if (!tx.isFinal(height, ts)) {
|
||||||
return done(new VerifyError(block,
|
return callback(new VerifyError(block,
|
||||||
'invalid',
|
'invalid',
|
||||||
'bad-txns-nonfinal',
|
'bad-txns-nonfinal',
|
||||||
10));
|
10));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return done(null, state);
|
return callback(null, state);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -587,11 +594,12 @@ Chain.prototype._verify = function _verify(block, prev, callback) {
|
|||||||
* @private
|
* @private
|
||||||
* @param {Block} block
|
* @param {Block} block
|
||||||
* @param {ChainBlock} prev
|
* @param {ChainBlock} prev
|
||||||
|
* @param {ChainBlock[]} ancestors
|
||||||
* @param {Function} callback - Returns
|
* @param {Function} callback - Returns
|
||||||
* [{@link VerifyError}, {@link DeploymentState}].
|
* [{@link VerifyError}, {@link DeploymentState}].
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Chain.prototype._checkDeployments = function _checkDeployments(block, prev, callback) {
|
Chain.prototype._checkDeployments = function _checkDeployments(block, prev, ancestors, callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
var height = prev.height + 1;
|
var height = prev.height + 1;
|
||||||
var state = {
|
var state = {
|
||||||
@ -615,41 +623,41 @@ Chain.prototype._checkDeployments = function _checkDeployments(block, prev, call
|
|||||||
|
|
||||||
// Only allow version 2 blocks (coinbase height)
|
// Only allow version 2 blocks (coinbase height)
|
||||||
// once the majority of blocks are using it.
|
// once the majority of blocks are using it.
|
||||||
if (block.version < 2 && prev.isOutdated(2))
|
if (block.version < 2 && prev.isOutdated(2, ancestors))
|
||||||
return callback(new VerifyError(block, 'obsolete', 'bad-version', 0));
|
return callback(new VerifyError(block, 'obsolete', 'bad-version', 0));
|
||||||
|
|
||||||
// Only allow version 3 blocks (sig validation)
|
// Only allow version 3 blocks (sig validation)
|
||||||
// once the majority of blocks are using it.
|
// once the majority of blocks are using it.
|
||||||
if (block.version < 3 && prev.isOutdated(3))
|
if (block.version < 3 && prev.isOutdated(3, ancestors))
|
||||||
return callback(new VerifyError(block, 'obsolete', 'bad-version', 0));
|
return callback(new VerifyError(block, 'obsolete', 'bad-version', 0));
|
||||||
|
|
||||||
// Only allow version 4 blocks (checklocktimeverify)
|
// Only allow version 4 blocks (checklocktimeverify)
|
||||||
// once the majority of blocks are using it.
|
// once the majority of blocks are using it.
|
||||||
if (block.version < 4 && prev.isOutdated(4))
|
if (block.version < 4 && prev.isOutdated(4, ancestors))
|
||||||
return callback(new VerifyError(block, 'obsolete', 'bad-version', 0));
|
return callback(new VerifyError(block, 'obsolete', 'bad-version', 0));
|
||||||
|
|
||||||
// Only allow version 5 blocks (bip141 - segnet3)
|
// Only allow version 5 blocks (bip141 - segnet3)
|
||||||
// once the majority of blocks are using it.
|
// once the majority of blocks are using it.
|
||||||
if (network.segwitHeight !== -1 && height >= network.segwitHeight) {
|
if (network.segwitHeight !== -1 && height >= network.segwitHeight) {
|
||||||
if (block.version < 5 && prev.isOutdated(5))
|
if (block.version < 5 && prev.isOutdated(5, ancestors))
|
||||||
return callback(new VerifyError(block, 'obsolete', 'bad-version', 0));
|
return callback(new VerifyError(block, 'obsolete', 'bad-version', 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure the height contained in the coinbase is correct.
|
// Make sure the height contained in the coinbase is correct.
|
||||||
if (block.version >= 2 && prev.isUpgraded(2))
|
if (block.version >= 2 && prev.isUpgraded(2, ancestors))
|
||||||
state.coinbaseHeight = true;
|
state.coinbaseHeight = true;
|
||||||
|
|
||||||
// Signature validation is now enforced (bip66)
|
// Signature validation is now enforced (bip66)
|
||||||
if (block.version >= 3 && prev.isUpgraded(3))
|
if (block.version >= 3 && prev.isUpgraded(3, ancestors))
|
||||||
state.flags |= constants.flags.VERIFY_DERSIG;
|
state.flags |= constants.flags.VERIFY_DERSIG;
|
||||||
|
|
||||||
// CHECKLOCKTIMEVERIFY is now usable (bip65)
|
// CHECKLOCKTIMEVERIFY is now usable (bip65)
|
||||||
if (block.version >= 4 && prev.isUpgraded(4))
|
if (block.version >= 4 && prev.isUpgraded(4, ancestors))
|
||||||
state.flags |= constants.flags.VERIFY_CHECKLOCKTIMEVERIFY;
|
state.flags |= constants.flags.VERIFY_CHECKLOCKTIMEVERIFY;
|
||||||
|
|
||||||
// Segregrated witness is now usable (bip141 - segnet3)
|
// Segregrated witness is now usable (bip141 - segnet3)
|
||||||
if (network.segwitHeight !== -1 && height >= network.segwitHeight) {
|
if (network.segwitHeight !== -1 && height >= network.segwitHeight) {
|
||||||
if (block.version >= 5 && prev.isUpgraded(5)) {
|
if (block.version >= 5 && prev.isUpgraded(5, ancestors)) {
|
||||||
state.flags |= constants.flags.VERIFY_WITNESS;
|
state.flags |= constants.flags.VERIFY_WITNESS;
|
||||||
state.segwit = true;
|
state.segwit = true;
|
||||||
}
|
}
|
||||||
@ -2046,7 +2054,6 @@ Chain.prototype.getTargetAsync = function getTargetAsync(last, block, callback)
|
|||||||
/**
|
/**
|
||||||
* Calculate the target synchronously. _Must_
|
* Calculate the target synchronously. _Must_
|
||||||
* have ancestors pre-allocated.
|
* have ancestors pre-allocated.
|
||||||
* @see ChainBlock#ensureAncestors.
|
|
||||||
* @param {ChainBlock} last - Previous entry.
|
* @param {ChainBlock} last - Previous entry.
|
||||||
* @param {Block|MerkleBlock|null} - Current block.
|
* @param {Block|MerkleBlock|null} - Current block.
|
||||||
* @param {Function} callback - returns [Error, Number]
|
* @param {Function} callback - returns [Error, Number]
|
||||||
@ -2061,9 +2068,6 @@ Chain.prototype.getTarget = function getTarget(last, block, ancestors) {
|
|||||||
if (!last)
|
if (!last)
|
||||||
return powLimit;
|
return powLimit;
|
||||||
|
|
||||||
if (!ancestors)
|
|
||||||
ancestors = last.ancestors;
|
|
||||||
|
|
||||||
// Do not retarget
|
// Do not retarget
|
||||||
if ((last.height + 1) % network.pow.retargetInterval !== 0) {
|
if ((last.height + 1) % network.pow.retargetInterval !== 0) {
|
||||||
if (network.pow.allowMinDifficultyBlocks) {
|
if (network.pow.allowMinDifficultyBlocks) {
|
||||||
@ -2391,21 +2395,17 @@ Chain.prototype._getInitialState = function _getInitialState(callback) {
|
|||||||
return callback();
|
return callback();
|
||||||
}
|
}
|
||||||
|
|
||||||
prev.ensureAncestors(function(err) {
|
prev.getRetargetAncestors(function(err, ancestors) {
|
||||||
if (err) {
|
if (err)
|
||||||
prev.free();
|
|
||||||
return callback(err);
|
return callback(err);
|
||||||
}
|
|
||||||
self._checkDeployments(self.tip, prev, function(err, state) {
|
self._checkDeployments(self.tip, prev, ancestors, function(err, state) {
|
||||||
if (err) {
|
if (err)
|
||||||
prev.free();
|
|
||||||
return callback(err);
|
return callback(err);
|
||||||
}
|
|
||||||
|
|
||||||
self.csvActive = state.csv;
|
self.csvActive = state.csv;
|
||||||
self.segwitActive = state.segwit;
|
self.segwitActive = state.segwit;
|
||||||
|
|
||||||
prev.free();
|
|
||||||
return callback();
|
return callback();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -57,7 +57,6 @@ function ChainBlock(chain, data, prev) {
|
|||||||
this.nonce = data.nonce;
|
this.nonce = data.nonce;
|
||||||
this.height = data.height;
|
this.height = data.height;
|
||||||
this.chainwork = data.chainwork || this.getChainwork(prev);
|
this.chainwork = data.chainwork || this.getChainwork(prev);
|
||||||
this.ancestors = [];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -99,7 +98,7 @@ ChainBlock.prototype.isGenesis = function isGenesis() {
|
|||||||
* @param {Function} callback
|
* @param {Function} callback
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ChainBlock.prototype.ensureAncestors = function ensureAncestors(callback) {
|
ChainBlock.prototype.getRetargetAncestors = function getRetargetAncestors(callback) {
|
||||||
var majorityWindow = network.block.majorityWindow;
|
var majorityWindow = network.block.majorityWindow;
|
||||||
var medianTimespan = constants.block.MEDIAN_TIMESPAN;
|
var medianTimespan = constants.block.MEDIAN_TIMESPAN;
|
||||||
var powDiffInterval = network.pow.retargetInterval;
|
var powDiffInterval = network.pow.retargetInterval;
|
||||||
@ -107,33 +106,7 @@ ChainBlock.prototype.ensureAncestors = function ensureAncestors(callback) {
|
|||||||
var max = Math.max(majorityWindow, medianTimespan);
|
var max = Math.max(majorityWindow, medianTimespan);
|
||||||
if ((this.height + 1) % powDiffInterval === 0 || allowMinDiff)
|
if ((this.height + 1) % powDiffInterval === 0 || allowMinDiff)
|
||||||
max = Math.max(max, powDiffInterval);
|
max = Math.max(max, powDiffInterval);
|
||||||
assert(this.ancestors.length === 0);
|
return this.getAncestors(max, callback);
|
||||||
return this.alloc(max, callback);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Allocate ancestors.
|
|
||||||
* @param {Number} max - Number of ancestors.
|
|
||||||
* @param {Function} callback
|
|
||||||
*/
|
|
||||||
|
|
||||||
ChainBlock.prototype.alloc = function alloc(max, callback) {
|
|
||||||
var self = this;
|
|
||||||
var i;
|
|
||||||
|
|
||||||
return this.getAncestors(max, function(err, ancestors) {
|
|
||||||
if (err)
|
|
||||||
return callback(err);
|
|
||||||
|
|
||||||
assert(ancestors);
|
|
||||||
|
|
||||||
self.ancestors.length = 0;
|
|
||||||
|
|
||||||
for (i = 0; i < ancestors.length; i++)
|
|
||||||
self.ancestors.push(ancestors[i]);
|
|
||||||
|
|
||||||
return callback();
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -144,14 +117,11 @@ ChainBlock.prototype.alloc = function alloc(max, callback) {
|
|||||||
|
|
||||||
ChainBlock.prototype.getAncestors = function getAncestors(max, callback) {
|
ChainBlock.prototype.getAncestors = function getAncestors(max, callback) {
|
||||||
var entry = this;
|
var entry = this;
|
||||||
var ancestors = this.ancestors.slice();
|
var ancestors = [];
|
||||||
|
|
||||||
if (max === 0)
|
if (max === 0)
|
||||||
return callback(null, []);
|
return callback(null, []);
|
||||||
|
|
||||||
if (ancestors.length)
|
|
||||||
entry = ancestors.pop();
|
|
||||||
|
|
||||||
assert(utils.isNumber(max));
|
assert(utils.isNumber(max));
|
||||||
|
|
||||||
// Try to do this iteratively and synchronously
|
// Try to do this iteratively and synchronously
|
||||||
@ -186,15 +156,6 @@ ChainBlock.prototype.getAncestors = function getAncestors(max, callback) {
|
|||||||
})(null, entry);
|
})(null, entry);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Free up ancestors. This is very important because
|
|
||||||
* chain entries are cached in the ChainDB's LRU cache.
|
|
||||||
*/
|
|
||||||
|
|
||||||
ChainBlock.prototype.free = function free() {
|
|
||||||
this.ancestors.length = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test whether the entry is in the main chain.
|
* Test whether the entry is in the main chain.
|
||||||
* @param {Function} callback - Return [Error, Boolean].
|
* @param {Function} callback - Return [Error, Boolean].
|
||||||
@ -291,9 +252,6 @@ ChainBlock.prototype.getMedianTime = function getMedianTime(ancestors) {
|
|||||||
var timeSpan = constants.block.MEDIAN_TIMESPAN;
|
var timeSpan = constants.block.MEDIAN_TIMESPAN;
|
||||||
var i;
|
var i;
|
||||||
|
|
||||||
if (!ancestors)
|
|
||||||
ancestors = this.ancestors;
|
|
||||||
|
|
||||||
for (i = 0; i < timeSpan && entry; i++, entry = ancestors[i])
|
for (i = 0; i < timeSpan && entry; i++, entry = ancestors[i])
|
||||||
median.push(entry.ts);
|
median.push(entry.ts);
|
||||||
|
|
||||||
@ -382,9 +340,6 @@ ChainBlock.prototype.isSuperMajority = function isSuperMajority(version, require
|
|||||||
var majorityWindow = network.block.majorityWindow;
|
var majorityWindow = network.block.majorityWindow;
|
||||||
var i;
|
var i;
|
||||||
|
|
||||||
if (!ancestors)
|
|
||||||
ancestors = this.ancestors;
|
|
||||||
|
|
||||||
for (i = 0; i < majorityWindow && found < required && entry; i++) {
|
for (i = 0; i < majorityWindow && found < required && entry; i++) {
|
||||||
if (entry.version >= version)
|
if (entry.version >= version)
|
||||||
found++;
|
found++;
|
||||||
@ -502,9 +457,7 @@ ChainBlock.fromJSON = function fromJSON(chain, json) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
ChainBlock.prototype.inspect = function inspect() {
|
ChainBlock.prototype.inspect = function inspect() {
|
||||||
var json = this.toJSON();
|
return this.toJSON();
|
||||||
json.ancestors = this.ancestors.length;
|
|
||||||
return json;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user