Changeset View
Changeset View
Standalone View
Standalone View
src/validation.cpp
Show First 20 Lines • Show All 1,494 Lines • ▼ Show 20 Lines | |||||
} // anon namespace | } // anon namespace | ||||
/** Restore the UTXO in a Coin at a given COutPoint. */ | /** Restore the UTXO in a Coin at a given COutPoint. */ | ||||
DisconnectResult UndoCoinSpend(const Coin &undo, CCoinsViewCache &view, | DisconnectResult UndoCoinSpend(const Coin &undo, CCoinsViewCache &view, | ||||
const COutPoint &out) { | const COutPoint &out) { | ||||
bool fClean = true; | bool fClean = true; | ||||
CCoinsModifier coins = view.ModifyCoins(out.hash); | if (view.HaveCoin(out)) { | ||||
if (undo.GetHeight() != 0) { | // Overwriting transaction output. | ||||
if (!coins->IsPruned()) { | |||||
if (coins->fCoinBase != undo.IsCoinBase() || | |||||
uint32_t(coins->nHeight) != undo.GetHeight()) { | |||||
// Metadata mismatch. | |||||
fClean = false; | fClean = false; | ||||
} | } | ||||
} | |||||
// Restore height/coinbase tx metadata from undo data. | if (undo.GetHeight() == 0) { | ||||
coins->fCoinBase = undo.IsCoinBase(); | // Missing undo metadata (height and coinbase). Older versions included | ||||
coins->nHeight = undo.GetHeight(); | // this information only in undo records for the last spend of a | ||||
} else { | // transactions' outputs. This implies that it must be present for some | ||||
// Undo data does not contain height/coinbase. This should never happen | // other output of the same tx. | ||||
// for newly created undo entries. Previously, this data was only saved | const Coin &alternate = AccessByTxid(view, out.hash); | ||||
// for the last spend of a transaction's outputs, so check IsPruned(). | if (alternate.IsSpent()) { | ||||
if (coins->IsPruned()) { | // Adding output for transaction without known metadata | ||||
// Adding output to missing transaction. | return DISCONNECT_FAILED; | ||||
fClean = false; | |||||
} | |||||
} | |||||
if (coins->IsAvailable(out.n)) { | |||||
// Overwriting existing output. | |||||
fClean = false; | |||||
} | } | ||||
if (coins->vout.size() < out.n + 1) { | // This is somewhat ugly, but hopefully utility is limited. This is only | ||||
coins->vout.resize(out.n + 1); | // useful when working from legacy on disck data. In any case, putting | ||||
// the correct information in there doesn't hurt. | |||||
const_cast<Coin &>(undo) = Coin(undo.GetTxOut(), alternate.GetHeight(), | |||||
alternate.IsCoinBase()); | |||||
} | } | ||||
coins->vout[out.n] = undo.GetTxOut(); | view.AddCoin(out, undo, undo.IsCoinBase()); | ||||
return fClean ? DISCONNECT_OK : DISCONNECT_UNCLEAN; | return fClean ? DISCONNECT_OK : DISCONNECT_UNCLEAN; | ||||
} | } | ||||
/** | /** | ||||
* Undo the effects of this block (with given index) on the UTXO set represented | * Undo the effects of this block (with given index) on the UTXO set represented | ||||
* by coins. When UNCLEAN or FAILED is returned, view is left in an | * by coins. When UNCLEAN or FAILED is returned, view is left in an | ||||
* indeterminate state. | * indeterminate state. | ||||
*/ | */ | ||||
Show All 30 Lines | DisconnectResult ApplyBlockUndo(const CBlockUndo &blockUndo, | ||||
// Undo transactions in reverse order. | // Undo transactions in reverse order. | ||||
size_t i = block.vtx.size(); | size_t i = block.vtx.size(); | ||||
while (i-- > 0) { | while (i-- > 0) { | ||||
const CTransaction &tx = *(block.vtx[i]); | const CTransaction &tx = *(block.vtx[i]); | ||||
uint256 txid = tx.GetId(); | uint256 txid = tx.GetId(); | ||||
// Check that all outputs are available and match the outputs in the | // Check that all outputs are available and match the outputs in the | ||||
// block itself exactly. | // block itself exactly. | ||||
{ | for (size_t o = 0; o < tx.vout.size(); o++) { | ||||
CCoinsModifier outs = view.ModifyCoins(txid); | if (tx.vout[o].scriptPubKey.IsUnspendable()) { | ||||
outs->ClearUnspendable(); | continue; | ||||
} | |||||
CCoins outsBlock(tx, pindex->nHeight); | COutPoint out(txid, o); | ||||
if (*outs != outsBlock) { | Coin coin; | ||||
// Transaction mismatch. | bool is_spent = view.SpendCoin(out, &coin); | ||||
if (!is_spent || tx.vout[o] != coin.GetTxOut()) { | |||||
// transaction output mismatch | |||||
fClean = false; | fClean = false; | ||||
} | } | ||||
// Remove outputs. | |||||
outs->Clear(); | |||||
} | } | ||||
// Restore inputs. | // Restore inputs. | ||||
if (i < 1) { | if (i < 1) { | ||||
// Skip the coinbase. | // Skip the coinbase. | ||||
continue; | continue; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 3,348 Lines • Show Last 20 Lines |