Skip to content

Commit

Permalink
Add rewind logic to deal with post-fork software updates
Browse files Browse the repository at this point in the history
  • Loading branch information
sipa committed Mar 26, 2016
1 parent 1a8a9fe commit 38a8b36
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 4 deletions.
2 changes: 2 additions & 0 deletions src/chain.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ enum BlockStatus {
BLOCK_FAILED_VALID = 32, //! stage after last reached validness failed
BLOCK_FAILED_CHILD = 64, //! descends from failed block
BLOCK_FAILED_MASK = BLOCK_FAILED_VALID | BLOCK_FAILED_CHILD,

BLOCK_OPT_WITNESS = 128, //! block data in blk*.data was received with a witness-enforcing client
};

/** The block chain is a tree shaped structure starting with the
Expand Down
8 changes: 8 additions & 0 deletions src/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1369,6 +1369,14 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
break;
}

if (!fReindex) {
uiInterface.InitMessage(_("Rewinding blocks..."));
if (!RewindBlockIndex(chainparams.GetConsensus())) {
strLoadError = _("Unable to rewind the database to a pre-fork state. You will need to redownload the blockchain");
break;
}
}

uiInterface.InitMessage(_("Verifying blocks..."));
if (fHavePruned && GetArg("-checkblocks", DEFAULT_CHECKBLOCKS) > MIN_BLOCKS_TO_KEEP) {
LogPrintf("Prune: pruned datadir may not have more than %d blocks; -checkblocks=%d may fail\n",
Expand Down
57 changes: 54 additions & 3 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2367,7 +2367,7 @@ void static UpdateTip(CBlockIndex *pindexNew) {
}

/** Disconnect chainActive's tip. You probably want to call mempool.removeForReorg and manually re-limit mempool size after this, with cs_main held. */
bool static DisconnectTip(CValidationState& state, const Consensus::Params& consensusParams)
bool static DisconnectTip(CValidationState& state, const Consensus::Params& consensusParams, bool fBare = false)
{
CBlockIndex *pindexDelete = chainActive.Tip();
assert(pindexDelete);
Expand All @@ -2387,6 +2387,9 @@ bool static DisconnectTip(CValidationState& state, const Consensus::Params& cons
// Write the chain state to disk, if necessary.
if (!FlushStateToDisk(state, FLUSH_STATE_IF_NEEDED))
return false;
if (fBare)
return true;

// Resurrect mempool transactions from the disconnected block.
std::vector<uint256> vHashUpdate;
BOOST_FOREACH(const CTransaction &tx, block.vtx) {
Expand Down Expand Up @@ -2823,7 +2826,7 @@ bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBl
pindexNew->nFile = pos.nFile;
pindexNew->nDataPos = pos.nPos;
pindexNew->nUndoPos = 0;
pindexNew->nStatus |= BLOCK_HAVE_DATA;
pindexNew->nStatus |= BLOCK_HAVE_DATA | BLOCK_OPT_WITNESS;
pindexNew->RaiseValidity(BLOCK_VALID_TRANSACTIONS);
setDirtyBlockIndex.insert(pindexNew);

Expand Down Expand Up @@ -3048,7 +3051,7 @@ static bool CheckIndexAgainstCheckpoint(const CBlockIndex* pindexPrev, CValidati
return true;
}

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

bool RewindBlockIndex(const Consensus::Params& params)
{
LOCK(cs_main);

int nHeight = 1;
while (nHeight <= chainActive.Height()) {
CBlockHeader header = chainActive[nHeight]->GetBlockHeader();
if (IsWitnessEnabled(header, chainActive[nHeight - 1], params) && !(chainActive[nHeight]->nStatus & BLOCK_OPT_WITNESS)) {
break;
}
nHeight++;
}

// nHeight is now the height of the first insufficiently-validated block, or tipheight + 1
CValidationState state;
CBlockIndex* pindex = chainActive.Tip();
while (chainActive.Height() >= nHeight) {
if (!DisconnectTip(state, Params().GetConsensus(), true)) {
return error("RewindBlockIndex: unable to disconnect block at height %i", pindex->nHeight);
}
// Occasionally flush state to disk.
if (!FlushStateToDisk(state, FLUSH_STATE_PERIODIC))
return false;
}

// Reduce validity flag and have-data flags.
// We do this after actual disconnecting, otherwise we'll end up writing the lack of data
// to disk before writing the chainstate, resulting in a failure to continue if interrupted.
while (pindex->nHeight >= nHeight) {
// Reduce validity
pindex->nStatus = std::min<unsigned int>(pindex->nStatus & BLOCK_VALID_MASK, BLOCK_VALID_TREE) | (pindex->nStatus & ~BLOCK_VALID_MASK);
// Remove have-data flags.
pindex->nStatus &= ~(BLOCK_HAVE_DATA | BLOCK_HAVE_UNDO);
// Remove storage location.
pindex->nFile = 0;
pindex->nDataPos = 0;
pindex->nUndoPos = 0;
// Make sure it gets written.
setDirtyBlockIndex.insert(pindex);
}

if (!FlushStateToDisk(state, FLUSH_STATE_ALWAYS)) {
return false;
}

return true;
}

void UnloadBlockIndex()
{
LOCK(cs_main);
Expand Down
4 changes: 3 additions & 1 deletion src/main.h
Original file line number Diff line number Diff line change
Expand Up @@ -418,7 +418,9 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn
bool TestBlockValidity(CValidationState& state, const CChainParams& chainparams, const CBlock& block, CBlockIndex* pindexPrev, bool fCheckPOW = true, bool fCheckMerkleRoot = true);

/** Check whether witness commitments are required for block. */
bool IsWitnessEnabled(const CBlock& block, const CBlockIndex* pindexPrev, const Consensus::Params& params);
bool IsWitnessEnabled(const CBlockHeader& block, const CBlockIndex* pindexPrev, const Consensus::Params& params);

bool RewindBlockIndex(const Consensus::Params& params);

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

Expand Down

0 comments on commit 38a8b36

Please sign in to comment.