diff --git a/lib/bcoin/blockdb.js b/lib/bcoin/blockdb.js index 5154dd38..ba9bb1dc 100644 --- a/lib/bcoin/blockdb.js +++ b/lib/bcoin/blockdb.js @@ -513,6 +513,96 @@ BlockDB.prototype.getCoinsByAddress = function getCoinsByAddress(addresses, call }); }; +BlockDB.prototype.getCoinsByAddress = function getCoinsByAddress(addresses, options, callback) { + var self = this; + var coins = []; + + if (!callback) { + callback = options; + options = {}; + } + + if (typeof addresses === 'string') + addresses = [addresses]; + + addresses = utils.uniqs(addresses); + + utils.forEach(addresses, function(address, done) { + var iter = self.index.db.iterator({ + gte: 'u/a/' + address, + lte: 'u/a/' + address + '~', + keys: true, + values: true, + fillCache: true, + keyAsBuffer: false, + valueAsBuffer: true + }); + + (function next() { + iter.next(function(err, key, value) { + var record, parts, hash, index; + + if (err) { + return iter.end(function() { + done(err); + }); + } + + // iter.end() here? + if (!key) + return done(); + + parts = key.split('/').slice(3); + hash = parts[0]; + index = +parts[1]; + record = self.parseOffset(value); + + self.data.getAsync(record.size, record.offset, function(err, data) { + var coin; + + if (err) { + return iter.end(function() { + done(err); + }); + } + + if (!data) + return done(); + + try { + data = self.parser.parseOutput(data); + } catch (e) { + return iter.end(function() { + done(e); + }); + } + + coin = bcoin.coin({ + version: 1, + hash: hash, + index: index, + height: record.height, + script: data.script, + value: data.value, + spent: false + }); + + if (self.options.cache) + self.cache.unspent.set(id, coin); + + coins.push(coin); + + next(); + }); + }); + })(); + }, function(err) { + if (err) + return callback(err); + return callback(null, coins); + }); +}; + BlockDB.prototype._getCoinsByAddress = function _getCoinsByAddress(address, callback) { var self = this; var pending = 0; @@ -640,23 +730,25 @@ BlockDB.prototype.getCoin = function getCoin(hash, index, callback) { if (err) return callback(err); - if (data) { - try { - data = self.parser.parseOutput(data); - } catch (e) { - return callback(e); - } - coin = bcoin.coin({ - version: 1, - hash: hash, - index: index, - height: record.height, - script: data.script, - value: data.value, - spent: false - }); + if (!data) + return callback(); + + try { + data = self.parser.parseOutput(data); + } catch (e) { + return callback(e); } + coin = bcoin.coin({ + version: 1, + hash: hash, + index: index, + height: record.height, + script: data.script, + value: data.value, + spent: false + }); + return callback(null, coin); }); }); @@ -688,6 +780,119 @@ BlockDB.prototype.getTXByAddress = function getTXByAddress(addresses, callback) }); }; +BlockDB.prototype.getTXByAddress = function getTXByAddress(addresses, options, callback) { + var self = this; + var txs = []; + var have = {}; + + if (!callback) { + callback = options; + options = {}; + } + + if (typeof addresses === 'string') + addresses = [addresses]; + + addresses = utils.uniqs(addresses); + + utils.forEach(addresses, function(address, done) { + var iter = self.index.db.iterator({ + gte: 't/a/' + address, + lte: 't/a/' + address + '~', + keys: true, + values: true, + fillCache: true, + keyAsBuffer: false, + valueAsBuffer: true + }); + + (function next() { + iter.next(function(err, key, value) { + var record, parts, hash, index; + + if (err) { + return iter.end(function() { + done(err); + }); + } + + // iter.end() here? + if (!key) + return done(); + + parts = key.split('/').slice(3); + hash = parts[0]; + record = self.parseOffset(value); + + if (addresses.length > 1) { + if (have[hash]) + return next(); + + have[hash] = true; + } + + if (self.options.cache && self.cache.tx.has(hash)) { + txs.push(self.cache.tx.get(hash)); + return done(); + } + + self.data.getAsync(record.size, record.offset, function(err, data) { + var coin; + + if (err) { + return iter.end(function() { + done(err); + }); + } + + if (!data) + return next(); + + try { + tx = self.parser.parseTX(data); + tx = new bcoin.tx(tx); + } catch (e) { + return iter.end(function() { + done(e); + }); + } + + return self._getEntry(record.height, function(err, entry) { + if (err) { + return iter.end(function() { + done(err); + }); + } + + tx.network = true; + tx.height = record.height; + + if (entry) { + tx.ts = entry.ts; + tx.block = entry.hash; + } + + txs.push(tx); + + if (self.options.cache) + self.cache.tx.set(hash, tx); + + if (self.options.paranoid && tx.hash('hex') !== hash) + return next(new Error('BlockDB is corrupt. All is lost.')); + + next(); + }); + }); + }); + })(); + }, function(err) { + if (err) + return callback(err); + return callback(null, txs); + }); +}; + + BlockDB.prototype._getTXByAddress = function _getTXByAddress(address, callback) { var self = this; var pending = 0; @@ -711,11 +916,11 @@ BlockDB.prototype._getTXByAddress = function _getTXByAddress(address, callback) pending++; if (self.options.cache && self.cache.tx.has(hash)) { - coins.push(self.cache.tx.get(hash)); + txs.push(self.cache.tx.get(hash)); pending--; if (done) { if (!pending) - return callback(null, coins); + return callback(null, txs); } return; }