LCOV - code coverage report
Current view: top level - src/node - chainstate.cpp (source / functions) Hit Total Coverage
Test: coverage.lcov Lines: 73 85 85.9 %
Date: 2022-04-21 14:51:19 Functions: 5 5 100.0 %
Legend: Modified by patch:
Lines: hit not hit | Branches: + taken - not taken # not executed

Not modified by patch:
Lines: hit not hit | Branches: + taken - not taken # not executed
Branches: 60 68 88.2 %

           Branch data     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 <consensus/params.h>
#       8                 :            : #include <node/blockstorage.h>
#       9                 :            : #include <validation.h>
#      10                 :            : 
#      11                 :            : namespace node {
#      12                 :            : std::optional<ChainstateLoadingError> LoadChainstate(bool fReset,
#      13                 :            :                                                      ChainstateManager& chainman,
#      14                 :            :                                                      CTxMemPool* mempool,
#      15                 :            :                                                      bool fPruneMode,
#      16                 :            :                                                      const Consensus::Params& consensus_params,
#      17                 :            :                                                      bool fReindexChainState,
#      18                 :            :                                                      int64_t nBlockTreeDBCache,
#      19                 :            :                                                      int64_t nCoinDBCache,
#      20                 :            :                                                      int64_t nCoinCacheUsage,
#      21                 :            :                                                      bool block_tree_db_in_memory,
#      22                 :            :                                                      bool coins_db_in_memory,
#      23                 :            :                                                      std::function<bool()> shutdown_requested,
#      24                 :            :                                                      std::function<void()> coins_error_cb)
#      25                 :        940 : {
#      26                 :        940 :     auto is_coinsview_empty = [&](CChainState* chainstate) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) {
#      27 [ +  + ][ +  + ]:        934 :         return fReset || fReindexChainState || chainstate->CoinsTip().GetBestBlock().IsNull();
#                 [ +  + ]
#      28                 :        934 :     };
#      29                 :            : 
#      30                 :        940 :     LOCK(cs_main);
#      31                 :        940 :     chainman.InitializeChainstate(mempool);
#      32                 :        940 :     chainman.m_total_coinstip_cache = nCoinCacheUsage;
#      33                 :        940 :     chainman.m_total_coinsdb_cache = nCoinDBCache;
#      34                 :            : 
#      35                 :        940 :     UnloadBlockIndex(mempool, chainman);
#      36                 :            : 
#      37                 :        940 :     auto& pblocktree{chainman.m_blockman.m_block_tree_db};
#      38                 :            :     // new CBlockTreeDB tries to delete the existing file, which
#      39                 :            :     // fails if it's still open from the previous loop. Close it first:
#      40                 :        940 :     pblocktree.reset();
#      41                 :        940 :     pblocktree.reset(new CBlockTreeDB(nBlockTreeDBCache, block_tree_db_in_memory, fReset));
#      42                 :            : 
#      43         [ +  + ]:        940 :     if (fReset) {
#      44                 :         10 :         pblocktree->WriteReindexing(true);
#      45                 :            :         //If we're reindexing in prune mode, wipe away unusable block files and all undo data files
#      46         [ +  + ]:         10 :         if (fPruneMode)
#      47                 :          1 :             CleanupBlockRevFiles();
#      48                 :         10 :     }
#      49                 :            : 
#      50 [ +  + ][ +  + ]:        940 :     if (shutdown_requested && shutdown_requested()) return ChainstateLoadingError::SHUTDOWN_PROBED;
#      51                 :            : 
#      52                 :            :     // LoadBlockIndex will load fHavePruned if we've ever removed a
#      53                 :            :     // block file from disk.
#      54                 :            :     // Note that it also sets fReindex based on the disk flag!
#      55                 :            :     // From here on out fReindex and fReset mean something different!
#      56         [ +  + ]:        938 :     if (!chainman.LoadBlockIndex()) {
#      57 [ +  - ][ +  + ]:          2 :         if (shutdown_requested && shutdown_requested()) return ChainstateLoadingError::SHUTDOWN_PROBED;
#      58                 :          1 :         return ChainstateLoadingError::ERROR_LOADING_BLOCK_DB;
#      59                 :          2 :     }
#      60                 :            : 
#      61         [ +  + ]:        936 :     if (!chainman.BlockIndex().empty() &&
#      62         [ -  + ]:        936 :             !chainman.m_blockman.LookupBlockIndex(consensus_params.hashGenesisBlock)) {
#      63                 :          0 :         return ChainstateLoadingError::ERROR_BAD_GENESIS_BLOCK;
#      64                 :          0 :     }
#      65                 :            : 
#      66                 :            :     // Check for changed -prune state.  What we are concerned about is a user who has pruned blocks
#      67                 :            :     // in the past, but is now trying to run unpruned.
#      68 [ +  + ][ -  + ]:        936 :     if (fHavePruned && !fPruneMode) {
#      69                 :          0 :         return ChainstateLoadingError::ERROR_PRUNED_NEEDS_REINDEX;
#      70                 :          0 :     }
#      71                 :            : 
#      72                 :            :     // At this point blocktree args are consistent with what's on disk.
#      73                 :            :     // If we're not mid-reindex (based on disk + args), add a genesis block on disk
#      74                 :            :     // (otherwise we use the one already on disk).
#      75                 :            :     // This is called again in ThreadImport after the reindex completes.
#      76 [ +  + ][ -  + ]:        936 :     if (!fReindex && !chainman.ActiveChainstate().LoadGenesisBlock()) {
#      77                 :          0 :         return ChainstateLoadingError::ERROR_LOAD_GENESIS_BLOCK_FAILED;
#      78                 :          0 :     }
#      79                 :            : 
#      80                 :            :     // At this point we're either in reindex or we've loaded a useful
#      81                 :            :     // block tree into BlockIndex()!
#      82                 :            : 
#      83         [ +  + ]:        936 :     for (CChainState* chainstate : chainman.GetAll()) {
#      84                 :        935 :         chainstate->InitCoinsDB(
#      85                 :        935 :             /*cache_size_bytes=*/nCoinDBCache,
#      86                 :        935 :             /*in_memory=*/coins_db_in_memory,
#      87 [ +  + ][ +  + ]:        935 :             /*should_wipe=*/fReset || fReindexChainState);
#      88                 :            : 
#      89         [ +  + ]:        935 :         if (coins_error_cb) {
#      90                 :        733 :             chainstate->CoinsErrorCatcher().AddReadErrCallback(coins_error_cb);
#      91                 :        733 :         }
#      92                 :            : 
#      93                 :            :         // Refuse to load unsupported database format.
#      94                 :            :         // This is a no-op if we cleared the coinsviewdb with -reindex or -reindex-chainstate
#      95         [ -  + ]:        935 :         if (chainstate->CoinsDB().NeedsUpgrade()) {
#      96                 :          0 :             return ChainstateLoadingError::ERROR_CHAINSTATE_UPGRADE_FAILED;
#      97                 :          0 :         }
#      98                 :            : 
#      99                 :            :         // ReplayBlocks is a no-op if we cleared the coinsviewdb with -reindex or -reindex-chainstate
#     100         [ -  + ]:        935 :         if (!chainstate->ReplayBlocks()) {
#     101                 :          0 :             return ChainstateLoadingError::ERROR_REPLAYBLOCKS_FAILED;
#     102                 :          0 :         }
#     103                 :            : 
#     104                 :            :         // The on-disk coinsdb is now in a good state, create the cache
#     105                 :        935 :         chainstate->InitCoinsCache(nCoinCacheUsage);
#     106                 :        935 :         assert(chainstate->CanFlushToDisk());
#     107                 :            : 
#     108         [ +  + ]:        935 :         if (!is_coinsview_empty(chainstate)) {
#     109                 :            :             // LoadChainTip initializes the chain based on CoinsTip()'s best block
#     110         [ -  + ]:        465 :             if (!chainstate->LoadChainTip()) {
#     111                 :          0 :                 return ChainstateLoadingError::ERROR_LOADCHAINTIP_FAILED;
#     112                 :          0 :             }
#     113                 :        465 :             assert(chainstate->m_chain.Tip() != nullptr);
#     114                 :        465 :         }
#     115                 :        935 :     }
#     116                 :            : 
#     117         [ +  + ]:        936 :     if (!fReset) {
#     118                 :        924 :         auto chainstates{chainman.GetAll()};
#     119         [ +  + ]:        924 :         if (std::any_of(chainstates.begin(), chainstates.end(),
#     120                 :        924 :                         [](const CChainState* cs) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { return cs->NeedsRedownload(); })) {
#     121                 :          1 :             return ChainstateLoadingError::ERROR_BLOCKS_WITNESS_INSUFFICIENTLY_VALIDATED;
#     122                 :          1 :         }
#     123                 :        924 :     }
#     124                 :            : 
#     125                 :        935 :     return std::nullopt;
#     126                 :        936 : }
#     127                 :            : 
#     128                 :            : std::optional<ChainstateLoadVerifyError> VerifyLoadedChainstate(ChainstateManager& chainman,
#     129                 :            :                                                                 bool fReset,
#     130                 :            :                                                                 bool fReindexChainState,
#     131                 :            :                                                                 const Consensus::Params& consensus_params,
#     132                 :            :                                                                 int check_blocks,
#     133                 :            :                                                                 int check_level,
#     134                 :            :                                                                 std::function<int64_t()> get_unix_time_seconds)
#     135                 :        933 : {
#     136                 :        933 :     auto is_coinsview_empty = [&](CChainState* chainstate) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) {
#     137 [ +  + ][ +  + ]:        933 :         return fReset || fReindexChainState || chainstate->CoinsTip().GetBestBlock().IsNull();
#                 [ +  + ]
#     138                 :        933 :     };
#     139                 :            : 
#     140                 :        933 :     LOCK(cs_main);
#     141                 :            : 
#     142         [ +  + ]:        933 :     for (CChainState* chainstate : chainman.GetAll()) {
#     143         [ +  + ]:        933 :         if (!is_coinsview_empty(chainstate)) {
#     144                 :        464 :             const CBlockIndex* tip = chainstate->m_chain.Tip();
#     145 [ +  - ][ +  + ]:        464 :             if (tip && tip->nTime > get_unix_time_seconds() + MAX_FUTURE_BLOCK_TIME) {
#     146                 :          1 :                 return ChainstateLoadVerifyError::ERROR_BLOCK_FROM_FUTURE;
#     147                 :          1 :             }
#     148                 :            : 
#     149         [ +  + ]:        463 :             if (!CVerifyDB().VerifyDB(
#     150                 :        463 :                     *chainstate, consensus_params, chainstate->CoinsDB(),
#     151                 :        463 :                     check_level,
#     152                 :        463 :                     check_blocks)) {
#     153                 :          1 :                 return ChainstateLoadVerifyError::ERROR_CORRUPTED_BLOCK_DB;
#     154                 :          1 :             }
#     155                 :        463 :         }
#     156                 :        933 :     }
#     157                 :            : 
#     158                 :        931 :     return std::nullopt;
#     159                 :        933 : }
#     160                 :            : } // namespace node

Generated by: LCOV version 0-eol-96201-ge66f56f4af6a