From 514e735a96aa089dec7453d016595f8b50ac3279 Mon Sep 17 00:00:00 2001 From: Christopher Jeffrey Date: Sat, 17 Dec 2016 13:50:45 -0800 Subject: [PATCH] net: refactor reject msg. broadcast orphans. --- lib/net/packets.js | 23 +++++++++++++++++++++++ lib/net/peer.js | 23 ++++++++++++----------- lib/net/pool.js | 16 +++------------- lib/node/fullnode.js | 37 +++++++++++++++++++++++++++++++------ lib/node/spvnode.js | 12 ++++++++---- 5 files changed, 77 insertions(+), 34 deletions(-) diff --git a/lib/net/packets.js b/lib/net/packets.js index 645a1bbb..3734f3f8 100644 --- a/lib/net/packets.js +++ b/lib/net/packets.js @@ -1894,6 +1894,29 @@ RejectPacket.fromOptions = function fromOptions(options) { return new RejectPacket().fromOptions(options); }; +/** + * Get uint256le hash if present. + * @returns {Hash} + */ + +RejectPacket.prototype.rhash = function rhash() { + return this.hash ? util.revHex(this.hash) : null; +}; + +/** + * Get symbolic code. + * @returns {String} + */ + +RejectPacket.prototype.getCode = function getCode() { + var code = constants.rejectByVal[this.code]; + + if (!code) + return this.code + ''; + + return code.toLowerCase(); +}; + /** * Get serialization size. * @returns {Number} diff --git a/lib/net/peer.js b/lib/net/peer.js index 9f275f63..e8c305bf 100644 --- a/lib/net/peer.js +++ b/lib/net/peer.js @@ -183,8 +183,8 @@ Peer.prototype._init = function init() { try { yield self.handlePacket(packet); } catch (e) { - self.destroy(); self.error(e); + self.destroy(); } })); @@ -195,8 +195,8 @@ Peer.prototype._init = function init() { if (this.bip151) { this.bip151.on('error', function(err) { - self.reject(null, 'malformed', 'error parsing message', 10); self.error(err); + self.reject(null, 'malformed', 'error parsing message', 10); }); this.bip151.on('rekey', function() { self.logger.debug('Rekeying with peer (%s).', self.hostname); @@ -231,8 +231,8 @@ Peer.prototype.bind = function bind(socket) { this.socket = socket; this.socket.once('error', function(err) { - self.destroy(); self.error(err); + self.destroy(); switch (err.code) { case 'ECONNREFUSED': @@ -250,10 +250,8 @@ Peer.prototype.bind = function bind(socket) { }); this.socket.once('close', function() { - if (self.destroyed) - return; - self.destroy(); self.error('socket hangup'); + self.destroy(); }); this.socket.on('drain', function() { @@ -332,7 +330,7 @@ Peer.prototype.open = co(function* open() { yield this.finalize(); if (this.destroyed) - throw new Error('Peer was destroyed.'); + throw new Error('Peer was destroyed before handshake.'); // Finally we can let the pool know // that this peer is ready to go. @@ -348,8 +346,8 @@ Peer.prototype.tryOpen = co(function* tryOpen() { try { yield this.open(); } catch (e) { - this.destroy(); this.error(e); + this.destroy(); } }); @@ -917,8 +915,8 @@ Peer.prototype.write = function write(data) { Peer.prototype.needsDrain = function needsDrain(size) { if (this.maybeStall()) { - this.destroy(); this.error('Peer stalled (drain).'); + this.destroy(); return; } @@ -930,8 +928,8 @@ Peer.prototype.needsDrain = function needsDrain(size) { 'Peer is not reading: %dmb buffered (%s).', util.mb(this.drainSize), this.hostname); - this.destroy(); this.error('Peer stalled (drain).'); + this.destroy(); } }; @@ -948,8 +946,8 @@ Peer.prototype.maybeStall = function maybeStall() { return false; this.drainSize = 0; - this.destroy(); this.error('Peer stalled.'); + this.destroy(); return true; }; @@ -998,6 +996,9 @@ Peer.prototype.sendRaw = function sendRaw(cmd, body, checksum) { Peer.prototype.error = function error(err) { var i, args, msg; + if (this.destroyed) + return; + if (typeof err === 'string') { args = new Array(arguments.length); diff --git a/lib/net/pool.js b/lib/net/pool.js index abdc0c92..364d800f 100644 --- a/lib/net/pool.js +++ b/lib/net/pool.js @@ -1385,23 +1385,13 @@ Pool.prototype.handleTXInv = function handleTXInv(txs, peer) { */ Pool.prototype.handleReject = function handleReject(reject, peer) { - var data, code; - - if (reject.hash) - data = util.revHex(reject.hash); - - code = constants.rejectByVal[reject.code]; - - if (code) - code = code.toLowerCase(); - this.logger.warning( - 'Received reject (%s): msg=%s code=%s reason=%s data=%s.', + 'Received reject (%s): msg=%s code=%s reason=%s hash=%s.', peer.hostname, reject.message, - code || reject.code, + reject.getCode(), reject.reason, - data || null); + reject.rhash()); this.emit('reject', reject, peer); }; diff --git a/lib/node/fullnode.js b/lib/node/fullnode.js index f586feca..0f4811b8 100644 --- a/lib/node/fullnode.js +++ b/lib/node/fullnode.js @@ -303,9 +303,13 @@ FullNode.prototype.scan = function scan(start, filter, iter) { * @returns {Promise} */ -FullNode.prototype.broadcast = function broadcast(item) { - return this.pool.broadcast(item); -}; +FullNode.prototype.broadcast = co(function* broadcast(item) { + try { + yield this.pool.broadcast(item); + } catch (e) { + this.emit('error', e); + } +}); /** * Verify a transaction, add it to the mempool, and broadcast. @@ -317,19 +321,40 @@ FullNode.prototype.broadcast = function broadcast(item) { */ FullNode.prototype.sendTX = co(function* sendTX(tx) { + var missing; + try { - yield this.mempool.addTX(tx); + missing = yield this.mempool.addTX(tx); } catch (err) { - if (err.type === 'VerifyError') { + if (err.type === 'VerifyError' && err.score === 0) { this._error(err); this.logger.warning('Verification failed for tx: %s.', tx.txid()); this.logger.warning('Attempting to broadcast anyway...'); - yield this.pool.broadcast(tx); + this.broadcast(tx); return; } throw err; } + 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; + } + + // We need to announce by hand if + // we're running in selfish mode. if (this.options.selfish) this.pool.announceTX(tx); }); diff --git a/lib/node/spvnode.js b/lib/node/spvnode.js index 69d03e72..a0673765 100644 --- a/lib/node/spvnode.js +++ b/lib/node/spvnode.js @@ -282,9 +282,13 @@ SPVNode.prototype.watchBlock = co(function* watchBlock(entry, block) { * @returns {Promise} */ -SPVNode.prototype.broadcast = function broadcast(item) { - return this.pool.broadcast(item); -}; +SPVNode.prototype.broadcast = co(function* broadcast(item) { + try { + yield this.pool.broadcast(item); + } catch (e) { + this.emit('error', e); + } +}); /** * Broadcast a transaction (note that this will _not_ be verified @@ -295,7 +299,7 @@ SPVNode.prototype.broadcast = function broadcast(item) { */ SPVNode.prototype.sendTX = function sendTX(tx) { - return this.pool.broadcast(tx); + return this.broadcast(tx); }; /**