|
|
@ -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) |
|
|
|