From 66856b2b3c598da8f57d40302fa2b99b132e1574 Mon Sep 17 00:00:00 2001 From: Daira Hopwood Date: Tue, 31 Jul 2018 22:29:14 +0100 Subject: [PATCH] Support testnet rollback. Signed-off-by: Daira Hopwood --- src/init.cpp | 6 ++++-- src/main.cpp | 58 ++++++++++++++++++++++++++++++++++++---------------- src/main.h | 5 ++++- 3 files changed, 48 insertions(+), 21 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 8c50acc78ad..92ca21723ce 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1443,6 +1443,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) LogPrintf("* Using %.1fMiB for chain state database\n", nCoinDBCache * (1.0 / 1024 / 1024)); LogPrintf("* Using %.1fMiB for in-memory UTXO set\n", nCoinCacheUsage * (1.0 / 1024 / 1024)); + bool clearWitnessCaches = false; + bool fLoaded = false; while (!fLoaded) { bool fReset = fReindex; @@ -1502,7 +1504,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) if (!fReindex) { uiInterface.InitMessage(_("Rewinding blocks if needed...")); - if (!RewindBlockIndex(chainparams)) { + if (!RewindBlockIndex(chainparams, clearWitnessCaches)) { strLoadError = _("Unable to rewind the database to a pre-upgrade state. You will need to redownload the blockchain"); break; } @@ -1652,7 +1654,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) RegisterValidationInterface(pwalletMain); CBlockIndex *pindexRescan = chainActive.Tip(); - if (GetBoolArg("-rescan", false)) + if (clearWitnessCaches || GetBoolArg("-rescan", false)) { pwalletMain->ClearNoteWitnessCache(); pindexRescan = chainActive.Genesis(); diff --git a/src/main.cpp b/src/main.cpp index cbec77b07b3..264d242e181 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4217,7 +4217,7 @@ bool CVerifyDB::VerifyDB(CCoinsView *coinsview, int nCheckLevel, int nCheckDepth return true; } -bool RewindBlockIndex(const CChainParams& params) +bool RewindBlockIndex(const CChainParams& params, bool& clearWitnessCaches) { LOCK(cs_main); @@ -4249,23 +4249,45 @@ bool RewindBlockIndex(const CChainParams& params) // nHeight is now the height of the first insufficiently-validated block, or tipheight + 1 auto rewindLength = chainActive.Height() - nHeight; - if (rewindLength > 0 && rewindLength > MAX_REORG_LENGTH) { - auto pindexOldTip = chainActive.Tip(); - auto pindexRewind = chainActive[nHeight - 1]; - auto msg = strprintf(_( - "A block chain rewind has been detected that would roll back %d blocks! " - "This is larger than the maximum of %d blocks, and so the node is shutting down for your safety." - ), rewindLength, MAX_REORG_LENGTH) + "\n\n" + - _("Rewind details") + ":\n" + - "- " + strprintf(_("Current tip: %s, height %d"), - pindexOldTip->phashBlock->GetHex(), pindexOldTip->nHeight) + "\n" + - "- " + strprintf(_("Rewinding to: %s, height %d"), - pindexRewind->phashBlock->GetHex(), pindexRewind->nHeight) + "\n\n" + - _("Please help, human!"); - LogPrintf("*** %s\n", msg); - uiInterface.ThreadSafeMessageBox(msg, "", CClientUIInterface::MSG_ERROR); - StartShutdown(); - return false; + LogPrintf("*** First insufficiently validated block at height %d, rewind length %d\n", nHeight, rewindLength); + clearWitnessCaches = false; + + if (rewindLength > 0) { + const uint256 *phashFirstInsufValidated = chainActive[nHeight]->phashBlock; + auto networkID = params.NetworkIDString(); + + // This is true when we intend to do a long rewind. + bool intendedRewind = + (networkID == "test" && nHeight == 252500 && *phashFirstInsufValidated == + uint256S("0018bd16a9c6f15795a754c498d2b2083ab78f14dae44a66a8d0e90ba8464d9c")); + + clearWitnessCaches = (rewindLength > MAX_REORG_LENGTH && intendedRewind); + + if (clearWitnessCaches) { + auto msg = strprintf(_( + "An intended block chain rewind has been detected: network %s, hash %s, height %d" + ), networkID, phashFirstInsufValidated->GetHex(), nHeight); + LogPrintf("*** %s\n", msg); + } + + if (rewindLength > MAX_REORG_LENGTH && !intendedRewind) { + auto pindexOldTip = chainActive.Tip(); + auto pindexRewind = chainActive[nHeight - 1]; + auto msg = strprintf(_( + "A block chain rewind has been detected that would roll back %d blocks! " + "This is larger than the maximum of %d blocks, and so the node is shutting down for your safety." + ), rewindLength, MAX_REORG_LENGTH) + "\n\n" + + _("Rewind details") + ":\n" + + "- " + strprintf(_("Current tip: %s, height %d"), + pindexOldTip->phashBlock->GetHex(), pindexOldTip->nHeight) + "\n" + + "- " + strprintf(_("Rewinding to: %s, height %d"), + pindexRewind->phashBlock->GetHex(), pindexRewind->nHeight) + "\n\n" + + _("Please help, human!"); + LogPrintf("*** %s\n", msg); + uiInterface.ThreadSafeMessageBox(msg, "", CClientUIInterface::MSG_ERROR); + StartShutdown(); + return false; + } } CValidationState state; diff --git a/src/main.h b/src/main.h index 201637ab1e1..9481a609014 100644 --- a/src/main.h +++ b/src/main.h @@ -478,8 +478,11 @@ bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, CBloc * When there are blocks in the active chain with missing data (e.g. if the * activation height and branch ID of a particular upgrade have been altered), * rewind the chainstate and remove them from the block index. + * + * clearWitnessCaches is an output parameter that will be set to true iff + * witness caches should be cleared in order to handle an intended long rewind. */ -bool RewindBlockIndex(const CChainParams& params); +bool RewindBlockIndex(const CChainParams& params, bool& clearWitnessCaches); class CBlockFileInfo {