From f4be7651cd27dea9586b2b5869d4b397af459800 Mon Sep 17 00:00:00 2001 From: Christopher Jeffrey Date: Fri, 13 May 2016 04:49:21 -0700 Subject: [PATCH] refactor txdb and chaindb db usage. --- lib/bcoin/chain.js | 2 +- lib/bcoin/chaindb.js | 336 +++++++++--------------------- lib/bcoin/env.js | 2 + lib/bcoin/protocol/parser.js | 4 +- lib/bcoin/txdb.js | 383 ++++++++--------------------------- 5 files changed, 187 insertions(+), 540 deletions(-) diff --git a/lib/bcoin/chain.js b/lib/bcoin/chain.js index fd5d3fa9..4a57ffe6 100644 --- a/lib/bcoin/chain.js +++ b/lib/bcoin/chain.js @@ -106,7 +106,7 @@ Chain.prototype._init = function _init() { if (self.height < network.block.slowHeight) return; - bcoin.debug('Block %s (%d) added to chain', + bcoin.debug('Block %s (%d) added to chain.', utils.revHex(entry.hash), entry.height); }); diff --git a/lib/bcoin/chaindb.js b/lib/bcoin/chaindb.js index 6c98bf34..fb33c50c 100644 --- a/lib/bcoin/chaindb.js +++ b/lib/bcoin/chaindb.js @@ -24,6 +24,7 @@ module.exports = function(bcoin) { var EventEmitter = require('events').EventEmitter; var network = bcoin.protocol.network; +var constants = bcoin.protocol.constants; var utils = require('./utils'); var assert = utils.assert; var pad32 = utils.pad32; @@ -125,8 +126,8 @@ ChainDB.prototype._init = function _init() { self.emit('open'); } - self.db.get('h/' + network.genesis.hash, function(err, exists) { - if (err && err.type !== 'NotFoundError') + self.db.has('h/' + network.genesis.hash, function(err, exists) { + if (err) return self.emit('error', err); if (exists) @@ -233,21 +234,23 @@ ChainDB.prototype.getHeight = function getHeight(hash, callback) { if (typeof hash === 'number') return callback(null, hash); - // When prevBlock=zero-hash - if (+hash === 0) + if (hash === constants.NULL_HASH) return callback(null, -1); if (this.cacheHash.has(hash)) return callback(null, this.cacheHash.get(hash).height); - this.db.get('h/' + hash, function(err, height) { - if (err && err.type !== 'NotFoundError') + this.db.fetch('h/' + hash, function(data) { + assert(data.length === 4, 'Database corruption.'); + return utils.readU32(data, 0); + }, function(err, height) { + if (err) return callback(err); if (height == null) return callback(null, -1); - return callback(null, utils.readU32(height, 0)); + return callback(null, height); }); }; @@ -270,15 +273,10 @@ ChainDB.prototype.getHash = function getHash(height, callback) { if (this.cacheHeight.has(height)) return callback(null, this.cacheHeight.get(height).hash); - this.db.get('H/' + pad32(height), function(err, hash) { - if (err && err.type !== 'NotFoundError') - return callback(err); - - if (hash == null) - return callback(null, null); - - return callback(null, hash.toString('hex')); - }); + this.db.fetch('H/' + pad32(height), function(data) { + assert(data.length === 32, 'Database corruption.'); + return data.toString('hex'); + }, callback); }; /** @@ -387,14 +385,13 @@ ChainDB.prototype.getBoth = function getBoth(block, callback) { * @param {Function} callback - Returns [Error, {@link ChainBlock}]. */ -ChainDB.prototype._getEntry = function _getEntry(hash, callback) { +ChainDB.prototype.getEntry = function getEntry(hash, callback) { var self = this; - var entry; if (hash == null || hash < 0) return utils.nextTick(callback); - return this.getBoth(hash, function(err, hash, height) { + return this.getHash(hash, function(err, hash) { if (err && err.type !== 'NotFoundError') return callback(err); @@ -404,21 +401,9 @@ ChainDB.prototype._getEntry = function _getEntry(hash, callback) { if (self.cacheHash.has(hash)) return callback(null, self.cacheHash.get(hash)); - return self.db.get('e/' + hash, function(err, data) { - if (err && err.type !== 'NotFoundError') - return callback(err); - - if (!data) - return callback(); - - try { - entry = bcoin.chainblock.fromRaw(self.chain, data); - } catch (e) { - return callback(e); - } - - return callback(null, entry); - }); + return self.db.fetch('e/' + hash, function(data) { + return bcoin.chainblock.fromRaw(self.chain, data); + }, callback); }); }; @@ -428,10 +413,10 @@ ChainDB.prototype._getEntry = function _getEntry(hash, callback) { * @param {Function} callback - Returns [Error, {@link ChainBlock}]. */ -ChainDB.prototype.get = function get(height, callback) { +ChainDB.prototype.get = function get(hash, callback) { var self = this; - return this._getEntry(height, function(err, entry) { + return this.getEntry(hash, function(err, entry) { if (err) return callback(err); @@ -509,14 +494,17 @@ ChainDB.prototype.save = function save(entry, block, connect, callback) { ChainDB.prototype.getTip = function getTip(callback) { var self = this; - return this.db.get('R', function(err, hash) { - if (err && err.type !== 'NotFoundError') + return this.db.fetch('R', function(data) { + assert(data.length === 32, 'Database corruption.'); + return data.toString('hex'); + }, function(err, hash) { + if (err) return callback(err); if (!hash) return callback(); - return self.get(hash.toString('hex'), callback); + return self.get(hash, callback); }); }; @@ -605,15 +593,10 @@ ChainDB.prototype._ensureEntry = function _ensureEntry(block, callback) { */ ChainDB.prototype.getNextHash = function getNextHash(hash, callback) { - return this.db.get('n/' + hash, function(err, nextHash) { - if (err && err.type !== 'NotFoundError') - return callback(err); - - if (!nextHash) - return callback(); - - return callback(null, nextHash.toString('hex')); - }); + return this.db.fetch('n/' + hash, function(data) { + assert(data.length === 32, 'Database corruption.'); + return data.toString('hex'); + }, callback); }; /** @@ -1057,68 +1040,33 @@ ChainDB.prototype.fillHistory = function fillHistory(tx, callback) { ChainDB.prototype.getCoinsByAddress = function getCoinsByAddress(addresses, callback) { var self = this; - var ids = []; var coins = []; - if (typeof addresses === 'string') + if (!Array.isArray(addresses)) addresses = [addresses]; addresses = utils.uniq(addresses); - utils.forEachSerial(addresses, function(address, done) { - var iter = self.db.iterator({ - gte: 'C/' + address + '/', - lte: 'C/' + address + '/~', - keys: true, - values: true, - fillCache: true, - keyAsBuffer: false, - valueAsBuffer: true - }); - - (function next() { - iter.next(function(err, key, value) { - var parts, hash, index; - - if (err) { - return iter.end(function() { - done(err); - }); - } - - if (key === undefined) - return iter.end(done); - - parts = key.split('/'); - hash = parts[2]; - index = +parts[3]; - - ids.push([hash, index]); - - next(); - }); - })(); - }, function(err) { - if (err) - return callback(err); - - utils.forEachSerial(ids, function(item, next) { - var hash = item[0]; - var index = item[1]; - self.getCoin(hash, index, function(err, coin) { - if (err) - return next(err); - - if (!coin) - return next(); - - coins.push(coin); - next(); - }); - }, function(err) { + utils.forEachSerial(addresses, function(address, next) { + self.db.lookup({ + gte: 'C/' + address, + lte: 'C/' + address + '~', + transform: function(key) { + key = key.split('/'); + return 'c/' + key[2] + '/' + key[3]; + }, + parse: function(data, key) { + var coin = bcoin.coin.fromRaw(data); + var hash = key.split('/'); + coin.hash = hash[1]; + coin.index = +hash[2]; + return coin; + } + }, function(err, coin) { if (err) - return callback(err); - return callback(null, coins); + return next(err); + coins = coins.concat(coin); + next(); }); }); }; @@ -1139,25 +1087,13 @@ ChainDB.prototype.getCoin = function getCoin(hash, index, callback) { if (coin) return utils.asyncify(callback)(null, coin); - this.db.get('c/' + key, function(err, data) { - if (err && err.type !== 'NotFoundError') - return callback(err); - - if (!data) - return callback(); - - try { - coin = bcoin.coin.fromRaw(data); - coin.hash = hash; - coin.index = index; - } catch (e) { - return callback(e); - } - + this.db.fetch('c/' + key, function(data) { + var coin = bcoin.coin.fromRaw(data); + coin.hash = hash; + coin.index = index; self.coinCache.set(key, coin); - - return callback(null, coin); - }); + return coin; + }, callback); }; /** @@ -1168,73 +1104,40 @@ ChainDB.prototype.getCoin = function getCoin(hash, index, callback) { ChainDB.prototype.getTXByAddress = function getTXByAddress(addresses, callback) { var self = this; - var hashes = []; var txs = []; var have = {}; - if (typeof addresses === 'string') + if (!Array.isArray(addresses)) addresses = [addresses]; addresses = utils.uniq(addresses); utils.forEachSerial(addresses, function(address, done) { - var iter = self.db.iterator({ - gte: 'T/' + address + '/', - lte: 'T/' + address + '/~', - keys: true, - values: true, - fillCache: true, - keyAsBuffer: false, - valueAsBuffer: true - }); - - (function next() { - iter.next(function(err, key, value) { - var hash; - - if (err) { - return iter.end(function() { - done(err); - }); - } - - if (key === undefined) - return iter.end(done); - - hash = key.split('/')[2]; - + self.db.lookup({ + gte: 'T/' + address, + lte: 'T/' + address + '~', + transform: function(key) { + var hash = key.split('/')[2]; if (addresses.length > 1) { if (have[hash]) - return next(); - + return false; have[hash] = true; } - - hashes.push(hash); - - next(); - }); - })(); + return 't/' + hash; + }, + parse: function(data, key) { + return bcoin.tx.fromRaw(data); + } + }, function(err, tx) { + if (err) + return next(err); + txs = txs.concat(tx); + next(); + }); }, function(err) { if (err) return callback(err); - - utils.forEachSerial(hashes, function(hash, next) { - self.getTX(hash, function(err, tx) { - if (err) - return next(err); - - if (!tx) - return next(); - - txs.push(tx); - next(); - }); - }, function(err) { - if (err) - return callback(err); - return callback(null, txs); - }); + return callback(null, txs); }); }; @@ -1246,25 +1149,16 @@ ChainDB.prototype.getTXByAddress = function getTXByAddress(addresses, callback) ChainDB.prototype.getTX = function getTX(hash, callback) { var self = this; - var key = 't/' + hash; - var tx; if (!this.options.indexTX) return utils.nextTick(callback); - this.db.get(key, function(err, data) { - if (err && err.type !== 'NotFoundError') + this.db.fetch('t/' + hash, function(data) { + return bcoin.tx.fromExtended(data); + }, function(err, tx) { + if (err) return callback(err); - if (!data) - return callback(); - - try { - tx = bcoin.tx.fromExtended(data); - } catch (e) { - return callback(e); - } - if (self.options.paranoid) assert(tx.hash('hex') === hash, 'Database is corrupt.'); @@ -1281,12 +1175,7 @@ ChainDB.prototype.hasTX = function hasTX(hash, callback) { if (!this.options.indexTX) return utils.asyncify(callback)(null, false); - return this.getTX(hash, function(err, tx) { - if (err) - return callback(err); - - return callback(null, tx != null); - }); + return this.db.has('t/' + hash, callback); }; /** @@ -1406,29 +1295,18 @@ ChainDB.prototype.fillBlock = function fillBlock(block, callback) { */ ChainDB.prototype.getUndoCoins = function getUndoCoins(hash, callback) { - var coins, p, coin, i, tx; + return this.db.fetch('u/' + hash, function(data) { + var p = new BufferReader(data); + var coins = []; + var coin; - return this.db.get('u/' + hash, function(err, data) { - if (err && err.type !== 'NotFoundError') - return callback(err); - - if (!data) - return callback(); - - coins = []; - p = new BufferReader(data); - - try { - while (p.left()) { - coin = Parser.parseCoin(p, false); - coins.push(new bcoin.coin(coin)); - } - } catch (e) { - return callback(e); + while (p.left()) { + coin = Parser.parseCoin(p, false); + coins.push(new bcoin.coin(coin)); } - return callback(null, coins); - }); + return coins; + }, callback); }; /** @@ -1473,8 +1351,6 @@ ChainDB.prototype.fillHistoryBlock = function fillHistoryBlock(block, callback) ChainDB.prototype.getBlock = function getBlock(hash, callback) { var self = this; - var key, block; - return this.getBoth(hash, function(err, hash, height) { if (err) return callback(err); @@ -1482,24 +1358,11 @@ ChainDB.prototype.getBlock = function getBlock(hash, callback) { if (!hash) return callback(); - key = 'b/' + hash; - - self.db.get(key, function(err, data) { - if (err && err.type !== 'NotFoundError') - return callback(err); - - if (!data) - return callback(); - - try { - block = bcoin.block.fromRaw(data); - block.setHeight(height); - } catch (e) { - return callback(e); - } - - return callback(null, block); - }); + self.db.fetch('b/' + hash, function(data) { + var block = bcoin.block.fromRaw(data); + block.setHeight(height); + return block; + }, callback); }); }; @@ -1577,15 +1440,16 @@ ChainDB.prototype._pruneBlock = function _pruneBlock(block, batch, callback) { key = 'b/q/' + pad32(block.height); - this.db.get(key, function(err, hash) { - if (err && err.type !== 'NotFoundError') + this.db.fetch(key, function(data) { + assert(data.length === 32, 'Database corruption.'); + return data.toString('hex'); + }, function(err, hash) { + if (err) return callback(err); if (!hash) return callback(); - hash = hash.toString('hex'); - batch.del(key); batch.del('b/' + hash); batch.del('u/' + hash); diff --git a/lib/bcoin/env.js b/lib/bcoin/env.js index 18a64b9e..99092ff7 100644 --- a/lib/bcoin/env.js +++ b/lib/bcoin/env.js @@ -86,6 +86,7 @@ try { * @property {Function} chaindb - {@link ChainDB} constructor. * @property {Function} chain - {@link Chain} constructor. * @property {Function} mempool - {@link Mempool} constructor. + * @property {Function} mempoolentry - {@link MempoolEntry} constructor. * @property {Function} keypair - {@link KeyPair} constructor. * @property {Function} hd - {@link HD} constructor. * @property {Function} address - {@link Address} constructor. @@ -207,6 +208,7 @@ function Environment(options) { this.chaindb = require('./chaindb')(this); this.chain = require('./chain')(this); this.mempool = require('./mempool')(this); + this.mempoolentry = this.mempool.mempoolentry; this.keypair = require('./keypair')(this); this.hd = require('./hd')(this); this.address = require('./address')(this); diff --git a/lib/bcoin/protocol/parser.js b/lib/bcoin/protocol/parser.js index db4a056d..572203d6 100644 --- a/lib/bcoin/protocol/parser.js +++ b/lib/bcoin/protocol/parser.js @@ -694,7 +694,7 @@ Parser.parseBlockHeaders = function parseBlockHeaders(p) { /** * Parse a transaction in "extended" serialization format. - * @param {Buffer} p + * @param {Buffer|BufferReader} p * @param {Boolean?} saveCoins - If true, the function will * attempt to parse the coins. * @param {String?} enc - One of `"hex"` or `null`. @@ -702,7 +702,7 @@ Parser.parseBlockHeaders = function parseBlockHeaders(p) { */ Parser.parseExtendedTX = function parseExtendedTX(p, saveCoins) { - var tx, coinCount, coin, i, tmp; + var i, tx, coinCount, coin; p = new BufferReader(p); diff --git a/lib/bcoin/txdb.js b/lib/bcoin/txdb.js index c4a2e227..4106c772 100644 --- a/lib/bcoin/txdb.js +++ b/lib/bcoin/txdb.js @@ -134,7 +134,6 @@ TXDB.prototype.getMap = function getMap(tx, callback) { TXDB.prototype.mapAddresses = function mapAddresses(address, callback) { var self = this; var table = {}; - var iter; if (Array.isArray(address)) { return utils.forEachSerial(address, function(address, next) { @@ -155,41 +154,20 @@ TXDB.prototype.mapAddresses = function mapAddresses(address, callback) { }); } - iter = this.db.iterator({ + this.db.iterate({ gte: 'W/' + address, lte: 'W/' + address + '~', - keys: true, - values: false, - fillCache: false, - keyAsBuffer: false + transform: function(key) { + return key.split('/')[2]; + } + }, function(err, keys) { + if (err) + return callback(err); + + table[address] = keys; + + return callback(null, table); }); - - callback = utils.ensure(callback); - - table[address] = []; - - (function next() { - iter.next(function(err, key, value) { - if (err) { - return iter.end(function() { - callback(err); - }); - } - - if (key === undefined) { - return iter.end(function(err) { - if (err) - return callback(err); - return callback(null, table); - }); - } - - key = key.split('/')[2]; - table[address].push(key); - - next(); - }); - })(); }; /** @@ -230,29 +208,26 @@ TXDB.prototype._addOrphan = function _addOrphan(key, hash, index, callback) { TXDB.prototype._getOrphans = function _getOrphans(key, callback) { var self = this; - var p, orphans; - this.db.get('o/' + key, function(err, buf) { - if (err && err.type !== 'NotFoundError') + this.db.fetch('o/' + key, function(buf) { + var p = new BufferReader(buf); + var orphans = []; + + while (p.left()) { + orphans.push({ + hash: p.readHash('hex'), + index: p.readU32() + }); + } + + return orphans; + }, function(err, orphans) { + if (err) return callback(err); - if (!buf) + if (!orphans) return callback(); - p = new BufferReader(buf); - orphans = []; - - try { - while (p.left()) { - orphans.push({ - hash: p.readHash('hex'), - index: p.readU32() - }); - } - } catch (e) { - return callback(e); - } - utils.forEach(orphans, function(orphan, next) { self.getTX(orphan.hash, function(err, tx) { if (err) @@ -627,14 +602,11 @@ TXDB.prototype.isDoubleSpend = function isDoubleSpend(tx, callback) { self.isSpent(input.prevout.hash, input.prevout.index, function(err, spent) { if (err) return next(err); - if (spent) - return next(null, false); - return next(null, true); + return next(null, !spent); }); }, function(err, result) { if (err) return callback(err); - return callback(null, !result); }); }; @@ -647,18 +619,10 @@ TXDB.prototype.isDoubleSpend = function isDoubleSpend(tx, callback) { */ TXDB.prototype.isSpent = function isSpent(hash, index, callback) { - var self = this; var key = 's/' + hash + '/' + index; - - return this.db.get(key, function(err, hash) { - if (err && err.type !== 'NotFoundError') - return callback(err); - - if (!hash) - return callback(null, null); - - return callback(null, hash.toString('hex')); - }); + return this.db.fetch(key, function(hash) { + return hash.toString('hex'); + }, callback); }; /** @@ -1070,8 +1034,6 @@ TXDB.prototype._unconfirm = function unconfirm(tx, map, callback, force) { TXDB.prototype.getHistoryHashes = function getHistoryHashes(address, callback) { var self = this; - var txs = []; - var iter; if (typeof address === 'function') { callback = address; @@ -1100,39 +1062,16 @@ TXDB.prototype.getHistoryHashes = function getHistoryHashes(address, callback) { }); } - iter = this.db.iterator({ + this.db.iterate({ gte: address ? 'T/' + address : 't', lte: address ? 'T/' + address + '~' : 't~', - keys: true, - values: false, - fillCache: false, - keyAsBuffer: false - }); - - (function next() { - iter.next(function(err, key, value) { - if (err) { - return iter.end(function() { - callback(err); - }); - } - - if (key === undefined) { - return iter.end(function(err) { - if (err) - return callback(err); - return callback(null, txs); - }); - } - + transform: function(key) { + key = key.split('/'); if (address) - txs.push(key.split('/')[2]); - else - txs.push(key.split('/')[1]); - - next(); - }); - })(); + return key[2]; + return key[1]; + } + }, callback); }; /** @@ -1143,8 +1082,6 @@ TXDB.prototype.getHistoryHashes = function getHistoryHashes(address, callback) { TXDB.prototype.getUnconfirmedHashes = function getUnconfirmedHashes(address, callback) { var self = this; - var txs = []; - var iter; if (typeof address === 'function') { callback = address; @@ -1174,39 +1111,16 @@ TXDB.prototype.getUnconfirmedHashes = function getUnconfirmedHashes(address, cal }); } - iter = this.db.iterator({ + this.db.iterate({ gte: address ? 'P/' + address : 'p', lte: address ? 'P/' + address + '~' : 'p~', - keys: true, - values: false, - fillCache: false, - keyAsBuffer: false - }); - - (function next() { - iter.next(function(err, key, value) { - if (err) { - return iter.end(function() { - callback(err); - }); - } - - if (key === undefined) { - return iter.end(function(err) { - if (err) - return callback(err); - return callback(null, txs); - }); - } - + transform: function(key) { + key = key.split('/'); if (address) - txs.push(key.split('/')[2]); - else - txs.push(key.split('/')[1]); - - next(); - }); - })(); + return key[2]; + return key[1]; + } + }, callback); }; /** @@ -1217,8 +1131,6 @@ TXDB.prototype.getUnconfirmedHashes = function getUnconfirmedHashes(address, cal TXDB.prototype.getCoinHashes = function getCoinHashes(address, callback) { var self = this; - var coins = []; - var iter; if (typeof address === 'function') { callback = address; @@ -1245,45 +1157,16 @@ TXDB.prototype.getCoinHashes = function getCoinHashes(address, callback) { }); } - iter = this.db.iterator({ - gte: address - ? 'C/' + address - : 'c', - lte: address - ? 'C/' + address + '~' - : 'c~', - keys: true, - values: false, - fillCache: false, - keyAsBuffer: false - }); - - (function next() { - iter.next(function(err, key, value) { - if (err) { - return iter.end(function() { - callback(err); - }); - } - - if (key === undefined) { - return iter.end(function(err) { - if (err) - return callback(err); - return callback(null, coins); - }); - } - + this.db.iterate({ + gte: address ? 'C/' + address : 'c', + lte: address ? 'C/' + address + '~' : 'c~', + transform: function(key) { key = key.split('/'); - if (address) - coins.push([key[2], +key[3]]); - else - coins.push([key[1], +key[2]]); - - next(); - }); - })(); + return [key[2], +key[3]]; + return [key[1], +key[2]]; + } + }, callback); }; /** @@ -1298,13 +1181,7 @@ TXDB.prototype.getCoinHashes = function getCoinHashes(address, callback) { */ TXDB.prototype.getHeightRangeHashes = function getHeightRangeHashes(address, options, callback) { - var txs = []; - var iter; - - if (typeof address === 'function') { - callback = address; - address = null; - } else if (address && typeof address === 'object') { + if (typeof address !== 'string') { callback = options; options = address; address = null; @@ -1312,45 +1189,22 @@ TXDB.prototype.getHeightRangeHashes = function getHeightRangeHashes(address, opt callback = utils.ensure(callback); - iter = this.db.iterator({ + this.db.iterate({ gte: address ? 'H/' + address + '/' + pad32(options.start) + '/' : 'h/' + pad32(options.start) + '/', lte: address ? 'H/' + address + '/' + pad32(options.end) + '/~' : 'h/' + pad32(options.end) + '/~', - keys: true, - values: false, - fillCache: false, - keyAsBuffer: false, limit: options.limit, - reverse: options.reverse - }); - - (function next() { - iter.next(function(err, key, value) { - if (err) { - return iter.end(function() { - callback(err); - }); - } - - if (key === undefined) { - return iter.end(function(err) { - if (err) - return callback(err); - return callback(null, txs); - }); - } - + reverse: options.reverse, + transform: function(key) { + key = key.split('/'); if (address) - txs.push(key.split('/')[3]); - else - txs.push(key.split('/')[2]); - - next(); - }); - })(); + return key[3]; + return key[2]; + } + }, callback); }; /** @@ -1375,9 +1229,6 @@ TXDB.prototype.getHeightHashes = function getHeightHashes(height, callback) { */ TXDB.prototype.getRangeHashes = function getRangeHashes(address, options, callback) { - var txs = []; - var iter; - if (typeof address === 'function') { callback = address; address = null; @@ -1385,45 +1236,22 @@ TXDB.prototype.getRangeHashes = function getRangeHashes(address, options, callba callback = utils.ensure(callback); - iter = this.db.iterator({ + this.db.iterate({ gte: address ? 'M/' + address + '/' + pad32(options.start) + '/' : 'm/' + pad32(options.start) + '/', lte: address ? 'M/' + address + '/' + pad32(options.end) + '/~' : 'm/' + pad32(options.end) + '/~', - keys: true, - values: false, - fillCache: false, - keyAsBuffer: false, limit: options.limit, - reverse: options.reverse - }); - - (function next() { - iter.next(function(err, key, value) { - if (err) { - return iter.end(function() { - callback(err); - }); - } - - if (key === undefined) { - return iter.end(function(err) { - if (err) - return callback(err); - return callback(null, txs); - }); - } - + reverse: options.reverse, + transform: function(key) { + key = key.split('/'); if (address) - txs.push(key.split('/')[3]); - else - txs.push(key.split('/')[2]); - - next(); - }); - })(); + return key[3]; + return key[2]; + } + }, callback); }; /** @@ -1657,12 +1485,7 @@ TXDB.prototype.fillHistory = function fillHistory(tx, callback) { if (Array.isArray(tx)) { return utils.forEachSerial(tx, function(tx, next) { - self.fillHistory(tx, function(err) { - if (err) - return next(err); - - next(); - }); + self.fillHistory(tx, next); }, callback); } @@ -1702,12 +1525,7 @@ TXDB.prototype.fillCoins = function fillCoins(tx, callback) { if (Array.isArray(tx)) { return utils.forEachSerial(tx, function(tx, next) { - self.fillCoins(tx, function(err) { - if (err) - return next(err); - - next(); - }); + self.fillCoins(tx, next); }, callback); } @@ -1743,23 +1561,9 @@ TXDB.prototype.fillCoins = function fillCoins(tx, callback) { */ TXDB.prototype.getTX = function getTX(hash, callback) { - var key = 't/' + hash; - - this.db.get(key, function(err, tx) { - if (err && err.type !== 'NotFoundError') - return callback(err); - - if (!tx) - return callback(); - - try { - tx = bcoin.tx.fromExtended(tx); - } catch (e) { - return callback(e); - } - - return callback(null, tx); - }); + this.db.fetch('t/' + hash, function(tx) { + return bcoin.tx.fromExtended(tx); + }, callback); }; /** @@ -1769,12 +1573,7 @@ TXDB.prototype.getTX = function getTX(hash, callback) { */ TXDB.prototype.hasTX = function hasTX(hash, callback) { - return this.getTX(hash, function(err, tx) { - if (err) - return callback(err); - - return callback(null, tx != null); - }); + return this.db.has('t/' + hash, callback); }; /** @@ -1785,25 +1584,12 @@ TXDB.prototype.hasTX = function hasTX(hash, callback) { */ TXDB.prototype.getCoin = function getCoin(hash, index, callback) { - var key = 'c/' + hash + '/' + index; - - this.db.get(key, function(err, coin) { - if (err && err.type !== 'NotFoundError') - return callback(err); - - if (!coin) - return callback(); - - try { - coin = bcoin.coin.fromRaw(coin); - coin.hash = hash; - coin.index = index; - } catch (e) { - return callback(e); - } - - return callback(null, coin); - }); + this.db.fetch('c/' + hash + '/' + index, function(coin) { + coin = bcoin.coin.fromRaw(coin); + coin.hash = hash; + coin.index = index; + return coin; + }, callback); }; /** @@ -1813,12 +1599,7 @@ TXDB.prototype.getCoin = function getCoin(hash, index, callback) { */ TXDB.prototype.hasCoin = function hasCoin(hash, index, callback) { - return this.getCoin(hash, index, function(err, coin) { - if (err) - return callback(err); - - return callback(null, coin != null); - }); + return this.db.has('c/' + hash + '/' + index, callback); }; /**