LCOV - code coverage report
Current view: top level - src/node - chainstate.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 51 53 96.2 %
Date: 2026-06-25 07:23:43 Functions: 6 6 100.0 %

          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        3063 : 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        6112 :     auto is_coinsview_empty = [&](CChainState* chainstate) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) {
      64        3049 :         return fReset || fReindexChainState || chainstate->CoinsTip().GetBestBlock().IsNull();
      65             :     };
      66             : 
      67        3063 :     LOCK(cs_main);
      68             : 
      69        3063 :     evodb.reset();
      70        3063 :     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        3063 : 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        3063 :     dmnman.reset();
     206        3063 :     dmnman = std::make_unique<CDeterministicMNManager>(evodb, mn_metaman);
     207             : 
     208        3063 :     llmq_ctx.reset();
     209        6126 :     llmq_ctx = std::make_unique<LLMQContext>(*dmnman, evodb, sporkman, chainman,
     210        3063 :                                              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        3065 : 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        3065 :     chain_helper.reset();
     228        3065 :     llmq_ctx.reset();
     229        3065 :     if (mempool) {
     230        3065 :         mempool->DisconnectManagers();
     231        3065 :     }
     232        3065 :     dmnman.reset();
     233        3065 : }
     234             : 
     235        3049 : 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        6098 :     auto is_coinsview_empty = [&](CChainState* chainstate) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) {
     246        3049 :         return fReset || fReindexChainState || chainstate->CoinsTip().GetBestBlock().IsNull();
     247             :     };
     248             : 
     249        3049 :     LOCK(cs_main);
     250             : 
     251        6098 :     for (CChainState* chainstate : chainman.GetAll()) {
     252        3049 :         if (!is_coinsview_empty(chainstate)) {
     253        1976 :             const CBlockIndex* tip = chainstate->m_chain.Tip();
     254        1976 :             if (tip && tip->nTime > get_unix_time_seconds() + MAX_FUTURE_BLOCK_TIME) {
     255           4 :                 return ChainstateLoadVerifyError::ERROR_BLOCK_FROM_FUTURE;
     256             :             }
     257        1972 :             const bool v19active{DeploymentActiveAfter(tip, consensus_params, Consensus::DEPLOYMENT_V19)};
     258        1972 :             if (v19active) {
     259        1947 :                 bls::bls_legacy_scheme.store(false);
     260        1947 :                 if (notify_bls_state) notify_bls_state(bls::bls_legacy_scheme.load());
     261        1947 :             }
     262             : 
     263        3944 :             if (!CVerifyDB().VerifyDB(
     264        1972 :                     *chainstate, consensus_params, chainstate->CoinsDB(),
     265        1972 :                     evodb,
     266        1972 :                     check_level,
     267        1972 :                     check_blocks)) {
     268           4 :                 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        1966 :             if (v19active && bls::bls_legacy_scheme.load()) {
     274           3 :                 bls::bls_legacy_scheme.store(false);
     275           3 :                 if (notify_bls_state) notify_bls_state(bls::bls_legacy_scheme.load());
     276           3 :             }
     277             : 
     278        1966 :             if (check_level >= 3) {
     279        1962 :                 chainstate->ResetBlockFailureFlags(nullptr);
     280        1962 :             }
     281             : 
     282        1966 :         } 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        1073 :             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        3039 :     return std::nullopt;
     294        3051 : }
     295             : } // namespace node

Generated by: LCOV version 1.16