diff --git a/lib/bcoin/chain.js b/lib/bcoin/chain.js index 6618528d..ca9882f2 100644 --- a/lib/bcoin/chain.js +++ b/lib/bcoin/chain.js @@ -18,9 +18,9 @@ var VerifyError = utils.VerifyError; * Chain */ -function Chain(node, options) { +function Chain(options) { if (!(this instanceof Chain)) - return new Chain(node, options); + return new Chain(options); EventEmitter.call(this); @@ -29,9 +29,7 @@ function Chain(node, options) { this.options = options; - this.node = node; this.loaded = false; - this.mempool = node.mempool; this.db = new bcoin.chaindb(this, options); this.total = 0; this.orphanLimit = options.orphanLimit || (20 << 20); @@ -43,7 +41,6 @@ function Chain(node, options) { this.tip = null; this.height = -1; this.segwitActive = null; - this.spv = !!options.spv; this.orphan = { map: {}, @@ -52,8 +49,6 @@ function Chain(node, options) { size: 0 }; - Chain.global = this; - this._init(); } @@ -63,17 +58,7 @@ Chain.prototype._init = function _init() { var self = this; function getHost() { - var peer; - - if (!self.node || !self.node.pool) - return; - - peer = self.node.pool.peers.load; - - if (!peer) - return 'unknown'; - - return peer.host; + return 'unknown'; } // Hook into events for debugging @@ -242,7 +227,7 @@ Chain.prototype._preload = function _preload(callback) { if (!this.options.preload) return callback(); - if (!this.spv) + if (!this.options.spv) return callback(); if (network.type !== 'main') @@ -592,7 +577,7 @@ Chain.prototype._checkDuplicates = function _checkDuplicates(block, prev, callba var self = this; var height = prev.height + 1; - if (this.spv || block.type !== 'block') + if (this.options.spv || block.type !== 'block') return callback(); if (block.isGenesis()) @@ -629,7 +614,7 @@ Chain.prototype._checkInputs = function _checkInputs(block, prev, flags, callbac var scriptCheck = true; var historical = false; - if (this.spv || block.type !== 'block') + if (this.options.spv || block.type !== 'block') return callback(); if (block.isGenesis()) diff --git a/lib/bcoin/chaindb.js b/lib/bcoin/chaindb.js index 0d473bd6..af24453a 100644 --- a/lib/bcoin/chaindb.js +++ b/lib/bcoin/chaindb.js @@ -27,19 +27,12 @@ function ChainDB(chain, options) { EventEmitter.call(this); this.options = options; - this.node = chain.node; - this.network = chain.node.network; this.chain = chain; - this.queue = {}; - this.queueSize = 0; - this.size = 0; - this.fd = null; - this.loaded = false; - this.keepBlocks = options.keepBlocks || 288; this.prune = !!options.prune; - this.spv = !!options.spv; + + this.loaded = false; // Need to cache up to the retarget interval // if we're going to be checking the damn @@ -66,7 +59,9 @@ ChainDB.prototype._init = function _init() { if (this.loaded) return; - this.db = bcoin.ldb(this.spv ? 'spvchain' : 'chain', { + this.db = bcoin.ldb({ + name: this.options.name || (this.options.spv ? 'spvchain' : 'chain'), + location: this.options.location, compression: true, cacheSize: 16 << 20, writeBufferSize: 8 << 20 @@ -82,10 +77,10 @@ ChainDB.prototype._init = function _init() { if (err) return self.emit('error', err); + utils.debug('Chain successfully loaded.'); + self.loaded = true; self.emit('open'); - - utils.debug('Chain successfully loaded.'); } self.db.get('c/b/' + network.genesis.hash, function(err, exists) { @@ -578,7 +573,7 @@ ChainDB.prototype.has = function has(height, callback) { }; ChainDB.prototype.saveBlock = function saveBlock(block, batch, connect, callback) { - if (this.spv) + if (this.options.spv) return utils.nextTick(callback); batch.put('b/b/' + block.hash('hex'), block.toCompact()); @@ -596,7 +591,7 @@ ChainDB.prototype.saveBlock = function saveBlock(block, batch, connect, callback ChainDB.prototype.removeBlock = function removeBlock(hash, batch, callback) { var self = this; - if (this.spv) + if (this.options.spv) return utils.nextTick(callback); this._ensureHistory(hash, function(err, block) { @@ -619,7 +614,7 @@ ChainDB.prototype.removeBlock = function removeBlock(hash, batch, callback) { ChainDB.prototype.connectBlock = function connectBlock(block, batch, callback) { var self = this; - if (this.spv) { + if (this.options.spv) { self.emit('add block', block); return utils.nextTick(callback); } @@ -690,7 +685,7 @@ ChainDB.prototype.connectBlock = function connectBlock(block, batch, callback) { ChainDB.prototype.disconnectBlock = function disconnectBlock(hash, batch, callback) { var self = this; - if (this.spv) + if (this.options.spv) return utils.nextTick(callback); this._ensureHistory(hash, function(err, block) { @@ -1258,7 +1253,7 @@ ChainDB.prototype._getTX = function _getTX(hash, callback) { ChainDB.prototype.isUnspentTX = function isUnspentTX(hash, callback) { return callback(null, false); - if (this.spv) + if (this.options.spv) return callback(null, false); return this.isSpentTX(hash, function(err, spent) { @@ -1300,7 +1295,7 @@ ChainDB.prototype.isSpentTX = function isSpentTX(hash, callback) { ChainDB.prototype._pruneBlock = function _pruneBlock(block, batch, callback) { var futureHeight; - if (this.spv) + if (this.options.spv) return callback(); if (!this.prune) diff --git a/lib/bcoin/fullnode.js b/lib/bcoin/fullnode.js index 0e940e8c..1cb02d53 100644 --- a/lib/bcoin/fullnode.js +++ b/lib/bcoin/fullnode.js @@ -23,8 +23,6 @@ function Fullnode(options) { this.loaded = false; - Fullnode.global = this; - this._init(); } @@ -36,15 +34,16 @@ Fullnode.prototype._init = function _init() { this.wallet = null; - this.chain = new bcoin.chain(this, { + this.chain = new bcoin.chain({ preload: false, spv: false, prune: this.options.prune, useCheckpoints: this.options.useCheckpoints }); - // Mempool needs access to blockdb. - this.mempool = new bcoin.mempool(this, { + // Mempool needs access to the chain. + this.mempool = new bcoin.mempool({ + chain: this.chain, limitFree: this.options.limitFree, limitFreeRelay: this.options.limitFreeRelay, requireStandard: this.options.requireStandard, @@ -52,26 +51,31 @@ Fullnode.prototype._init = function _init() { replaceByFee: this.options.replaceByFee }); - // Pool needs access to the chain. - this.pool = new bcoin.pool(this, { + // Pool needs access to the chain and mempool. + this.pool = new bcoin.pool({ + chain: this.chain, + mempool: this.mempool, witness: this.network.witness, listen: this.options.listen, selfish: this.options.selfish, spv: false }); - // Miner needs access to the mempool. - this.miner = new bcoin.miner(this, { + // Miner needs access to the chain and mempool. + this.miner = new bcoin.miner({ + chain: this.chain, + mempool: this.mempool, address: this.options.payoutAddress, coinbaseFlags: this.options.coinbaseFlags }); - // WalletDB needs access to the network type. - this.walletdb = new bcoin.walletdb(this); + this.walletdb = new bcoin.walletdb({ + verify: false + }); - // HTTP needs access to the mempool - // and blockdb. - this.http = new bcoin.http.server(this, { + // HTTP needs access to the node. + this.http = new bcoin.http.server({ + node: this, key: this.options.sslKey, cert: this.options.sslCert, port: this.options.httpPort || 8080, @@ -141,6 +145,10 @@ Fullnode.prototype._init = function _init() { }); }); + this.miner.on('block', function(block) { + self.pool.sendBlock(block); + }); + function load(err) { if (err) return self.emit('error', err); diff --git a/lib/bcoin/http/server.js b/lib/bcoin/http/server.js index 38ea3493..f3cbb278 100644 --- a/lib/bcoin/http/server.js +++ b/lib/bcoin/http/server.js @@ -16,14 +16,17 @@ var assert = utils.assert; * NodeServer */ -function NodeServer(node, options) { +function NodeServer(options) { if (!options) options = {}; this.options = options; - this.node = node; - this.walletdb = node.walletdb; - this.pool = node.pool; + this.node = options.node; + + assert(this.node, 'HTTP requires a Node.'); + + this.walletdb = this.node.walletdb; + this.pool = this.node.pool; this.loaded = false; this.server = new HTTPServer(options); @@ -145,7 +148,7 @@ NodeServer.prototype._init = function _init() { this.get('/', function(req, res, next, send) { send(200, { version: constants.userAgent, - network: self.node.network.type + network: network.type }); }); diff --git a/lib/bcoin/ldb.js b/lib/bcoin/ldb.js index 83de5249..b90578a3 100644 --- a/lib/bcoin/ldb.js +++ b/lib/bcoin/ldb.js @@ -14,8 +14,8 @@ var db = {}; * LDB */ -function ldb(name, options) { - var file = getLocation(name); +function ldb(options) { + var file = getLocation(options); if (!db[file]) { if (!options) @@ -49,8 +49,10 @@ function ldb(name, options) { return db[file]; } -function getLocation(name) { - return bcoin.prefix + '/' + name + '-' + network.type + '.db'; +function getLocation(options) { + if (options.location) + return options.location; + return bcoin.prefix + '/' + options.name + '-' + network.type + '.db'; } function getBackend(backend) { @@ -77,15 +79,9 @@ function getBackend(backend) { return require(backend); } -function destroy(name, backend, callback) { - var file = getLocation(name); - - if (!callback) { - callback = backend; - backend = null; - } - - backend = getBackend(backend); +function destroy(options, callback) { + var file = getLocation(options); + var backend = getBackend(options.db); if (!backend.destroy) return utils.nextTick(callback); @@ -93,15 +89,9 @@ function destroy(name, backend, callback) { backend.destroy(file, callback); } -function repair(name, backend, callback) { - var file = getLocation(name); - - if (!callback) { - callback = backend; - backend = null; - } - - backend = getBackend(backend); +function repair(options, callback) { + var file = getLocation(options); + var backend = getBackend(options.db); if (!backend.repair) return utils.asyncify(callback)(new Error('Cannot repair.')); diff --git a/lib/bcoin/mempool.js b/lib/bcoin/mempool.js index 33a9e332..a4bb911c 100644 --- a/lib/bcoin/mempool.js +++ b/lib/bcoin/mempool.js @@ -15,14 +15,16 @@ var assert = utils.assert; var BufferWriter = require('./writer'); var BufferReader = require('./reader'); var VerifyError = utils.VerifyError; +var pad32 = utils.pad32; +var DUMMY = new Buffer([0]); /** * Mempool */ -function Mempool(node, options) { +function Mempool(options) { if (!(this instanceof Mempool)) - return new Mempool(node, options); + return new Mempool(options); EventEmitter.call(this); @@ -30,12 +32,14 @@ function Mempool(node, options) { options = {}; this.options = options; - this.node = node; - this.chain = node.chain; + this.chain = options.chain; + + assert(this.chain, 'Mempool requires a blockchain.'); this.loaded = false; this.locker = new bcoin.locker(this, this.addTX, 20 << 20); + this.writeLock = new bcoin.locker(this); this.db = null; this.tx = null; @@ -55,8 +59,6 @@ function Mempool(node, options) { // Use an in-memory binary search tree by default this.backend = this.options.memory === false ? 'leveldb' : 'memory'; - Mempool.global = this; - this._init(); } @@ -82,6 +84,11 @@ Mempool.prototype.purgePending = function purgePending() { Mempool.prototype._init = function _init() { var self = this; var unlock = this._lock(utils.nop, []); + var options = { + name: this.options.name || 'mempool', + location: this.options.location, + db: this.backend + }; assert(unlock); @@ -89,22 +96,16 @@ Mempool.prototype._init = function _init() { // reason for using an on-disk db for the mempool // is not for persistence, but to keep ~300mb of // txs out of main memory. - bcoin.ldb.destroy('mempool', this.backend, function(err) { + bcoin.ldb.destroy(options, function(err) { if (err) { unlock(); return self.emit('error', err); } - self.db = bcoin.ldb('mempool', { - db: self.backend - }); + self.db = bcoin.ldb(options); - self.tx = new bcoin.txdb('m', self.db, { - indexExtra: false, - indexAddress: false, - mapAddress: false, - verify: false - }); + // Use the txdb object for its get methods. + self.tx = new bcoin.txdb('m', self.db); self.db.open(function(err) { if (err) { @@ -456,7 +457,7 @@ Mempool.prototype.addTX = function addTX(tx, callback, force) { Mempool.prototype.addUnchecked = function addUnchecked(tx, callback) { var self = this; - this.tx.addUnchecked(tx, function(err) { + this._addUnchecked(tx, function(err) { if (err) return callback(err); @@ -466,9 +467,6 @@ Mempool.prototype.addUnchecked = function addUnchecked(tx, callback) { utils.debug('Added tx %s to the mempool.', tx.rhash); - if (self.options.relay) - self.node.broadcast(tx); - self.resolveOrphans(tx, function(err, resolved) { if (err) return callback(err); @@ -509,7 +507,7 @@ Mempool.prototype.removeUnchecked = function removeUnchecked(tx, callback) { if (err) return callback(err); - self.tx.removeUnchecked(tx, function(err) { + self._removeUnchecked(tx, function(err) { if (err) return callback(err); self.size -= tx.getSize(); @@ -1088,6 +1086,137 @@ Mempool.prototype.getConfidence = function getConfidence(hash, callback) { }); }; +Mempool.prototype._addUnchecked = function addUnchecked(tx, callback, force) { + var self = this; + var prefix = 'm/'; + var hash = tx.hash('hex'); + var batch; + + var unlock = this.writeLock.lock(addUnchecked, [tx, callback], force); + if (!unlock) + return; + + callback = utils.wrap(callback, unlock); + + batch = this.db.batch(); + + batch.put(prefix + 't/t/' + hash, tx.toExtended()); + batch.put(prefix + 't/s/s/' + pad32(tx.ps) + '/' + hash, DUMMY); + + tx.getAddresses().forEach(function(address) { + batch.put(prefix + 't/a/' + address + '/' + hash, DUMMY); + }); + + tx.inputs.forEach(function(input) { + var key = input.prevout.hash + '/' + input.prevout.index; + var address; + + if (tx.isCoinbase()) + return; + + assert(input.coin); + address = input.getAddress(); + + batch.del(prefix + 'u/t/' + key); + batch.put(prefix + 's/t/' + key, tx.hash()); + + if (address) + batch.del(prefix + 'u/a/' + address + '/' + key); + }); + + tx.outputs.forEach(function(output, i) { + var key = hash + '/' + i; + var address = output.getAddress(); + var coin = bcoin.coin(tx, i).toRaw(); + + batch.put(prefix + 'u/t/' + key, coin); + + if (address) + batch.put(prefix + 'u/a/' + address + '/' + key, DUMMY); + }); + + return batch.write(callback); +}; + +Mempool.prototype._removeUnchecked = function removeUnchecked(hash, callback, force) { + var self = this; + var prefix = 'm/'; + var batch; + + var unlock = this.writeLock.lock(removeUnchecked, [hash, callback], force); + if (!unlock) + return; + + callback = utils.wrap(callback, unlock); + + if (hash.hash) + hash = hash.hash('hex'); + + this.getTX(hash, function(err, tx) { + if (err) + return callback(err); + + if (!tx) + return callback(); + + batch = self.db.batch(); + + batch.del(prefix + 't/t/' + hash); + batch.del(prefix + 't/s/s/' + pad32(tx.ps) + '/' + hash); + + tx.getAddresses().forEach(function(address) { + batch.del(prefix + 't/a/' + address + '/' + hash); + }); + + utils.forEachSerial(tx.inputs, function(input, next) { + var key = input.prevout.hash + '/' + input.prevout.index; + var address; + + if (tx.isCoinbase()) + return next(); + + if (!input.coin) + return next(); + + address = input.getAddress(); + + batch.del(prefix + 's/t/' + key); + + self.hasTX(input.prevout.hash, function(err, result) { + if (err) + return next(err); + + if (result) { + batch.put(prefix + 'u/t/' + key, input.coin.toRaw()); + if (address) + batch.put(prefix + 'u/a/' + address + '/' + key, DUMMY); + } else { + batch.del(prefix + 'u/t/' + key); + if (address) + batch.del(prefix + 'u/a/' + address + '/' + key); + } + + next(); + }); + }, function(err) { + if (err) + return callback(err); + + tx.outputs.forEach(function(output, i) { + var key = hash + '/' + i; + var address = output.getAddress(); + + batch.del(prefix + 'u/t/' + key); + + if (address) + batch.del(prefix + 'u/a/' + address + '/' + key); + }); + + return batch.write(callback); + }); + }); +}; + /** * Expose */ diff --git a/lib/bcoin/miner.js b/lib/bcoin/miner.js index 43e641ec..f85fe4a9 100644 --- a/lib/bcoin/miner.js +++ b/lib/bcoin/miner.js @@ -17,9 +17,9 @@ var EventEmitter = require('events').EventEmitter; * Miner */ -function Miner(node, options) { +function Miner(options) { if (!(this instanceof Miner)) - return new Miner(node, options); + return new Miner(options); EventEmitter.call(this); @@ -34,10 +34,11 @@ function Miner(node, options) { // wants to pass in a faster linked in function. this.dsha256 = this.options.dsha256 || utils.dsha256; - this.node = node; - this.pool = node.pool; - this.chain = node.chain; - this.mempool = node.mempool; + this.pool = options.pool; + this.chain = options.chain; + this.mempool = options.mempool; + + assert(this.chain, 'Miner requires a blockchain.'); this.running = false; this.timeout = null; @@ -69,7 +70,7 @@ Miner.prototype._init = function _init() { return; self.addTX(tx); }); - } else { + } else if (this.pool) { this.pool.on('tx', function(tx) { if (!self.running) return; @@ -93,7 +94,6 @@ Miner.prototype._init = function _init() { block.hash('hex')); // Emit the block hex as a failsafe (in case we can't send it) utils.debug('Raw: %s', utils.toHex(block.render())); - self.pool.sendBlock(block); }); this.on('status', function(stat) { diff --git a/lib/bcoin/node.js b/lib/bcoin/node.js index 4df49c7f..9cdf85e4 100644 --- a/lib/bcoin/node.js +++ b/lib/bcoin/node.js @@ -39,8 +39,6 @@ function Node(options) { this.chain = null; this.miner = null; this.walletdb = null; - - Node.global = this; } utils.inherits(Node, EventEmitter); diff --git a/lib/bcoin/peer.js b/lib/bcoin/peer.js index cd274420..c17953e0 100644 --- a/lib/bcoin/peer.js +++ b/lib/bcoin/peer.js @@ -637,7 +637,7 @@ Peer.prototype._handleGetHeaders = function _handleGetHeaders(payload) { if (this.chain.db.options.spv) return; - if (this.chain.db.prune) + if (this.chain.db.options.prune) return; function collect(err, hash) { @@ -705,7 +705,7 @@ Peer.prototype._handleGetBlocks = function _handleGetBlocks(payload) { if (this.chain.db.options.spv) return; - if (this.chain.db.prune) + if (this.chain.db.options.prune) return; function done(err) { @@ -907,7 +907,7 @@ Peer.prototype._handleGetData = function handleGetData(items) { notfound.push({ type: constants.inv.block, hash: hash }); return next(); } - if (self.chain.db.prune) { + if (self.chain.db.options.prune) { notfound.push({ type: constants.inv.block, hash: hash }); return; } @@ -944,7 +944,7 @@ Peer.prototype._handleGetData = function handleGetData(items) { notfound.push({ type: constants.inv.block, hash: hash }); return next(); } - if (self.chain.db.prune) { + if (self.chain.db.options.prune) { notfound.push({ type: constants.inv.block, hash: hash }); return; } diff --git a/lib/bcoin/pool.js b/lib/bcoin/pool.js index 959c904e..3c9501aa 100644 --- a/lib/bcoin/pool.js +++ b/lib/bcoin/pool.js @@ -16,12 +16,12 @@ var constants = bcoin.protocol.constants; * Pool */ -function Pool(node, options) { +function Pool(options) { var self = this; var seeds; if (!(this instanceof Pool)) - return new Pool(node, options); + return new Pool(options); EventEmitter.call(this); @@ -29,7 +29,10 @@ function Pool(node, options) { options = {}; this.options = options; - this.network = node.network; + this.chain = options.chain; + this.mempool = options.mempool; + + assert(this.chain, 'Pool requires a blockchain.'); if (options.relay == null) { if (options.spv) @@ -54,9 +57,6 @@ function Pool(node, options) { this.size = options.size || 8; this.connected = false; - this.chain = node.chain; - this.mempool = node.mempool; - if (options.spv) { if (options.headers == null) options.headers = true; @@ -138,8 +138,6 @@ function Pool(node, options) { timeout: options.invTimeout || 60000 }; - Pool.global = this; - this.chain.open(function(err) { if (err) return self.emit('error', err); @@ -161,11 +159,19 @@ Pool.prototype.open = function open(callback) { }; Pool.prototype.connect = function connect() { + var self = this; + assert(this.loaded, 'Pool is not loaded.'); if (this.connected) return; + if (this.mempool && this.options.broadcast) { + this.mempool.on('tx', function(tx) { + self.broadcast(tx); + }); + } + if (this.originalSeeds.length > 0) { this._addLoader(); diff --git a/lib/bcoin/spvnode.js b/lib/bcoin/spvnode.js index a0510175..fe884765 100644 --- a/lib/bcoin/spvnode.js +++ b/lib/bcoin/spvnode.js @@ -23,8 +23,6 @@ function SPVNode(options) { this.loaded = false; - SPVNode.global = this; - this._init(); } @@ -36,24 +34,26 @@ SPVNode.prototype._init = function _init() { this.wallet = null; - this.chain = new bcoin.chain(this, { + this.chain = new bcoin.chain({ preload: this.options.preload, - spv: true, - useCheckpoints: this.options.useCheckpoints + useCheckpoints: this.options.useCheckpoints, + spv: true }); - // Pool needs access to the chain. - this.pool = new bcoin.pool(this, { + this.pool = new bcoin.pool({ + chain: this.chain, witness: this.network.witness, selfish: true, listen: false, spv: true }); - // WalletDB needs access to the network type. - this.walletdb = new bcoin.walletdb(this); + this.walletdb = new bcoin.walletdb({ + verify: true + }); - this.http = new bcoin.http.server(this, { + this.http = new bcoin.http.server({ + node: this, key: this.options.sslKey, cert: this.options.sslCert, port: this.options.httpPort || 8080, diff --git a/lib/bcoin/txdb.js b/lib/bcoin/txdb.js index 7acec30f..3eeee40d 100644 --- a/lib/bcoin/txdb.js +++ b/lib/bcoin/txdb.js @@ -1621,146 +1621,6 @@ TXPool.prototype.getBalanceByAddress = function getBalanceByAddress(address, cal return this.getBalance(address, callback); }; -TXPool.prototype.addUnchecked = function addUnchecked(tx, callback, force) { - var self = this; - var prefix = this.prefix + '/'; - var hash = tx.hash('hex'); - var batch; - - var unlock = this._lock(addUnchecked, [tx, callback], force); - if (!unlock) - return; - - callback = utils.wrap(callback, unlock); - - batch = this.db.batch(); - - batch.put(prefix + 't/t/' + hash, tx.toExtended()); - batch.put(prefix + 't/s/s/' + pad32(tx.ps) + '/' + hash, DUMMY); - - tx.getAddresses().forEach(function(address) { - batch.put(prefix + 't/a/' + address + '/' + hash, DUMMY); - }); - - tx.inputs.forEach(function(input) { - var key = input.prevout.hash + '/' + input.prevout.index; - var address; - - if (tx.isCoinbase()) - return; - - assert(input.coin); - address = input.getAddress(); - - batch.del(prefix + 'u/t/' + key); - batch.put(prefix + 's/t/' + key, tx.hash()); - - if (address) - batch.del(prefix + 'u/a/' + address + '/' + key); - }); - - tx.outputs.forEach(function(output, i) { - var key = hash + '/' + i; - var address = output.getAddress(); - var coin = bcoin.coin(tx, i).toRaw(); - batch.put(prefix + 'u/t/' + key, coin); - - if (address) - batch.put(prefix + 'u/a/' + address + '/' + key, DUMMY); - }); - - return batch.write(function(err) { - if (err) - return callback(err); - self.emit('add tx', tx); - return callback(); - }); -}; - -TXPool.prototype.removeUnchecked = function removeUnchecked(hash, callback, force) { - var self = this; - var prefix = this.prefix + '/'; - var batch; - - var unlock = this._lock(removeUnchecked, [hash, callback], force); - if (!unlock) - return; - - callback = utils.wrap(callback, unlock); - - if (hash.hash) - hash = hash.hash('hex'); - - this.getTX(hash, function(err, tx) { - if (err) - return callback(err); - - if (!tx) - return callback(); - - batch = self.db.batch(); - - batch.del(prefix + 't/t/' + hash); - batch.del(prefix + 't/s/s/' + pad32(tx.ps) + '/' + hash); - - tx.getAddresses().forEach(function(address) { - batch.del(prefix + 't/a/' + address + '/' + hash); - }); - - utils.forEachSerial(tx.inputs, function(input, next) { - var key = input.prevout.hash + '/' + input.prevout.index; - var address; - - if (tx.isCoinbase()) - return next(); - - if (!input.coin) - return next(); - - address = input.getAddress(); - - batch.del(prefix + 's/t/' + key); - - self.hasTX(input.prevout.hash, function(err, result) { - if (err) - return next(err); - - if (result) { - batch.put(prefix + 'u/t/' + key, input.coin.toRaw()); - if (address) - batch.put(prefix + 'u/a/' + address + '/' + key, DUMMY); - } else { - batch.del(prefix + 'u/t/' + key); - if (address) - batch.del(prefix + 'u/a/' + address + '/' + key); - } - - next(); - }); - }, function(err) { - if (err) - return callback(err); - - tx.outputs.forEach(function(output, i) { - var key = hash + '/' + i; - var address = output.getAddress(); - - batch.del(prefix + 'u/t/' + key); - - if (address) - batch.del(prefix + 'u/a/' + address + '/' + key); - }); - - batch.write(function(err) { - if (err) - return callback(err); - self.emit('remove tx', tx); - return callback(); - }); - }); - }); -}; - TXPool.prototype.zap = function zap(address, now, age, callback, force) { var self = this; diff --git a/lib/bcoin/walletdb.js b/lib/bcoin/walletdb.js index d6146679..ac235beb 100644 --- a/lib/bcoin/walletdb.js +++ b/lib/bcoin/walletdb.js @@ -15,31 +15,23 @@ var DUMMY = new Buffer([0]); * WalletDB */ -function WalletDB(node, options) { +function WalletDB(options) { if (!(this instanceof WalletDB)) - return new WalletDB(node, options); - - if (WalletDB.global) - return WalletDB.global; + return new WalletDB(options); if (!options) options = {}; EventEmitter.call(this); - this.node = node; this.options = options; this.loaded = false; - WalletDB.global = this; - this._init(); } utils.inherits(WalletDB, EventEmitter); -WalletDB._db = {}; - WalletDB.prototype.dump = function dump(callback) { var records = {}; @@ -84,7 +76,9 @@ WalletDB.prototype._init = function _init() { if (this.loaded) return; - this.db = bcoin.ldb('wallet', { + this.db = bcoin.ldb({ + name: this.options.name || 'wallet', + location: this.options.location, cacheSize: 8 << 20, writeBufferSize: 4 << 20 });