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