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