From 7a8a7a5a2b30ed26f3648bb2fdf345382bcc1b5e Mon Sep 17 00:00:00 2001 From: Christopher Jeffrey Date: Sat, 2 Jan 2016 03:44:25 -0800 Subject: [PATCH] better wallet searching for spv. pool methods. --- lib/bcoin/chain.js | 15 ++++++++ lib/bcoin/fullchain.js | 15 ++++++++ lib/bcoin/pool.js | 83 +++++++++++++++++++++++++++++++++++------- lib/bcoin/utils.js | 8 +++- 4 files changed, 106 insertions(+), 15 deletions(-) diff --git a/lib/bcoin/chain.js b/lib/bcoin/chain.js index dca86ee8..bd1b8972 100644 --- a/lib/bcoin/chain.js +++ b/lib/bcoin/chain.js @@ -215,6 +215,21 @@ Chain.prototype.resetHeight = function resetHeight(height) { this.index.lastTs = this.index.ts[this.index.ts.length - 1]; }; +Chain.prototype._heightByTime = function _heightByTime(ts) { + for (var i = this.index.ts.length - 1; i >= 0; i--) { + if (ts >= this.index.ts[i]) + return this.index.heights[i]; + } + return -1; +}; + +Chain.prototype.resetTime = function resetTime(ts) { + var height = this._heightByTime(ts); + if (height === -1) + return; + return this.resetHeight(height); +}; + Chain.prototype._killFork = function _killFork(probe) { var self = this; var delta = 2 * 3600; diff --git a/lib/bcoin/fullchain.js b/lib/bcoin/fullchain.js index 92b6b623..0208504c 100644 --- a/lib/bcoin/fullchain.js +++ b/lib/bcoin/fullchain.js @@ -164,6 +164,21 @@ Chain.prototype.resetHeight = function resetHeight(height) { }); }; +Chain.prototype._heightByTime = function _heightByTime(ts) { + for (var i = this.index.entries.length - 1; i >= 0; i--) { + if (ts >= this.index.entries[i].ts) + return this.index.entries[i].height; + } + return -1; +}; + +Chain.prototype.resetTime = function resetTime(ts) { + var height = this._heightByTime(ts); + if (height === -1) + return; + return this.resetHeight(height); +}; + Chain.prototype.add = function add(block) { if (this.loading) { this.once('load', function() { diff --git a/lib/bcoin/pool.js b/lib/bcoin/pool.js index 5dc6c968..82efec79 100644 --- a/lib/bcoin/pool.js +++ b/lib/bcoin/pool.js @@ -425,7 +425,7 @@ Pool.prototype._loadRange = function _loadRange(hashes, force) { last = hashes[hashes.length - 1]; hashes.slice(0, -1).forEach(function(hash) { - this.peers.load.loadBlocks([ hash ], last); + this.peers.load.loadBlocks([hash], last); }, this); }; @@ -449,7 +449,7 @@ Pool.prototype._load = function _load() { if (!self.peers.load) self._addLoader(); else - self.peers.load.loadBlocks([ hash ]); + self.peers.load.loadBlocks([hash], 0); }; // Load more blocks, starting from last hash @@ -734,11 +734,6 @@ Pool.prototype.addWallet = function addWallet(w, defaultTs) { e = new EventEmitter(); - if (w.loaded) - search(w.lastTs); - else - w.once('load', function() { search(w.lastTs) }); - function search(ts) { // Relay pending TXs // NOTE: It is important to do it after search, because search could @@ -754,9 +749,15 @@ Pool.prototype.addWallet = function addWallet(w, defaultTs) { if (!ts) ts = defaultTs || ((+new Date / 1000) - 7 * 24 * 3600); - self.search(false, ts, e); + // self.search(false, ts, e); + self.searchWallet(ts); } + if (w.loaded) + search(w.lastTs); + else + w.once('load', function() { search(w.lastTs) }); + return e; }; @@ -796,6 +797,36 @@ Pool.prototype.unwatchWallet = function unwatchWallet(w) { this.unwatch(w.getOwnPublicKey()); }; +Pool.prototype.searchWallet = function(w) { + var self = this; + var ts; + + if (!w) { + ts = this.wallets.reduce(function(ts, w) { + if (w.lastTs < ts) + return w.lastTs; + return ts; + }, Infinity); + assert(ts !== Infinity); + } else if (typeof w === 'number') { + ts = w; + } else { + if (!w.loaded) { + w.once('load', function() { + self.searchWallet(w.lastTs); + }); + return; + } + ts = w.lastTs; + if (!ts) + ts = (+new Date / 1000) - 7 * 24 * 3600; + } + + this.emit('debug', 'Wallet time: %s', new Date(ts * 1000)); + + this.chain.resetTime(ts); +}; + Pool.prototype.search = function search(id, range, e) { var self = this; @@ -833,6 +864,14 @@ Pool.prototype.search = function search(id, range, e) { this.chain.hashesInRange(range.start, range.end, function(hashes, count) { var waiting = count; + self.emit('debug', + 'Search for %s (%s) hashes between %s and %s', + hashes.length, + count, + new Date(range.start * 1000).toISOString(), + new Date(range.end * 1000).toISOString() + ); + if (id) self.watch(id); @@ -841,7 +880,7 @@ Pool.prototype.search = function search(id, range, e) { hashes = hashes.slice().reverse(); hashes.forEach(function(hash, i) { // Get the block that is in index - self.chain.get(hash, true, function(block) { + self.chain.request.add(hash, function(block) { loadBlock(block, hashes[i + 1]); }); }); @@ -853,7 +892,7 @@ Pool.prototype.search = function search(id, range, e) { // Get block's prev and request it and all of it's parents up to // the next known block hash - self.chain.get(block.prevBlock, block.prevBlock !== stop, function(prev) { + self.chain.request.add(block.prevBlock, function(prev) { done(); // First hash loaded @@ -1002,10 +1041,26 @@ Pool.prototype._doRequests = function _doRequests() { this.peers.load.getData(req); }; +Pool.prototype.getBlock = function getBlock(hash, cb) { + var type = this.options.fullNode ? 'block' : 'filtered'; + + if (this.chain.request.add(hash, cb)) { + this._request(type, hash, { force: true }); + this._scheduleRequests(); + } +}; + +Pool.prototype.sendBlock = function sendBlock(block) { + return this.sendTX(block); +}; + Pool.prototype.getTX = function getTX(hash, range, cb) { var self = this; var cbs, tx, finished, req, delta; + if (this.options.fullNode) + return cb(new Error('Cannot get tx with full node')); + hash = utils.toHex(hash); if (typeof range === 'function') { @@ -1017,7 +1072,7 @@ Pool.prototype.getTX = function getTX(hash, range, cb) { if (this.validate.map[hash]) return this.validate.map[hash].push(cb); - cbs = [ cb ]; + cbs = [cb]; this.validate.map[hash] = cbs; // Add request without queueing it to get notification at the time of load @@ -1043,14 +1098,14 @@ Pool.prototype.getTX = function getTX(hash, range, cb) { if (finished) { delete self.validate.map[hash]; cbs.forEach(function(cb) { - cb(tx, range); + cb(null, tx, range); }); return; } // Tried everything, but still no matches if (empty) - return cb(null); + return cb(new Error('Not found.')); // Not found yet, continue scanning range.end = range.start; @@ -1146,7 +1201,7 @@ function LoadRequest(pool, type, hash, cb) { this.pool = pool; this.type = type; this.hash = hash; - this.cbs = cb ? [ cb ] : []; + this.cbs = cb ? [cb] : []; this.timer = null; this.peer = null; this.ts = +new Date(); diff --git a/lib/bcoin/utils.js b/lib/bcoin/utils.js index ed40319d..b83e4482 100644 --- a/lib/bcoin/utils.js +++ b/lib/bcoin/utils.js @@ -453,6 +453,8 @@ function RequestCache() { } RequestCache.prototype.add = function add(id, cb) { + id = utils.toHex(id); + if (this.map[id]) { this.map[id].push(cb); return false; @@ -464,7 +466,11 @@ RequestCache.prototype.add = function add(id, cb) { }; RequestCache.prototype.fullfill = function fullfill(id, err, data) { - var cbs = this.map[id]; + var cbs; + + id = utils.toHex(id); + + cbs = this.map[id]; if (!this.map[id]) return;