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 List = require('../utils/list');
|
||||
var IP = require('../utils/ip');
|
||||
var invTypes = constants.inv;
|
||||
var packetTypes = packets.types;
|
||||
var VerifyResult = errors.VerifyResult;
|
||||
|
||||
@ -673,10 +674,10 @@ Peer.prototype.announceList = function announceList() {
|
||||
|
||||
for (item = this.pool.invItems.head; item; item = item.next) {
|
||||
switch (item.type) {
|
||||
case constants.inv.TX:
|
||||
case invTypes.TX:
|
||||
txs.push(item.msg);
|
||||
break;
|
||||
case constants.inv.BLOCK:
|
||||
case invTypes.BLOCK:
|
||||
blocks.push(item.msg);
|
||||
break;
|
||||
default:
|
||||
@ -1065,6 +1066,39 @@ Peer.prototype.response = function response(cmd, payload) {
|
||||
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.
|
||||
* @param {LoadRequest[]} items
|
||||
@ -1076,16 +1110,7 @@ Peer.prototype.getData = function getData(items) {
|
||||
|
||||
for (i = 0; i < items.length; i++) {
|
||||
item = items[i];
|
||||
item = item.toInv();
|
||||
|
||||
if (this.options.compact
|
||||
&& this.compactMode
|
||||
&& item.isBlock()
|
||||
&& !item.hasWitness()) {
|
||||
item.type = constants.inv.CMPCT_BLOCK;
|
||||
}
|
||||
|
||||
inv.push(item);
|
||||
inv.push(item.toInv());
|
||||
}
|
||||
|
||||
this.send(new packets.GetDataPacket(inv));
|
||||
@ -1503,7 +1528,7 @@ Peer.prototype.handleGetBlocks = co(function* handleGetBlocks(packet) {
|
||||
hash = yield this.chain.db.getNextHash(hash);
|
||||
|
||||
while (hash) {
|
||||
blocks.push(new InvItem(constants.inv.BLOCK, hash));
|
||||
blocks.push(new InvItem(invTypes.BLOCK, hash));
|
||||
|
||||
if (hash === packet.stop)
|
||||
break;
|
||||
@ -1622,7 +1647,7 @@ Peer.prototype.handleMempool = co(function* handleMempool(packet) {
|
||||
hashes = this.mempool.getSnapshot();
|
||||
|
||||
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);
|
||||
|
||||
@ -1644,7 +1669,7 @@ Peer.prototype.getBroadcasted = function getBroadcasted(item) {
|
||||
|
||||
this.logger.debug(
|
||||
'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),
|
||||
item.hasWitness() ? 'witness' : 'normal',
|
||||
this.hostname);
|
||||
@ -1655,10 +1680,10 @@ Peer.prototype.getBroadcasted = function getBroadcasted(item) {
|
||||
return;
|
||||
|
||||
if (item.isTX()) {
|
||||
if (entry.type !== constants.inv.TX)
|
||||
if (entry.type !== invTypes.TX)
|
||||
return;
|
||||
} else {
|
||||
if (entry.type !== constants.inv.BLOCK)
|
||||
if (entry.type !== invTypes.BLOCK)
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1810,8 +1835,8 @@ Peer.prototype.handleGetData = co(function* handleGetData(packet) {
|
||||
}
|
||||
|
||||
switch (item.type) {
|
||||
case constants.inv.BLOCK:
|
||||
case constants.inv.WITNESS_BLOCK:
|
||||
case invTypes.BLOCK:
|
||||
case invTypes.WITNESS_BLOCK:
|
||||
result = yield this.sendBlock(item, item.hasWitness());
|
||||
if (!result) {
|
||||
notFound.push(item);
|
||||
@ -1819,8 +1844,8 @@ Peer.prototype.handleGetData = co(function* handleGetData(packet) {
|
||||
}
|
||||
blocks++;
|
||||
break;
|
||||
case constants.inv.FILTERED_BLOCK:
|
||||
case constants.inv.WITNESS_FILTERED_BLOCK:
|
||||
case invTypes.FILTERED_BLOCK:
|
||||
case invTypes.WITNESS_FILTERED_BLOCK:
|
||||
if (!this.spvFilter) {
|
||||
notFound.push(item);
|
||||
continue;
|
||||
@ -1846,7 +1871,7 @@ Peer.prototype.handleGetData = co(function* handleGetData(packet) {
|
||||
blocks++;
|
||||
|
||||
break;
|
||||
case constants.inv.CMPCT_BLOCK:
|
||||
case invTypes.CMPCT_BLOCK:
|
||||
// Fallback to full block.
|
||||
height = yield this.chain.db.getHeight(item.hash);
|
||||
if (height < this.chain.tip.height - 10) {
|
||||
@ -1878,7 +1903,7 @@ Peer.prototype.handleGetData = co(function* handleGetData(packet) {
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -2058,10 +2083,10 @@ Peer.prototype.handleInv = co(function* handleInv(packet) {
|
||||
for (i = 0; i < items.length; i++) {
|
||||
item = items[i];
|
||||
switch (item.type) {
|
||||
case constants.inv.TX:
|
||||
case invTypes.TX:
|
||||
txs.push(item.hash);
|
||||
break;
|
||||
case constants.inv.BLOCK:
|
||||
case invTypes.BLOCK:
|
||||
blocks.push(item.hash);
|
||||
break;
|
||||
default:
|
||||
@ -2408,7 +2433,7 @@ Peer.prototype.handleGetBlockTxn = co(function* handleGetBlockTxn(packet) {
|
||||
if (this.options.selfish)
|
||||
return;
|
||||
|
||||
item = new InvItem(constants.inv.BLOCK, req.hash);
|
||||
item = new InvItem(invTypes.BLOCK, req.hash);
|
||||
|
||||
block = yield this.getItem(item);
|
||||
|
||||
@ -2715,7 +2740,7 @@ Peer.prototype.sync = co(function* sync() {
|
||||
if (!this.version.hasNetwork())
|
||||
return;
|
||||
|
||||
if (this.options.witness && !this.version.hasWitness())
|
||||
if (this.options.witness && !this.haveWitness)
|
||||
return;
|
||||
|
||||
if (!this.isLoader()) {
|
||||
|
||||
@ -28,6 +28,7 @@ var request = require('../http/request');
|
||||
var List = require('../utils/list');
|
||||
var tcp = require('./tcp');
|
||||
var dns = require('./dns');
|
||||
var invTypes = constants.inv;
|
||||
var VerifyError = errors.VerifyError;
|
||||
var VerifyResult = errors.VerifyResult;
|
||||
|
||||
@ -128,9 +129,6 @@ function Pool(options) {
|
||||
this.peers = new PeerList(this);
|
||||
this.hosts = new HostList(this);
|
||||
|
||||
this.blockType = constants.inv.BLOCK;
|
||||
this.txType = constants.inv.TX;
|
||||
|
||||
this.localNonce = util.nonce();
|
||||
|
||||
this.spvFilter = null;
|
||||
@ -220,16 +218,7 @@ Pool.prototype._initOptions = function _initOptions() {
|
||||
this.hosts.setSeeds(this.options.seeds);
|
||||
|
||||
if (this.options.preferredSeed)
|
||||
this.hosts.addSeed(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;
|
||||
this.hosts.setSeeds([this.options.preferredSeed]);
|
||||
|
||||
if (this.options.spv)
|
||||
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())
|
||||
return;
|
||||
|
||||
if (this.options.witness && !peer.version.hasWitness())
|
||||
if (this.options.witness && !peer.haveWitness)
|
||||
return;
|
||||
|
||||
// Request headers instead.
|
||||
@ -1668,13 +1657,16 @@ Pool.prototype.getBlock = function getBlock(peer, hash) {
|
||||
if (!this.loaded)
|
||||
return;
|
||||
|
||||
if (!peer.ack)
|
||||
throw new Error('Peer handshake not complete (getdata).');
|
||||
|
||||
if (peer.destroyed)
|
||||
throw new Error('Peer is already destroyed (getdata).');
|
||||
|
||||
if (this.requestMap[hash])
|
||||
return;
|
||||
|
||||
item = new LoadRequest(this, peer, this.blockType, hash);
|
||||
item = new LoadRequest(this, peer, invTypes.BLOCK, hash);
|
||||
|
||||
peer.queueBlock.push(item);
|
||||
};
|
||||
@ -1714,13 +1706,16 @@ Pool.prototype.getTX = function getTX(peer, hash) {
|
||||
if (!this.loaded)
|
||||
return;
|
||||
|
||||
if (!peer.ack)
|
||||
throw new Error('Peer handshake not complete (getdata).');
|
||||
|
||||
if (peer.destroyed)
|
||||
throw new Error('Peer is already destroyed (getdata).');
|
||||
|
||||
if (this.hasTX(hash))
|
||||
return true;
|
||||
|
||||
item = new LoadRequest(this, peer, this.txType, hash);
|
||||
item = new LoadRequest(this, peer, invTypes.TX, hash);
|
||||
|
||||
if (peer.queueTX.size === 0) {
|
||||
util.nextTick(function() {
|
||||
@ -2410,7 +2405,7 @@ LoadRequest.prototype.destroy = function destroy() {
|
||||
*/
|
||||
|
||||
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(
|
||||
'Loader took too long serving a block. Finding a new one.');
|
||||
this.peer.destroy();
|
||||
@ -2428,7 +2423,7 @@ LoadRequest.prototype.start = function start() {
|
||||
this.active = true;
|
||||
this.pool.activeRequest++;
|
||||
|
||||
if (this.type === this.pool.txType)
|
||||
if (this.type === invTypes.TX)
|
||||
this.pool.activeTX++;
|
||||
else
|
||||
this.pool.activeBlocks++;
|
||||
@ -2442,19 +2437,22 @@ LoadRequest.prototype.start = function start() {
|
||||
*/
|
||||
|
||||
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];
|
||||
if (this.active) {
|
||||
this.active = false;
|
||||
this.pool.activeRequest--;
|
||||
if (this.type === this.pool.txType)
|
||||
if (this.type === invTypes.TX)
|
||||
this.pool.activeTX--;
|
||||
else
|
||||
this.pool.activeBlocks--;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.type === this.pool.txType)
|
||||
if (this.type === invTypes.TX)
|
||||
this.peer.queueTX.remove(this);
|
||||
else
|
||||
this.peer.queueBlock.remove(this);
|
||||
@ -2473,7 +2471,7 @@ LoadRequest.prototype.finish = function finish() {
|
||||
LoadRequest.prototype.inspect = function inspect() {
|
||||
return '<LoadRequest:'
|
||||
+ ' id=' + this.id
|
||||
+ ' type=' + (this.type === this.pool.txType ? 'tx' : 'block')
|
||||
+ ' type=' + (this.type === invTypes.TX ? 'tx' : 'block')
|
||||
+ ' active=' + this.active
|
||||
+ ' hash=' + util.revHex(this.hash)
|
||||
+ '>';
|
||||
@ -2485,7 +2483,11 @@ LoadRequest.prototype.inspect = function inspect() {
|
||||
*/
|
||||
|
||||
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() {
|
||||
switch (this.type) {
|
||||
case constants.inv.TX:
|
||||
case invTypes.TX:
|
||||
this.pool.announceTX(this.msg);
|
||||
break;
|
||||
case constants.inv.BLOCK:
|
||||
case invTypes.BLOCK:
|
||||
this.pool.announceBlock(this.msg);
|
||||
break;
|
||||
default:
|
||||
@ -2649,7 +2651,7 @@ BroadcastItem.prototype.reject = function reject(peer) {
|
||||
BroadcastItem.prototype.inspect = function inspect() {
|
||||
return '<BroadcastItem:'
|
||||
+ ' id=' + this.id
|
||||
+ ' type=' + (this.type === constants.inv.TX ? 'tx' : 'block')
|
||||
+ ' type=' + (this.type === invTypes.TX ? 'tx' : 'block')
|
||||
+ ' hash=' + util.revHex(this.hash)
|
||||
+ '>';
|
||||
};
|
||||
|
||||
@ -338,18 +338,8 @@ FullNode.prototype.sendTX = co(function* sendTX(tx) {
|
||||
|
||||
if (missing) {
|
||||
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.broadcast(tx);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user