@@ -1526,28 +1526,36 @@ bool ApplyTxInUndo(const CTxInUndo& undo, CCoinsViewCache& view, const COutPoint
1526
1526
return fClean ;
1527
1527
}
1528
1528
1529
+ enum DisconnectResult
1530
+ {
1531
+ DISCONNECT_OK, // All good.
1532
+ DISCONNECT_UNCLEAN, // Rolled back, but UTXO set was inconsistent with block.
1533
+ DISCONNECT_FAILED // Something else went wrong.
1534
+ };
1535
+
1529
1536
/* * Undo the effects of this block (with given index) on the UTXO set represented by coins.
1530
- * In case pfClean is provided, operation will try to be tolerant about errors, and *pfClean
1531
- * will be true if no problems were found. Otherwise, the return value will be false in case
1532
- * of problems. Note that in any case, coins may be modified. */
1533
- static bool DisconnectBlock (const CBlock& block, CValidationState& state, const CBlockIndex* pindex, CCoinsViewCache& view, bool * pfClean = NULL )
1537
+ * When UNCLEAN or FAILED is returned, view is left in an indeterminate state. */
1538
+ static DisconnectResult DisconnectBlock (const CBlock& block, const CBlockIndex* pindex, CCoinsViewCache& view)
1534
1539
{
1535
1540
assert (pindex->GetBlockHash () == view.GetBestBlock ());
1536
1541
1537
- if (pfClean)
1538
- *pfClean = false ;
1539
-
1540
1542
bool fClean = true ;
1541
1543
1542
1544
CBlockUndo blockUndo;
1543
1545
CDiskBlockPos pos = pindex->GetUndoPos ();
1544
- if (pos.IsNull ())
1545
- return error (" DisconnectBlock(): no undo data available" );
1546
- if (!UndoReadFromDisk (blockUndo, pos, pindex->pprev ->GetBlockHash ()))
1547
- return error (" DisconnectBlock(): failure reading undo data" );
1546
+ if (pos.IsNull ()) {
1547
+ error (" DisconnectBlock(): no undo data available" );
1548
+ return DISCONNECT_FAILED;
1549
+ }
1550
+ if (!UndoReadFromDisk (blockUndo, pos, pindex->pprev ->GetBlockHash ())) {
1551
+ error (" DisconnectBlock(): failure reading undo data" );
1552
+ return DISCONNECT_FAILED;
1553
+ }
1548
1554
1549
- if (blockUndo.vtxundo .size () + 1 != block.vtx .size ())
1550
- return error (" DisconnectBlock(): block and undo data inconsistent" );
1555
+ if (blockUndo.vtxundo .size () + 1 != block.vtx .size ()) {
1556
+ error (" DisconnectBlock(): block and undo data inconsistent" );
1557
+ return DISCONNECT_FAILED;
1558
+ }
1551
1559
1552
1560
// undo transactions in reverse order
1553
1561
for (int i = block.vtx .size () - 1 ; i >= 0 ; i--) {
@@ -1576,8 +1584,10 @@ static bool DisconnectBlock(const CBlock& block, CValidationState& state, const
1576
1584
// restore inputs
1577
1585
if (i > 0 ) { // not coinbases
1578
1586
const CTxUndo &txundo = blockUndo.vtxundo [i-1 ];
1579
- if (txundo.vprevout .size () != tx.vin .size ())
1580
- return error (" DisconnectBlock(): transaction and undo data inconsistent" );
1587
+ if (txundo.vprevout .size () != tx.vin .size ()) {
1588
+ error (" DisconnectBlock(): transaction and undo data inconsistent" );
1589
+ return DISCONNECT_FAILED;
1590
+ }
1581
1591
for (unsigned int j = tx.vin .size (); j-- > 0 ;) {
1582
1592
const COutPoint &out = tx.vin [j].prevout ;
1583
1593
const CTxInUndo &undo = txundo.vprevout [j];
@@ -1590,12 +1600,7 @@ static bool DisconnectBlock(const CBlock& block, CValidationState& state, const
1590
1600
// move best block pointer to prevout block
1591
1601
view.SetBestBlock (pindex->pprev ->GetBlockHash ());
1592
1602
1593
- if (pfClean) {
1594
- *pfClean = fClean ;
1595
- return true ;
1596
- }
1597
-
1598
- return fClean ;
1603
+ return fClean ? DISCONNECT_OK : DISCONNECT_UNCLEAN;
1599
1604
}
1600
1605
1601
1606
void static FlushBlockFile (bool fFinalize = false )
@@ -2131,7 +2136,7 @@ bool static DisconnectTip(CValidationState& state, const CChainParams& chainpara
2131
2136
int64_t nStart = GetTimeMicros ();
2132
2137
{
2133
2138
CCoinsViewCache view (pcoinsTip);
2134
- if (! DisconnectBlock (block, state, pindexDelete, view))
2139
+ if (DisconnectBlock (block, pindexDelete, view) != DISCONNECT_OK )
2135
2140
return error (" DisconnectTip(): DisconnectBlock %s failed" , pindexDelete->GetBlockHash ().ToString ());
2136
2141
bool flushed = view.Flush ();
2137
2142
assert (flushed);
@@ -3656,15 +3661,17 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview,
3656
3661
}
3657
3662
// check level 3: check for inconsistencies during memory-only disconnect of tip blocks
3658
3663
if (nCheckLevel >= 3 && pindex == pindexState && (coins.DynamicMemoryUsage () + pcoinsTip->DynamicMemoryUsage ()) <= nCoinCacheUsage) {
3659
- bool fClean = true ;
3660
- if (! DisconnectBlock (block, state, pindex, coins, & fClean ))
3664
+ DisconnectResult res = DisconnectBlock (block, pindex, coins) ;
3665
+ if (res == DISCONNECT_FAILED) {
3661
3666
return error (" VerifyDB(): *** irrecoverable inconsistency in block data at %d, hash=%s" , pindex->nHeight , pindex->GetBlockHash ().ToString ());
3667
+ }
3662
3668
pindexState = pindex->pprev ;
3663
- if (! fClean ) {
3669
+ if (res == DISCONNECT_UNCLEAN ) {
3664
3670
nGoodTransactions = 0 ;
3665
3671
pindexFailure = pindex;
3666
- } else
3672
+ } else {
3667
3673
nGoodTransactions += block.vtx .size ();
3674
+ }
3668
3675
}
3669
3676
if (ShutdownRequested ())
3670
3677
return true ;
0 commit comments