Store/allow tx metadata in all undo records

Previously, transaction metadata (height, coinbase or not, and before
the previous commit also nVersion) was only stored for undo records
that correspond to the last output of a transaction being spent.

This only saves 2 bytes per undo record. Change this to storing this
information for every undo record, and stop complaining for having it
in non-last output spends. This means that undo dat written with
this patch won't be readable by older versions anymore.
This commit is contained in:
Pieter Wuille 2017-04-25 11:29:19 -07:00
parent c3aa0c1194
commit 7d991b55db
2 changed files with 11 additions and 9 deletions

View file

@ -12,8 +12,7 @@
/** Undo information for a CTxIn /** Undo information for a CTxIn
* *
* Contains the prevout's CTxOut being spent, and if this was the * Contains the prevout's CTxOut being spent, and its metadata as well
* last output of the affected transaction, its metadata as well
* (coinbase or not, height). Earlier versions also stored the transaction * (coinbase or not, height). Earlier versions also stored the transaction
* version. * version.
*/ */

View file

@ -1082,13 +1082,11 @@ void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, CTxUndo &txund
// mark an outpoint spent, and construct undo information // mark an outpoint spent, and construct undo information
txundo.vprevout.push_back(CTxInUndo(coins->vout[nPos])); txundo.vprevout.push_back(CTxInUndo(coins->vout[nPos]));
coins->Spend(nPos); coins->Spend(nPos);
if (coins->vout.size() == 0) {
CTxInUndo& undo = txundo.vprevout.back(); CTxInUndo& undo = txundo.vprevout.back();
undo.nHeight = coins->nHeight; undo.nHeight = coins->nHeight;
undo.fCoinBase = coins->fCoinBase; undo.fCoinBase = coins->fCoinBase;
} }
} }
}
// add outputs // add outputs
inputs.ModifyNewCoins(tx.GetHash(), tx.IsCoinBase())->FromTx(tx, nHeight); inputs.ModifyNewCoins(tx.GetHash(), tx.IsCoinBase())->FromTx(tx, nHeight);
} }
@ -1266,11 +1264,16 @@ int ApplyTxInUndo(const CTxInUndo& undo, CCoinsViewCache& view, const COutPoint&
CCoinsModifier coins = view.ModifyCoins(out.hash); CCoinsModifier coins = view.ModifyCoins(out.hash);
if (undo.nHeight != 0) { if (undo.nHeight != 0) {
// undo data contains height: this is the last output of the prevout tx being spent if (!coins->IsPruned()) {
if (!coins->IsPruned()) fClean = false; // overwriting existing transaction if (coins->fCoinBase != undo.fCoinBase || (uint32_t)coins->nHeight != undo.nHeight) fClean = false; // metadata mismatch
}
// restore height/coinbase tx metadata from undo data
coins->fCoinBase = undo.fCoinBase; coins->fCoinBase = undo.fCoinBase;
coins->nHeight = undo.nHeight; coins->nHeight = undo.nHeight;
} else { } else {
// Undo data does not contain height/coinbase. This should never happen
// for newly created undo entries. Previously, this data was only saved
// for the last spend of a transaction's outputs, so check IsPruned().
if (coins->IsPruned()) fClean = false; // adding output to missing transaction if (coins->IsPruned()) fClean = false; // adding output to missing transaction
} }
if (coins->IsAvailable(out.n)) fClean = false; // overwriting existing output if (coins->IsAvailable(out.n)) fClean = false; // overwriting existing output