diff --git a/lib/blockchain/chaindb.js b/lib/blockchain/chaindb.js index cdfd56ca..b74fa448 100644 --- a/lib/blockchain/chaindb.js +++ b/lib/blockchain/chaindb.js @@ -1700,35 +1700,14 @@ ChainDB.prototype.connectBlock = co(function* connectBlock(block, view) { if (this.options.spv) return; - this.pending.connect(block); + this.pending.connect(block, view); // Genesis block's coinbase is unspendable. if (this.chain.isGenesis(block)) return; - for (i = 0; i < block.txs.length; i++) { - tx = block.txs[i]; - - if (i > 0) { - for (j = 0; j < tx.inputs.length; j++) { - input = tx.inputs[j]; - assert(input.coin); - this.pending.spend(input.coin); - } - } - - for (j = 0; j < tx.outputs.length; j++) { - output = tx.outputs[j]; - - if (output.script.isUnspendable()) - continue; - - this.pending.add(output); - } - - // Index the transaction if enabled. - this.indexTX(tx); - } + // Index transactions if enabled. + this.indexBlock(block.txs); // Commit new coin state. this.saveView(view); @@ -1754,24 +1733,14 @@ ChainDB.prototype.disconnectBlock = co(function* disconnectBlock(block) { view = yield this.getUndoView(block); - this.pending.disconnect(block); - for (i = block.txs.length - 1; i >= 0; i--) { tx = block.txs[i]; hash = tx.hash('hex'); - if (i > 0) { - for (j = 0; j < tx.inputs.length; j++) { - input = tx.inputs[j]; - assert(input.coin); - this.pending.add(input.coin); - } - } - // Add all of the coins we are about to // remove. This is to ensure they appear // in the view array below. - view.addTX(tx); + view.add(Coins.fromTX(tx)); for (j = 0; j < tx.outputs.length; j++) { output = tx.outputs[j]; @@ -1781,14 +1750,14 @@ ChainDB.prototype.disconnectBlock = co(function* disconnectBlock(block) { // Spend added coin. view.spend(hash, j); - - this.pending.spend(output); } // Remove from transaction index. this.unindexTX(tx); } + this.pending.disconnect(block, view); + // Commit new coin state. this.saveView(view); @@ -1836,6 +1805,24 @@ ChainDB.prototype.saveOptions = function saveOptions() { return this.db.put(layout.O, this.options.toRaw()); }; +/** + * Index transactions by txid and address. + * @private + * @param {TX[]} txs + */ + +ChainDB.prototype.indexBlock = function indexBlock(txs) { + var i, tx; + + if (!this.options.indexTX && !this.options.indexAddress) + return; + + for (i = 0; i < block.txs.length; i++) { + tx = block.txs[i]; + this.indexTX(tx); + } +}; + /** * Index a transaction by txid and address. * @private @@ -2114,22 +2101,16 @@ ChainState.prototype.clone = function clone() { return state; }; -ChainState.prototype.connect = function connect(block) { +ChainState.prototype.connect = function connect(block, view) { this.tx += block.txs.length; + this.coin += view.coinDelta; + this.value += view.valueDelta; }; -ChainState.prototype.disconnect = function connect(block) { +ChainState.prototype.disconnect = function connect(block, view) { this.tx -= block.txs.length; -}; - -ChainState.prototype.add = function add(coin) { - this.coin++; - this.value += coin.value; -}; - -ChainState.prototype.spend = function spend(coin) { - this.coin--; - this.value -= coin.value; + this.coin += view.coinDelta; + this.value += view.valueDelta; }; ChainState.prototype.commit = function commit(hash) { diff --git a/lib/blockchain/coinview.js b/lib/blockchain/coinview.js index b2a6540e..c736f2d7 100644 --- a/lib/blockchain/coinview.js +++ b/lib/blockchain/coinview.js @@ -23,6 +23,8 @@ function CoinView(coins) { this.coins = coins || {}; this.undo = new UndoCoins(); + this.coinDelta = 0; + this.valueDelta = 0; } /** @@ -40,7 +42,21 @@ CoinView.prototype.add = function add(coins) { */ CoinView.prototype.addTX = function addTX(tx) { - this.add(Coins.fromTX(tx)); + var coins = Coins.fromTX(tx); + var i, entry; + + this.coinDelta += coins.outputs.length; + + for (i = 0; i < coins.outputs.length; i++) { + entry = coins.outputs[i]; + + if (!entry) + continue; + + this.valueDelta += entry.output.value; + } + + this.add(coins); }; /** @@ -90,7 +106,7 @@ CoinView.prototype.has = function has(hash, index) { CoinView.prototype.spend = function spend(hash, index) { var coins = this.coins[hash]; - var entry, undo; + var entry, undo, coin; if (!coins) return; @@ -109,7 +125,12 @@ CoinView.prototype.spend = function spend(hash, index) { undo.version = coins.version; } - return entry.toCoin(coins, index); + coin = entry.toCoin(coins, index); + + this.coinDelta -= 1; + this.valueDelta -= coin.value; + + return coin; }; /** diff --git a/lib/blockchain/undocoins.js b/lib/blockchain/undocoins.js index 1a5c1b76..ea795a89 100644 --- a/lib/blockchain/undocoins.js +++ b/lib/blockchain/undocoins.js @@ -117,7 +117,7 @@ UndoCoins.prototype.apply = function apply(i, view, outpoint) { var undo = this.items[i]; var hash = outpoint.hash; var index = outpoint.index; - var coins; + var coins, coin; assert(undo); @@ -137,7 +137,13 @@ UndoCoins.prototype.apply = function apply(i, view, outpoint) { coins.add(index, undo.toOutput()); - return coins.getCoin(index); + coin = coins.getCoin(index); + assert(coin); + + view.coinDelta += 1; + view.valueDelta += coin.value; + + return coin; }; /**