@@ -1523,28 +1523,36 @@ bool ApplyTxInUndo(const CTxInUndo& undo, CCoinsViewCache& view, const COutPoint
1523
1523
return fClean;
1524
1524
}
1525
1525
1526
+ enum DisconnectResult
1527
+ {
1528
+ DISCONNECT_OK, // All good.
1529
+ DISCONNECT_UNCLEAN, // Rolled back, but UTXO set was inconsistent with block.
1530
+ DISCONNECT_FAILED // Something else went wrong.
1531
+ };
1532
+
1526
1533
/** Undo the effects of this block (with given index) on the UTXO set represented by coins.
1527
- * In case pfClean is provided, operation will try to be tolerant about errors, and *pfClean
1528
- * will be true if no problems were found. Otherwise, the return value will be false in case
1529
- * of problems. Note that in any case, coins may be modified. */
1530
- static bool DisconnectBlock(const CBlock& block, CValidationState& state, const CBlockIndex* pindex, CCoinsViewCache& view, bool* pfClean = NULL)
1534
+ * When UNCLEAN or FAILED is returned, view is left in an indeterminate state. */
1535
+ static DisconnectResult DisconnectBlock(const CBlock& block, const CBlockIndex* pindex, CCoinsViewCache& view)
1531
1536
{
1532
1537
assert(pindex->GetBlockHash() == view.GetBestBlock());
1533
1538
1534
- if (pfClean)
1535
- *pfClean = false;
1536
-
1537
1539
bool fClean = true;
1538
1540
1539
1541
CBlockUndo blockUndo;
1540
1542
CDiskBlockPos pos = pindex->GetUndoPos();
1541
- if (pos.IsNull())
1542
- return error("DisconnectBlock(): no undo data available");
1543
- if (!UndoReadFromDisk(blockUndo, pos, pindex->pprev->GetBlockHash()))
1544
- return error("DisconnectBlock(): failure reading undo data");
1543
+ if (pos.IsNull()) {
1544
+ error("DisconnectBlock(): no undo data available");
1545
+ return DISCONNECT_FAILED;
1546
+ }
1547
+ if (!UndoReadFromDisk(blockUndo, pos, pindex->pprev->GetBlockHash())) {
1548
+ error("DisconnectBlock(): failure reading undo data");
1549
+ return DISCONNECT_FAILED;
1550
+ }
1545
1551
1546
- if (blockUndo.vtxundo.size() + 1 != block.vtx.size())
1547
- return error("DisconnectBlock(): block and undo data inconsistent");
1552
+ if (blockUndo.vtxundo.size() + 1 != block.vtx.size()) {
1553
+ error("DisconnectBlock(): block and undo data inconsistent");
1554
+ return DISCONNECT_FAILED;
1555
+ }
1548
1556
1549
1557
// undo transactions in reverse order
1550
1558
for (int i = block.vtx.size() - 1; i >= 0; i--) {
@@ -1573,8 +1581,10 @@ static bool DisconnectBlock(const CBlock& block, CValidationState& state, const
1573
1581
// restore inputs
1574
1582
if (i > 0) { // not coinbases
1575
1583
const CTxUndo &txundo = blockUndo.vtxundo[i-1];
1576
- if (txundo.vprevout.size() != tx.vin.size())
1577
- return error("DisconnectBlock(): transaction and undo data inconsistent");
1584
+ if (txundo.vprevout.size() != tx.vin.size()) {
1585
+ error("DisconnectBlock(): transaction and undo data inconsistent");
1586
+ return DISCONNECT_FAILED;
1587
+ }
1578
1588
for (unsigned int j = tx.vin.size(); j-- > 0;) {
1579
1589
const COutPoint &out = tx.vin[j].prevout;
1580
1590
const CTxInUndo &undo = txundo.vprevout[j];
@@ -1587,12 +1597,7 @@ static bool DisconnectBlock(const CBlock& block, CValidationState& state, const
1587
1597
// move best block pointer to prevout block
1588
1598
view.SetBestBlock(pindex->pprev->GetBlockHash());
1589
1599
1590
- if (pfClean) {
1591
- *pfClean = fClean;
1592
- return true;
1593
- }
1594
-
1595
- return fClean;
1600
+ return fClean ? DISCONNECT_OK : DISCONNECT_UNCLEAN;
1596
1601
}
1597
1602
1598
1603
void static FlushBlockFile(bool fFinalize = false)
@@ -2128,7 +2133,7 @@ bool static DisconnectTip(CValidationState& state, const CChainParams& chainpara
2128
2133
int64_t nStart = GetTimeMicros();
2129
2134
{
2130
2135
CCoinsViewCache view(pcoinsTip);
2131
- if (! DisconnectBlock(block, state, pindexDelete, view))
2136
+ if (DisconnectBlock(block, pindexDelete, view) != DISCONNECT_OK )
2132
2137
return error("DisconnectTip(): DisconnectBlock %s failed", pindexDelete->GetBlockHash().ToString());
2133
2138
bool flushed = view.Flush();
2134
2139
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