chain/pool: disable checkpoints on checkpoint failure. see #121.
This commit is contained in:
parent
77032f758d
commit
e7413aabb7
@ -53,7 +53,6 @@ replace-by-fee: false
|
||||
#
|
||||
|
||||
selfish: false
|
||||
headers: true
|
||||
compact: true
|
||||
bip151: true
|
||||
listen: true
|
||||
|
||||
@ -1685,17 +1685,20 @@ Chain.prototype.maybeSync = function maybeSync() {
|
||||
if (this.synced)
|
||||
return;
|
||||
|
||||
if (!this.hasChainwork())
|
||||
return;
|
||||
|
||||
if (this.checkpoints) {
|
||||
this.logger.info('Minimum chainwork reached. Disabling checkpoints.');
|
||||
if (this.tip.height < this.network.lastCheckpoint)
|
||||
return;
|
||||
|
||||
this.logger.info('Last checkpoint reached. Disabling checkpoints.');
|
||||
this.checkpoints = false;
|
||||
}
|
||||
|
||||
if (this.tip.ts < util.now() - this.network.block.maxTipAge)
|
||||
return;
|
||||
|
||||
if (!this.hasChainwork())
|
||||
return;
|
||||
|
||||
this.synced = true;
|
||||
this.emit('full');
|
||||
};
|
||||
@ -2302,7 +2305,7 @@ function ChainOptions(options) {
|
||||
this.coinCache = 0;
|
||||
this.entryCache = (2016 + 1) * 2 + 100;
|
||||
this.orphanLimit = 20 << 20;
|
||||
this.checkpoints = false;
|
||||
this.checkpoints = true;
|
||||
|
||||
if (options)
|
||||
this.fromOptions(options);
|
||||
|
||||
114
lib/net/pool.js
114
lib/net/pool.js
@ -47,8 +47,6 @@ var packetTypes = packets.types;
|
||||
* @param {Boolean?} options.spv - Do an SPV sync.
|
||||
* @param {Boolean?} options.noRelay - Whether to ask
|
||||
* for relayed transactions.
|
||||
* @param {Boolean?} options.headers - Whether
|
||||
* to use `getheaders` for sync.
|
||||
* @param {Number?} [options.feeRate] - Fee filter rate.
|
||||
* @param {Number?} [options.invTimeout=60000] - Timeout for broadcasted
|
||||
* objects.
|
||||
@ -116,6 +114,7 @@ function Pool(options) {
|
||||
this.headerChain = new List();
|
||||
this.headerNext = null;
|
||||
this.headerTip = null;
|
||||
this.headerFails = 0;
|
||||
|
||||
this.peers = new PeerList();
|
||||
this.authdb = new BIP150.AuthDB(this.options);
|
||||
@ -231,7 +230,7 @@ Pool.prototype._open = co(function* _open() {
|
||||
Pool.prototype.resetChain = function resetChain() {
|
||||
var tip = this.chain.tip;
|
||||
|
||||
if (!this.options.headers)
|
||||
if (!this.options.checkpoints)
|
||||
return;
|
||||
|
||||
this.headersFirst = false;
|
||||
@ -239,14 +238,14 @@ Pool.prototype.resetChain = function resetChain() {
|
||||
this.headerChain.reset();
|
||||
this.headerNext = null;
|
||||
|
||||
if (!this.chain.hasChainwork()) {
|
||||
if (tip.height < this.network.lastCheckpoint) {
|
||||
this.headersFirst = true;
|
||||
this.headerTip = this.getNextTip(tip.height);
|
||||
this.headerChain.push(new HeaderEntry(tip.hash, tip.height));
|
||||
this.logger.info(
|
||||
'Initialized header chain to height %d (watermark=%d).',
|
||||
'Initialized header chain to height %d (checkpoint=%s).',
|
||||
tip.height,
|
||||
this.headerTip.height);
|
||||
this.headerTip.hash);
|
||||
}
|
||||
};
|
||||
|
||||
@ -680,7 +679,7 @@ Pool.prototype.resolveHeaders = function resolveHeaders(peer) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Find the next highest watermark block.
|
||||
* Find the next checkpoint.
|
||||
* @private
|
||||
* @param {Number} height
|
||||
* @returns {Object}
|
||||
@ -689,19 +688,13 @@ Pool.prototype.resolveHeaders = function resolveHeaders(peer) {
|
||||
Pool.prototype.getNextTip = function getNextTip(height) {
|
||||
var i, next;
|
||||
|
||||
if (this.options.checkpoints) {
|
||||
for (i = 0; i < this.network.checkpoints.length; i++) {
|
||||
next = this.network.checkpoints[i];
|
||||
if (next.height > height)
|
||||
return new HeaderEntry(next.hash, next.height);
|
||||
}
|
||||
throw new Error('Could not find next tip.');
|
||||
for (i = 0; i < this.network.checkpoints.length; i++) {
|
||||
next = this.network.checkpoints[i];
|
||||
if (next.height > height)
|
||||
return new HeaderEntry(next.hash, next.height);
|
||||
}
|
||||
|
||||
if (this.chain.hasChainwork())
|
||||
throw new Error('Could not find next tip.');
|
||||
|
||||
return new HeaderEntry(null, height + 20000);
|
||||
throw new Error('Next checkpoint not found.');
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1755,7 +1748,7 @@ Pool.prototype.handleHeaders = co(function* handleHeaders(peer, packet) {
|
||||
|
||||
Pool.prototype._handleHeaders = co(function* handleHeaders(peer, packet) {
|
||||
var headers = packet.items;
|
||||
var isWatermark = false;
|
||||
var checkpoint = false;
|
||||
var i, header, hash, height, last, node;
|
||||
|
||||
if (!this.headersFirst)
|
||||
@ -1783,14 +1776,6 @@ Pool.prototype._handleHeaders = co(function* handleHeaders(peer, packet) {
|
||||
hash = header.hash('hex');
|
||||
height = last.height + 1;
|
||||
|
||||
if (header.prevBlock !== last.hash) {
|
||||
this.logger.warning(
|
||||
'Peer sent a bad header chain (%s).',
|
||||
peer.hostname());
|
||||
peer.destroy();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!header.verify()) {
|
||||
this.logger.warning(
|
||||
'Peer sent an invalid header (%s).',
|
||||
@ -1800,20 +1785,45 @@ Pool.prototype._handleHeaders = co(function* handleHeaders(peer, packet) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (header.prevBlock !== last.hash) {
|
||||
this.logger.warning(
|
||||
'Peer sent a bad header chain (%s).',
|
||||
peer.hostname());
|
||||
|
||||
if (++this.headerFails < 4) {
|
||||
peer.destroy();
|
||||
return;
|
||||
}
|
||||
|
||||
this.logger.warning(
|
||||
'Switching to getblocks (%s).',
|
||||
peer.hostname());
|
||||
|
||||
yield this.switchSync(peer);
|
||||
return;
|
||||
}
|
||||
|
||||
node = new HeaderEntry(hash, height);
|
||||
|
||||
if (node.height === this.headerTip.height) {
|
||||
if (this.options.checkpoints) {
|
||||
if (node.hash !== this.headerTip.hash) {
|
||||
this.logger.warning(
|
||||
'Peer sent an invalid checkpoint (%s).',
|
||||
peer.hostname());
|
||||
peer.increaseBan(100);
|
||||
if (node.hash !== this.headerTip.hash) {
|
||||
this.logger.warning(
|
||||
'Peer sent an invalid checkpoint (%s).',
|
||||
peer.hostname());
|
||||
|
||||
if (++this.headerFails < 4) {
|
||||
peer.destroy();
|
||||
return;
|
||||
}
|
||||
|
||||
this.logger.warning(
|
||||
'Switching to getblocks (%s).',
|
||||
peer.hostname());
|
||||
|
||||
yield this.switchSync(peer);
|
||||
return;
|
||||
}
|
||||
isWatermark = true;
|
||||
checkpoint = true;
|
||||
}
|
||||
|
||||
if (!this.headerNext)
|
||||
@ -1828,7 +1838,7 @@ Pool.prototype._handleHeaders = co(function* handleHeaders(peer, packet) {
|
||||
peer.hostname());
|
||||
|
||||
// Request the blocks we just added.
|
||||
if (isWatermark) {
|
||||
if (checkpoint) {
|
||||
this.headerChain.shift();
|
||||
this.resolveHeaders(peer);
|
||||
return;
|
||||
@ -1971,10 +1981,10 @@ Pool.prototype.resolveChain = co(function* resolveChain(peer, hash) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.chain.hasChainwork()) {
|
||||
if (node.height < this.network.lastCheckpoint) {
|
||||
if (node.height === this.headerTip.height) {
|
||||
this.logger.info(
|
||||
'Hit high watermark %s (%d).',
|
||||
'Received checkpoint %s (%d).',
|
||||
util.revHex(node.hash), node.height);
|
||||
|
||||
this.headerTip = this.getNextTip(node.height);
|
||||
@ -1991,9 +2001,24 @@ Pool.prototype.resolveChain = co(function* resolveChain(peer, hash) {
|
||||
}
|
||||
|
||||
this.logger.info(
|
||||
'Chain hit target chainwork of %s. Switching to getblocks.',
|
||||
this.chain.tip.chainwork.toString('hex', 64));
|
||||
'Switching to getblocks (%s).',
|
||||
peer.hostname());
|
||||
|
||||
yield this.switchSync(peer, hash);
|
||||
});
|
||||
|
||||
/**
|
||||
* Switch to getblocks.
|
||||
* @private
|
||||
* @param {Peer} peer
|
||||
* @param {Hash} hash
|
||||
* @returns {Promise}
|
||||
*/
|
||||
|
||||
Pool.prototype.switchSync = co(function* switchSync(peer, hash) {
|
||||
assert(this.headersFirst);
|
||||
|
||||
this.chain.checkpoints = false;
|
||||
this.headersFirst = false;
|
||||
this.headerTip = null;
|
||||
this.headerChain.reset();
|
||||
@ -3165,10 +3190,9 @@ function PoolOptions(options) {
|
||||
this.address.port = this.network.port;
|
||||
|
||||
this.witness = true;
|
||||
this.checkpoints = false;
|
||||
this.checkpoints = true;
|
||||
this.spv = false;
|
||||
this.listen = false;
|
||||
this.headers = false;
|
||||
this.compact = false;
|
||||
this.noRelay = false;
|
||||
this.host = '0.0.0.0';
|
||||
@ -3259,13 +3283,6 @@ PoolOptions.prototype.fromOptions = function fromOptions(options) {
|
||||
this.listen = options.listen;
|
||||
}
|
||||
|
||||
if (options.headers != null) {
|
||||
assert(typeof options.headers === 'boolean');
|
||||
this.headers = options.headers;
|
||||
} else {
|
||||
this.headers = this.spv === true;
|
||||
}
|
||||
|
||||
if (options.compact != null) {
|
||||
assert(typeof options.compact === 'boolean');
|
||||
this.compact = options.compact;
|
||||
@ -3419,6 +3436,7 @@ PoolOptions.prototype.fromOptions = function fromOptions(options) {
|
||||
this.requiredServices |= common.services.BLOOM;
|
||||
this.services &= ~common.services.NETWORK;
|
||||
this.noRelay = true;
|
||||
this.checkpoints = true;
|
||||
}
|
||||
|
||||
if (this.selfish)
|
||||
|
||||
@ -102,7 +102,6 @@ function FullNode(options) {
|
||||
chain: this.chain,
|
||||
mempool: this.mempool,
|
||||
selfish: this.options.selfish,
|
||||
headers: this.options.headers,
|
||||
compact: this.options.compact,
|
||||
bip151: this.options.bip151,
|
||||
bip150: this.options.bip150,
|
||||
|
||||
@ -71,7 +71,6 @@ function SPVNode(options) {
|
||||
knownPeers: this.options.knownPeers,
|
||||
identityKey: this.options.identityKey,
|
||||
maxOutbound: this.options.maxOutbound,
|
||||
headers: this.options.headers,
|
||||
selfish: true,
|
||||
listen: false
|
||||
});
|
||||
|
||||
@ -181,7 +181,7 @@ main.pow = {
|
||||
*/
|
||||
|
||||
chainwork: new BN(
|
||||
'0000000000000000000000000000000000000000002fa4573e5f9cf6ca3e5e75',
|
||||
'0000000000000000000000000000000000000000003a315fa3a5ef47f4384cf2',
|
||||
'hex'
|
||||
),
|
||||
|
||||
@ -543,7 +543,7 @@ testnet.pow = {
|
||||
),
|
||||
bits: 486604799,
|
||||
chainwork: new BN(
|
||||
'00000000000000000000000000000000000000000000001a461538dc48da1a06',
|
||||
'00000000000000000000000000000000000000000000001e345893fa639796e9',
|
||||
'hex'
|
||||
),
|
||||
targetTimespan: 14 * 24 * 60 * 60,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user