diff --git a/lib/bcoin/chain.js b/lib/bcoin/chain.js index 47fb80ed..091ec9bc 100644 --- a/lib/bcoin/chain.js +++ b/lib/bcoin/chain.js @@ -20,9 +20,6 @@ function Chain(options) { this.block = { list: [], - // Bloom filter for all merkle trees - merkleBloom: new bcoin.bloom(8 * 1024 * 1024, 16, 0xdeadbeed), - // Bloom filter for all known blocks bloom: new bcoin.bloom(8 * 1024 * 1024, 16, 0xdeadbeef) }; @@ -215,7 +212,6 @@ Chain.prototype._compress = function compress() { // Bloom filter rebuilt is needed this.block.list = this.block.list.slice(-1000); this.block.bloom.reset(); - this.block.merkleBloom.reset(); for (var i = 0; i < this.block.list.length; i++) this._bloomBlock(this.block.list[i]); @@ -223,8 +219,6 @@ Chain.prototype._compress = function compress() { Chain.prototype._bloomBlock = function _bloomBlock(block) { this.block.bloom.add(block.hash(), 'hex'); - for (var i = 0; i < block.hashes.length; i++) - this.block.merkleBloom.add(block.hashes[i], 'hex'); }; Chain.prototype.has = function has(hash, noProbe, cb) { @@ -258,20 +252,6 @@ Chain.prototype.has = function has(hash, noProbe, cb) { return cb(!!this.orphan.map[hash]); }; -Chain.prototype.hasMerkle = function hasMerkle(hash) { - if (!this.block.merkleBloom.test(hash, 'hex')) - return false; - if (!this.strict) - return true; - - hash = utils.toHex(hash); - for (var i = 0; i < this.block.list.length; i++) - if (this.block.list[i].hasMerkle(hash)) - return true; - - return false; -}; - Chain.prototype.get = function get(hash, cb) { // Cached block found if (this.block.bloom.test(hash, 'hex')) { diff --git a/lib/bcoin/peer.js b/lib/bcoin/peer.js index fa03e819..32b5f514 100644 --- a/lib/bcoin/peer.js +++ b/lib/bcoin/peer.js @@ -250,15 +250,16 @@ Peer.prototype._onPacket = function onPacket(packet) { else if (cmd === 'pong') return this._handlePong(payload); - if (cmd === 'merkleblock' || cmd === 'block') + if (cmd === 'merkleblock' || cmd === 'block') { payload = bcoin.block(payload); - else if (cmd === 'tx') - payload = bcoin.tx(payload); - if (this._res(cmd, payload)) { - return; - } else { - this.emit(cmd, payload); + this.lastBlock = payload; + } else if (cmd === 'tx') { + payload = bcoin.tx(payload, this.lastBlock); } + if (this._res(cmd, payload)) + return; + else + this.emit(cmd, payload); }; Peer.prototype._handleVersion = function handleVersion(payload) { diff --git a/lib/bcoin/tx-pool.js b/lib/bcoin/tx-pool.js index 582bbb4a..aa5a4e88 100644 --- a/lib/bcoin/tx-pool.js +++ b/lib/bcoin/tx-pool.js @@ -12,10 +12,11 @@ function TXPool(wallet) { this._wallet = wallet; this._storage = wallet.storage; - this._prefix = 'bt/' + wallet.getAddress() + '/tx/'; + this._prefix = wallet.prefix + 'tx/'; this._all = {}; this._unspent = {}; this._orphans = {}; + this._lastTs = 0; // Load TXs from storage this._init(); @@ -39,6 +40,9 @@ TXPool.prototype._init = function init() { s.on('error', function(err) { self.emit('error', err); }); + s.on('end', function() { + self.emit('load', self._lastTs); + }); }; TXPool.prototype.add = function add(tx, noWrite) { @@ -76,6 +80,8 @@ TXPool.prototype.add = function add(tx, noWrite) { if (!own) return; + var updated = false; + // Add unspent outputs or fullfill orphans for (var i = 0; i < tx.outputs.length; i++) { var out = tx.outputs[i]; @@ -84,7 +90,7 @@ TXPool.prototype.add = function add(tx, noWrite) { var orphan = this._orphans[key]; if (!orphan) { this._unspent[key] = { tx: tx, index: i }; - this.emit('update'); + updated = true; continue; } delete this._orphans[key]; @@ -93,6 +99,10 @@ TXPool.prototype.add = function add(tx, noWrite) { orphan.tx.input(tx, orphan.index); } + this._lastTs = Math.max(tx.ts, this._lastTs); + if (updated) + this.emit('update', this._lastTs); + if (!noWrite && this._storage) { var self = this; this._storage.put(this._prefix + hash, tx.toJSON(), function(err) { diff --git a/lib/bcoin/tx.js b/lib/bcoin/tx.js index ea57429f..f4a3dca8 100644 --- a/lib/bcoin/tx.js +++ b/lib/bcoin/tx.js @@ -4,9 +4,9 @@ var bn = require('bn.js'); var bcoin = require('../bcoin'); var utils = bcoin.utils; -function TX(data) { +function TX(data, block) { if (!(this instanceof TX)) - return new TX(data); + return new TX(data, block); this.type = 'tx'; if (!data) @@ -16,6 +16,7 @@ function TX(data) { this.inputs = []; this.outputs = []; this.lock = data.lock || 0; + this.ts = data.ts || 0; this._hash = null; this._raw = data._raw || null; @@ -30,6 +31,9 @@ function TX(data) { this.out(out, null); }, this); } + + if (!data.ts && block && block.hasMerkle(this.hash('hex'))) + this.ts = block.ts; } module.exports = TX; @@ -174,10 +178,19 @@ TX.prototype.verify = function verify() { TX.prototype.toJSON = function toJSON() { // Compact representation - return utils.toBase58(this.render()); + var ts = new Array(4); + bcoin.utils.writeU32(ts, this.ts, 0); + return utils.toBase58(this.render().concat(ts)); }; TX.fromJSON = function fromJSON(json) { // Compact representation - return new TX(new bcoin.protocol.parser().parseTX(utils.fromBase58(json))); + var data = utils.fromBase58(json); + var tx = data.slice(0, -4); + var ts = bcoin.utils.readU32(data, data.length - 4); + + tx = new TX(new bcoin.protocol.parser().parseTX(tx)); + tx.ts = ts; + + return tx; }; diff --git a/lib/bcoin/wallet.js b/lib/bcoin/wallet.js index 82c73c6a..efc4830a 100644 --- a/lib/bcoin/wallet.js +++ b/lib/bcoin/wallet.js @@ -37,6 +37,7 @@ function Wallet(options, passphrase) { this.key = bcoin.ecdsa.genKeyPair(); } + this.prefix = 'bt/' + this.getAddress() + '/'; this.tx = new bcoin.txPool(this); this._init(); } @@ -47,13 +48,17 @@ Wallet.prototype._init = function init() { // Notify owners about new accepted transactions var self = this; var prevBalance = null; - this.tx.on('update', function(tx) { + this.tx.on('update', function() { var b = this.balance(); if (prevBalance && prevBalance.cmp(b) !== 0) self.emit('balance', b); prevBalance = b; }); + this.tx.once('load', function(ts) { + self.emit('load', ts); + }); + this.tx.on('error', function(err) { self.emit('error', err); }); @@ -186,7 +191,7 @@ Wallet.prototype.sign = function sign(tx, type) { return inputs.length; }; -Wallet.prototype.addTX = function addTX(tx) { +Wallet.prototype.addTX = function addTX(tx, block) { return this.tx.add(tx); };