@@ -28,6 +28,68 @@ void Scraper(bool bSingleShot = false);
2828void ScraperSubscriber ();
2929
3030namespace {
31+ // !
32+ // ! \brief Display a message that warns about a corrupted blockchain database.
33+ // !
34+ // ! For the GUI, this displays a modal dialog. It prints a message to the log
35+ // ! and to stderr on headless nodes.
36+ // !
37+ void ShowChainCorruptedMessage ()
38+ {
39+ uiInterface.ThreadSafeMessageBox (
40+ _ (" WARNING: Blockchain data may be corrupted.\n\n "
41+ " Gridcoin detected bad index entries. This may occur because of an "
42+ " unexpected exit, a power failure, or a late software upgrade.\n\n "
43+ " Please exit Gridcoin, open the data directory, and delete:\n "
44+ " - the blk****.dat files\n "
45+ " - the txleveldb folder\n\n "
46+ " Your wallet will re-download the blockchain. Your balance may "
47+ " appear incorrect until the synchronization finishes.\n " ),
48+ " Gridcoin" ,
49+ CClientUIInterface::OK | CClientUIInterface::MODAL);
50+ }
51+
52+ // !
53+ // ! \brief Compare the block index to the hardened checkpoints and display a
54+ // ! warning message and exit if an entry does not match.
55+ // !
56+ // ! \param pindexBest Block index entry for the tip of the chain.
57+ // !
58+ // ! \return \c false if a checkpoint does not match its corresponding block
59+ // ! index entry.
60+ // !
61+ bool VerifyCheckpoints (const CBlockIndex* const pindexBest)
62+ {
63+ LogPrintf (" Gridcoin: verifying checkpoints..." );
64+ uiInterface.InitMessage (_ (" Verifying checkpoints..." ));
65+
66+ for (const auto & checkpoint_pair : Params ().Checkpoints ().mapCheckpoints ) {
67+ if (checkpoint_pair.first > pindexBest->nHeight ) {
68+ return true ;
69+ }
70+
71+ const auto iter_pair = mapBlockIndex.find (checkpoint_pair.second );
72+
73+ if (iter_pair == mapBlockIndex.end ()
74+ || iter_pair->second == nullptr
75+ || !iter_pair->second ->IsInMainChain ()
76+ || iter_pair->second ->nHeight != checkpoint_pair.first )
77+ {
78+ // We could rewind the blockchain, but doing so might take longer
79+ // than a genesis sync for deep reorganizations. For now, we only
80+ // show the message, exit, and let the user choose a resolution:
81+ //
82+ LogPrintf (" WARNING: checkpoint mismatch at %d" , checkpoint_pair.first );
83+ ShowChainCorruptedMessage ();
84+ Shutdown (nullptr );
85+
86+ return false ;
87+ }
88+ }
89+
90+ return true ;
91+ }
92+
3193// !
3294// ! \brief Initialize the service that creates and validate superblocks.
3395// !
@@ -286,18 +348,7 @@ void CheckBlockIndexJob()
286348 return ;
287349 }
288350
289- // This prints a message to the log and stderr on headless:
290- uiInterface.ThreadSafeMessageBox (
291- _ (" WARNING: Blockchain data may be corrupt.\n\n "
292- " Gridcoin detected bad index entries. This may occur because of an "
293- " unexpected exit or power failure.\n\n "
294- " Please exit Gridcoin, open the data directory, and delete:\n "
295- " - the blk****.dat files\n "
296- " - the txleveldb folder\n\n "
297- " Your wallet will re-download the blockchain. Your balance may "
298- " appear incorrect until the synchronization finishes.\n " ),
299- " Gridcoin" ,
300- CClientUIInterface::OK | CClientUIInterface::MODAL);
351+ ShowChainCorruptedMessage ();
301352}
302353
303354// !
@@ -388,6 +439,10 @@ bool GRC::Initialize(ThreadHandlerPtr threads, CBlockIndex* pindexBest)
388439{
389440 LogPrintf (" Gridcoin: initializing..." );
390441
442+ if (!VerifyCheckpoints (pindexBest)) {
443+ return false ;
444+ }
445+
391446 InitializeSuperblockQuorum (pindexBest);
392447
393448 // This has to be before InitializeResearchRewardAccounting, because we need the beacon registry
0 commit comments