chain: refactor input spending.

This commit is contained in:
Christopher Jeffrey 2016-12-01 23:37:57 -08:00
parent 967449b0d5
commit b37b99a86e
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
4 changed files with 61 additions and 10 deletions

View File

@ -619,12 +619,12 @@ Chain.prototype.verifyDuplicates = co(function* verifyDuplicates(block, prev, st
*/ */
Chain.prototype.verifyInputs = co(function* verifyInputs(block, prev, state) { Chain.prototype.verifyInputs = co(function* verifyInputs(block, prev, state) {
var ret = new VerifyResult();
var view = new CoinView();
var height = prev.height + 1; var height = prev.height + 1;
var historical = prev.isHistorical(); var historical = prev.isHistorical();
var sigops = 0; var sigops = 0;
var jobs = []; var jobs = [];
var ret = new VerifyResult();
var view = new CoinView();
var i, tx, valid; var i, tx, valid;
if (this.options.spv) if (this.options.spv)
@ -639,15 +639,13 @@ Chain.prototype.verifyInputs = co(function* verifyInputs(block, prev, state) {
// Ensure tx is not double spending an output. // Ensure tx is not double spending an output.
if (i > 0) { if (i > 0) {
if (!(yield view.hasInputs(this.db, tx))) { if (!(yield view.spendInputs(this.db, tx))) {
assert(!historical, 'BUG: Spent inputs in historical data!'); assert(!historical, 'BUG: Spent inputs in historical data!');
throw new VerifyError(block, throw new VerifyError(block,
'invalid', 'invalid',
'bad-txns-inputs-missingorspent', 'bad-txns-inputs-missingorspent',
100); 100);
} }
view.spendCoins(tx);
} }
// Skip everything if we're // Skip everything if we're

View File

@ -1708,7 +1708,7 @@ ChainDB.prototype.connectBlock = co(function* connectBlock(block, view) {
// Write undo coins (if there are any). // Write undo coins (if there are any).
if (!view.undo.isEmpty()) if (!view.undo.isEmpty())
this.put(layout.u(block.hash()), view.undo.toRaw()); this.put(layout.u(block.hash()), view.undo.commit());
// Prune height-288 if pruning is enabled. // Prune height-288 if pruning is enabled.
yield this.pruneBlock(block); yield this.pruneBlock(block);

View File

@ -105,12 +105,23 @@ CoinView.prototype.has = function has(hash, index) {
CoinView.prototype.spend = function spend(hash, index) { CoinView.prototype.spend = function spend(hash, index) {
var coins = this.unspent[hash]; var coins = this.unspent[hash];
var entry, undo;
if (!coins) if (!coins)
return null; return null;
entry = coins.spend(index); return this.spendFrom(coins, index);
};
/**
* Remove a coin and return it.
* @param {Coins} coins
* @param {Number} index
* @returns {Coin}
*/
CoinView.prototype.spendFrom = function spendFrom(coins, index) {
var entry = coins.spend(index);
var undo;
if (!entry) if (!entry)
return null; return null;
@ -191,7 +202,7 @@ CoinView.prototype.ensureInputs = co(function* ensureInputs(db, tx) {
/** /**
* Spend coins for transaction. * Spend coins for transaction.
* @param {TX} tx * @param {TX} tx
* @throws on missing coin * @returns {Boolean}
*/ */
CoinView.prototype.spendCoins = function spendCoins(tx) { CoinView.prototype.spendCoins = function spendCoins(tx) {
@ -200,11 +211,42 @@ CoinView.prototype.spendCoins = function spendCoins(tx) {
for (i = 0; i < tx.inputs.length; i++) { for (i = 0; i < tx.inputs.length; i++) {
input = tx.inputs[i]; input = tx.inputs[i];
prevout = input.prevout; prevout = input.prevout;
input.coin = this.spend(prevout.hash, prevout.index); input.coin = this.spend(prevout.hash, prevout.index);
assert(input.coin, 'Not all coins available.');
if (!input.coin)
return false;
} }
return true;
}; };
/**
* Spend coins for transaction.
* @param {TX} tx
* @returns {Boolean}
*/
CoinView.prototype.spendInputs = co(function* spendInputs(db, tx) {
var i, input, prevout, coins;
for (i = 0; i < tx.inputs.length; i++) {
input = tx.inputs[i];
prevout = input.prevout;
coins = yield this.getCoins(db, prevout.hash);
if (!coins)
return false;
input.coin = this.spendFrom(coins, prevout.index);
if (!input.coin)
return false;
}
return true;
});
/** /**
* Convert collection to an array. * Convert collection to an array.
* @returns {Coins[]} * @returns {Coins[]}

View File

@ -99,6 +99,17 @@ UndoCoins.prototype.isEmpty = function isEmpty() {
return this.items.length === 0; return this.items.length === 0;
}; };
/**
* Render the undo coins.
* @returns {Buffer}
*/
UndoCoins.prototype.commit = function commit() {
var raw = this.toRaw();
this.items.length = 0;
return raw;
};
/** /**
* Retrieve the last undo coin. * Retrieve the last undo coin.
* @returns {UndoCoin} * @returns {UndoCoin}