Skip to content

Commit 38a8b36

Browse files
committed
Add rewind logic to deal with post-fork software updates
1 parent 1a8a9fe commit 38a8b36

File tree

4 files changed

+67
-4
lines changed

4 files changed

+67
-4
lines changed

src/chain.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@ enum BlockStatus {
9292
BLOCK_FAILED_VALID = 32, //! stage after last reached validness failed
9393
BLOCK_FAILED_CHILD = 64, //! descends from failed block
9494
BLOCK_FAILED_MASK = BLOCK_FAILED_VALID | BLOCK_FAILED_CHILD,
95+
96+
BLOCK_OPT_WITNESS = 128, //! block data in blk*.data was received with a witness-enforcing client
9597
};
9698

9799
/** The block chain is a tree shaped structure starting with the

src/init.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1369,6 +1369,14 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
13691369
break;
13701370
}
13711371

1372+
if (!fReindex) {
1373+
uiInterface.InitMessage(_("Rewinding blocks..."));
1374+
if (!RewindBlockIndex(chainparams.GetConsensus())) {
1375+
strLoadError = _("Unable to rewind the database to a pre-fork state. You will need to redownload the blockchain");
1376+
break;
1377+
}
1378+
}
1379+
13721380
uiInterface.InitMessage(_("Verifying blocks..."));
13731381
if (fHavePruned && GetArg("-checkblocks", DEFAULT_CHECKBLOCKS) > MIN_BLOCKS_TO_KEEP) {
13741382
LogPrintf("Prune: pruned datadir may not have more than %d blocks; -checkblocks=%d may fail\n",

src/main.cpp

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2367,7 +2367,7 @@ void static UpdateTip(CBlockIndex *pindexNew) {
23672367
}
23682368

23692369
/** Disconnect chainActive's tip. You probably want to call mempool.removeForReorg and manually re-limit mempool size after this, with cs_main held. */
2370-
bool static DisconnectTip(CValidationState& state, const Consensus::Params& consensusParams)
2370+
bool static DisconnectTip(CValidationState& state, const Consensus::Params& consensusParams, bool fBare = false)
23712371
{
23722372
CBlockIndex *pindexDelete = chainActive.Tip();
23732373
assert(pindexDelete);
@@ -2387,6 +2387,9 @@ bool static DisconnectTip(CValidationState& state, const Consensus::Params& cons
23872387
// Write the chain state to disk, if necessary.
23882388
if (!FlushStateToDisk(state, FLUSH_STATE_IF_NEEDED))
23892389
return false;
2390+
if (fBare)
2391+
return true;
2392+
23902393
// Resurrect mempool transactions from the disconnected block.
23912394
std::vector<uint256> vHashUpdate;
23922395
BOOST_FOREACH(const CTransaction &tx, block.vtx) {
@@ -2823,7 +2826,7 @@ bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBl
28232826
pindexNew->nFile = pos.nFile;
28242827
pindexNew->nDataPos = pos.nPos;
28252828
pindexNew->nUndoPos = 0;
2826-
pindexNew->nStatus |= BLOCK_HAVE_DATA;
2829+
pindexNew->nStatus |= BLOCK_HAVE_DATA | BLOCK_OPT_WITNESS;
28272830
pindexNew->RaiseValidity(BLOCK_VALID_TRANSACTIONS);
28282831
setDirtyBlockIndex.insert(pindexNew);
28292832

@@ -3048,7 +3051,7 @@ static bool CheckIndexAgainstCheckpoint(const CBlockIndex* pindexPrev, CValidati
30483051
return true;
30493052
}
30503053

3051-
bool IsWitnessEnabled(const CBlock& block, const CBlockIndex* pindexPrev, const Consensus::Params& params)
3054+
bool IsWitnessEnabled(const CBlockHeader& block, const CBlockIndex* pindexPrev, const Consensus::Params& params)
30523055
{
30533056
return (block.nVersion >= 5 && pindexPrev->nHeight + 1 >= params.SegWitHeight && IsSuperMajority(5, pindexPrev, params.nMajorityEnforceBlockUpgrade, params));
30543057
}
@@ -3779,6 +3782,54 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview,
37793782
return true;
37803783
}
37813784

3785+
bool RewindBlockIndex(const Consensus::Params& params)
3786+
{
3787+
LOCK(cs_main);
3788+
3789+
int nHeight = 1;
3790+
while (nHeight <= chainActive.Height()) {
3791+
CBlockHeader header = chainActive[nHeight]->GetBlockHeader();
3792+
if (IsWitnessEnabled(header, chainActive[nHeight - 1], params) && !(chainActive[nHeight]->nStatus & BLOCK_OPT_WITNESS)) {
3793+
break;
3794+
}
3795+
nHeight++;
3796+
}
3797+
3798+
// nHeight is now the height of the first insufficiently-validated block, or tipheight + 1
3799+
CValidationState state;
3800+
CBlockIndex* pindex = chainActive.Tip();
3801+
while (chainActive.Height() >= nHeight) {
3802+
if (!DisconnectTip(state, Params().GetConsensus(), true)) {
3803+
return error("RewindBlockIndex: unable to disconnect block at height %i", pindex->nHeight);
3804+
}
3805+
// Occasionally flush state to disk.
3806+
if (!FlushStateToDisk(state, FLUSH_STATE_PERIODIC))
3807+
return false;
3808+
}
3809+
3810+
// Reduce validity flag and have-data flags.
3811+
// We do this after actual disconnecting, otherwise we'll end up writing the lack of data
3812+
// to disk before writing the chainstate, resulting in a failure to continue if interrupted.
3813+
while (pindex->nHeight >= nHeight) {
3814+
// Reduce validity
3815+
pindex->nStatus = std::min<unsigned int>(pindex->nStatus & BLOCK_VALID_MASK, BLOCK_VALID_TREE) | (pindex->nStatus & ~BLOCK_VALID_MASK);
3816+
// Remove have-data flags.
3817+
pindex->nStatus &= ~(BLOCK_HAVE_DATA | BLOCK_HAVE_UNDO);
3818+
// Remove storage location.
3819+
pindex->nFile = 0;
3820+
pindex->nDataPos = 0;
3821+
pindex->nUndoPos = 0;
3822+
// Make sure it gets written.
3823+
setDirtyBlockIndex.insert(pindex);
3824+
}
3825+
3826+
if (!FlushStateToDisk(state, FLUSH_STATE_ALWAYS)) {
3827+
return false;
3828+
}
3829+
3830+
return true;
3831+
}
3832+
37823833
void UnloadBlockIndex()
37833834
{
37843835
LOCK(cs_main);

src/main.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -418,7 +418,9 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn
418418
bool TestBlockValidity(CValidationState& state, const CChainParams& chainparams, const CBlock& block, CBlockIndex* pindexPrev, bool fCheckPOW = true, bool fCheckMerkleRoot = true);
419419

420420
/** Check whether witness commitments are required for block. */
421-
bool IsWitnessEnabled(const CBlock& block, const CBlockIndex* pindexPrev, const Consensus::Params& params);
421+
bool IsWitnessEnabled(const CBlockHeader& block, const CBlockIndex* pindexPrev, const Consensus::Params& params);
422+
423+
bool RewindBlockIndex(const Consensus::Params& params);
422424

423425
void UpdateUncommitedBlockStructures(CBlock& block, const CBlockIndex* pindexPrev, const Consensus::Params& consensusParams);
424426

0 commit comments

Comments
 (0)