net: refactor inv type handling.
This commit is contained in:
parent
2691f9fcb6
commit
82d1345311
@ -27,6 +27,7 @@ var TX = require('../primitives/tx');
|
|||||||
var errors = require('../btc/errors');
|
var errors = require('../btc/errors');
|
||||||
var List = require('../utils/list');
|
var List = require('../utils/list');
|
||||||
var IP = require('../utils/ip');
|
var IP = require('../utils/ip');
|
||||||
|
var invTypes = constants.inv;
|
||||||
var packetTypes = packets.types;
|
var packetTypes = packets.types;
|
||||||
var VerifyResult = errors.VerifyResult;
|
var VerifyResult = errors.VerifyResult;
|
||||||
|
|
||||||
@ -673,10 +674,10 @@ Peer.prototype.announceList = function announceList() {
|
|||||||
|
|
||||||
for (item = this.pool.invItems.head; item; item = item.next) {
|
for (item = this.pool.invItems.head; item; item = item.next) {
|
||||||
switch (item.type) {
|
switch (item.type) {
|
||||||
case constants.inv.TX:
|
case invTypes.TX:
|
||||||
txs.push(item.msg);
|
txs.push(item.msg);
|
||||||
break;
|
break;
|
||||||
case constants.inv.BLOCK:
|
case invTypes.BLOCK:
|
||||||
blocks.push(item.msg);
|
blocks.push(item.msg);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -1065,6 +1066,39 @@ Peer.prototype.response = function response(cmd, payload) {
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate peer block inv type (filtered,
|
||||||
|
* compact, witness, or non-witness).
|
||||||
|
* @returns {Number}
|
||||||
|
*/
|
||||||
|
|
||||||
|
Peer.prototype.blockType = function blockType() {
|
||||||
|
if (this.options.spv)
|
||||||
|
return invTypes.FILTERED_BLOCK;
|
||||||
|
|
||||||
|
if (this.options.compact && this.compactMode) {
|
||||||
|
if (!this.options.witness || this.compactWitness)
|
||||||
|
return invTypes.CMPCT_BLOCK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.haveWitness)
|
||||||
|
return invTypes.WITNESS_BLOCK;
|
||||||
|
|
||||||
|
return invTypes.BLOCK;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate peer tx inv type (witness or non-witness).
|
||||||
|
* @returns {Number}
|
||||||
|
*/
|
||||||
|
|
||||||
|
Peer.prototype.txType = function txType() {
|
||||||
|
if (this.haveWitness)
|
||||||
|
return invTypes.WITNESS_TX;
|
||||||
|
|
||||||
|
return invTypes.TX;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send `getdata` to peer.
|
* Send `getdata` to peer.
|
||||||
* @param {LoadRequest[]} items
|
* @param {LoadRequest[]} items
|
||||||
@ -1076,16 +1110,7 @@ Peer.prototype.getData = function getData(items) {
|
|||||||
|
|
||||||
for (i = 0; i < items.length; i++) {
|
for (i = 0; i < items.length; i++) {
|
||||||
item = items[i];
|
item = items[i];
|
||||||
item = item.toInv();
|
inv.push(item.toInv());
|
||||||
|
|
||||||
if (this.options.compact
|
|
||||||
&& this.compactMode
|
|
||||||
&& item.isBlock()
|
|
||||||
&& !item.hasWitness()) {
|
|
||||||
item.type = constants.inv.CMPCT_BLOCK;
|
|
||||||
}
|
|
||||||
|
|
||||||
inv.push(item);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.send(new packets.GetDataPacket(inv));
|
this.send(new packets.GetDataPacket(inv));
|
||||||
@ -1503,7 +1528,7 @@ Peer.prototype.handleGetBlocks = co(function* handleGetBlocks(packet) {
|
|||||||
hash = yield this.chain.db.getNextHash(hash);
|
hash = yield this.chain.db.getNextHash(hash);
|
||||||
|
|
||||||
while (hash) {
|
while (hash) {
|
||||||
blocks.push(new InvItem(constants.inv.BLOCK, hash));
|
blocks.push(new InvItem(invTypes.BLOCK, hash));
|
||||||
|
|
||||||
if (hash === packet.stop)
|
if (hash === packet.stop)
|
||||||
break;
|
break;
|
||||||
@ -1622,7 +1647,7 @@ Peer.prototype.handleMempool = co(function* handleMempool(packet) {
|
|||||||
hashes = this.mempool.getSnapshot();
|
hashes = this.mempool.getSnapshot();
|
||||||
|
|
||||||
for (i = 0; i < hashes.length; i++)
|
for (i = 0; i < hashes.length; i++)
|
||||||
items.push(new InvItem(constants.inv.TX, hashes[i]));
|
items.push(new InvItem(invTypes.TX, hashes[i]));
|
||||||
|
|
||||||
this.logger.debug('Sending mempool snapshot (%s).', this.hostname);
|
this.logger.debug('Sending mempool snapshot (%s).', this.hostname);
|
||||||
|
|
||||||
@ -1644,7 +1669,7 @@ Peer.prototype.getBroadcasted = function getBroadcasted(item) {
|
|||||||
|
|
||||||
this.logger.debug(
|
this.logger.debug(
|
||||||
'Peer requested %s %s as a %s packet (%s).',
|
'Peer requested %s %s as a %s packet (%s).',
|
||||||
entry.type === constants.inv.TX ? 'tx' : 'block',
|
entry.type === invTypes.TX ? 'tx' : 'block',
|
||||||
util.revHex(entry.hash),
|
util.revHex(entry.hash),
|
||||||
item.hasWitness() ? 'witness' : 'normal',
|
item.hasWitness() ? 'witness' : 'normal',
|
||||||
this.hostname);
|
this.hostname);
|
||||||
@ -1655,10 +1680,10 @@ Peer.prototype.getBroadcasted = function getBroadcasted(item) {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (item.isTX()) {
|
if (item.isTX()) {
|
||||||
if (entry.type !== constants.inv.TX)
|
if (entry.type !== invTypes.TX)
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
if (entry.type !== constants.inv.BLOCK)
|
if (entry.type !== invTypes.BLOCK)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1810,8 +1835,8 @@ Peer.prototype.handleGetData = co(function* handleGetData(packet) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch (item.type) {
|
switch (item.type) {
|
||||||
case constants.inv.BLOCK:
|
case invTypes.BLOCK:
|
||||||
case constants.inv.WITNESS_BLOCK:
|
case invTypes.WITNESS_BLOCK:
|
||||||
result = yield this.sendBlock(item, item.hasWitness());
|
result = yield this.sendBlock(item, item.hasWitness());
|
||||||
if (!result) {
|
if (!result) {
|
||||||
notFound.push(item);
|
notFound.push(item);
|
||||||
@ -1819,8 +1844,8 @@ Peer.prototype.handleGetData = co(function* handleGetData(packet) {
|
|||||||
}
|
}
|
||||||
blocks++;
|
blocks++;
|
||||||
break;
|
break;
|
||||||
case constants.inv.FILTERED_BLOCK:
|
case invTypes.FILTERED_BLOCK:
|
||||||
case constants.inv.WITNESS_FILTERED_BLOCK:
|
case invTypes.WITNESS_FILTERED_BLOCK:
|
||||||
if (!this.spvFilter) {
|
if (!this.spvFilter) {
|
||||||
notFound.push(item);
|
notFound.push(item);
|
||||||
continue;
|
continue;
|
||||||
@ -1846,7 +1871,7 @@ Peer.prototype.handleGetData = co(function* handleGetData(packet) {
|
|||||||
blocks++;
|
blocks++;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case constants.inv.CMPCT_BLOCK:
|
case invTypes.CMPCT_BLOCK:
|
||||||
// Fallback to full block.
|
// Fallback to full block.
|
||||||
height = yield this.chain.db.getHeight(item.hash);
|
height = yield this.chain.db.getHeight(item.hash);
|
||||||
if (height < this.chain.tip.height - 10) {
|
if (height < this.chain.tip.height - 10) {
|
||||||
@ -1878,7 +1903,7 @@ Peer.prototype.handleGetData = co(function* handleGetData(packet) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (item.hash === this.hashContinue) {
|
if (item.hash === this.hashContinue) {
|
||||||
this.sendInv([new InvItem(constants.inv.BLOCK, this.chain.tip.hash)]);
|
this.sendInv([new InvItem(invTypes.BLOCK, this.chain.tip.hash)]);
|
||||||
this.hashContinue = null;
|
this.hashContinue = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2058,10 +2083,10 @@ Peer.prototype.handleInv = co(function* handleInv(packet) {
|
|||||||
for (i = 0; i < items.length; i++) {
|
for (i = 0; i < items.length; i++) {
|
||||||
item = items[i];
|
item = items[i];
|
||||||
switch (item.type) {
|
switch (item.type) {
|
||||||
case constants.inv.TX:
|
case invTypes.TX:
|
||||||
txs.push(item.hash);
|
txs.push(item.hash);
|
||||||
break;
|
break;
|
||||||
case constants.inv.BLOCK:
|
case invTypes.BLOCK:
|
||||||
blocks.push(item.hash);
|
blocks.push(item.hash);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -2408,7 +2433,7 @@ Peer.prototype.handleGetBlockTxn = co(function* handleGetBlockTxn(packet) {
|
|||||||
if (this.options.selfish)
|
if (this.options.selfish)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
item = new InvItem(constants.inv.BLOCK, req.hash);
|
item = new InvItem(invTypes.BLOCK, req.hash);
|
||||||
|
|
||||||
block = yield this.getItem(item);
|
block = yield this.getItem(item);
|
||||||
|
|
||||||
@ -2715,7 +2740,7 @@ Peer.prototype.sync = co(function* sync() {
|
|||||||
if (!this.version.hasNetwork())
|
if (!this.version.hasNetwork())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (this.options.witness && !this.version.hasWitness())
|
if (this.options.witness && !this.haveWitness)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!this.isLoader()) {
|
if (!this.isLoader()) {
|
||||||
|
|||||||
@ -28,6 +28,7 @@ var request = require('../http/request');
|
|||||||
var List = require('../utils/list');
|
var List = require('../utils/list');
|
||||||
var tcp = require('./tcp');
|
var tcp = require('./tcp');
|
||||||
var dns = require('./dns');
|
var dns = require('./dns');
|
||||||
|
var invTypes = constants.inv;
|
||||||
var VerifyError = errors.VerifyError;
|
var VerifyError = errors.VerifyError;
|
||||||
var VerifyResult = errors.VerifyResult;
|
var VerifyResult = errors.VerifyResult;
|
||||||
|
|
||||||
@ -128,9 +129,6 @@ function Pool(options) {
|
|||||||
this.peers = new PeerList(this);
|
this.peers = new PeerList(this);
|
||||||
this.hosts = new HostList(this);
|
this.hosts = new HostList(this);
|
||||||
|
|
||||||
this.blockType = constants.inv.BLOCK;
|
|
||||||
this.txType = constants.inv.TX;
|
|
||||||
|
|
||||||
this.localNonce = util.nonce();
|
this.localNonce = util.nonce();
|
||||||
|
|
||||||
this.spvFilter = null;
|
this.spvFilter = null;
|
||||||
@ -220,16 +218,7 @@ Pool.prototype._initOptions = function _initOptions() {
|
|||||||
this.hosts.setSeeds(this.options.seeds);
|
this.hosts.setSeeds(this.options.seeds);
|
||||||
|
|
||||||
if (this.options.preferredSeed)
|
if (this.options.preferredSeed)
|
||||||
this.hosts.addSeed(this.options.preferredSeed);
|
this.hosts.setSeeds([this.options.preferredSeed]);
|
||||||
|
|
||||||
if (this.options.witness) {
|
|
||||||
this.blockType |= constants.WITNESS_MASK;
|
|
||||||
this.txType |= constants.WITNESS_MASK;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Note: No witness bit for merkleblocks.
|
|
||||||
if (this.options.spv)
|
|
||||||
this.blockType = constants.inv.FILTERED_BLOCK;
|
|
||||||
|
|
||||||
if (this.options.spv)
|
if (this.options.spv)
|
||||||
this.spvFilter = Bloom.fromRate(10000, 0.001, constants.bloom.ALL);
|
this.spvFilter = Bloom.fromRate(10000, 0.001, constants.bloom.ALL);
|
||||||
@ -1285,7 +1274,7 @@ Pool.prototype._handleBlockInv = co(function* handleBlockInv(hashes, peer) {
|
|||||||
if (!this.chain.synced && !peer.isLoader())
|
if (!this.chain.synced && !peer.isLoader())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (this.options.witness && !peer.version.hasWitness())
|
if (this.options.witness && !peer.haveWitness)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Request headers instead.
|
// Request headers instead.
|
||||||
@ -1668,13 +1657,16 @@ Pool.prototype.getBlock = function getBlock(peer, hash) {
|
|||||||
if (!this.loaded)
|
if (!this.loaded)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (!peer.ack)
|
||||||
|
throw new Error('Peer handshake not complete (getdata).');
|
||||||
|
|
||||||
if (peer.destroyed)
|
if (peer.destroyed)
|
||||||
throw new Error('Peer is already destroyed (getdata).');
|
throw new Error('Peer is already destroyed (getdata).');
|
||||||
|
|
||||||
if (this.requestMap[hash])
|
if (this.requestMap[hash])
|
||||||
return;
|
return;
|
||||||
|
|
||||||
item = new LoadRequest(this, peer, this.blockType, hash);
|
item = new LoadRequest(this, peer, invTypes.BLOCK, hash);
|
||||||
|
|
||||||
peer.queueBlock.push(item);
|
peer.queueBlock.push(item);
|
||||||
};
|
};
|
||||||
@ -1714,13 +1706,16 @@ Pool.prototype.getTX = function getTX(peer, hash) {
|
|||||||
if (!this.loaded)
|
if (!this.loaded)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (!peer.ack)
|
||||||
|
throw new Error('Peer handshake not complete (getdata).');
|
||||||
|
|
||||||
if (peer.destroyed)
|
if (peer.destroyed)
|
||||||
throw new Error('Peer is already destroyed (getdata).');
|
throw new Error('Peer is already destroyed (getdata).');
|
||||||
|
|
||||||
if (this.hasTX(hash))
|
if (this.hasTX(hash))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
item = new LoadRequest(this, peer, this.txType, hash);
|
item = new LoadRequest(this, peer, invTypes.TX, hash);
|
||||||
|
|
||||||
if (peer.queueTX.size === 0) {
|
if (peer.queueTX.size === 0) {
|
||||||
util.nextTick(function() {
|
util.nextTick(function() {
|
||||||
@ -2410,7 +2405,7 @@ LoadRequest.prototype.destroy = function destroy() {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
LoadRequest.prototype._onTimeout = function _onTimeout() {
|
LoadRequest.prototype._onTimeout = function _onTimeout() {
|
||||||
if (this.type !== this.pool.txType && this.peer.isLoader()) {
|
if (this.type === invTypes.BLOCK && this.peer.isLoader()) {
|
||||||
this.pool.logger.debug(
|
this.pool.logger.debug(
|
||||||
'Loader took too long serving a block. Finding a new one.');
|
'Loader took too long serving a block. Finding a new one.');
|
||||||
this.peer.destroy();
|
this.peer.destroy();
|
||||||
@ -2428,7 +2423,7 @@ LoadRequest.prototype.start = function start() {
|
|||||||
this.active = true;
|
this.active = true;
|
||||||
this.pool.activeRequest++;
|
this.pool.activeRequest++;
|
||||||
|
|
||||||
if (this.type === this.pool.txType)
|
if (this.type === invTypes.TX)
|
||||||
this.pool.activeTX++;
|
this.pool.activeTX++;
|
||||||
else
|
else
|
||||||
this.pool.activeBlocks++;
|
this.pool.activeBlocks++;
|
||||||
@ -2442,19 +2437,22 @@ LoadRequest.prototype.start = function start() {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
LoadRequest.prototype.finish = function finish() {
|
LoadRequest.prototype.finish = function finish() {
|
||||||
if (this.pool.requestMap[this.hash] === this) {
|
var entry = this.pool.requestMap[this.hash];
|
||||||
|
|
||||||
|
if (entry) {
|
||||||
|
assert(entry === this);
|
||||||
delete this.pool.requestMap[this.hash];
|
delete this.pool.requestMap[this.hash];
|
||||||
if (this.active) {
|
if (this.active) {
|
||||||
this.active = false;
|
this.active = false;
|
||||||
this.pool.activeRequest--;
|
this.pool.activeRequest--;
|
||||||
if (this.type === this.pool.txType)
|
if (this.type === invTypes.TX)
|
||||||
this.pool.activeTX--;
|
this.pool.activeTX--;
|
||||||
else
|
else
|
||||||
this.pool.activeBlocks--;
|
this.pool.activeBlocks--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.type === this.pool.txType)
|
if (this.type === invTypes.TX)
|
||||||
this.peer.queueTX.remove(this);
|
this.peer.queueTX.remove(this);
|
||||||
else
|
else
|
||||||
this.peer.queueBlock.remove(this);
|
this.peer.queueBlock.remove(this);
|
||||||
@ -2473,7 +2471,7 @@ LoadRequest.prototype.finish = function finish() {
|
|||||||
LoadRequest.prototype.inspect = function inspect() {
|
LoadRequest.prototype.inspect = function inspect() {
|
||||||
return '<LoadRequest:'
|
return '<LoadRequest:'
|
||||||
+ ' id=' + this.id
|
+ ' id=' + this.id
|
||||||
+ ' type=' + (this.type === this.pool.txType ? 'tx' : 'block')
|
+ ' type=' + (this.type === invTypes.TX ? 'tx' : 'block')
|
||||||
+ ' active=' + this.active
|
+ ' active=' + this.active
|
||||||
+ ' hash=' + util.revHex(this.hash)
|
+ ' hash=' + util.revHex(this.hash)
|
||||||
+ '>';
|
+ '>';
|
||||||
@ -2485,7 +2483,11 @@ LoadRequest.prototype.inspect = function inspect() {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
LoadRequest.prototype.toInv = function toInv() {
|
LoadRequest.prototype.toInv = function toInv() {
|
||||||
return new InvItem(this.type, this.hash);
|
var type = this.type === invTypes.BLOCK
|
||||||
|
? this.peer.blockType()
|
||||||
|
: this.peer.txType();
|
||||||
|
|
||||||
|
return new InvItem(type, this.hash);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2571,10 +2573,10 @@ BroadcastItem.prototype.refresh = function refresh() {
|
|||||||
|
|
||||||
BroadcastItem.prototype.announce = function announce() {
|
BroadcastItem.prototype.announce = function announce() {
|
||||||
switch (this.type) {
|
switch (this.type) {
|
||||||
case constants.inv.TX:
|
case invTypes.TX:
|
||||||
this.pool.announceTX(this.msg);
|
this.pool.announceTX(this.msg);
|
||||||
break;
|
break;
|
||||||
case constants.inv.BLOCK:
|
case invTypes.BLOCK:
|
||||||
this.pool.announceBlock(this.msg);
|
this.pool.announceBlock(this.msg);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -2649,7 +2651,7 @@ BroadcastItem.prototype.reject = function reject(peer) {
|
|||||||
BroadcastItem.prototype.inspect = function inspect() {
|
BroadcastItem.prototype.inspect = function inspect() {
|
||||||
return '<BroadcastItem:'
|
return '<BroadcastItem:'
|
||||||
+ ' id=' + this.id
|
+ ' id=' + this.id
|
||||||
+ ' type=' + (this.type === constants.inv.TX ? 'tx' : 'block')
|
+ ' type=' + (this.type === invTypes.TX ? 'tx' : 'block')
|
||||||
+ ' hash=' + util.revHex(this.hash)
|
+ ' hash=' + util.revHex(this.hash)
|
||||||
+ '>';
|
+ '>';
|
||||||
};
|
};
|
||||||
|
|||||||
@ -338,18 +338,8 @@ FullNode.prototype.sendTX = co(function* sendTX(tx) {
|
|||||||
|
|
||||||
if (missing) {
|
if (missing) {
|
||||||
this.logger.warning('TX was orphaned in mempool: %s.', tx.txid());
|
this.logger.warning('TX was orphaned in mempool: %s.', tx.txid());
|
||||||
|
|
||||||
// Avoid getting dos'd by bitcoind for now.
|
|
||||||
// See: https://github.com/bitcoin/bitcoin/issues/9182
|
|
||||||
// Once this fix is widely deployed, we can remove this.
|
|
||||||
if (tx.hasWitness()) {
|
|
||||||
this.logger.warning('Not broadcasting for now to avoid bitcoind DoS.');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.logger.warning('Attempting to broadcast anyway...');
|
this.logger.warning('Attempting to broadcast anyway...');
|
||||||
this.broadcast(tx);
|
this.broadcast(tx);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user