diff --git a/lib/blockchain/chain.js b/lib/blockchain/chain.js index 9a7c35f9..bfe3d3fd 100644 --- a/lib/blockchain/chain.js +++ b/lib/blockchain/chain.js @@ -651,7 +651,7 @@ Chain.prototype.verifyInputs = co(function* verifyInputs(block, prev, state) { // Skip everything if we're // using checkpoints. if (historical) { - view.addTX(tx); + view.addTX(tx, height); continue; } @@ -689,7 +689,7 @@ Chain.prototype.verifyInputs = co(function* verifyInputs(block, prev, state) { } // Add new coins. - view.addTX(tx); + view.addTX(tx, height); } if (historical) diff --git a/lib/blockchain/chaindb.js b/lib/blockchain/chaindb.js index 377e9308..c4bb8083 100644 --- a/lib/blockchain/chaindb.js +++ b/lib/blockchain/chaindb.js @@ -1301,7 +1301,7 @@ ChainDB.prototype._save = co(function* save(entry, block, view) { if (!view) { // Save block data. - yield this.saveBlock(block); + yield this.saveBlock(entry, block); return; } @@ -1313,7 +1313,7 @@ ChainDB.prototype._save = co(function* save(entry, block, view) { this.cacheHeight.push(entry.height, entry); // Connect block and save data. - yield this.saveBlock(block, view); + yield this.saveBlock(entry, block, view); // Commit new chain state. this.put(layout.R, this.pending.commit(hash)); @@ -1364,7 +1364,7 @@ ChainDB.prototype._reconnect = co(function* reconnect(entry, block, view) { this.saveUpdates(); // Connect inputs. - yield this.connectBlock(block, view); + yield this.connectBlock(entry, block, view); // Update chain state. this.put(layout.R, this.pending.commit(hash)); @@ -1419,7 +1419,7 @@ ChainDB.prototype._disconnect = co(function* disconnect(entry) { throw new Error('Block not found.'); // Disconnect inputs. - yield this.disconnectBlock(block); + yield this.disconnectBlock(entry, block); // Revert chain state to previous tip. this.put(layout.R, this.pending.commit(entry.prevBlock)); @@ -1503,7 +1503,7 @@ ChainDB.prototype.reset = co(function* reset(block) { // Disconnect and remove block data. try { - yield this.removeBlock(tip.hash); + yield this.removeBlock(tip); } catch (e) { this.drop(); throw e; @@ -1593,7 +1593,7 @@ ChainDB.prototype._removeChain = co(function* removeChain(hash) { * @returns {Promise} - Returns {@link Block}. */ -ChainDB.prototype.saveBlock = co(function* saveBlock(block, view) { +ChainDB.prototype.saveBlock = co(function* saveBlock(entry, block, view) { if (this.options.spv) return; @@ -1604,30 +1604,30 @@ ChainDB.prototype.saveBlock = co(function* saveBlock(block, view) { if (!view) return; - yield this.connectBlock(block, view); + yield this.connectBlock(entry, block, view); }); /** * Remove a block (not an entry) to the database. * Disconnect inputs. - * @param {Block|Hash} block - {@link Block} or hash. + * @param {ChainEntry} entry * @returns {Promise} - Returns {@link Block}. */ -ChainDB.prototype.removeBlock = co(function* removeBlock(hash) { +ChainDB.prototype.removeBlock = co(function* removeBlock(entry) { var block; if (this.options.spv) return; - block = yield this.getBlock(hash); + block = yield this.getBlock(entry.hash); if (!block) throw new Error('Block not found.'); this.del(layout.b(block.hash())); - return yield this.disconnectBlock(block); + return yield this.disconnectBlock(entry, block); }); /** @@ -1660,7 +1660,7 @@ ChainDB.prototype.saveView = function saveView(view) { * @returns {Promise} - Returns {@link Block}. */ -ChainDB.prototype.connectBlock = co(function* connectBlock(block, view) { +ChainDB.prototype.connectBlock = co(function* connectBlock(entry, block, view) { var i, j, tx, input, output; if (this.options.spv) @@ -1705,7 +1705,7 @@ ChainDB.prototype.connectBlock = co(function* connectBlock(block, view) { this.put(layout.u(block.hash()), view.undo.commit()); // Prune height-288 if pruning is enabled. - yield this.pruneBlock(block); + yield this.pruneBlock(entry); }); /** @@ -1714,7 +1714,7 @@ ChainDB.prototype.connectBlock = co(function* connectBlock(block, view) { * @returns {Promise} - Returns {@link Block}. */ -ChainDB.prototype.disconnectBlock = co(function* disconnectBlock(block) { +ChainDB.prototype.disconnectBlock = co(function* disconnectBlock(entry, block) { var i, j, view, undo, tx, input, output; if (this.options.spv) @@ -1729,18 +1729,6 @@ ChainDB.prototype.disconnectBlock = co(function* disconnectBlock(block) { for (i = block.txs.length - 1; i >= 0; i--) { tx = block.txs[i]; - for (j = tx.outputs.length - 1; j >= 0; j--) { - output = tx.outputs[j]; - - if (output.script.isUnspendable()) - continue; - - this.pending.spend(output); - } - - // Remove any created coins. - view.removeTX(tx); - if (i > 0) { yield view.ensureInputs(this, tx); @@ -1751,6 +1739,18 @@ ChainDB.prototype.disconnectBlock = co(function* disconnectBlock(block) { } } + // Remove any created coins. + view.removeTX(tx, entry.height); + + for (j = tx.outputs.length - 1; j >= 0; j--) { + output = tx.outputs[j]; + + if (output.script.isUnspendable()) + continue; + + this.pending.spend(output); + } + // Remove from transaction index. this.unindexTX(tx); } @@ -1773,7 +1773,7 @@ ChainDB.prototype.disconnectBlock = co(function* disconnectBlock(block) { * @returns {Promise} */ -ChainDB.prototype.pruneBlock = co(function* pruneBlock(block) { +ChainDB.prototype.pruneBlock = co(function* pruneBlock(entry) { var height, hash; if (this.options.spv) @@ -1782,7 +1782,7 @@ ChainDB.prototype.pruneBlock = co(function* pruneBlock(block) { if (!this.options.prune) return; - height = block.height - this.network.block.keepBlocks; + height = entry.height - this.network.block.keepBlocks; if (height <= this.network.block.pruneAfterHeight) return; diff --git a/lib/blockchain/coins.js b/lib/blockchain/coins.js index f129f6ff..317080ed 100644 --- a/lib/blockchain/coins.js +++ b/lib/blockchain/coins.js @@ -428,12 +428,14 @@ Coins.fromRaw = function fromRaw(data, hash) { * @param {TX} tx */ -Coins.prototype.fromTX = function fromTX(tx) { +Coins.prototype.fromTX = function fromTX(tx, height) { var i, output; + assert(typeof height === 'number'); + this.version = tx.version; this.hash = tx.hash('hex'); - this.height = tx.height; + this.height = height; this.coinbase = tx.isCoinbase(); for (i = 0; i < tx.outputs.length; i++) { @@ -458,8 +460,8 @@ Coins.prototype.fromTX = function fromTX(tx) { * @returns {Coins} */ -Coins.fromTX = function fromTX(tx) { - return new Coins().fromTX(tx); +Coins.fromTX = function fromTX(tx, height) { + return new Coins().fromTX(tx, height); }; /** diff --git a/lib/blockchain/coinview.js b/lib/blockchain/coinview.js index 63829582..01efda57 100644 --- a/lib/blockchain/coinview.js +++ b/lib/blockchain/coinview.js @@ -41,8 +41,8 @@ CoinView.prototype.addCoins = function addCoins(coins) { * @param {TX} tx */ -CoinView.prototype.addTX = function addTX(tx) { - var coins = Coins.fromTX(tx); +CoinView.prototype.addTX = function addTX(tx, height) { + var coins = Coins.fromTX(tx, height); return this.addCoins(coins); }; @@ -51,8 +51,8 @@ CoinView.prototype.addTX = function addTX(tx) { * @param {TX} tx */ -CoinView.prototype.removeTX = function removeTX(tx) { - var coins = Coins.fromTX(tx); +CoinView.prototype.removeTX = function removeTX(tx, height) { + var coins = Coins.fromTX(tx, height); coins.outputs.length = 0; return this.addCoins(coins); };