diff --git a/lib/bcoin/pool.js b/lib/bcoin/pool.js index 105e0cc8..8d88f0da 100644 --- a/lib/bcoin/pool.js +++ b/lib/bcoin/pool.js @@ -329,9 +329,19 @@ Pool.prototype._handleMerkle = function _handleMerkle(block, peer) { }; Pool.prototype._handleBlock = function _handleBlock(block, peer) { + var self = this; var chainIndex = this.chain.index; var hash, len, orphan, err; + if (this.listeners('watched').length > 0) { + utils.nextTick(function() { + block.txs.forEach(function(tx) { + if (self.isWatched(tx)) + self.emit('watched', tx, peer); + }); + }); + } + backoff = 0; this._response(block); @@ -520,6 +530,9 @@ Pool.prototype._addPeer = function _addPeer(backoff) { peer.on('tx', function(tx) { self._response(tx); self.emit('tx', tx, peer); + + if (!self.options.fullNode) + self.emit('watched', tx, peer); }); peer.on('addr', function(addr) { @@ -575,9 +588,6 @@ Pool.prototype._removePeer = function _removePeer(peer) { Pool.prototype.watch = function watch(id) { var hid, i; - if (this.options.fullNode) - return; - if (id instanceof bcoin.wallet) { this.watchWallet(id); return; @@ -606,9 +616,6 @@ Pool.prototype.watch = function watch(id) { Pool.prototype.unwatch = function unwatch(id) { var i; - if (this.options.fullNode) - return; - id = utils.toHex(id); if (!this.bloom.test(id, 'hex')) @@ -633,6 +640,64 @@ Pool.prototype.unwatch = function unwatch(id) { this.peers.block[i].updateWatch(); }; +// See "Filter matching algorithm": +// https://github.com/bitcoin/bips/blob/master/bip-0037.mediawiki +Pool.prototype.isWatched = function(tx, bloom) { + var i, input, output, outHash; + + if (!bloom) + bloom = this.bloom; + + function testScript(script) { + return script.some(function(chunk) { + if (!Array.isArray(chunk) || chunk.length === 0) + return false; + return bloom.test(chunk); + }); + } + + // 1. Test the tx hash + if (bloom.test(tx.hash())) + return true; + + // 2. Test data elements in output scripts + // (may need to update filter on match) + for (i = 0; i < tx.outputs.length; i++) { + output = tx.outputs[i]; + // Test the output script + if (testScript(output.script)) + return true; + } + + // 3. Test prev_out structure + // 4. Test data elements in input scripts + for (i = 0; i < tx.inputs.length; i++) { + input = tx.inputs[i]; + outHash = input.out.hash; + + if (typeof outHash === 'string') + outHash = utils.toArray(outHash, 'hex'); + + // Test the prev_out tx hash + if (bloom.test(outHash)) + return true; + + // Test the prev_out script + if (input.out.tx) { + output = input.out.tx.outputs[input.out.index]; + if (testScript(output.script)) + return true; + } + + // Test the input script + if (testScript(input.script)) + return true; + } + + // 5. No match + return false; +}; + Pool.prototype.addWallet = function addWallet(w, defaultTs) { var self = this; var e; @@ -648,7 +713,7 @@ Pool.prototype.addWallet = function addWallet(w, defaultTs) { if (w.loaded) search(w.lastTs); else - w.once('load', function(lastTs) { search(w.lastTs) }); + w.once('load', function() { search(w.lastTs) }); function search(ts) { // Relay pending TXs @@ -680,9 +745,6 @@ Pool.prototype.removeWallet = function removeWallet(w) { }; Pool.prototype.watchWallet = function watchWallet(w) { - if (this.options.fullNode) - return; - if (w.type === 'scripthash') { // For the redeem script hash in outputs: this.watch(w.getFullHash()); @@ -697,9 +759,6 @@ Pool.prototype.watchWallet = function watchWallet(w) { }; Pool.prototype.unwatchWallet = function unwatchWallet(w) { - if (this.options.fullNode) - return; - if (w.type === 'scripthash') { // For the redeem script hash in p2sh outputs: this.unwatch(w.getFullHash());