7
7
#include < chainparams.h> // for CChainParams
8
8
#include < rpc/blockchain.h> // for RPCNotifyBlockChange
9
9
#include < util/time.h> // for GetTime
10
- #include < util/translation.h> // for bilingual_str
11
10
#include < node/blockstorage.h> // for CleanupBlockRevFiles, fHavePruned, fReindex
12
11
#include < node/context.h> // for NodeContext
13
12
#include < node/ui_interface.h> // for InitError, uiInterface, and CClientUIInterface member access
14
13
#include < shutdown.h> // for ShutdownRequested
15
14
#include < validation.h> // for a lot of things
16
15
17
- bool LoadChainstate (bool & fLoaded ,
18
- bilingual_str& strLoadError,
19
- bool fReset ,
20
- ChainstateManager& chainman,
21
- NodeContext& node,
22
- bool fPruneMode ,
23
- const CChainParams& chainparams,
24
- const ArgsManager& args,
25
- bool fReindexChainState ,
26
- int64_t nBlockTreeDBCache,
27
- int64_t nCoinDBCache,
28
- int64_t nCoinCacheUsage) {
16
+ std::optional<ChainstateLoadingError> LoadChainstate (bool fReset ,
17
+ ChainstateManager& chainman,
18
+ NodeContext& node,
19
+ bool fPruneMode ,
20
+ const CChainParams& chainparams,
21
+ const ArgsManager& args,
22
+ bool fReindexChainState ,
23
+ int64_t nBlockTreeDBCache,
24
+ int64_t nCoinDBCache,
25
+ int64_t nCoinCacheUsage)
26
+ {
29
27
auto is_coinsview_empty = [&](CChainState* chainstate) EXCLUSIVE_LOCKS_REQUIRED (::cs_main) {
30
28
return fReset || fReindexChainState || chainstate->CoinsTip ().GetBestBlock ().IsNull ();
31
29
};
@@ -52,46 +50,41 @@ bool LoadChainstate(bool& fLoaded,
52
50
CleanupBlockRevFiles ();
53
51
}
54
52
55
- if (ShutdownRequested ()) break ;
53
+ if (ShutdownRequested ()) return ChainstateLoadingError::SHUTDOWN_PROBED ;
56
54
57
55
// LoadBlockIndex will load fHavePruned if we've ever removed a
58
56
// block file from disk.
59
57
// Note that it also sets fReindex based on the disk flag!
60
58
// From here on out fReindex and fReset mean something different!
61
59
if (!chainman.LoadBlockIndex ()) {
62
- if (ShutdownRequested ()) break ;
63
- strLoadError = _ (" Error loading block database" );
64
- break ;
60
+ if (ShutdownRequested ()) return ChainstateLoadingError::SHUTDOWN_PROBED;
61
+ return ChainstateLoadingError::ERROR_LOADING_BLOCK_DB;
65
62
}
66
63
67
64
// If the loaded chain has a wrong genesis, bail out immediately
68
65
// (we're likely using a testnet datadir, or the other way around).
69
66
if (!chainman.BlockIndex ().empty () &&
70
67
!chainman.m_blockman .LookupBlockIndex (chainparams.GetConsensus ().hashGenesisBlock )) {
71
- return InitError ( _ ( " Incorrect or no genesis block found. Wrong datadir for network? " )) ;
68
+ return ChainstateLoadingError::ERROR_BAD_GENESIS_BLOCK ;
72
69
}
73
70
74
71
// Check for changed -prune state. What we are concerned about is a user who has pruned blocks
75
72
// in the past, but is now trying to run unpruned.
76
73
if (fHavePruned && !fPruneMode ) {
77
- strLoadError = _ (" You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain" );
78
- break ;
74
+ return ChainstateLoadingError::ERROR_PRUNED_NEEDS_REINDEX;
79
75
}
80
76
81
77
// At this point blocktree args are consistent with what's on disk.
82
78
// If we're not mid-reindex (based on disk + args), add a genesis block on disk
83
79
// (otherwise we use the one already on disk).
84
80
// This is called again in ThreadImport after the reindex completes.
85
81
if (!fReindex && !chainman.ActiveChainstate ().LoadGenesisBlock ()) {
86
- strLoadError = _ (" Error initializing block database" );
87
- break ;
82
+ return ChainstateLoadingError::ERROR_LOAD_GENESIS_BLOCK_FAILED;
88
83
}
89
84
90
85
// At this point we're either in reindex or we've loaded a useful
91
86
// block tree into BlockIndex()!
92
87
93
- bool failed_chainstate_init = false ;
94
-
95
88
for (CChainState* chainstate : chainman.GetAll ()) {
96
89
chainstate->InitCoinsDB (
97
90
/* cache_size_bytes */ nCoinDBCache,
@@ -107,16 +100,12 @@ bool LoadChainstate(bool& fLoaded,
107
100
// If necessary, upgrade from older database format.
108
101
// This is a no-op if we cleared the coinsviewdb with -reindex or -reindex-chainstate
109
102
if (!chainstate->CoinsDB ().Upgrade ()) {
110
- strLoadError = _ (" Error upgrading chainstate database" );
111
- failed_chainstate_init = true ;
112
- break ;
103
+ return ChainstateLoadingError::ERROR_CHAINSTATE_UPGRADE_FAILED;
113
104
}
114
105
115
106
// ReplayBlocks is a no-op if we cleared the coinsviewdb with -reindex or -reindex-chainstate
116
107
if (!chainstate->ReplayBlocks ()) {
117
- strLoadError = _ (" Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate." );
118
- failed_chainstate_init = true ;
119
- break ;
108
+ return ChainstateLoadingError::ERROR_REPLAYBLOCKS_FAILED;
120
109
}
121
110
122
111
// The on-disk coinsdb is now in a good state, create the cache
@@ -126,36 +115,25 @@ bool LoadChainstate(bool& fLoaded,
126
115
if (!is_coinsview_empty (chainstate)) {
127
116
// LoadChainTip initializes the chain based on CoinsTip()'s best block
128
117
if (!chainstate->LoadChainTip ()) {
129
- strLoadError = _ (" Error initializing block database" );
130
- failed_chainstate_init = true ;
131
- break ; // out of the per-chainstate loop
118
+ return ChainstateLoadingError::ERROR_LOADCHAINTIP_FAILED;
132
119
}
133
120
assert (chainstate->m_chain .Tip () != nullptr );
134
121
}
135
122
}
136
-
137
- if (failed_chainstate_init) {
138
- break ; // out of the chainstate activation do-while
139
- }
140
123
} catch (const std::exception& e) {
141
124
LogPrintf (" %s\n " , e.what ());
142
- strLoadError = _ (" Error opening block database" );
143
- break ;
125
+ return ChainstateLoadingError::ERROR_GENERIC_BLOCKDB_OPEN_FAILED;
144
126
}
145
127
146
128
if (!fReset ) {
147
129
LOCK (cs_main);
148
130
auto chainstates{chainman.GetAll ()};
149
131
if (std::any_of (chainstates.begin (), chainstates.end (),
150
132
[](const CChainState* cs) EXCLUSIVE_LOCKS_REQUIRED (cs_main) { return cs->NeedsRedownload (); })) {
151
- strLoadError = strprintf (_ (" Witness data for blocks after height %d requires validation. Please restart with -reindex." ),
152
- chainparams.GetConsensus ().SegwitHeight );
153
- break ;
133
+ return ChainstateLoadingError::ERROR_BLOCKS_WITNESS_INSUFFICIENTLY_VALIDATED;
154
134
}
155
135
}
156
136
157
- bool failed_verification = false ;
158
-
159
137
try {
160
138
LOCK (cs_main);
161
139
@@ -170,33 +148,21 @@ bool LoadChainstate(bool& fLoaded,
170
148
const CBlockIndex* tip = chainstate->m_chain .Tip ();
171
149
RPCNotifyBlockChange (tip);
172
150
if (tip && tip->nTime > GetTime () + MAX_FUTURE_BLOCK_TIME) {
173
- strLoadError = _ (" The block database contains a block which appears to be from the future. "
174
- " This may be due to your computer's date and time being set incorrectly. "
175
- " Only rebuild the block database if you are sure that your computer's date and time are correct" );
176
- failed_verification = true ;
177
- break ;
151
+ return ChainstateLoadingError::ERROR_BLOCK_FROM_FUTURE;
178
152
}
179
153
180
154
if (!CVerifyDB ().VerifyDB (
181
155
*chainstate, chainparams, chainstate->CoinsDB (),
182
156
args.GetIntArg (" -checklevel" , DEFAULT_CHECKLEVEL),
183
157
args.GetIntArg (" -checkblocks" , DEFAULT_CHECKBLOCKS))) {
184
- strLoadError = _ (" Corrupted block database detected" );
185
- failed_verification = true ;
186
- break ;
158
+ return ChainstateLoadingError::ERROR_CORRUPTED_BLOCK_DB;
187
159
}
188
160
}
189
161
}
190
162
} catch (const std::exception& e) {
191
163
LogPrintf (" %s\n " , e.what ());
192
- strLoadError = _ (" Error opening block database" );
193
- failed_verification = true ;
194
- break ;
195
- }
196
-
197
- if (!failed_verification) {
198
- fLoaded = true ;
164
+ return ChainstateLoadingError::ERROR_GENERIC_BLOCKDB_OPEN_FAILED;
199
165
}
200
166
} while (false );
201
- return true ;
167
+ return std::nullopt ;
202
168
}
0 commit comments