From f2bc10726b57f655e52a973eda1becb03b313efb Mon Sep 17 00:00:00 2001 From: Christopher Jeffrey Date: Tue, 7 Jun 2016 10:23:22 -0700 Subject: [PATCH] relay alerts. --- lib/bcoin/fullnode.js | 4 ++++ lib/bcoin/peer.js | 26 ++++++++++++--------- lib/bcoin/pool.js | 44 ++++++++++++++++++++++++++++++++---- lib/bcoin/protocol/framer.js | 18 +++++++++++---- lib/bcoin/protocol/parser.js | 1 + lib/bcoin/spvnode.js | 4 ++++ lib/bcoin/timedata.js | 5 ---- 7 files changed, 77 insertions(+), 25 deletions(-) diff --git a/lib/bcoin/fullnode.js b/lib/bcoin/fullnode.js index 36399cc3..cb7f8480 100644 --- a/lib/bcoin/fullnode.js +++ b/lib/bcoin/fullnode.js @@ -144,6 +144,10 @@ Fullnode.prototype._init = function _init() { }); } + this.pool.on('alert', function(details) { + self.emit('alert', details); + }); + this.on('tx', function(tx) { self.walletdb.addTX(tx, function(err) { if (err) diff --git a/lib/bcoin/peer.js b/lib/bcoin/peer.js index 0f7f8a82..f86ed610 100644 --- a/lib/bcoin/peer.js +++ b/lib/bcoin/peer.js @@ -1556,20 +1556,24 @@ Peer.prototype._handleReject = function _handleReject(payload) { }; Peer.prototype._handleAlert = function _handleAlert(details) { - var hash = utils.dsha256(details.payload); - var signature = details.signature; - - if (!bcoin.ec.verify(hash, signature, this.network.alertKey)) { - bcoin.debug('Peer sent a phony alert packet (%s).', this.hostname); - // Let's look at it because why not? - bcoin.debug(details); - this.setMisbehavior(100); - return; - } - + this.invFilter.add(details.hash, 'hex'); this.fire('alert', details); }; +/** + * Send an `alert` to peer. + * @param {AlertPacket} details + */ + +Peer.prototype.sendAlert = function sendAlert(details) { + var data = bcoin.protocol.framer.alert(details); + + if (!this.invFilter.added(details.hash, 'hex')) + return; + + this.write(this.framer.packet('alert', data)); +}; + /** * Send `getheaders` to peer. Note that unlike * `getblocks`, `getheaders` can have a null locator. diff --git a/lib/bcoin/pool.js b/lib/bcoin/pool.js index 24f70988..255e9ca6 100644 --- a/lib/bcoin/pool.js +++ b/lib/bcoin/pool.js @@ -988,10 +988,8 @@ Pool.prototype._createPeer = function _createPeer(options) { self.emit('reject', payload, peer); }); - peer.on('alert', function(payload) { - bcoin.debug('Received alert from peer (%s).', peer.hostname); - bcoin.debug(payload); - self.emit('alert', payload, peer); + peer.on('alert', function(details) { + self._handleAlert(details, peer); }); peer.on('notfound', function(items) { @@ -1077,6 +1075,44 @@ Pool.prototype._createPeer = function _createPeer(options) { return peer; }; +Pool.prototype._handleAlert = function _handleAlert(details, peer) { + var hash = new Buffer(details.hash, 'hex'); + var signature = details.signature; + var now = bcoin.now(); + var i; + + if (!this.rejects.added(hash)) + return; + + if (!bcoin.ec.verify(hash, signature, this.network.alertKey)) { + bcoin.debug('Peer sent a phony alert packet (%s).', peer.hostname); + // Let's look at it because why not? + bcoin.debug(details); + peer.setMisbehavior(100); + return; + } + + if (now >= details.relayUntil || now >= details.expiration) { + bcoin.debug('Peer sent an expired alert packet (%s).', peer.hostname); + bcoin.debug(details); + return; + } + + bcoin.debug('Received alert from peer (%s).', peer.hostname); + bcoin.debug(details); + + if (this.peers.load) + this.peers.load.sendAlert(details); + + for (i = 0; i < this.peers.regular.length; i++) + this.peers.regular[i].sendAlert(details); + + for (i = 0; i < this.peers.leeches.length; i++) + this.peers.leeches[i].sendAlert(details); + + this.emit('alert', details, peer); +}; + Pool.prototype._handleTX = function _handleTX(tx, peer, callback) { var self = this; var requested; diff --git a/lib/bcoin/protocol/framer.js b/lib/bcoin/protocol/framer.js index 2b6688be..fe372a0e 100644 --- a/lib/bcoin/protocol/framer.js +++ b/lib/bcoin/protocol/framer.js @@ -1193,7 +1193,7 @@ Framer.addr = function addr(hosts, writer) { Framer.alert = function alert(data, writer) { var network = bcoin.network.get(data.network); var key = data.key; - var p, i, payload; + var p, i, payload, hash; if (!key && network.alertPrivateKey) key = network.alertPrivateKey; @@ -1225,12 +1225,20 @@ Framer.alert = function alert(data, writer) { p = new BufferWriter(writer); p.writeVarBytes(payload); - if (data.signature) + if (data.signature) { p.writeVarBytes(data.signature); - else if (key) - p.writeVarBytes(bcoin.ec.sign(utils.dsha256(payload), key)); - else + } else if (key) { + hash = utils.dsha256(payload); + p.writeVarBytes(bcoin.ec.sign(hash, key)); + } else { assert(false, 'No key or signature.'); + } + + if (!data.hash) { + if (!hash) + hash = utils.dsha256(payload); + data.hash = hash.toString('hex'); + } if (!writer) p = p.render(); diff --git a/lib/bcoin/protocol/parser.js b/lib/bcoin/protocol/parser.js index 2b8089df..dda8d108 100644 --- a/lib/bcoin/protocol/parser.js +++ b/lib/bcoin/protocol/parser.js @@ -1276,6 +1276,7 @@ Parser.parseAlert = function parseAlert(p) { reserved = p.readVarString('ascii'); return { + hash: utils.dsha256(payload).toString('hex'), version: version, relayUntil: relayUntil, expiration: expiration, diff --git a/lib/bcoin/spvnode.js b/lib/bcoin/spvnode.js index dd8d6074..f197fd12 100644 --- a/lib/bcoin/spvnode.js +++ b/lib/bcoin/spvnode.js @@ -101,6 +101,10 @@ SPVNode.prototype._init = function _init() { }); } + this.pool.on('alert', function(details) { + self.emit('alert', details); + }); + this.on('tx', function(tx) { self.walletdb.addTX(tx, function(err) { if (err) diff --git a/lib/bcoin/timedata.js b/lib/bcoin/timedata.js index cbfb546a..1c30c23a 100644 --- a/lib/bcoin/timedata.js +++ b/lib/bcoin/timedata.js @@ -6,7 +6,6 @@ */ var bcoin = require('./env'); -var EventEmitter = require('events').EventEmitter; var utils = require('./utils'); /** @@ -27,8 +26,6 @@ function TimeData(limit) { if (!(this instanceof TimeData)) return new TimeData(limit); - EventEmitter.call(this); - if (limit == null) limit = 200; @@ -39,8 +36,6 @@ function TimeData(limit) { this._checked = false; } -utils.inherits(TimeData, EventEmitter); - /** * Add time data. * @param {String} host