Line data Source code
1 : // Copyright (c) 2021 The Bitcoin Core developers
2 : // Distributed under the MIT software license, see the accompanying
3 : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 :
5 : #include <node/chainstate.h>
6 :
7 : #include <chain.h>
8 : #include <coins.h>
9 : #include <chainparamsbase.h>
10 : #include <consensus/params.h>
11 : #include <deploymentstatus.h>
12 : #include <node/blockstorage.h>
13 : #include <sync.h>
14 : #include <threadsafety.h>
15 : #include <tinyformat.h>
16 : #include <txdb.h>
17 : #include <txmempool.h>
18 : #include <uint256.h>
19 : #include <util/translation.h>
20 : #include <validation.h>
21 :
22 : #include <bls/bls.h>
23 : #include <evo/chainhelper.h>
24 : #include <evo/deterministicmns.h>
25 : #include <evo/evodb.h>
26 : #include <evo/mnhftx.h>
27 : #include <gsl/pointers.h>
28 : #include <llmq/context.h>
29 :
30 : #include <atomic>
31 : #include <cassert>
32 : #include <memory>
33 : #include <vector>
34 :
35 : namespace node {
36 178 : std::optional<ChainstateLoadingError> LoadChainstate(bool fReset,
37 : ChainstateManager& chainman,
38 : CMasternodeMetaMan& mn_metaman,
39 : CSporkManager& sporkman,
40 : chainlock::Chainlocks& chainlocks,
41 : const CMasternodeSync& mn_sync,
42 : std::unique_ptr<CChainstateHelper>& chain_helper,
43 : std::unique_ptr<CDeterministicMNManager>& dmnman,
44 : std::unique_ptr<CEvoDB>& evodb,
45 : std::unique_ptr<LLMQContext>& llmq_ctx,
46 : CTxMemPool* mempool,
47 : const fs::path& data_dir,
48 : bool fPruneMode,
49 : const Consensus::Params& consensus_params,
50 : bool fReindexChainState,
51 : int64_t nBlockTreeDBCache,
52 : int64_t nCoinDBCache,
53 : int64_t nCoinCacheUsage,
54 : bool block_tree_db_in_memory,
55 : bool coins_db_in_memory,
56 : bool dash_dbs_in_memory,
57 : int8_t bls_threads,
58 : int16_t worker_count,
59 : int64_t max_recsigs_age,
60 : std::function<bool()> shutdown_requested,
61 : std::function<void()> coins_error_cb)
62 : {
63 356 : auto is_coinsview_empty = [&](CChainState* chainstate) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) {
64 178 : return fReset || fReindexChainState || chainstate->CoinsTip().GetBestBlock().IsNull();
65 : };
66 :
67 178 : LOCK(cs_main);
68 :
69 178 : evodb.reset();
70 178 : evodb = std::make_unique<CEvoDB>(util::DbWrapperParams{.path = data_dir, .memory = dash_dbs_in_memory, .wipe = fReset || fReindexChainState});
71 :
72 : chainman.InitializeChainstate(mempool, *evodb, chain_helper);
73 : chainman.m_total_coinstip_cache = nCoinCacheUsage;
74 : chainman.m_total_coinsdb_cache = nCoinDBCache;
75 :
76 : auto& pblocktree{chainman.m_blockman.m_block_tree_db};
77 : // new CBlockTreeDB tries to delete the existing file, which
78 : // fails if it's still open from the previous loop. Close it first:
79 : pblocktree.reset();
80 : pblocktree.reset(new CBlockTreeDB(nBlockTreeDBCache, block_tree_db_in_memory, fReset));
81 :
82 : DashChainstateSetup(chainman, mn_metaman, sporkman, chainlocks, mn_sync, chain_helper,
83 : dmnman, *evodb, llmq_ctx, mempool, data_dir, dash_dbs_in_memory,
84 : /*llmq_dbs_wipe=*/fReset || fReindexChainState, bls_threads, worker_count,
85 : max_recsigs_age, consensus_params);
86 :
87 : if (fReset) {
88 : pblocktree->WriteReindexing(true);
89 : //If we're reindexing in prune mode, wipe away unusable block files and all undo data files
90 : if (fPruneMode)
91 : CleanupBlockRevFiles();
92 : }
93 :
94 : if (shutdown_requested && shutdown_requested()) return ChainstateLoadingError::SHUTDOWN_PROBED;
95 :
96 : // LoadBlockIndex will load m_have_pruned if we've ever removed a
97 : // block file from disk.
98 : // Note that it also sets fReindex based on the disk flag!
99 : // From here on out fReindex and fReset mean something different!
100 : if (!chainman.LoadBlockIndex()) {
101 : if (shutdown_requested && shutdown_requested()) return ChainstateLoadingError::SHUTDOWN_PROBED;
102 : return ChainstateLoadingError::ERROR_LOADING_BLOCK_DB;
103 : }
104 :
105 : if (!chainman.BlockIndex().empty() &&
106 : !chainman.m_blockman.LookupBlockIndex(consensus_params.hashGenesisBlock)) {
107 : return ChainstateLoadingError::ERROR_BAD_GENESIS_BLOCK;
108 : }
109 :
110 : if (!consensus_params.hashDevnetGenesisBlock.IsNull() && !chainman.BlockIndex().empty() &&
111 : !chainman.m_blockman.LookupBlockIndex(consensus_params.hashDevnetGenesisBlock)) {
112 : return ChainstateLoadingError::ERROR_BAD_DEVNET_GENESIS_BLOCK;
113 : }
114 :
115 : // Check for changed -prune state. What we are concerned about is a user who has pruned blocks
116 : // in the past, but is now trying to run unpruned.
117 : if (chainman.m_blockman.m_have_pruned && !fPruneMode) {
118 : return ChainstateLoadingError::ERROR_PRUNED_NEEDS_REINDEX;
119 : }
120 :
121 : // At this point blocktree args are consistent with what's on disk.
122 : // If we're not mid-reindex (based on disk + args), add a genesis block on disk
123 : // (otherwise we use the one already on disk).
124 : // This is called again in ThreadImport after the reindex completes.
125 : if (!fReindex && !chainman.ActiveChainstate().LoadGenesisBlock()) {
126 : return ChainstateLoadingError::ERROR_LOAD_GENESIS_BLOCK_FAILED;
127 : }
128 :
129 : // At this point we're either in reindex or we've loaded a useful
130 : // block tree into BlockIndex()!
131 :
132 : for (CChainState* chainstate : chainman.GetAll()) {
133 : chainstate->InitCoinsDB(
134 : /*cache_size_bytes=*/nCoinDBCache,
135 : /*in_memory=*/coins_db_in_memory,
136 : /*should_wipe=*/fReset || fReindexChainState);
137 :
138 : if (coins_error_cb) {
139 : chainstate->CoinsErrorCatcher().AddReadErrCallback(coins_error_cb);
140 : }
141 :
142 : // Refuse to load unsupported database format.
143 : // This is a no-op if we cleared the coinsviewdb with -reindex or -reindex-chainstate
144 : if (chainstate->CoinsDB().NeedsUpgrade()) {
145 : return ChainstateLoadingError::ERROR_CHAINSTATE_UPGRADE_FAILED;
146 : }
147 :
148 : // ReplayBlocks is a no-op if we cleared the coinsviewdb with -reindex or -reindex-chainstate
149 : if (!chainstate->ReplayBlocks()) {
150 : return ChainstateLoadingError::ERROR_REPLAYBLOCKS_FAILED;
151 : }
152 :
153 : // The on-disk coinsdb is now in a good state, create the cache
154 : chainstate->InitCoinsCache(nCoinCacheUsage);
155 : assert(chainstate->CanFlushToDisk());
156 :
157 : // flush evodb
158 : // TODO: CEvoDB instance should probably be a part of CChainState
159 : // (for multiple chainstates to actually work in parallel)
160 : // and not a global
161 : if (&chainman.ActiveChainstate() == chainstate && !evodb->CommitRootTransaction()) {
162 : return ChainstateLoadingError::ERROR_COMMITING_EVO_DB;
163 : }
164 :
165 : if (!is_coinsview_empty(chainstate)) {
166 : // LoadChainTip initializes the chain based on CoinsTip()'s best block
167 : if (!chainstate->LoadChainTip()) {
168 : return ChainstateLoadingError::ERROR_LOADCHAINTIP_FAILED;
169 : }
170 : assert(chainstate->m_chain.Tip() != nullptr);
171 : }
172 : }
173 :
174 : if (!chain_helper->ehf_manager->ForceSignalDBUpdate()) {
175 : return ChainstateLoadingError::ERROR_UPGRADING_SIGNALS_DB;
176 : }
177 :
178 : // Check if nVersion-first migration is needed and perform it
179 : if (dmnman->IsMigrationRequired() && !dmnman->MigrateLegacyDiffs(chainman.ActiveChainstate().m_chain.Tip())) {
180 : return ChainstateLoadingError::ERROR_UPGRADING_EVO_DB;
181 : }
182 :
183 : return std::nullopt;
184 0 : }
185 :
186 180 : void DashChainstateSetup(ChainstateManager& chainman,
187 : CMasternodeMetaMan& mn_metaman,
188 : CSporkManager& sporkman,
189 : chainlock::Chainlocks& chainlocks,
190 : const CMasternodeSync& mn_sync,
191 : std::unique_ptr<CChainstateHelper>& chain_helper,
192 : std::unique_ptr<CDeterministicMNManager>& dmnman,
193 : CEvoDB& evodb,
194 : std::unique_ptr<LLMQContext>& llmq_ctx,
195 : CTxMemPool* mempool,
196 : const fs::path& data_dir,
197 : bool llmq_dbs_in_memory,
198 : bool llmq_dbs_wipe,
199 : int8_t bls_threads,
200 : int16_t worker_count,
201 : int64_t max_recsigs_age,
202 : const Consensus::Params& consensus_params)
203 : {
204 : // Same logic as pblocktree
205 180 : dmnman.reset();
206 180 : dmnman = std::make_unique<CDeterministicMNManager>(evodb, mn_metaman);
207 :
208 180 : llmq_ctx.reset();
209 360 : llmq_ctx = std::make_unique<LLMQContext>(*dmnman, evodb, sporkman, chainman,
210 180 : util::DbWrapperParams{.path = data_dir, .memory = llmq_dbs_in_memory, .wipe = llmq_dbs_wipe},
211 : bls_threads, worker_count, max_recsigs_age);
212 : if (mempool) {
213 : mempool->ConnectManagers(dmnman.get(), llmq_ctx->isman.get());
214 : }
215 : chain_helper.reset();
216 : chain_helper = std::make_unique<CChainstateHelper>(evodb, *dmnman, mn_sync, *(llmq_ctx->isman), *(llmq_ctx->quorum_block_processor),
217 : *(llmq_ctx->qsnapman), chainman, consensus_params, chainlocks,
218 : *(llmq_ctx->qman));
219 : }
220 :
221 180 : void DashChainstateSetupClose(std::unique_ptr<CChainstateHelper>& chain_helper,
222 : std::unique_ptr<CDeterministicMNManager>& dmnman,
223 : std::unique_ptr<LLMQContext>& llmq_ctx,
224 : CTxMemPool* mempool)
225 :
226 : {
227 180 : chain_helper.reset();
228 180 : llmq_ctx.reset();
229 180 : if (mempool) {
230 180 : mempool->DisconnectManagers();
231 180 : }
232 180 : dmnman.reset();
233 180 : }
234 :
235 178 : std::optional<ChainstateLoadVerifyError> VerifyLoadedChainstate(ChainstateManager& chainman,
236 : CEvoDB& evodb,
237 : bool fReset,
238 : bool fReindexChainState,
239 : const Consensus::Params& consensus_params,
240 : int check_blocks,
241 : int check_level,
242 : std::function<int64_t()> get_unix_time_seconds,
243 : std::function<void(bool)> notify_bls_state)
244 : {
245 356 : auto is_coinsview_empty = [&](CChainState* chainstate) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) {
246 178 : return fReset || fReindexChainState || chainstate->CoinsTip().GetBestBlock().IsNull();
247 : };
248 :
249 178 : LOCK(cs_main);
250 :
251 356 : for (CChainState* chainstate : chainman.GetAll()) {
252 178 : if (!is_coinsview_empty(chainstate)) {
253 0 : const CBlockIndex* tip = chainstate->m_chain.Tip();
254 0 : if (tip && tip->nTime > get_unix_time_seconds() + MAX_FUTURE_BLOCK_TIME) {
255 0 : return ChainstateLoadVerifyError::ERROR_BLOCK_FROM_FUTURE;
256 : }
257 0 : const bool v19active{DeploymentActiveAfter(tip, consensus_params, Consensus::DEPLOYMENT_V19)};
258 0 : if (v19active) {
259 0 : bls::bls_legacy_scheme.store(false);
260 0 : if (notify_bls_state) notify_bls_state(bls::bls_legacy_scheme.load());
261 0 : }
262 :
263 0 : if (!CVerifyDB().VerifyDB(
264 0 : *chainstate, consensus_params, chainstate->CoinsDB(),
265 0 : evodb,
266 0 : check_level,
267 0 : check_blocks)) {
268 0 : return ChainstateLoadVerifyError::ERROR_CORRUPTED_BLOCK_DB;
269 : }
270 :
271 : // VerifyDB() disconnects blocks which might result in us switching back to legacy.
272 : // Make sure we use the right scheme.
273 0 : if (v19active && bls::bls_legacy_scheme.load()) {
274 0 : bls::bls_legacy_scheme.store(false);
275 0 : if (notify_bls_state) notify_bls_state(bls::bls_legacy_scheme.load());
276 0 : }
277 :
278 0 : if (check_level >= 3) {
279 0 : chainstate->ResetBlockFailureFlags(nullptr);
280 0 : }
281 :
282 0 : } else {
283 : // TODO: CEvoDB instance should probably be a part of CChainState
284 : // (for multiple chainstates to actually work in parallel)
285 : // and not a global
286 178 : if (&chainman.ActiveChainstate() == chainstate && !evodb.IsEmpty()) {
287 : // EvoDB processed some blocks earlier but we have no blocks anymore, something is wrong
288 0 : return ChainstateLoadVerifyError::ERROR_EVO_DB_SANITY_FAILED;
289 : }
290 : }
291 : }
292 :
293 178 : return std::nullopt;
294 178 : }
295 : } // namespace node
|