chain: improve reset. fix versionbits checkpoints.
This commit is contained in:
parent
96e6cee67d
commit
9e0542dba1
@ -248,13 +248,12 @@ Chain.prototype._close = function close() {
|
||||
*/
|
||||
|
||||
Chain.prototype.verifyContext = co(function* verifyContext(block, prev) {
|
||||
var state, view;
|
||||
var state = yield this.verify(block, prev);
|
||||
var view;
|
||||
|
||||
state = yield this.verify(block, prev);
|
||||
yield this.verifyDuplicates(block, prev, state);
|
||||
|
||||
yield this.checkDuplicates(block, prev);
|
||||
|
||||
view = yield this.checkInputs(block, prev, state);
|
||||
view = yield this.verifyInputs(block, prev, state);
|
||||
|
||||
// Expose the state globally.
|
||||
this.state = state;
|
||||
@ -288,6 +287,10 @@ Chain.prototype.verify = co(function* verify(block, prev) {
|
||||
var i, err, height, ts, tx, medianTime;
|
||||
var commitmentHash, ancestors, state;
|
||||
|
||||
// Skip the genesis block.
|
||||
if (this.isGenesis(block))
|
||||
return this.state;
|
||||
|
||||
if (!block.verify(ret)) {
|
||||
err = new VerifyError(block,
|
||||
'invalid',
|
||||
@ -308,24 +311,23 @@ Chain.prototype.verify = co(function* verify(block, prev) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
// Skip the genesis block. Skip all blocks in spv mode.
|
||||
if (this.options.spv || this.isGenesis(block))
|
||||
// Skip all blocks in spv mode.
|
||||
if (this.options.spv)
|
||||
return this.state;
|
||||
|
||||
// Ensure it's not an orphan
|
||||
if (!prev) {
|
||||
throw new VerifyError(block,
|
||||
'invalid',
|
||||
'bad-prevblk',
|
||||
0);
|
||||
// Skip any blocks below the last checkpoint.
|
||||
if (!this.options.witness) {
|
||||
// We can't skip this with segwit
|
||||
// enabled since the block may have
|
||||
// been malleated: we don't know
|
||||
// until we verify the witness
|
||||
// merkle root.
|
||||
if (prev.isHistorical())
|
||||
return this.state;
|
||||
}
|
||||
|
||||
if (prev.isHistorical())
|
||||
return this.state;
|
||||
|
||||
ancestors = yield prev.getRetargetAncestors();
|
||||
|
||||
height = prev.height + 1;
|
||||
ancestors = yield prev.getRetargetAncestors();
|
||||
medianTime = prev.getMedianTime(ancestors);
|
||||
|
||||
// Ensure the timestamp is correct
|
||||
@ -345,10 +347,6 @@ Chain.prototype.verify = co(function* verify(block, prev) {
|
||||
|
||||
state = yield this.getDeployments(block, prev, ancestors);
|
||||
|
||||
// Can't verify any further when merkleblock or headers.
|
||||
if (this.options.spv)
|
||||
return state;
|
||||
|
||||
// Make sure the height contained in the coinbase is correct.
|
||||
if (state.hasBIP34()) {
|
||||
if (block.getCoinbaseHeight() !== height) {
|
||||
@ -549,9 +547,9 @@ Chain.prototype.getDeployments = co(function* getDeployments(block, prev, ancest
|
||||
* @returns {Promise}
|
||||
*/
|
||||
|
||||
Chain.prototype.checkDuplicates = co(function* checkDuplicates(block, prev) {
|
||||
Chain.prototype.verifyDuplicates = co(function* verifyDuplicates(block, prev, state) {
|
||||
var height = prev.height + 1;
|
||||
var entry;
|
||||
var i, tx, result;
|
||||
|
||||
if (this.options.spv)
|
||||
return;
|
||||
@ -562,39 +560,12 @@ Chain.prototype.checkDuplicates = co(function* checkDuplicates(block, prev) {
|
||||
if (prev.isHistorical())
|
||||
return;
|
||||
|
||||
if (this.network.block.bip34height === -1
|
||||
|| height <= this.network.block.bip34height) {
|
||||
yield this.findDuplicates(block, prev);
|
||||
return;
|
||||
}
|
||||
|
||||
// It was no longer possible to create duplicate
|
||||
// TXs once bip34 went into effect. We can check
|
||||
// for this to avoid a DB lookup.
|
||||
entry = yield this.db.get(this.network.block.bip34height);
|
||||
|
||||
if (entry && entry.hash === this.network.block.bip34hash)
|
||||
// BIP34 made it impossible to
|
||||
// create duplicate txids.
|
||||
if (state.hasBIP34())
|
||||
return;
|
||||
|
||||
yield this.findDuplicates(block, prev);
|
||||
});
|
||||
|
||||
/**
|
||||
* Check block for duplicate txids in blockchain
|
||||
* history (BIP30). Note that txids are only considered
|
||||
* duplicate if they are not yet completely spent.
|
||||
* @private
|
||||
* @see https://github.com/bitcoin/bips/blob/master/bip-0030.mediawiki
|
||||
* @param {Block|MerkleBlock} block
|
||||
* @param {ChainEntry} prev
|
||||
* @returns {Promise}
|
||||
*/
|
||||
|
||||
Chain.prototype.findDuplicates = co(function* findDuplicates(block, prev) {
|
||||
var height = prev.height + 1;
|
||||
var i, tx, result;
|
||||
|
||||
// Check all transactions
|
||||
// Check all transactions.
|
||||
for (i = 0; i < block.txs.length; i++) {
|
||||
tx = block.txs[i];
|
||||
result = yield this.db.hasCoins(tx.hash());
|
||||
@ -629,7 +600,7 @@ Chain.prototype.findDuplicates = co(function* findDuplicates(block, prev) {
|
||||
* @returns {Promise}
|
||||
*/
|
||||
|
||||
Chain.prototype.checkInputs = co(function* checkInputs(block, prev, state) {
|
||||
Chain.prototype.verifyInputs = co(function* verifyInputs(block, prev, state) {
|
||||
var height = prev.height + 1;
|
||||
var historical = prev.isHistorical();
|
||||
var sigops = 0;
|
||||
@ -967,14 +938,14 @@ Chain.prototype.reset = co(function* reset(height) {
|
||||
*/
|
||||
|
||||
Chain.prototype._reset = co(function* reset(height) {
|
||||
var result = yield this.db.reset(height);
|
||||
yield this.db.reset(height);
|
||||
|
||||
this.state = yield this.getDeploymentState();
|
||||
|
||||
// Reset the orphan map completely. There may
|
||||
// have been some orphans on a forked chain we
|
||||
// no longer need.
|
||||
this.purgeOrphans();
|
||||
|
||||
return result;
|
||||
});
|
||||
|
||||
/**
|
||||
@ -1162,8 +1133,9 @@ Chain.prototype._add = co(function* add(block) {
|
||||
if (this.options.useCheckpoints) {
|
||||
checkpoint = this.network.checkpoints[height];
|
||||
if (checkpoint) {
|
||||
// Someone is either trying to fool us, or
|
||||
// the consensus protocol is broken and
|
||||
// Someone is either mining on top of
|
||||
// an old block for no reason, or the
|
||||
// consensus protocol is broken and
|
||||
// there was a 20k+ block reorg.
|
||||
if (hash !== checkpoint) {
|
||||
this.logger.warning('Checkpoint mismatch!');
|
||||
@ -1216,6 +1188,17 @@ Chain.prototype._add = co(function* add(block) {
|
||||
// our tip's. Add the block but do _not_
|
||||
// connect the inputs.
|
||||
if (entry.chainwork.cmp(this.tip.chainwork) <= 0) {
|
||||
try {
|
||||
yield this.verify(block, prev);
|
||||
} catch (e) {
|
||||
if (e.type === 'VerifyError') {
|
||||
if (!e.malleated)
|
||||
this.invalid[entry.hash] = true;
|
||||
this.emit('invalid', block, entry.height);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
|
||||
yield this.db.save(entry, block);
|
||||
|
||||
this.emit('competitor', block, entry);
|
||||
@ -1327,11 +1310,18 @@ Chain.prototype.finish = function finish(block, entry) {
|
||||
*/
|
||||
|
||||
Chain.prototype.purgeOrphans = function purgeOrphans() {
|
||||
this.emit('purge', this.orphan.count, this.orphan.size);
|
||||
var count = this.orphan.count;
|
||||
var size = this.orphan.size;
|
||||
|
||||
if (count === 0)
|
||||
return;
|
||||
|
||||
this.orphan.map = {};
|
||||
this.orphan.bmap = {};
|
||||
this.orphan.count = 0;
|
||||
this.orphan.size = 0;
|
||||
|
||||
this.emit('purge', count, size);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1783,8 +1773,10 @@ Chain.prototype.findLocator = co(function* findLocator(locator) {
|
||||
Chain.prototype.isActive = co(function* isActive(prev, id) {
|
||||
var state;
|
||||
|
||||
if (prev.isHistorical())
|
||||
return false;
|
||||
if (!this.options.witness) {
|
||||
if (prev.isHistorical())
|
||||
return false;
|
||||
}
|
||||
|
||||
state = yield this.getState(prev, id);
|
||||
|
||||
|
||||
@ -1272,11 +1272,20 @@ ChainDB.prototype.reset = co(function* reset(block) {
|
||||
var tip;
|
||||
|
||||
if (!entry)
|
||||
return;
|
||||
throw new Error('Block not found.');
|
||||
|
||||
if (!(yield entry.isMainChain()))
|
||||
throw new Error('Cannot reset on alternate chain.');
|
||||
|
||||
if (this.prune)
|
||||
throw new Error('Cannot reset when pruned.');
|
||||
|
||||
tip = yield this.getTip();
|
||||
assert(tip);
|
||||
|
||||
while (tip && !tip.isGenesis()) {
|
||||
this.logger.debug('Resetting main chain to: %s', entry.rhash);
|
||||
|
||||
while (!tip.isGenesis()) {
|
||||
this.start();
|
||||
|
||||
if (tip.hash === entry.hash) {
|
||||
@ -1300,7 +1309,11 @@ ChainDB.prototype.reset = co(function* reset(block) {
|
||||
|
||||
yield this.commit();
|
||||
|
||||
this.cacheHeight.remove(tip.height);
|
||||
this.cacheHash.remove(tip.hash);
|
||||
|
||||
tip = yield this.get(tip.prevBlock);
|
||||
assert(tip);
|
||||
}
|
||||
});
|
||||
|
||||
@ -1332,10 +1345,15 @@ ChainDB.prototype.saveBlock = co(function* saveBlock(block, view) {
|
||||
*/
|
||||
|
||||
ChainDB.prototype.removeBlock = co(function* removeBlock(hash) {
|
||||
var block = yield this.getBlock(hash);
|
||||
var block;
|
||||
|
||||
if (this.options.spv)
|
||||
return;
|
||||
|
||||
block = yield this.getBlock(hash);
|
||||
|
||||
if (!block)
|
||||
return;
|
||||
throw new Error('Block not found.');
|
||||
|
||||
this.del(layout.b(block.hash()));
|
||||
|
||||
|
||||
@ -2492,6 +2492,9 @@ Peer.prototype.sync = function sync() {
|
||||
if (!this.version.hasNetwork())
|
||||
return Promise.resolve();
|
||||
|
||||
if (this.options.witness && !this.version.hasWitness())
|
||||
return;
|
||||
|
||||
if (!this.isLoader()) {
|
||||
if (!this.chain.synced)
|
||||
return Promise.resolve();
|
||||
|
||||
@ -644,6 +644,7 @@ Pool.prototype.setLoader = function setLoader(peer) {
|
||||
this.logger.info('Repurposing peer for loader (%s).', peer.hostname);
|
||||
this.peers.repurpose(peer);
|
||||
this.fillPeers();
|
||||
|
||||
peer.sync();
|
||||
|
||||
utils.nextTick(function() {
|
||||
@ -892,6 +893,9 @@ Pool.prototype.__handleInv = co(function* _handleInv(hashes, peer) {
|
||||
if (!this.chain.synced && !peer.isLoader())
|
||||
return;
|
||||
|
||||
if (this.options.witness && !peer.version.hasWitness())
|
||||
return;
|
||||
|
||||
if (!this.options.headers) {
|
||||
yield this._handleBlocks(hashes, peer);
|
||||
return;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user