66
77#include < consensus/params.h>
88#include < node/blockstorage.h>
9+ #include < node/caches.h>
910#include < validation.h>
1011
11- std::optional<ChainstateLoadingError> LoadChainstate (bool fReset ,
12- ChainstateManager& chainman,
13- CTxMemPool* mempool,
14- bool fPruneMode ,
15- const Consensus::Params& consensus_params,
16- bool fReindexChainState ,
17- int64_t nBlockTreeDBCache,
18- int64_t nCoinDBCache,
19- int64_t nCoinCacheUsage,
20- bool block_tree_db_in_memory,
21- bool coins_db_in_memory,
22- std::optional<std::function<bool ()>> shutdown_requested,
23- std::optional<std::function<void()>> coins_error_cb)
12+ InitResult LoadChainstate (
13+ ChainstateManager& chainman,
14+ const Consensus::Params& consensus_params,
15+ const CacheSizes& cache_sizes,
16+ const InitOptions& options)
2417{
2518 auto is_coinsview_empty = [&](CChainState* chainstate) EXCLUSIVE_LOCKS_REQUIRED (::cs_main) {
26- return fReset || fReindexChainState || chainstate->CoinsTip ().GetBestBlock ().IsNull ();
19+ return options. reset || options. reindex || chainstate->CoinsTip ().GetBestBlock ().IsNull ();
2720 };
2821
2922 {
3023 LOCK (cs_main);
31- chainman.InitializeChainstate (mempool);
32- chainman.m_total_coinstip_cache = nCoinCacheUsage ;
33- chainman.m_total_coinsdb_cache = nCoinDBCache ;
24+ chainman.InitializeChainstate (options. mempool );
25+ chainman.m_total_coinstip_cache = cache_sizes. coins ;
26+ chainman.m_total_coinsdb_cache = cache_sizes. coins_db ;
3427
35- UnloadBlockIndex (mempool, chainman);
28+ UnloadBlockIndex (options. mempool , chainman);
3629
3730 auto & pblocktree{chainman.m_blockman .m_block_tree_db };
3831 // new CBlockTreeDB tries to delete the existing file, which
3932 // fails if it's still open from the previous loop. Close it first:
4033 pblocktree.reset ();
41- pblocktree.reset (new CBlockTreeDB (nBlockTreeDBCache, block_tree_db_in_memory, fReset ));
34+ pblocktree.reset (new CBlockTreeDB (cache_sizes. block_tree_db , options. block_tree_db_in_memory , options. reset ));
4235
43- if (fReset ) {
36+ if (options. reset ) {
4437 pblocktree->WriteReindexing (true );
4538 // If we're reindexing in prune mode, wipe away unusable block files and all undo data files
4639 if (fPruneMode )
4740 CleanupBlockRevFiles ();
4841 }
4942
50- if (shutdown_requested && (*shutdown_requested)()) return ChainstateLoadingError::SHUTDOWN_PROBED ;
43+ if (options. check_interrupt && options. check_interrupt ()) return {InitStatus::INTERRUPTED, {}} ;
5144
5245 // LoadBlockIndex will load fHavePruned if we've ever removed a
5346 // block file from disk.
5447 // Note that it also sets fReindex based on the disk flag!
5548 // From here on out fReindex and fReset mean something different!
5649 if (!chainman.LoadBlockIndex ()) {
57- if (shutdown_requested && (*shutdown_requested)()) return ChainstateLoadingError::SHUTDOWN_PROBED ;
58- return ChainstateLoadingError::ERROR_LOADING_BLOCK_DB ;
50+ if (options. check_interrupt && options. check_interrupt ()) return {InitStatus::INTERRUPTED, {}} ;
51+ return {InitStatus::FAILURE, _ ( " Error loading block database " )} ;
5952 }
6053
6154 if (!chainman.BlockIndex ().empty () &&
6255 !chainman.m_blockman .LookupBlockIndex (consensus_params.hashGenesisBlock )) {
63- return ChainstateLoadingError::ERROR_BAD_GENESIS_BLOCK;
56+ // If the loaded chain has a wrong genesis, bail out immediately
57+ // (we're likely using a testnet datadir, or the other way around).
58+ return {InitStatus::FAILURE, _ (" Incorrect or no genesis block found. Wrong datadir for network?" )};
6459 }
6560
6661 // Check for changed -prune state. What we are concerned about is a user who has pruned blocks
6762 // in the past, but is now trying to run unpruned.
6863 if (fHavePruned && !fPruneMode ) {
69- return ChainstateLoadingError::ERROR_PRUNED_NEEDS_REINDEX ;
64+ return {InitStatus::FAILURE, _ ( " You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain " )} ;
7065 }
7166
7267 // At this point blocktree args are consistent with what's on disk.
7368 // If we're not mid-reindex (based on disk + args), add a genesis block on disk
7469 // (otherwise we use the one already on disk).
7570 // This is called again in ThreadImport after the reindex completes.
7671 if (!fReindex && !chainman.ActiveChainstate ().LoadGenesisBlock ()) {
77- return ChainstateLoadingError::ERROR_LOAD_GENESIS_BLOCK_FAILED ;
72+ return {InitStatus::FAILURE, _ ( " Error initializing block database " )} ;
7873 }
7974
8075 // At this point we're either in reindex or we've loaded a useful
8176 // block tree into BlockIndex()!
8277
8378 for (CChainState* chainstate : chainman.GetAll ()) {
8479 chainstate->InitCoinsDB (
85- /* cache_size_bytes */ nCoinDBCache ,
86- /* in_memory */ coins_db_in_memory,
87- /* should_wipe */ fReset || fReindexChainState );
80+ /* cache_size_bytes */ cache_sizes. coins_db ,
81+ /* in_memory */ options. coins_db_in_memory ,
82+ /* should_wipe */ options. reset || options. reindex );
8883
89- if (coins_error_cb. has_value () ) {
90- chainstate->CoinsErrorCatcher ().AddReadErrCallback (coins_error_cb. value () );
84+ if (options. coins_error_cb ) {
85+ chainstate->CoinsErrorCatcher ().AddReadErrCallback (options. coins_error_cb );
9186 }
9287
9388 // If necessary, upgrade from older database format.
9489 // This is a no-op if we cleared the coinsviewdb with -reindex or -reindex-chainstate
9590 if (!chainstate->CoinsDB ().Upgrade ()) {
96- return ChainstateLoadingError::ERROR_CHAINSTATE_UPGRADE_FAILED ;
91+ return {InitStatus::FAILURE, _ ( " Error upgrading chainstate database " )} ;
9792 }
9893
9994 // ReplayBlocks is a no-op if we cleared the coinsviewdb with -reindex or -reindex-chainstate
10095 if (!chainstate->ReplayBlocks ()) {
101- return ChainstateLoadingError::ERROR_REPLAYBLOCKS_FAILED ;
96+ return {InitStatus::FAILURE, _ ( " Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate. " )} ;
10297 }
10398
10499 // The on-disk coinsdb is now in a good state, create the cache
105- chainstate->InitCoinsCache (nCoinCacheUsage );
100+ chainstate->InitCoinsCache (cache_sizes. coins );
106101 assert (chainstate->CanFlushToDisk ());
107102
108103 if (!is_coinsview_empty (chainstate)) {
109104 // LoadChainTip initializes the chain based on CoinsTip()'s best block
110105 if (!chainstate->LoadChainTip ()) {
111- return ChainstateLoadingError::ERROR_LOADCHAINTIP_FAILED ;
106+ return {InitStatus::FAILURE, _ ( " Error initializing block database " )} ;
112107 }
113108 assert (chainstate->m_chain .Tip () != nullptr );
114109 }
115110 }
116111
117- if (!fReset ) {
112+ if (!options. reset ) {
118113 auto chainstates{chainman.GetAll ()};
119114 if (std::any_of (chainstates.begin (), chainstates.end (),
120115 [](const CChainState* cs) EXCLUSIVE_LOCKS_REQUIRED (cs_main) { return cs->NeedsRedownload (); })) {
121- return ChainstateLoadingError::ERROR_BLOCKS_WITNESS_INSUFFICIENTLY_VALIDATED;
116+ return {InitStatus::FAILURE, strprintf (_ (" Witness data for blocks after height %d requires validation. Please restart with -reindex." ),
117+ consensus_params.SegwitHeight )};
122118 }
123119 }
124120 }
125121
126- return std:: nullopt ;
122+ return {InitStatus::SUCCESS, {}} ;
127123}
128124
129- std::optional<ChainstateLoadVerifyError> VerifyLoadedChainstate (ChainstateManager& chainman,
130- bool fReset ,
131- bool fReindexChainState ,
132- const Consensus::Params& consensus_params,
133- unsigned int check_blocks,
134- unsigned int check_level,
135- std::function<int64_t ()> get_unix_time_seconds)
125+ InitResult VerifyLoadedChainstate (
126+ ChainstateManager& chainman,
127+ const Consensus::Params& consensus_params,
128+ const InitOptions& options)
136129{
137130 auto is_coinsview_empty = [&](CChainState* chainstate) EXCLUSIVE_LOCKS_REQUIRED (::cs_main) {
138- return fReset || fReindexChainState || chainstate->CoinsTip ().GetBestBlock ().IsNull ();
131+ return options. reset || options. reindex || chainstate->CoinsTip ().GetBestBlock ().IsNull ();
139132 };
140133
141134 {
@@ -144,19 +137,21 @@ std::optional<ChainstateLoadVerifyError> VerifyLoadedChainstate(ChainstateManage
144137 for (CChainState* chainstate : chainman.GetAll ()) {
145138 if (!is_coinsview_empty (chainstate)) {
146139 const CBlockIndex* tip = chainstate->m_chain .Tip ();
147- if (tip && tip->nTime > get_unix_time_seconds () + 2 * 60 * 60 ) {
148- return ChainstateLoadVerifyError::ERROR_BLOCK_FROM_FUTURE;
140+ if (tip && tip->nTime > options.get_unix_time_seconds () + 2 * 60 * 60 ) {
141+ return {InitStatus::FAILURE, _ (" The block database contains a block which appears to be from the future. "
142+ " This may be due to your computer's date and time being set incorrectly. "
143+ " Only rebuild the block database if you are sure that your computer's date and time are correct" )};
149144 }
150145
151146 if (!CVerifyDB ().VerifyDB (
152147 *chainstate, consensus_params, chainstate->CoinsDB (),
153- check_level,
154- check_blocks)) {
155- return ChainstateLoadVerifyError::ERROR_CORRUPTED_BLOCK_DB ;
148+ options. check_level ,
149+ options. check_blocks )) {
150+ return {InitStatus::FAILURE, _ ( " Corrupted block database detected " )} ;
156151 }
157152 }
158153 }
159154 }
160155
161- return std:: nullopt ;
156+ return {InitStatus::SUCCESS, {}} ;
162157}
0 commit comments