From 7d991b55dbf0b0f6e21c0680ee3ebd09df09012f Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Tue, 25 Apr 2017 11:29:19 -0700 Subject: [PATCH] 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. --- src/undo.h | 3 +-- src/validation.cpp | 17 ++++++++++------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/undo.h b/src/undo.h index d21b82e2e..37a1c89f4 100644 --- a/src/undo.h +++ b/src/undo.h @@ -12,8 +12,7 @@ /** Undo information for a CTxIn * - * Contains the prevout's CTxOut being spent, and if this was the - * last output of the affected transaction, its metadata as well + * Contains the prevout's CTxOut being spent, and its metadata as well * (coinbase or not, height). Earlier versions also stored the transaction * version. */ diff --git a/src/validation.cpp b/src/validation.cpp index be0c9b564..fccef1719 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -1082,11 +1082,9 @@ void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, CTxUndo &txund // mark an outpoint spent, and construct undo information txundo.vprevout.push_back(CTxInUndo(coins->vout[nPos])); coins->Spend(nPos); - if (coins->vout.size() == 0) { - CTxInUndo& undo = txundo.vprevout.back(); - undo.nHeight = coins->nHeight; - undo.fCoinBase = coins->fCoinBase; - } + CTxInUndo& undo = txundo.vprevout.back(); + undo.nHeight = coins->nHeight; + undo.fCoinBase = coins->fCoinBase; } } // add outputs @@ -1266,11 +1264,16 @@ int ApplyTxInUndo(const CTxInUndo& undo, CCoinsViewCache& view, const COutPoint& CCoinsModifier coins = view.ModifyCoins(out.hash); if (undo.nHeight != 0) { - // undo data contains height: this is the last output of the prevout tx being spent - if (!coins->IsPruned()) fClean = false; // overwriting existing transaction + if (!coins->IsPruned()) { + 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->nHeight = undo.nHeight; } 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->IsAvailable(out.n)) fClean = false; // overwriting existing output