From c7fb41f4cd5ad9675ad6055db3512b509b22de23 Mon Sep 17 00:00:00 2001 From: Christopher Jeffrey Date: Wed, 28 Sep 2016 09:24:11 -0700 Subject: [PATCH] wallet/txdb: refactor. --- lib/utils/uri.js | 4 +- lib/wallet/txdb.js | 120 ++++++++++++++++++++--------------------- lib/wallet/walletdb.js | 26 +++++---- 3 files changed, 77 insertions(+), 73 deletions(-) diff --git a/lib/utils/uri.js b/lib/utils/uri.js index 284a1bc8..e13bfd06 100644 --- a/lib/utils/uri.js +++ b/lib/utils/uri.js @@ -46,9 +46,9 @@ URI.prototype.fromOptions = function fromOptions(options) { this.message = options.message; } - if (options.r) { + if (options.request) { assert(typeof options.request === 'string'); - this.request = options.r; + this.request = options.request; } return this; diff --git a/lib/wallet/txdb.js b/lib/wallet/txdb.js index 10ce8d76..35a0c171 100644 --- a/lib/wallet/txdb.js +++ b/lib/wallet/txdb.js @@ -441,13 +441,13 @@ TXDB.prototype.getOrphans = co(function* getOrphans(hash, index) { TXDB.prototype.verify = co(function* verify(tx, info) { var i, input, prevout, address, coin, spent, conflict; + if (tx.isCoinbase()) + return true; + for (i = 0; i < tx.inputs.length; i++) { input = tx.inputs[i]; prevout = input.prevout; - if (tx.isCoinbase()) - continue; - address = input.getHash('hex'); // Only bother if this input is ours. @@ -491,7 +491,7 @@ TXDB.prototype.verify = co(function* verify(tx, info) { return false; } - this.logger.warning('Removing conflicting tx: %s.', + this.logger.warning('Handling conflicting tx: %s.', utils.revHex(spent.hash)); // Remove the older double spender. @@ -502,6 +502,8 @@ TXDB.prototype.verify = co(function* verify(tx, info) { if (!conflict) return false; + this.logger.warning('Removed conflict: %s.', conflict.tx.rhash); + // Emit the _removed_ transaction. this.emit('conflict', conflict.tx, conflict.info); } @@ -632,43 +634,42 @@ TXDB.prototype._add = co(function* add(tx, info) { } // Consume unspent money or add orphans - for (i = 0; i < tx.inputs.length; i++) { - input = tx.inputs[i]; - prevout = input.prevout; + if (!tx.isCoinbase()) { + for (i = 0; i < tx.inputs.length; i++) { + input = tx.inputs[i]; + prevout = input.prevout; - if (tx.isCoinbase()) - continue; + address = input.getHash('hex'); + path = info.getPath(address); - address = input.getHash('hex'); - path = info.getPath(address); + // Only bother if this input is ours. + if (!path) + continue; - // Only bother if this input is ours. - if (!path) - continue; + key = prevout.hash + prevout.index; - key = prevout.hash + prevout.index; + // s[outpoint-key] -> [spender-hash]|[spender-input-index] + spender = bcoin.outpoint.fromTX(tx, i).toRaw(); + this.put(layout.s(prevout.hash, prevout.index), spender); - // s[outpoint-key] -> [spender-hash]|[spender-input-index] - spender = bcoin.outpoint.fromTX(tx, i).toRaw(); - this.put(layout.s(prevout.hash, prevout.index), spender); - - // Add orphan, if no parent transaction is yet known - if (!input.coin) { - try { - yield this.addOrphan(prevout, spender); - } catch (e) { - this.drop(); - throw e; + // Add orphan, if no parent transaction is yet known + if (!input.coin) { + try { + yield this.addOrphan(prevout, spender); + } catch (e) { + this.drop(); + throw e; + } + continue; } - continue; + + this.del(layout.c(prevout.hash, prevout.index)); + this.del(layout.C(path.account, prevout.hash, prevout.index)); + this.put(layout.d(hash, i), input.coin.toRaw()); + this.balance.sub(input.coin); + + this.coinCache.remove(key); } - - this.del(layout.c(prevout.hash, prevout.index)); - this.del(layout.C(path.account, prevout.hash, prevout.index)); - this.put(layout.d(hash, i), input.coin.toRaw()); - this.balance.sub(input.coin); - - this.coinCache.remove(key); } // Add unspent outputs or resolve orphans @@ -743,7 +744,7 @@ TXDB.prototype.removeConflict = co(function* removeConflict(hash, ref) { // If both are confirmed but replacement // is older than spender, do nothing. - if (ref.ts < tx.ts) + if (ref.height < tx.height) return; } else { // If spender is unconfirmed and replacement @@ -1033,36 +1034,35 @@ TXDB.prototype.__remove = co(function* remove(tx, info) { this.del(layout.M(account, tx.ps, hash)); } - yield this.fillHistory(tx); + if (!tx.isCoinbase()) { + yield this.fillHistory(tx); - for (i = 0; i < tx.inputs.length; i++) { - input = tx.inputs[i]; - key = input.prevout.hash + input.prevout.index; - prevout = input.prevout; - address = input.getHash('hex'); + for (i = 0; i < tx.inputs.length; i++) { + input = tx.inputs[i]; + key = input.prevout.hash + input.prevout.index; + prevout = input.prevout; + address = input.getHash('hex'); - if (tx.isCoinbase()) - break; + if (!input.coin) + continue; - if (!input.coin) - continue; + path = info.getPath(address); - path = info.getPath(address); + if (!path) + continue; - if (!path) - continue; + this.balance.add(input.coin); - this.balance.add(input.coin); + coin = input.coin.toRaw(); - coin = input.coin.toRaw(); + this.put(layout.c(prevout.hash, prevout.index), coin); + this.put(layout.C(path.account, prevout.hash, prevout.index), DUMMY); + this.del(layout.d(hash, i)); + this.del(layout.s(prevout.hash, prevout.index)); + this.del(layout.o(prevout.hash, prevout.index)); - this.put(layout.c(prevout.hash, prevout.index), coin); - this.put(layout.C(path.account, prevout.hash, prevout.index), DUMMY); - this.del(layout.d(hash, i)); - this.del(layout.s(prevout.hash, prevout.index)); - this.del(layout.o(prevout.hash, prevout.index)); - - this.coinCache.set(key, coin); + this.coinCache.set(key, coin); + } } for (i = 0; i < tx.outputs.length; i++) { @@ -1356,7 +1356,7 @@ TXDB.prototype.getUnconfirmedHashes = function getUnconfirmedHashes(account) { * @returns {Promise} - Returns {@link Hash}[]. */ -TXDB.prototype.getCoinHashes = function getCoinHashes(account) { +TXDB.prototype.getOutpoints = function getOutpoints(account) { return this.iterate({ gte: account != null ? layout.C(account, constants.NULL_HASH, 0) @@ -1632,7 +1632,7 @@ TXDB.prototype.getCoins = function getCoins(account) { */ TXDB.prototype.getAccountCoins = co(function* getCoins(account) { - var prevout = yield this.getCoinHashes(account); + var prevout = yield this.getOutpoints(account); var coins = []; var i, op, coin; @@ -1921,7 +1921,7 @@ TXDB.prototype.getBalance = co(function* getBalance(account) { */ TXDB.prototype.getAccountBalance = co(function* getBalance(account) { - var prevout = yield this.getCoinHashes(account); + var prevout = yield this.getOutpoints(account); var balance = new Balance(this.wallet); var i, ckey, key, coin, op, data; diff --git a/lib/wallet/walletdb.js b/lib/wallet/walletdb.js index f4bc963f..6896d0ae 100644 --- a/lib/wallet/walletdb.js +++ b/lib/wallet/walletdb.js @@ -441,17 +441,13 @@ WalletDB.prototype.getWalletID = co(function* getWalletID(id) { */ WalletDB.prototype.get = co(function* get(wid) { - var wallet, unlock; + var unlock; wid = yield this.getWalletID(wid); + if (!wid) return; - wallet = this.wallets[wid]; - if (wallet) - return wallet; - - // NOTE: Lock must start here! unlock = yield this.readLock.lock(wid); try { @@ -469,8 +465,16 @@ WalletDB.prototype.get = co(function* get(wid) { */ WalletDB.prototype._get = co(function* get(wid) { - var data = yield this.db.get(layout.w(wid)); - var wallet; + var data, wallet; + + // By the time the lock is released, + // the wallet may be watched. + wallet = this.wallets[wid]; + + if (wallet) + return wallet; + + data = yield this.db.get(layout.w(wid)); if (!data) return; @@ -976,9 +980,9 @@ WalletDB.prototype._rescan = co(function* rescan(chaindb, height) { this.logger.info('Scanning for %d addresses.', hashes.length); - yield chaindb.scan(height, hashes, co(function *(block, txs) { - yield self._addBlock(block, txs); - })); + yield chaindb.scan(height, hashes, function(block, txs) { + return self._addBlock(block, txs); + }); }); /**