Split logic to undo txin's off DisconnectBlock.
Instead, create a separate function that applies the undo operation of a CTxInUndo object onto a CCoinsViewCache. This method is used from DisconnectBlock.
This commit is contained in:
parent
fcf646c9b0
commit
eb1c2cd37f
1 changed files with 38 additions and 24 deletions
62
src/main.cpp
62
src/main.cpp
|
@ -1588,6 +1588,39 @@ bool UndoReadFromDisk(CBlockUndo& blockundo, const CDiskBlockPos& pos, const uin
|
||||||
|
|
||||||
} // anon namespace
|
} // anon namespace
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply the undo operation of a CTxInUndo to the given chain state.
|
||||||
|
* @param undo The undo object.
|
||||||
|
* @param view The coins view to which to apply the changes.
|
||||||
|
* @param out The out point that corresponds to the tx input.
|
||||||
|
* @return True on success.
|
||||||
|
*/
|
||||||
|
static bool ApplyTxInUndo(const CTxInUndo& undo, CCoinsViewCache& view, const COutPoint& out)
|
||||||
|
{
|
||||||
|
bool fClean = true;
|
||||||
|
|
||||||
|
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 = fClean && error("%s: undo data overwriting existing transaction", __func__);
|
||||||
|
coins->Clear();
|
||||||
|
coins->fCoinBase = undo.fCoinBase;
|
||||||
|
coins->nHeight = undo.nHeight;
|
||||||
|
coins->nVersion = undo.nVersion;
|
||||||
|
} else {
|
||||||
|
if (coins->IsPruned())
|
||||||
|
fClean = fClean && error("%s: undo data adding output to missing transaction", __func__);
|
||||||
|
}
|
||||||
|
if (coins->IsAvailable(out.n))
|
||||||
|
fClean = fClean && error("%s: undo data overwriting existing output", __func__);
|
||||||
|
if (coins->vout.size() < out.n+1)
|
||||||
|
coins->vout.resize(out.n+1);
|
||||||
|
coins->vout[out.n] = undo.txout;
|
||||||
|
|
||||||
|
return fClean;
|
||||||
|
}
|
||||||
|
|
||||||
bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, bool* pfClean)
|
bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, bool* pfClean)
|
||||||
{
|
{
|
||||||
assert(pindex->GetBlockHash() == view.GetBestBlock());
|
assert(pindex->GetBlockHash() == view.GetBestBlock());
|
||||||
|
@ -1613,11 +1646,8 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex
|
||||||
uint256 hash = tx.GetHash();
|
uint256 hash = tx.GetHash();
|
||||||
|
|
||||||
// Check that all outputs are available and match the outputs in the block itself
|
// Check that all outputs are available and match the outputs in the block itself
|
||||||
// exactly. Note that transactions with only provably unspendable outputs won't
|
// exactly.
|
||||||
// have outputs available even in the block itself, so we handle that case
|
|
||||||
// specially with outsEmpty.
|
|
||||||
{
|
{
|
||||||
CCoins outsEmpty;
|
|
||||||
CCoinsModifier outs = view.ModifyCoins(hash);
|
CCoinsModifier outs = view.ModifyCoins(hash);
|
||||||
outs->ClearUnspendable();
|
outs->ClearUnspendable();
|
||||||
|
|
||||||
|
@ -1642,24 +1672,8 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex
|
||||||
for (unsigned int j = tx.vin.size(); j-- > 0;) {
|
for (unsigned int j = tx.vin.size(); j-- > 0;) {
|
||||||
const COutPoint &out = tx.vin[j].prevout;
|
const COutPoint &out = tx.vin[j].prevout;
|
||||||
const CTxInUndo &undo = txundo.vprevout[j];
|
const CTxInUndo &undo = txundo.vprevout[j];
|
||||||
CCoinsModifier coins = view.ModifyCoins(out.hash);
|
if (!ApplyTxInUndo(undo, view, out))
|
||||||
if (undo.nHeight != 0) {
|
fClean = false;
|
||||||
// undo data contains height: this is the last output of the prevout tx being spent
|
|
||||||
if (!coins->IsPruned())
|
|
||||||
fClean = fClean && error("DisconnectBlock(): undo data overwriting existing transaction");
|
|
||||||
coins->Clear();
|
|
||||||
coins->fCoinBase = undo.fCoinBase;
|
|
||||||
coins->nHeight = undo.nHeight;
|
|
||||||
coins->nVersion = undo.nVersion;
|
|
||||||
} else {
|
|
||||||
if (coins->IsPruned())
|
|
||||||
fClean = fClean && error("DisconnectBlock(): undo data adding output to missing transaction");
|
|
||||||
}
|
|
||||||
if (coins->IsAvailable(out.n))
|
|
||||||
fClean = fClean && error("DisconnectBlock(): undo data overwriting existing output");
|
|
||||||
if (coins->vout.size() < out.n+1)
|
|
||||||
coins->vout.resize(out.n+1);
|
|
||||||
coins->vout[out.n] = undo.txout;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1670,9 +1684,9 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex
|
||||||
if (pfClean) {
|
if (pfClean) {
|
||||||
*pfClean = fClean;
|
*pfClean = fClean;
|
||||||
return true;
|
return true;
|
||||||
} else {
|
|
||||||
return fClean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return fClean;
|
||||||
}
|
}
|
||||||
|
|
||||||
void static FlushBlockFile(bool fFinalize = false)
|
void static FlushBlockFile(bool fFinalize = false)
|
||||||
|
|
Loading…
Reference in a new issue