88#include < deploymentstatus.h> // for DeploymentActiveAfter
99#include < rpc/blockchain.h> // for RPCNotifyBlockChange
1010#include < util/time.h> // for GetTime
11- #include < util/translation.h> // for bilingual_str
1211#include < node/blockstorage.h> // for CleanupBlockRevFiles, fHavePruned, fReindex
1312#include < node/context.h> // for NodeContext
1413#include < node/ui_interface.h> // for InitError, uiInterface, and CClientUIInterface member access
2524#include < llmq/instantsend.h> // for llmq::quorumInstantSendManager
2625#include < llmq/snapshot.h> // for llmq::quorumSnapshotManager
2726
28- bool LoadChainstate (bool & fLoaded ,
29- bilingual_str& strLoadError,
30- bool fReset ,
31- ChainstateManager& chainman,
32- NodeContext& node,
33- bool fPruneMode ,
34- bool is_governance_enabled,
35- const CChainParams& chainparams,
36- const ArgsManager& args,
37- bool fReindexChainState ,
38- int64_t nBlockTreeDBCache,
39- int64_t nCoinDBCache,
40- int64_t nCoinCacheUsage) {
27+ std::optional<ChainstateLoadingError> LoadChainstate (bool fReset ,
28+ ChainstateManager& chainman,
29+ NodeContext& node,
30+ bool fPruneMode ,
31+ bool is_governance_enabled,
32+ const CChainParams& chainparams,
33+ const ArgsManager& args,
34+ bool fReindexChainState ,
35+ int64_t nBlockTreeDBCache,
36+ int64_t nCoinDBCache,
37+ int64_t nCoinCacheUsage)
38+ {
4139 auto is_coinsview_empty = [&](CChainState* chainstate) EXCLUSIVE_LOCKS_REQUIRED (::cs_main) {
4240 return fReset || fReindexChainState || chainstate->CoinsTip ().GetBestBlock ().IsNull ();
4341 };
@@ -95,51 +93,49 @@ bool LoadChainstate(bool& fLoaded,
9593 CleanupBlockRevFiles ();
9694 }
9795
98- if (ShutdownRequested ()) break ;
96+ if (ShutdownRequested ()) return ChainstateLoadingError::SHUTDOWN_PROBED ;
9997
10098 // LoadBlockIndex will load m_have_pruned if we've ever removed a
10199 // block file from disk.
102100 // Note that it also sets fReindex based on the disk flag!
103101 // From here on out fReindex and fReset mean something different!
104102 if (!chainman.LoadBlockIndex ()) {
105- if (ShutdownRequested ()) break ;
106- strLoadError = _ (" Error loading block database" );
107- break ;
103+ if (ShutdownRequested ()) return ChainstateLoadingError::SHUTDOWN_PROBED;
104+ return ChainstateLoadingError::ERROR_LOADING_BLOCK_DB;
108105 }
109106
110- if (is_governance_enabled && !args.GetBoolArg (" -txindex" , DEFAULT_TXINDEX) && chainparams.NetworkIDString () != CBaseChainParams::REGTEST) { // TODO remove this when pruning is fixed. See https://github.com/dashpay/dash/pull/1817 and https://github.com/dashpay/dash/pull/1743
111- return InitError (_ (" Transaction index can't be disabled with governance validation enabled. Either start with -disablegovernance command line switch or enable transaction index." ));
107+ // TODO: Remove this when pruning is fixed.
108+ // See https://github.com/dashpay/dash/pull/1817 and https://github.com/dashpay/dash/pull/1743
109+ if (is_governance_enabled && !args.GetBoolArg (" -txindex" , DEFAULT_TXINDEX) && chainparams.NetworkIDString () != CBaseChainParams::REGTEST) {
110+ return ChainstateLoadingError::ERROR_TXINDEX_DISABLED_WHEN_GOV_ENABLED;
112111 }
113112
114113 // If the loaded chain has a wrong genesis, bail out immediately
115114 // (we're likely using a testnet datadir, or the other way around).
116115 if (!chainman.BlockIndex ().empty () &&
117116 !chainman.m_blockman .LookupBlockIndex (chainparams.GetConsensus ().hashGenesisBlock )) {
118- return InitError ( _ ( " Incorrect or no genesis block found. Wrong datadir for network? " )) ;
117+ return ChainstateLoadingError::ERROR_BAD_GENESIS_BLOCK ;
119118 }
120119
121120 if (!chainparams.GetConsensus ().hashDevnetGenesisBlock .IsNull () && !chainman.BlockIndex ().empty () &&
122121 !chainman.m_blockman .LookupBlockIndex (chainparams.GetConsensus ().hashDevnetGenesisBlock )) {
123- return InitError ( _ ( " Incorrect or no devnet genesis block found. Wrong datadir for devnet specified? " )) ;
122+ return ChainstateLoadingError::ERROR_BAD_DEVNET_GENESIS_BLOCK ;
124123 }
125124
126125 if (!fReset && !fReindexChainState ) {
127126 // Check for changed -addressindex state
128127 if (!fAddressIndex && fAddressIndex != args.GetBoolArg (" -addressindex" , DEFAULT_ADDRESSINDEX)) {
129- strLoadError = _ (" You need to rebuild the database using -reindex to enable -addressindex" );
130- break ;
128+ return ChainstateLoadingError::ERROR_ADDRIDX_NEEDS_REINDEX;
131129 }
132130
133131 // Check for changed -timestampindex state
134132 if (!fTimestampIndex && fTimestampIndex != args.GetBoolArg (" -timestampindex" , DEFAULT_TIMESTAMPINDEX)) {
135- strLoadError = _ (" You need to rebuild the database using -reindex to enable -timestampindex" );
136- break ;
133+ return ChainstateLoadingError::ERROR_TIMEIDX_NEEDS_REINDEX;
137134 }
138135
139136 // Check for changed -spentindex state
140137 if (!fSpentIndex && fSpentIndex != args.GetBoolArg (" -spentindex" , DEFAULT_SPENTINDEX)) {
141- strLoadError = _ (" You need to rebuild the database using -reindex to enable -spentindex" );
142- break ;
138+ return ChainstateLoadingError::ERROR_SPENTIDX_NEEDS_REINDEX;
143139 }
144140 }
145141
@@ -152,24 +148,20 @@ bool LoadChainstate(bool& fLoaded,
152148 // Check for changed -prune state. What we are concerned about is a user who has pruned blocks
153149 // in the past, but is now trying to run unpruned.
154150 if (chainman.m_blockman .m_have_pruned && !fPruneMode ) {
155- strLoadError = _ (" You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain" );
156- break ;
151+ return ChainstateLoadingError::ERROR_PRUNED_NEEDS_REINDEX;
157152 }
158153
159154 // At this point blocktree args are consistent with what's on disk.
160155 // If we're not mid-reindex (based on disk + args), add a genesis block on disk
161156 // (otherwise we use the one already on disk).
162157 // This is called again in ThreadImport after the reindex completes.
163158 if (!fReindex && !chainman.ActiveChainstate ().LoadGenesisBlock ()) {
164- strLoadError = _ (" Error initializing block database" );
165- break ;
159+ return ChainstateLoadingError::ERROR_LOAD_GENESIS_BLOCK_FAILED;
166160 }
167161
168162 // At this point we're either in reindex or we've loaded a useful
169163 // block tree into BlockIndex()!
170164
171- bool failed_chainstate_init = false ;
172-
173165 for (CChainState* chainstate : chainman.GetAll ()) {
174166 chainstate->InitCoinsDB (
175167 /* cache_size_bytes */ nCoinDBCache,
@@ -185,16 +177,12 @@ bool LoadChainstate(bool& fLoaded,
185177 // If necessary, upgrade from older database format.
186178 // This is a no-op if we cleared the coinsviewdb with -reindex or -reindex-chainstate
187179 if (!chainstate->CoinsDB ().Upgrade ()) {
188- strLoadError = _ (" Error upgrading chainstate database" );
189- failed_chainstate_init = true ;
190- break ;
180+ return ChainstateLoadingError::ERROR_CHAINSTATE_UPGRADE_FAILED;
191181 }
192182
193183 // ReplayBlocks is a no-op if we cleared the coinsviewdb with -reindex or -reindex-chainstate
194184 if (!chainstate->ReplayBlocks ()) {
195- strLoadError = _ (" Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate." );
196- failed_chainstate_init = true ;
197- break ;
185+ return ChainstateLoadingError::ERROR_REPLAYBLOCKS_FAILED;
198186 }
199187
200188 // The on-disk coinsdb is now in a good state, create the cache
@@ -206,46 +194,29 @@ bool LoadChainstate(bool& fLoaded,
206194 // (for multiple chainstates to actually work in parallel)
207195 // and not a global
208196 if (&chainman.ActiveChainstate () == chainstate && !node.evodb ->CommitRootTransaction ()) {
209- strLoadError = _ (" Failed to commit EvoDB" );
210- failed_chainstate_init = true ;
211- break ;
197+ return ChainstateLoadingError::ERROR_COMMITING_EVO_DB;
212198 }
213199
214200 if (!is_coinsview_empty (chainstate)) {
215201 // LoadChainTip initializes the chain based on CoinsTip()'s best block
216202 if (!chainstate->LoadChainTip ()) {
217- strLoadError = _ (" Error initializing block database" );
218- failed_chainstate_init = true ;
219- break ; // out of the per-chainstate loop
203+ return ChainstateLoadingError::ERROR_LOADCHAINTIP_FAILED;
220204 }
221205 assert (chainstate->m_chain .Tip () != nullptr );
222206 }
223207 }
224208
225- if (failed_chainstate_init) {
226- break ; // out of the chainstate activation do-while
227- }
228-
229- if (!node.dmnman ->MigrateDBIfNeeded ()) {
230- strLoadError = _ (" Error upgrading evo database" );
231- break ;
232- }
233- if (!node.dmnman ->MigrateDBIfNeeded2 ()) {
234- strLoadError = _ (" Error upgrading evo database" );
235- break ;
209+ if (!node.dmnman ->MigrateDBIfNeeded () || !node.dmnman ->MigrateDBIfNeeded2 ()) {
210+ return ChainstateLoadingError::ERROR_UPGRADING_EVO_DB;
236211 }
237212 if (!node.mnhf_manager ->ForceSignalDBUpdate ()) {
238- strLoadError = _ (" Error upgrading evo database for EHF" );
239- break ;
213+ return ChainstateLoadingError::ERROR_UPGRADING_SIGNALS_DB;
240214 }
241215 } catch (const std::exception& e) {
242216 LogPrintf (" %s\n " , e.what ());
243- strLoadError = _ (" Error opening block database" );
244- break ;
217+ return ChainstateLoadingError::ERROR_GENERIC_BLOCKDB_OPEN_FAILED;
245218 }
246219
247- bool failed_verification = false ;
248-
249220 try {
250221 LOCK (cs_main);
251222
@@ -260,11 +231,7 @@ bool LoadChainstate(bool& fLoaded,
260231 const CBlockIndex* tip = chainstate->m_chain .Tip ();
261232 RPCNotifyBlockChange (tip);
262233 if (tip && tip->nTime > GetTime () + MAX_FUTURE_BLOCK_TIME) {
263- strLoadError = _ (" The block database contains a block which appears to be from the future. "
264- " This may be due to your computer's date and time being set incorrectly. "
265- " Only rebuild the block database if you are sure that your computer's date and time are correct" );
266- failed_verification = true ;
267- break ;
234+ return ChainstateLoadingError::ERROR_BLOCK_FROM_FUTURE;
268235 }
269236 const bool v19active{DeploymentActiveAfter (tip, chainparams.GetConsensus (), Consensus::DEPLOYMENT_V19)};
270237 if (v19active) {
@@ -277,9 +244,7 @@ bool LoadChainstate(bool& fLoaded,
277244 *node.evodb ,
278245 args.GetArg (" -checklevel" , DEFAULT_CHECKLEVEL),
279246 args.GetArg (" -checkblocks" , DEFAULT_CHECKBLOCKS))) {
280- strLoadError = _ (" Corrupted block database detected" );
281- failed_verification = true ;
282- break ;
247+ return ChainstateLoadingError::ERROR_CORRUPTED_BLOCK_DB;
283248 }
284249
285250 // VerifyDB() disconnects blocks which might result in us switching back to legacy.
@@ -299,22 +264,14 @@ bool LoadChainstate(bool& fLoaded,
299264 // and not a global
300265 if (&chainman.ActiveChainstate () == chainstate && !node.evodb ->IsEmpty ()) {
301266 // EvoDB processed some blocks earlier but we have no blocks anymore, something is wrong
302- strLoadError = _ (" Error initializing block database" );
303- failed_verification = true ;
304- break ;
267+ return ChainstateLoadingError::ERROR_EVO_DB_SANITY_FAILED;
305268 }
306269 }
307270 }
308271 } catch (const std::exception& e) {
309272 LogPrintf (" %s\n " , e.what ());
310- strLoadError = _ (" Error opening block database" );
311- failed_verification = true ;
312- break ;
313- }
314-
315- if (!failed_verification) {
316- fLoaded = true ;
273+ return ChainstateLoadingError::ERROR_GENERIC_BLOCKDB_OPEN_FAILED;
317274 }
318275 } while (false );
319- return true ;
276+ return std:: nullopt ;
320277}
0 commit comments