pool: allow use of headersFirst without checkpoints.
This commit is contained in:
parent
fe52210c5e
commit
3fb2150dc4
@ -1138,6 +1138,8 @@ HeadersPacket.prototype.getSize = function getSize() {
|
||||
HeadersPacket.prototype.toWriter = function toWriter(bw) {
|
||||
var i, item;
|
||||
|
||||
assert(this.items.length <= 2000, 'Too many headers.');
|
||||
|
||||
bw.writeVarint(this.items.length);
|
||||
|
||||
for (i = 0; i < this.items.length; i++) {
|
||||
@ -1168,6 +1170,8 @@ HeadersPacket.prototype.fromReader = function fromReader(br) {
|
||||
var count = br.readVarint();
|
||||
var i;
|
||||
|
||||
assert(count <= 2000, 'Too many headers.');
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
this.items.push(Headers.fromReader(br));
|
||||
|
||||
|
||||
@ -2186,7 +2186,7 @@ Peer.prototype.reject = function reject(msg, code, reason, score) {
|
||||
*/
|
||||
|
||||
Peer.prototype.sync = co(function* sync() {
|
||||
var locator, tip, checkpoint;
|
||||
var locator, tip, watermark;
|
||||
|
||||
if (!this.pool.syncing)
|
||||
return false;
|
||||
@ -2220,8 +2220,8 @@ Peer.prototype.sync = co(function* sync() {
|
||||
|
||||
if (this.pool.headersFirst) {
|
||||
tip = this.chain.tip;
|
||||
checkpoint = this.pool.nextCheckpoint;
|
||||
this.sendGetHeaders([tip.hash], checkpoint.hash);
|
||||
watermark = this.pool.headerTip;
|
||||
this.sendGetHeaders([tip.hash], watermark.hash);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
114
lib/net/pool.js
114
lib/net/pool.js
@ -116,7 +116,7 @@ function Pool(options) {
|
||||
this.headersFirst = false;
|
||||
this.headerChain = new List();
|
||||
this.headerNext = null;
|
||||
this.nextCheckpoint = null;
|
||||
this.headerTip = null;
|
||||
this.checkpoints = [];
|
||||
|
||||
this.peers = new PeerList();
|
||||
@ -241,29 +241,26 @@ Pool.prototype._open = co(function* _open() {
|
||||
|
||||
Pool.prototype.resetChain = function resetChain() {
|
||||
var tip = this.chain.tip;
|
||||
var checkpoint;
|
||||
var watermark;
|
||||
|
||||
if (!this.options.headers)
|
||||
return;
|
||||
|
||||
if (!this.chain.options.useCheckpoints)
|
||||
return;
|
||||
|
||||
this.headersFirst = false;
|
||||
this.nextCheckpoint = null;
|
||||
this.headerTip = null;
|
||||
this.headerChain.reset();
|
||||
this.headerNext = null;
|
||||
|
||||
checkpoint = this.getNextCheckpoint(tip.height);
|
||||
watermark = this.getNextTip(tip.height);
|
||||
|
||||
if (checkpoint) {
|
||||
if (watermark) {
|
||||
this.headersFirst = true;
|
||||
this.nextCheckpoint = checkpoint;
|
||||
this.headerTip = watermark;
|
||||
this.headerChain.push(new BlockNode(tip.hash, tip.height));
|
||||
this.logger.info(
|
||||
'Initialized header chain to height %d (checkpoint=%d).',
|
||||
'Initialized header chain to height %d (watermark=%d).',
|
||||
tip.height,
|
||||
checkpoint.height);
|
||||
watermark.height);
|
||||
}
|
||||
};
|
||||
|
||||
@ -383,7 +380,7 @@ Pool.prototype._disconnect = co(function* disconnect() {
|
||||
}
|
||||
|
||||
this.headersFirst = false;
|
||||
this.nextCheckpoint = null;
|
||||
this.headerTip = null;
|
||||
this.headerChain.reset();
|
||||
this.headerNext = null;
|
||||
|
||||
@ -594,7 +591,7 @@ Pool.prototype.sendGetAddr = function sendGetAddr() {
|
||||
* @returns {Promise}
|
||||
*/
|
||||
|
||||
Pool.prototype.resolveHeaders = co(function* resolveHeaders(peer) {
|
||||
Pool.prototype.requestHeaders = co(function* requestHeaders(peer) {
|
||||
var items = [];
|
||||
var node;
|
||||
|
||||
@ -619,15 +616,21 @@ Pool.prototype.resolveHeaders = co(function* resolveHeaders(peer) {
|
||||
});
|
||||
|
||||
/**
|
||||
* Find the next highest checkpoint.
|
||||
* Find the next highest watermark block.
|
||||
* @private
|
||||
* @param {Number} height
|
||||
* @returns {Object}
|
||||
*/
|
||||
|
||||
Pool.prototype.getNextCheckpoint = function getNextCheckpoint(height) {
|
||||
Pool.prototype.getNextTip = function getNextTip(height) {
|
||||
var i, next;
|
||||
|
||||
if (!this.options.useCheckpoints) {
|
||||
if (this.chain.isFull())
|
||||
return;
|
||||
return new BlockNode(null, height + 20000);
|
||||
}
|
||||
|
||||
for (i = 0; i < this.checkpoints.length; i++) {
|
||||
next = this.checkpoints[i];
|
||||
if (next.height > height)
|
||||
@ -1527,7 +1530,7 @@ Pool.prototype.handleHeaders = co(function* handleHeaders(peer, packet) {
|
||||
|
||||
Pool.prototype._handleHeaders = co(function* handleHeaders(peer, packet) {
|
||||
var headers = packet.items;
|
||||
var isCheckpoint = false;
|
||||
var isWatermark = false;
|
||||
var i, header, hash, height, last, node;
|
||||
|
||||
if (!this.headersFirst)
|
||||
@ -1539,13 +1542,22 @@ Pool.prototype._handleHeaders = co(function* handleHeaders(peer, packet) {
|
||||
if (!peer.isLoader())
|
||||
return;
|
||||
|
||||
if (headers.length === 0)
|
||||
return;
|
||||
|
||||
if (headers.length > 2000) {
|
||||
this.increaseBan(100);
|
||||
peer.increaseBan(100);
|
||||
return;
|
||||
}
|
||||
|
||||
if (headers.length === 0)
|
||||
if (this.headerChain.size > 40000) {
|
||||
this.logger.warning(
|
||||
'Peer is sending too many headers (%s).',
|
||||
peer.hostname);
|
||||
peer.increaseBan(100);
|
||||
peer.destroy();
|
||||
return;
|
||||
}
|
||||
|
||||
assert(this.headerChain.size > 0);
|
||||
|
||||
@ -1556,13 +1568,16 @@ Pool.prototype._handleHeaders = co(function* handleHeaders(peer, packet) {
|
||||
height = last.height + 1;
|
||||
|
||||
if (header.prevBlock !== last.hash) {
|
||||
peer.increaseBan(100);
|
||||
throw new Error('Bad header chain.');
|
||||
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).', peer.hostname);
|
||||
peer.increaseBan(100);
|
||||
throw new Error('Invalid header.');
|
||||
peer.destroy();
|
||||
return;
|
||||
}
|
||||
|
||||
node = new BlockNode(hash, last.height + 1);
|
||||
@ -1570,12 +1585,18 @@ Pool.prototype._handleHeaders = co(function* handleHeaders(peer, packet) {
|
||||
if (!this.headerNext)
|
||||
this.headerNext = node;
|
||||
|
||||
if (node.height === this.nextCheckpoint.height) {
|
||||
if (node.hash !== this.nextCheckpoint.hash) {
|
||||
peer.increaseBan(100);
|
||||
throw new Error('Bad checkpoint header.');
|
||||
if (node.height === this.headerTip.height) {
|
||||
if (this.options.useCheckpoints) {
|
||||
if (node.hash !== this.headerTip.hash) {
|
||||
this.logger.warning(
|
||||
'Peer sent an invalid checkpoint (%s).',
|
||||
peer.hostname);
|
||||
peer.increaseBan(100);
|
||||
peer.destroy();
|
||||
return;
|
||||
}
|
||||
}
|
||||
isCheckpoint = true;
|
||||
isWatermark = true;
|
||||
}
|
||||
|
||||
this.headerChain.push(node);
|
||||
@ -1589,14 +1610,14 @@ Pool.prototype._handleHeaders = co(function* handleHeaders(peer, packet) {
|
||||
this.emit('headers', packet, peer);
|
||||
|
||||
// Request the hashes we just added.
|
||||
if (isCheckpoint) {
|
||||
if (isWatermark) {
|
||||
this.headerChain.shift();
|
||||
yield this.resolveHeaders(peer);
|
||||
yield this.requestHeaders(peer);
|
||||
return;
|
||||
}
|
||||
|
||||
// Restart the getheaders process.
|
||||
peer.sendGetHeaders([node.hash], this.nextCheckpoint.hash);
|
||||
peer.sendGetHeaders([node.hash], this.headerTip.hash);
|
||||
});
|
||||
|
||||
/**
|
||||
@ -1658,8 +1679,8 @@ Pool.prototype.addBlock = co(function* addBlock(peer, block) {
|
||||
|
||||
Pool.prototype._addBlock = co(function* addBlock(peer, block) {
|
||||
var hash = block.hash('hex');
|
||||
var isCheckpoint = false;
|
||||
var node, checkpoint;
|
||||
var isWatermark = false;
|
||||
var node, watermark;
|
||||
|
||||
if (!this.syncing)
|
||||
return;
|
||||
@ -1677,11 +1698,11 @@ Pool.prototype._addBlock = co(function* addBlock(peer, block) {
|
||||
assert(node);
|
||||
|
||||
if (hash === node.hash) {
|
||||
if (hash === this.nextCheckpoint.hash) {
|
||||
if (node.height === this.headerTip.height) {
|
||||
this.logger.info(
|
||||
'Received checkpoint block %s (%d).',
|
||||
hash, node.height);
|
||||
isCheckpoint = true;
|
||||
isWatermark = true;
|
||||
} else {
|
||||
this.headerChain.shift();
|
||||
}
|
||||
@ -1716,26 +1737,26 @@ Pool.prototype._addBlock = co(function* addBlock(peer, block) {
|
||||
if (!this.headersFirst)
|
||||
return;
|
||||
|
||||
if (!isCheckpoint) {
|
||||
yield this.resolveHeaders(peer);
|
||||
if (!isWatermark && !this.chain.isFull()) {
|
||||
yield this.requestHeaders(peer);
|
||||
return;
|
||||
}
|
||||
|
||||
node = this.nextCheckpoint;
|
||||
checkpoint = this.getNextCheckpoint(node.height);
|
||||
node = this.headerTip;
|
||||
watermark = this.getNextTip(node.height);
|
||||
|
||||
if (checkpoint) {
|
||||
this.nextCheckpoint = checkpoint;
|
||||
peer.sendGetHeaders([node.hash], checkpoint.hash);
|
||||
if (watermark) {
|
||||
this.headerTip = watermark;
|
||||
peer.sendGetHeaders([hash], watermark.hash);
|
||||
return;
|
||||
}
|
||||
|
||||
this.headersFirst = false;
|
||||
this.nextCheckpoint = null;
|
||||
this.headerTip = null;
|
||||
this.headerChain.reset();
|
||||
this.headerNext = null;
|
||||
|
||||
peer.sendGetBlocks([hash], null);
|
||||
yield this.getBlocks(peer, hash);
|
||||
});
|
||||
|
||||
/**
|
||||
@ -2884,6 +2905,7 @@ function PoolOptions(options) {
|
||||
this.mempool = null;
|
||||
|
||||
this.witness = this.network.witness;
|
||||
this.useCheckpoints = false;
|
||||
this.spv = false;
|
||||
this.listen = false;
|
||||
this.headers = false;
|
||||
@ -2956,6 +2978,14 @@ PoolOptions.prototype.fromOptions = function fromOptions(options) {
|
||||
this.witness = this.chain.options.witness;
|
||||
}
|
||||
|
||||
if (options.useCheckpoints != null) {
|
||||
assert(typeof options.useCheckpoints === 'boolean');
|
||||
assert(options.useCheckpoints === this.chain.options.useCheckpoints);
|
||||
this.useCheckpoints = options.useCheckpoints;
|
||||
} else {
|
||||
this.useCheckpoints = this.chain.options.useCheckpoints;
|
||||
}
|
||||
|
||||
if (options.spv != null) {
|
||||
assert(typeof options.spv === 'boolean');
|
||||
assert(options.spv === this.chain.options.spv);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user