LCOV - code coverage report
Current view: top level - src/node - blockstorage.cpp (source / functions) Hit Total Coverage
Test: coverage.lcov Lines: 502 618 81.2 %
Date: 2022-04-21 14:51:19 Functions: 41 41 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: 205 274 74.8 %

           Branch data     Line data    Source code
#       1                 :            : // Copyright (c) 2011-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/blockstorage.h>
#       6                 :            : 
#       7                 :            : #include <chain.h>
#       8                 :            : #include <chainparams.h>
#       9                 :            : #include <clientversion.h>
#      10                 :            : #include <consensus/validation.h>
#      11                 :            : #include <flatfile.h>
#      12                 :            : #include <fs.h>
#      13                 :            : #include <hash.h>
#      14                 :            : #include <pow.h>
#      15                 :            : #include <reverse_iterator.h>
#      16                 :            : #include <shutdown.h>
#      17                 :            : #include <signet.h>
#      18                 :            : #include <streams.h>
#      19                 :            : #include <undo.h>
#      20                 :            : #include <util/syscall_sandbox.h>
#      21                 :            : #include <util/system.h>
#      22                 :            : #include <validation.h>
#      23                 :            : 
#      24                 :            : namespace node {
#      25                 :            : std::atomic_bool fImporting(false);
#      26                 :            : std::atomic_bool fReindex(false);
#      27                 :            : bool fHavePruned = false;
#      28                 :            : bool fPruneMode = false;
#      29                 :            : uint64_t nPruneTarget = 0;
#      30                 :            : 
#      31                 :            : bool CBlockIndexWorkComparator::operator()(const CBlockIndex* pa, const CBlockIndex* pb) const
#      32                 :  280334392 : {
#      33                 :            :     // First sort by most total work, ...
#      34         [ +  + ]:  280334392 :     if (pa->nChainWork > pb->nChainWork) return false;
#      35         [ +  + ]:  233809956 :     if (pa->nChainWork < pb->nChainWork) return true;
#      36                 :            : 
#      37                 :            :     // ... then by earliest time received, ...
#      38         [ +  + ]:    1583716 :     if (pa->nSequenceId < pb->nSequenceId) return false;
#      39         [ +  + ]:    1541098 :     if (pa->nSequenceId > pb->nSequenceId) return true;
#      40                 :            : 
#      41                 :            :     // Use pointer address as tie breaker (should only happen with blocks
#      42                 :            :     // loaded from disk, as those all have id 0).
#      43         [ +  + ]:    1533225 :     if (pa < pb) return false;
#      44         [ +  + ]:    1533213 :     if (pa > pb) return true;
#      45                 :            : 
#      46                 :            :     // Identical blocks.
#      47                 :    1533198 :     return false;
#      48                 :    1533213 : }
#      49                 :            : 
#      50                 :            : bool CBlockIndexHeightOnlyComparator::operator()(const CBlockIndex* pa, const CBlockIndex* pb) const
#      51                 :    1619195 : {
#      52                 :    1619195 :     return pa->nHeight < pb->nHeight;
#      53                 :    1619195 : }
#      54                 :            : 
#      55                 :            : static FILE* OpenUndoFile(const FlatFilePos& pos, bool fReadOnly = false);
#      56                 :            : static FlatFileSeq BlockFileSeq();
#      57                 :            : static FlatFileSeq UndoFileSeq();
#      58                 :            : 
#      59                 :            : std::vector<CBlockIndex*> BlockManager::GetAllBlockIndices()
#      60                 :       1857 : {
#      61                 :       1857 :     AssertLockHeld(cs_main);
#      62                 :       1857 :     std::vector<CBlockIndex*> rv;
#      63                 :       1857 :     rv.reserve(m_block_index.size());
#      64         [ +  + ]:     157547 :     for (auto& [_, block_index] : m_block_index) {
#      65                 :     157547 :         rv.push_back(&block_index);
#      66                 :     157547 :     }
#      67                 :       1857 :     return rv;
#      68                 :       1857 : }
#      69                 :            : 
#      70                 :            : CBlockIndex* BlockManager::LookupBlockIndex(const uint256& hash)
#      71                 :     668333 : {
#      72                 :     668333 :     AssertLockHeld(cs_main);
#      73                 :     668333 :     BlockMap::iterator it = m_block_index.find(hash);
#      74         [ +  + ]:     668333 :     return it == m_block_index.end() ? nullptr : &it->second;
#      75                 :     668333 : }
#      76                 :            : 
#      77                 :            : const CBlockIndex* BlockManager::LookupBlockIndex(const uint256& hash) const
#      78                 :          1 : {
#      79                 :          1 :     AssertLockHeld(cs_main);
#      80                 :          1 :     BlockMap::const_iterator it = m_block_index.find(hash);
#      81         [ -  + ]:          1 :     return it == m_block_index.end() ? nullptr : &it->second;
#      82                 :          1 : }
#      83                 :            : 
#      84                 :            : CBlockIndex* BlockManager::AddToBlockIndex(const CBlockHeader& block)
#      85                 :      67535 : {
#      86                 :      67535 :     AssertLockHeld(cs_main);
#      87                 :            : 
#      88                 :      67535 :     auto [mi, inserted] = m_block_index.try_emplace(block.GetHash(), block);
#      89         [ +  + ]:      67535 :     if (!inserted) {
#      90                 :          3 :         return &mi->second;
#      91                 :          3 :     }
#      92                 :      67532 :     CBlockIndex* pindexNew = &(*mi).second;
#      93                 :            : 
#      94                 :            :     // We assign the sequence id to blocks only when the full data is available,
#      95                 :            :     // to avoid miners withholding blocks but broadcasting headers, to get a
#      96                 :            :     // competitive advantage.
#      97                 :      67532 :     pindexNew->nSequenceId = 0;
#      98                 :            : 
#      99                 :      67532 :     pindexNew->phashBlock = &((*mi).first);
#     100                 :      67532 :     BlockMap::iterator miPrev = m_block_index.find(block.hashPrevBlock);
#     101         [ +  + ]:      67532 :     if (miPrev != m_block_index.end()) {
#     102                 :      67062 :         pindexNew->pprev = &(*miPrev).second;
#     103                 :      67062 :         pindexNew->nHeight = pindexNew->pprev->nHeight + 1;
#     104                 :      67062 :         pindexNew->BuildSkip();
#     105                 :      67062 :     }
#     106         [ +  + ]:      67532 :     pindexNew->nTimeMax = (pindexNew->pprev ? std::max(pindexNew->pprev->nTimeMax, pindexNew->nTime) : pindexNew->nTime);
#     107         [ +  + ]:      67532 :     pindexNew->nChainWork = (pindexNew->pprev ? pindexNew->pprev->nChainWork : 0) + GetBlockProof(*pindexNew);
#     108                 :      67532 :     pindexNew->RaiseValidity(BLOCK_VALID_TREE);
#     109 [ +  + ][ +  + ]:      67532 :     if (pindexBestHeader == nullptr || pindexBestHeader->nChainWork < pindexNew->nChainWork)
#     110                 :      65497 :         pindexBestHeader = pindexNew;
#     111                 :            : 
#     112                 :      67532 :     m_dirty_blockindex.insert(pindexNew);
#     113                 :            : 
#     114                 :      67532 :     return pindexNew;
#     115                 :      67535 : }
#     116                 :            : 
#     117                 :            : void BlockManager::PruneOneBlockFile(const int fileNumber)
#     118                 :         10 : {
#     119                 :         10 :     AssertLockHeld(cs_main);
#     120                 :         10 :     LOCK(cs_LastBlockFile);
#     121                 :            : 
#     122         [ +  + ]:      14013 :     for (auto& entry : m_block_index) {
#     123                 :      14013 :         CBlockIndex* pindex = &entry.second;
#     124         [ +  + ]:      14013 :         if (pindex->nFile == fileNumber) {
#     125                 :       1958 :             pindex->nStatus &= ~BLOCK_HAVE_DATA;
#     126                 :       1958 :             pindex->nStatus &= ~BLOCK_HAVE_UNDO;
#     127                 :       1958 :             pindex->nFile = 0;
#     128                 :       1958 :             pindex->nDataPos = 0;
#     129                 :       1958 :             pindex->nUndoPos = 0;
#     130                 :       1958 :             m_dirty_blockindex.insert(pindex);
#     131                 :            : 
#     132                 :            :             // Prune from m_blocks_unlinked -- any block we prune would have
#     133                 :            :             // to be downloaded again in order to consider its chain, at which
#     134                 :            :             // point it would be considered as a candidate for
#     135                 :            :             // m_blocks_unlinked or setBlockIndexCandidates.
#     136                 :       1958 :             auto range = m_blocks_unlinked.equal_range(pindex->pprev);
#     137         [ -  + ]:       1958 :             while (range.first != range.second) {
#     138                 :          0 :                 std::multimap<CBlockIndex*, CBlockIndex*>::iterator _it = range.first;
#     139                 :          0 :                 range.first++;
#     140         [ #  # ]:          0 :                 if (_it->second == pindex) {
#     141                 :          0 :                     m_blocks_unlinked.erase(_it);
#     142                 :          0 :                 }
#     143                 :          0 :             }
#     144                 :       1958 :         }
#     145                 :      14013 :     }
#     146                 :            : 
#     147                 :         10 :     m_blockfile_info[fileNumber].SetNull();
#     148                 :         10 :     m_dirty_fileinfo.insert(fileNumber);
#     149                 :         10 : }
#     150                 :            : 
#     151                 :            : void BlockManager::FindFilesToPruneManual(std::set<int>& setFilesToPrune, int nManualPruneHeight, int chain_tip_height)
#     152                 :          3 : {
#     153                 :          3 :     assert(fPruneMode && nManualPruneHeight > 0);
#     154                 :            : 
#     155                 :          3 :     LOCK2(cs_main, cs_LastBlockFile);
#     156         [ -  + ]:          3 :     if (chain_tip_height < 0) {
#     157                 :          0 :         return;
#     158                 :          0 :     }
#     159                 :            : 
#     160                 :            :     // last block to prune is the lesser of (user-specified height, MIN_BLOCKS_TO_KEEP from the tip)
#     161                 :          3 :     unsigned int nLastBlockWeCanPrune = std::min((unsigned)nManualPruneHeight, chain_tip_height - MIN_BLOCKS_TO_KEEP);
#     162                 :          3 :     int count = 0;
#     163         [ +  + ]:         19 :     for (int fileNumber = 0; fileNumber < m_last_blockfile; fileNumber++) {
#     164 [ +  + ][ +  + ]:         16 :         if (m_blockfile_info[fileNumber].nSize == 0 || m_blockfile_info[fileNumber].nHeightLast > nLastBlockWeCanPrune) {
#     165                 :          9 :             continue;
#     166                 :          9 :         }
#     167                 :          7 :         PruneOneBlockFile(fileNumber);
#     168                 :          7 :         setFilesToPrune.insert(fileNumber);
#     169                 :          7 :         count++;
#     170                 :          7 :     }
#     171                 :          3 :     LogPrintf("Prune (Manual): prune_height=%d removed %d blk/rev pairs\n", nLastBlockWeCanPrune, count);
#     172                 :          3 : }
#     173                 :            : 
#     174                 :            : void BlockManager::FindFilesToPrune(std::set<int>& setFilesToPrune, uint64_t nPruneAfterHeight, int chain_tip_height, int prune_height, bool is_ibd)
#     175                 :         56 : {
#     176                 :         56 :     LOCK2(cs_main, cs_LastBlockFile);
#     177 [ +  + ][ -  + ]:         56 :     if (chain_tip_height < 0 || nPruneTarget == 0) {
#     178                 :          2 :         return;
#     179                 :          2 :     }
#     180         [ +  + ]:         54 :     if ((uint64_t)chain_tip_height <= nPruneAfterHeight) {
#     181                 :          5 :         return;
#     182                 :          5 :     }
#     183                 :            : 
#     184                 :         49 :     unsigned int nLastBlockWeCanPrune{(unsigned)std::min(prune_height, chain_tip_height - static_cast<int>(MIN_BLOCKS_TO_KEEP))};
#     185                 :         49 :     uint64_t nCurrentUsage = CalculateCurrentUsage();
#     186                 :            :     // We don't check to prune until after we've allocated new space for files
#     187                 :            :     // So we should leave a buffer under our target to account for another allocation
#     188                 :            :     // before the next pruning.
#     189                 :         49 :     uint64_t nBuffer = BLOCKFILE_CHUNK_SIZE + UNDOFILE_CHUNK_SIZE;
#     190                 :         49 :     uint64_t nBytesToPrune;
#     191                 :         49 :     int count = 0;
#     192                 :            : 
#     193         [ -  + ]:         49 :     if (nCurrentUsage + nBuffer >= nPruneTarget) {
#     194                 :            :         // On a prune event, the chainstate DB is flushed.
#     195                 :            :         // To avoid excessive prune events negating the benefit of high dbcache
#     196                 :            :         // values, we should not prune too rapidly.
#     197                 :            :         // So when pruning in IBD, increase the buffer a bit to avoid a re-prune too soon.
#     198         [ #  # ]:          0 :         if (is_ibd) {
#     199                 :            :             // Since this is only relevant during IBD, we use a fixed 10%
#     200                 :          0 :             nBuffer += nPruneTarget / 10;
#     201                 :          0 :         }
#     202                 :            : 
#     203         [ #  # ]:          0 :         for (int fileNumber = 0; fileNumber < m_last_blockfile; fileNumber++) {
#     204                 :          0 :             nBytesToPrune = m_blockfile_info[fileNumber].nSize + m_blockfile_info[fileNumber].nUndoSize;
#     205                 :            : 
#     206         [ #  # ]:          0 :             if (m_blockfile_info[fileNumber].nSize == 0) {
#     207                 :          0 :                 continue;
#     208                 :          0 :             }
#     209                 :            : 
#     210         [ #  # ]:          0 :             if (nCurrentUsage + nBuffer < nPruneTarget) { // are we below our target?
#     211                 :          0 :                 break;
#     212                 :          0 :             }
#     213                 :            : 
#     214                 :            :             // don't prune files that could have a block within MIN_BLOCKS_TO_KEEP of the main chain's tip but keep scanning
#     215         [ #  # ]:          0 :             if (m_blockfile_info[fileNumber].nHeightLast > nLastBlockWeCanPrune) {
#     216                 :          0 :                 continue;
#     217                 :          0 :             }
#     218                 :            : 
#     219                 :          0 :             PruneOneBlockFile(fileNumber);
#     220                 :            :             // Queue up the files for removal
#     221                 :          0 :             setFilesToPrune.insert(fileNumber);
#     222                 :          0 :             nCurrentUsage -= nBytesToPrune;
#     223                 :          0 :             count++;
#     224                 :          0 :         }
#     225                 :          0 :     }
#     226                 :            : 
#     227         [ +  - ]:         49 :     LogPrint(BCLog::PRUNE, "Prune: target=%dMiB actual=%dMiB diff=%dMiB max_prune_height=%d removed %d blk/rev pairs\n",
#     228                 :         49 :            nPruneTarget/1024/1024, nCurrentUsage/1024/1024,
#     229                 :         49 :            ((int64_t)nPruneTarget - (int64_t)nCurrentUsage)/1024/1024,
#     230                 :         49 :            nLastBlockWeCanPrune, count);
#     231                 :         49 : }
#     232                 :            : 
#     233                 :            : CBlockIndex* BlockManager::InsertBlockIndex(const uint256& hash)
#     234                 :     157348 : {
#     235                 :     157348 :     AssertLockHeld(cs_main);
#     236                 :            : 
#     237         [ +  + ]:     157348 :     if (hash.IsNull()) {
#     238                 :        472 :         return nullptr;
#     239                 :        472 :     }
#     240                 :            : 
#     241                 :     156876 :     const auto [mi, inserted]{m_block_index.try_emplace(hash)};
#     242                 :     156876 :     CBlockIndex* pindex = &(*mi).second;
#     243         [ +  + ]:     156876 :     if (inserted) {
#     244                 :      78672 :         pindex->phashBlock = &((*mi).first);
#     245                 :      78672 :     }
#     246                 :     156876 :     return pindex;
#     247                 :     157348 : }
#     248                 :            : 
#     249                 :            : bool BlockManager::LoadBlockIndex(const Consensus::Params& consensus_params)
#     250                 :        929 : {
#     251         [ -  + ]:     157348 :     if (!m_block_tree_db->LoadBlockIndexGuts(consensus_params, [this](const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { return this->InsertBlockIndex(hash); })) {
#     252                 :          0 :         return false;
#     253                 :          0 :     }
#     254                 :            : 
#     255                 :            :     // Calculate nChainWork
#     256                 :        929 :     std::vector<CBlockIndex*> vSortedByHeight{GetAllBlockIndices()};
#     257                 :        929 :     std::sort(vSortedByHeight.begin(), vSortedByHeight.end(),
#     258                 :        929 :               CBlockIndexHeightOnlyComparator());
#     259                 :            : 
#     260         [ +  + ]:      78874 :     for (CBlockIndex* pindex : vSortedByHeight) {
#     261         [ -  + ]:      78874 :         if (ShutdownRequested()) return false;
#     262         [ +  + ]:      78874 :         pindex->nChainWork = (pindex->pprev ? pindex->pprev->nChainWork : 0) + GetBlockProof(*pindex);
#     263         [ +  + ]:      78874 :         pindex->nTimeMax = (pindex->pprev ? std::max(pindex->pprev->nTimeMax, pindex->nTime) : pindex->nTime);
#     264                 :            : 
#     265                 :            :         // We can link the chain of blocks for which we've received transactions at some point, or
#     266                 :            :         // blocks that are assumed-valid on the basis of snapshot load (see
#     267                 :            :         // PopulateAndValidateSnapshot()).
#     268                 :            :         // Pruned nodes may have deleted the block.
#     269         [ +  + ]:      78874 :         if (pindex->nTx > 0) {
#     270         [ +  + ]:      78325 :             if (pindex->pprev) {
#     271         [ +  - ]:      77853 :                 if (pindex->pprev->nChainTx > 0) {
#     272                 :      77853 :                     pindex->nChainTx = pindex->pprev->nChainTx + pindex->nTx;
#     273                 :      77853 :                 } else {
#     274                 :          0 :                     pindex->nChainTx = 0;
#     275                 :          0 :                     m_blocks_unlinked.insert(std::make_pair(pindex->pprev, pindex));
#     276                 :          0 :                 }
#     277                 :      77853 :             } else {
#     278                 :        472 :                 pindex->nChainTx = pindex->nTx;
#     279                 :        472 :             }
#     280                 :      78325 :         }
#     281 [ +  + ][ +  + ]:      78874 :         if (!(pindex->nStatus & BLOCK_FAILED_MASK) && pindex->pprev && (pindex->pprev->nStatus & BLOCK_FAILED_MASK)) {
#                 [ -  + ]
#     282                 :          0 :             pindex->nStatus |= BLOCK_FAILED_CHILD;
#     283                 :          0 :             m_dirty_blockindex.insert(pindex);
#     284                 :          0 :         }
#     285         [ +  + ]:      78874 :         if (pindex->pprev) {
#     286                 :      78402 :             pindex->BuildSkip();
#     287                 :      78402 :         }
#     288 [ +  + ][ +  + ]:      78874 :         if (pindex->IsValid(BLOCK_VALID_TREE) && (pindexBestHeader == nullptr || CBlockIndexWorkComparator()(pindexBestHeader, pindex)))
#         [ +  + ][ +  + ]
#     289                 :      78659 :             pindexBestHeader = pindex;
#     290                 :      78874 :     }
#     291                 :            : 
#     292                 :        929 :     return true;
#     293                 :        929 : }
#     294                 :            : 
#     295                 :            : void BlockManager::Unload()
#     296                 :       3069 : {
#     297                 :       3069 :     m_blocks_unlinked.clear();
#     298                 :            : 
#     299                 :       3069 :     m_block_index.clear();
#     300                 :            : 
#     301                 :       3069 :     m_blockfile_info.clear();
#     302                 :       3069 :     m_last_blockfile = 0;
#     303                 :       3069 :     m_dirty_blockindex.clear();
#     304                 :       3069 :     m_dirty_fileinfo.clear();
#     305                 :       3069 : }
#     306                 :            : 
#     307                 :            : bool BlockManager::WriteBlockIndexDB()
#     308                 :       1623 : {
#     309                 :       1623 :     AssertLockHeld(::cs_main);
#     310                 :       1623 :     std::vector<std::pair<int, const CBlockFileInfo*>> vFiles;
#     311                 :       1623 :     vFiles.reserve(m_dirty_fileinfo.size());
#     312         [ +  + ]:       2220 :     for (std::set<int>::iterator it = m_dirty_fileinfo.begin(); it != m_dirty_fileinfo.end();) {
#     313                 :        597 :         vFiles.push_back(std::make_pair(*it, &m_blockfile_info[*it]));
#     314                 :        597 :         m_dirty_fileinfo.erase(it++);
#     315                 :        597 :     }
#     316                 :       1623 :     std::vector<const CBlockIndex*> vBlocks;
#     317                 :       1623 :     vBlocks.reserve(m_dirty_blockindex.size());
#     318         [ +  + ]:      64541 :     for (std::set<CBlockIndex*>::iterator it = m_dirty_blockindex.begin(); it != m_dirty_blockindex.end();) {
#     319                 :      62918 :         vBlocks.push_back(*it);
#     320                 :      62918 :         m_dirty_blockindex.erase(it++);
#     321                 :      62918 :     }
#     322         [ -  + ]:       1623 :     if (!m_block_tree_db->WriteBatchSync(vFiles, m_last_blockfile, vBlocks)) {
#     323                 :          0 :         return false;
#     324                 :          0 :     }
#     325                 :       1623 :     return true;
#     326                 :       1623 : }
#     327                 :            : 
#     328                 :            : bool BlockManager::LoadBlockIndexDB()
#     329                 :        929 : {
#     330         [ -  + ]:        929 :     if (!LoadBlockIndex(::Params().GetConsensus())) {
#     331                 :          0 :         return false;
#     332                 :          0 :     }
#     333                 :            : 
#     334                 :            :     // Load block file info
#     335                 :        929 :     m_block_tree_db->ReadLastBlockFile(m_last_blockfile);
#     336                 :        929 :     m_blockfile_info.resize(m_last_blockfile + 1);
#     337                 :        929 :     LogPrintf("%s: last block file = %i\n", __func__, m_last_blockfile);
#     338         [ +  + ]:       1880 :     for (int nFile = 0; nFile <= m_last_blockfile; nFile++) {
#     339                 :        951 :         m_block_tree_db->ReadBlockFileInfo(nFile, m_blockfile_info[nFile]);
#     340                 :        951 :     }
#     341                 :        929 :     LogPrintf("%s: last block file info: %s\n", __func__, m_blockfile_info[m_last_blockfile].ToString());
#     342                 :        929 :     for (int nFile = m_last_blockfile + 1; true; nFile++) {
#     343                 :        929 :         CBlockFileInfo info;
#     344         [ -  + ]:        929 :         if (m_block_tree_db->ReadBlockFileInfo(nFile, info)) {
#     345                 :          0 :             m_blockfile_info.push_back(info);
#     346                 :        929 :         } else {
#     347                 :        929 :             break;
#     348                 :        929 :         }
#     349                 :        929 :     }
#     350                 :            : 
#     351                 :            :     // Check presence of blk files
#     352                 :        929 :     LogPrintf("Checking all blk files are present...\n");
#     353                 :        929 :     std::set<int> setBlkDataFiles;
#     354         [ +  + ]:      78874 :     for (const auto& [_, block_index] : m_block_index) {
#     355         [ +  + ]:      78874 :         if (block_index.nStatus & BLOCK_HAVE_DATA) {
#     356                 :      74799 :             setBlkDataFiles.insert(block_index.nFile);
#     357                 :      74799 :         }
#     358                 :      78874 :     }
#     359         [ +  + ]:       1408 :     for (std::set<int>::iterator it = setBlkDataFiles.begin(); it != setBlkDataFiles.end(); it++) {
#     360                 :        480 :         FlatFilePos pos(*it, 0);
#     361         [ +  + ]:        480 :         if (CAutoFile(OpenBlockFile(pos, true), SER_DISK, CLIENT_VERSION).IsNull()) {
#     362                 :          1 :             return false;
#     363                 :          1 :         }
#     364                 :        480 :     }
#     365                 :            : 
#     366                 :            :     // Check whether we have ever pruned block & undo files
#     367                 :        928 :     m_block_tree_db->ReadFlag("prunedblockfiles", fHavePruned);
#     368         [ +  + ]:        928 :     if (fHavePruned) {
#     369                 :          4 :         LogPrintf("LoadBlockIndexDB(): Block files have previously been pruned\n");
#     370                 :          4 :     }
#     371                 :            : 
#     372                 :            :     // Check whether we need to continue reindexing
#     373                 :        928 :     bool fReindexing = false;
#     374                 :        928 :     m_block_tree_db->ReadReindexing(fReindexing);
#     375         [ -  + ]:        928 :     if (fReindexing) fReindex = true;
#     376                 :            : 
#     377                 :        928 :     return true;
#     378                 :        929 : }
#     379                 :            : 
#     380                 :            : const CBlockIndex* BlockManager::GetLastCheckpoint(const CCheckpointData& data)
#     381                 :      95070 : {
#     382                 :      95070 :     const MapCheckpoints& checkpoints = data.mapCheckpoints;
#     383                 :            : 
#     384         [ +  + ]:      95070 :     for (const MapCheckpoints::value_type& i : reverse_iterate(checkpoints)) {
#     385                 :      95053 :         const uint256& hash = i.second;
#     386                 :      95053 :         const CBlockIndex* pindex = LookupBlockIndex(hash);
#     387         [ +  + ]:      95053 :         if (pindex) {
#     388                 :      94505 :             return pindex;
#     389                 :      94505 :         }
#     390                 :      95053 :     }
#     391                 :        565 :     return nullptr;
#     392                 :      95070 : }
#     393                 :            : 
#     394                 :            : bool IsBlockPruned(const CBlockIndex* pblockindex)
#     395                 :       4335 : {
#     396                 :       4335 :     AssertLockHeld(::cs_main);
#     397 [ -  + ][ #  # ]:       4335 :     return (fHavePruned && !(pblockindex->nStatus & BLOCK_HAVE_DATA) && pblockindex->nTx > 0);
#                 [ #  # ]
#     398                 :       4335 : }
#     399                 :            : 
#     400                 :            : // If we're using -prune with -reindex, then delete block files that will be ignored by the
#     401                 :            : // reindex.  Since reindexing works by starting at block file 0 and looping until a blockfile
#     402                 :            : // is missing, do the same here to delete any later block files after a gap.  Also delete all
#     403                 :            : // rev files since they'll be rewritten by the reindex anyway.  This ensures that m_blockfile_info
#     404                 :            : // is in sync with what's actually on disk by the time we start downloading, so that pruning
#     405                 :            : // works correctly.
#     406                 :            : void CleanupBlockRevFiles()
#     407                 :          1 : {
#     408                 :          1 :     std::map<std::string, fs::path> mapBlockFiles;
#     409                 :            : 
#     410                 :            :     // Glob all blk?????.dat and rev?????.dat files from the blocks directory.
#     411                 :            :     // Remove the rev files immediately and insert the blk file paths into an
#     412                 :            :     // ordered map keyed by block file index.
#     413                 :          1 :     LogPrintf("Removing unusable blk?????.dat and rev?????.dat files for -reindex with -prune\n");
#     414                 :          1 :     fs::path blocksdir = gArgs.GetBlocksDirPath();
#     415         [ +  + ]:          8 :     for (fs::directory_iterator it(blocksdir); it != fs::directory_iterator(); it++) {
#     416                 :          7 :         const std::string path = fs::PathToString(it->path().filename());
#     417 [ +  + ][ +  + ]:          7 :         if (fs::is_regular_file(*it) &&
#     418         [ +  - ]:          7 :             path.length() == 12 &&
#     419         [ +  - ]:          7 :             path.substr(8,4) == ".dat")
#     420                 :          6 :         {
#     421         [ +  + ]:          6 :             if (path.substr(0, 3) == "blk") {
#     422                 :          3 :                 mapBlockFiles[path.substr(3, 5)] = it->path();
#     423         [ +  - ]:          3 :             } else if (path.substr(0, 3) == "rev") {
#     424                 :          3 :                 remove(it->path());
#     425                 :          3 :             }
#     426                 :          6 :         }
#     427                 :          7 :     }
#     428                 :            : 
#     429                 :            :     // Remove all block files that aren't part of a contiguous set starting at
#     430                 :            :     // zero by walking the ordered map (keys are block file indices) by
#     431                 :            :     // keeping a separate counter.  Once we hit a gap (or if 0 doesn't exist)
#     432                 :            :     // start removing block files.
#     433                 :          1 :     int nContigCounter = 0;
#     434         [ +  + ]:          3 :     for (const std::pair<const std::string, fs::path>& item : mapBlockFiles) {
#     435         [ -  + ]:          3 :         if (LocaleIndependentAtoi<int>(item.first) == nContigCounter) {
#     436                 :          0 :             nContigCounter++;
#     437                 :          0 :             continue;
#     438                 :          0 :         }
#     439                 :          3 :         remove(item.second);
#     440                 :          3 :     }
#     441                 :          1 : }
#     442                 :            : 
#     443                 :            : CBlockFileInfo* BlockManager::GetBlockFileInfo(size_t n)
#     444                 :          2 : {
#     445                 :          2 :     LOCK(cs_LastBlockFile);
#     446                 :            : 
#     447                 :          2 :     return &m_blockfile_info.at(n);
#     448                 :          2 : }
#     449                 :            : 
#     450                 :            : static bool UndoWriteToDisk(const CBlockUndo& blockundo, FlatFilePos& pos, const uint256& hashBlock, const CMessageHeader::MessageStartChars& messageStart)
#     451                 :      60074 : {
#     452                 :            :     // Open history file to append
#     453                 :      60074 :     CAutoFile fileout(OpenUndoFile(pos), SER_DISK, CLIENT_VERSION);
#     454         [ -  + ]:      60074 :     if (fileout.IsNull()) {
#     455                 :          0 :         return error("%s: OpenUndoFile failed", __func__);
#     456                 :          0 :     }
#     457                 :            : 
#     458                 :            :     // Write index header
#     459                 :      60074 :     unsigned int nSize = GetSerializeSize(blockundo, fileout.GetVersion());
#     460                 :      60074 :     fileout << messageStart << nSize;
#     461                 :            : 
#     462                 :            :     // Write undo data
#     463                 :      60074 :     long fileOutPos = ftell(fileout.Get());
#     464         [ -  + ]:      60074 :     if (fileOutPos < 0) {
#     465                 :          0 :         return error("%s: ftell failed", __func__);
#     466                 :          0 :     }
#     467                 :      60074 :     pos.nPos = (unsigned int)fileOutPos;
#     468                 :      60074 :     fileout << blockundo;
#     469                 :            : 
#     470                 :            :     // calculate & write checksum
#     471                 :      60074 :     CHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION);
#     472                 :      60074 :     hasher << hashBlock;
#     473                 :      60074 :     hasher << blockundo;
#     474                 :      60074 :     fileout << hasher.GetHash();
#     475                 :            : 
#     476                 :      60074 :     return true;
#     477                 :      60074 : }
#     478                 :            : 
#     479                 :            : bool UndoReadFromDisk(CBlockUndo& blockundo, const CBlockIndex* pindex)
#     480                 :      18458 : {
#     481                 :      18458 :     const FlatFilePos pos{WITH_LOCK(::cs_main, return pindex->GetUndoPos())};
#     482                 :            : 
#     483         [ -  + ]:      18458 :     if (pos.IsNull()) {
#     484                 :          0 :         return error("%s: no undo data available", __func__);
#     485                 :          0 :     }
#     486                 :            : 
#     487                 :            :     // Open history file to read
#     488                 :      18458 :     CAutoFile filein(OpenUndoFile(pos, true), SER_DISK, CLIENT_VERSION);
#     489         [ +  + ]:      18458 :     if (filein.IsNull()) {
#     490                 :          5 :         return error("%s: OpenUndoFile failed", __func__);
#     491                 :          5 :     }
#     492                 :            : 
#     493                 :            :     // Read block
#     494                 :      18453 :     uint256 hashChecksum;
#     495                 :      18453 :     CHashVerifier<CAutoFile> verifier(&filein); // We need a CHashVerifier as reserializing may lose data
#     496                 :      18453 :     try {
#     497                 :      18453 :         verifier << pindex->pprev->GetBlockHash();
#     498                 :      18453 :         verifier >> blockundo;
#     499                 :      18453 :         filein >> hashChecksum;
#     500                 :      18453 :     } catch (const std::exception& e) {
#     501                 :          1 :         return error("%s: Deserialize or I/O error - %s", __func__, e.what());
#     502                 :          1 :     }
#     503                 :            : 
#     504                 :            :     // Verify checksum
#     505         [ -  + ]:      18452 :     if (hashChecksum != verifier.GetHash()) {
#     506                 :          0 :         return error("%s: Checksum mismatch", __func__);
#     507                 :          0 :     }
#     508                 :            : 
#     509                 :      18452 :     return true;
#     510                 :      18452 : }
#     511                 :            : 
#     512                 :            : void BlockManager::FlushUndoFile(int block_file, bool finalize)
#     513                 :       1642 : {
#     514                 :       1642 :     FlatFilePos undo_pos_old(block_file, m_blockfile_info[block_file].nUndoSize);
#     515         [ -  + ]:       1642 :     if (!UndoFileSeq().Flush(undo_pos_old, finalize)) {
#     516                 :          0 :         AbortNode("Flushing undo file to disk failed. This is likely the result of an I/O error.");
#     517                 :          0 :     }
#     518                 :       1642 : }
#     519                 :            : 
#     520                 :            : void BlockManager::FlushBlockFile(bool fFinalize, bool finalize_undo)
#     521                 :       1642 : {
#     522                 :       1642 :     LOCK(cs_LastBlockFile);
#     523                 :       1642 :     FlatFilePos block_pos_old(m_last_blockfile, m_blockfile_info[m_last_blockfile].nSize);
#     524         [ -  + ]:       1642 :     if (!BlockFileSeq().Flush(block_pos_old, fFinalize)) {
#     525                 :          0 :         AbortNode("Flushing block file to disk failed. This is likely the result of an I/O error.");
#     526                 :          0 :     }
#     527                 :            :     // we do not always flush the undo file, as the chain tip may be lagging behind the incoming blocks,
#     528                 :            :     // e.g. during IBD or a sync after a node going offline
#     529 [ +  + ][ +  - ]:       1642 :     if (!fFinalize || finalize_undo) FlushUndoFile(m_last_blockfile, finalize_undo);
#     530                 :       1642 : }
#     531                 :            : 
#     532                 :            : uint64_t BlockManager::CalculateCurrentUsage()
#     533                 :        490 : {
#     534                 :        490 :     LOCK(cs_LastBlockFile);
#     535                 :            : 
#     536                 :        490 :     uint64_t retval = 0;
#     537         [ +  + ]:        728 :     for (const CBlockFileInfo& file : m_blockfile_info) {
#     538                 :        728 :         retval += file.nSize + file.nUndoSize;
#     539                 :        728 :     }
#     540                 :        490 :     return retval;
#     541                 :        490 : }
#     542                 :            : 
#     543                 :            : void UnlinkPrunedFiles(const std::set<int>& setFilesToPrune)
#     544                 :          6 : {
#     545         [ +  + ]:         16 :     for (std::set<int>::iterator it = setFilesToPrune.begin(); it != setFilesToPrune.end(); ++it) {
#     546                 :         10 :         FlatFilePos pos(*it, 0);
#     547                 :         10 :         fs::remove(BlockFileSeq().FileName(pos));
#     548                 :         10 :         fs::remove(UndoFileSeq().FileName(pos));
#     549         [ +  - ]:         10 :         LogPrint(BCLog::BLOCKSTORE, "Prune: %s deleted blk/rev (%05u)\n", __func__, *it);
#     550                 :         10 :     }
#     551                 :          6 : }
#     552                 :            : 
#     553                 :            : static FlatFileSeq BlockFileSeq()
#     554                 :     265595 : {
#     555         [ +  + ]:     265595 :     return FlatFileSeq(gArgs.GetBlocksDirPath(), "blk", gArgs.GetBoolArg("-fastprune", false) ? 0x4000 /* 16kb */ : BLOCKFILE_CHUNK_SIZE);
#     556                 :     265595 : }
#     557                 :            : 
#     558                 :            : static FlatFileSeq UndoFileSeq()
#     559                 :     140258 : {
#     560                 :     140258 :     return FlatFileSeq(gArgs.GetBlocksDirPath(), "rev", UNDOFILE_CHUNK_SIZE);
#     561                 :     140258 : }
#     562                 :            : 
#     563                 :            : FILE* OpenBlockFile(const FlatFilePos& pos, bool fReadOnly)
#     564                 :     200666 : {
#     565                 :     200666 :     return BlockFileSeq().Open(pos, fReadOnly);
#     566                 :     200666 : }
#     567                 :            : 
#     568                 :            : /** Open an undo file (rev?????.dat) */
#     569                 :            : static FILE* OpenUndoFile(const FlatFilePos& pos, bool fReadOnly)
#     570                 :      78532 : {
#     571                 :      78532 :     return UndoFileSeq().Open(pos, fReadOnly);
#     572                 :      78532 : }
#     573                 :            : 
#     574                 :            : fs::path GetBlockPosFilename(const FlatFilePos& pos)
#     575                 :         19 : {
#     576                 :         19 :     return BlockFileSeq().FileName(pos);
#     577                 :         19 : }
#     578                 :            : 
#     579                 :            : bool BlockManager::FindBlockPos(FlatFilePos& pos, unsigned int nAddSize, unsigned int nHeight, CChain& active_chain, uint64_t nTime, bool fKnown)
#     580                 :      64594 : {
#     581                 :      64594 :     LOCK(cs_LastBlockFile);
#     582                 :            : 
#     583         [ +  + ]:      64594 :     unsigned int nFile = fKnown ? pos.nFile : m_last_blockfile;
#     584         [ +  + ]:      64594 :     if (m_blockfile_info.size() <= nFile) {
#     585                 :         13 :         m_blockfile_info.resize(nFile + 1);
#     586                 :         13 :     }
#     587                 :            : 
#     588                 :      64594 :     bool finalize_undo = false;
#     589         [ +  + ]:      64594 :     if (!fKnown) {
#     590 [ +  + ][ +  + ]:      63277 :         while (m_blockfile_info[nFile].nSize + nAddSize >= (gArgs.GetBoolArg("-fastprune", false) ? 0x10000 /* 64kb */ : MAX_BLOCKFILE_SIZE)) {
#     591                 :            :             // when the undo file is keeping up with the block file, we want to flush it explicitly
#     592                 :            :             // when it is lagging behind (more blocks arrive than are being connected), we let the
#     593                 :            :             // undo block write case handle it
#     594                 :         19 :             finalize_undo = (m_blockfile_info[nFile].nHeightLast == (unsigned int)active_chain.Tip()->nHeight);
#     595                 :         19 :             nFile++;
#     596         [ +  - ]:         19 :             if (m_blockfile_info.size() <= nFile) {
#     597                 :         19 :                 m_blockfile_info.resize(nFile + 1);
#     598                 :         19 :             }
#     599                 :         19 :         }
#     600                 :      63258 :         pos.nFile = nFile;
#     601                 :      63258 :         pos.nPos = m_blockfile_info[nFile].nSize;
#     602                 :      63258 :     }
#     603                 :            : 
#     604         [ +  + ]:      64594 :     if ((int)nFile != m_last_blockfile) {
#     605         [ +  - ]:         19 :         if (!fKnown) {
#     606         [ +  - ]:         19 :             LogPrint(BCLog::BLOCKSTORE, "Leaving block file %i: %s\n", m_last_blockfile, m_blockfile_info[m_last_blockfile].ToString());
#     607                 :         19 :         }
#     608                 :         19 :         FlushBlockFile(!fKnown, finalize_undo);
#     609                 :         19 :         m_last_blockfile = nFile;
#     610                 :         19 :     }
#     611                 :            : 
#     612                 :      64594 :     m_blockfile_info[nFile].AddBlock(nHeight, nTime);
#     613         [ +  + ]:      64594 :     if (fKnown) {
#     614                 :       1336 :         m_blockfile_info[nFile].nSize = std::max(pos.nPos + nAddSize, m_blockfile_info[nFile].nSize);
#     615                 :      63258 :     } else {
#     616                 :      63258 :         m_blockfile_info[nFile].nSize += nAddSize;
#     617                 :      63258 :     }
#     618                 :            : 
#     619         [ +  + ]:      64594 :     if (!fKnown) {
#     620                 :      63258 :         bool out_of_space;
#     621                 :      63258 :         size_t bytes_allocated = BlockFileSeq().Allocate(pos, nAddSize, out_of_space);
#     622         [ -  + ]:      63258 :         if (out_of_space) {
#     623                 :          0 :             return AbortNode("Disk space is too low!", _("Disk space is too low!"));
#     624                 :          0 :         }
#     625 [ +  + ][ +  + ]:      63258 :         if (bytes_allocated != 0 && fPruneMode) {
#     626                 :         38 :             m_check_for_pruning = true;
#     627                 :         38 :         }
#     628                 :      63258 :     }
#     629                 :            : 
#     630                 :      64594 :     m_dirty_fileinfo.insert(nFile);
#     631                 :      64594 :     return true;
#     632                 :      64594 : }
#     633                 :            : 
#     634                 :            : bool BlockManager::FindUndoPos(BlockValidationState& state, int nFile, FlatFilePos& pos, unsigned int nAddSize)
#     635                 :      60074 : {
#     636                 :      60074 :     pos.nFile = nFile;
#     637                 :            : 
#     638                 :      60074 :     LOCK(cs_LastBlockFile);
#     639                 :            : 
#     640                 :      60074 :     pos.nPos = m_blockfile_info[nFile].nUndoSize;
#     641                 :      60074 :     m_blockfile_info[nFile].nUndoSize += nAddSize;
#     642                 :      60074 :     m_dirty_fileinfo.insert(nFile);
#     643                 :            : 
#     644                 :      60074 :     bool out_of_space;
#     645                 :      60074 :     size_t bytes_allocated = UndoFileSeq().Allocate(pos, nAddSize, out_of_space);
#     646         [ -  + ]:      60074 :     if (out_of_space) {
#     647                 :          0 :         return AbortNode(state, "Disk space is too low!", _("Disk space is too low!"));
#     648                 :          0 :     }
#     649 [ +  + ][ +  + ]:      60074 :     if (bytes_allocated != 0 && fPruneMode) {
#     650                 :         10 :         m_check_for_pruning = true;
#     651                 :         10 :     }
#     652                 :            : 
#     653                 :      60074 :     return true;
#     654                 :      60074 : }
#     655                 :            : 
#     656                 :            : static bool WriteBlockToDisk(const CBlock& block, FlatFilePos& pos, const CMessageHeader::MessageStartChars& messageStart)
#     657                 :      63258 : {
#     658                 :            :     // Open history file to append
#     659                 :      63258 :     CAutoFile fileout(OpenBlockFile(pos), SER_DISK, CLIENT_VERSION);
#     660         [ -  + ]:      63258 :     if (fileout.IsNull()) {
#     661                 :          0 :         return error("WriteBlockToDisk: OpenBlockFile failed");
#     662                 :          0 :     }
#     663                 :            : 
#     664                 :            :     // Write index header
#     665                 :      63258 :     unsigned int nSize = GetSerializeSize(block, fileout.GetVersion());
#     666                 :      63258 :     fileout << messageStart << nSize;
#     667                 :            : 
#     668                 :            :     // Write block
#     669                 :      63258 :     long fileOutPos = ftell(fileout.Get());
#     670         [ -  + ]:      63258 :     if (fileOutPos < 0) {
#     671                 :          0 :         return error("WriteBlockToDisk: ftell failed");
#     672                 :          0 :     }
#     673                 :      63258 :     pos.nPos = (unsigned int)fileOutPos;
#     674                 :      63258 :     fileout << block;
#     675                 :            : 
#     676                 :      63258 :     return true;
#     677                 :      63258 : }
#     678                 :            : 
#     679                 :            : bool BlockManager::WriteUndoDataForBlock(const CBlockUndo& blockundo, BlockValidationState& state, CBlockIndex* pindex, const CChainParams& chainparams)
#     680                 :      61743 : {
#     681                 :      61743 :     AssertLockHeld(::cs_main);
#     682                 :            :     // Write undo information to disk
#     683         [ +  + ]:      61743 :     if (pindex->GetUndoPos().IsNull()) {
#     684                 :      60074 :         FlatFilePos _pos;
#     685         [ -  + ]:      60074 :         if (!FindUndoPos(state, pindex->nFile, _pos, ::GetSerializeSize(blockundo, CLIENT_VERSION) + 40)) {
#     686                 :          0 :             return error("ConnectBlock(): FindUndoPos failed");
#     687                 :          0 :         }
#     688         [ -  + ]:      60074 :         if (!UndoWriteToDisk(blockundo, _pos, pindex->pprev->GetBlockHash(), chainparams.MessageStart())) {
#     689                 :          0 :             return AbortNode(state, "Failed to write undo data");
#     690                 :          0 :         }
#     691                 :            :         // rev files are written in block height order, whereas blk files are written as blocks come in (often out of order)
#     692                 :            :         // we want to flush the rev (undo) file once we've written the last block, which is indicated by the last height
#     693                 :            :         // in the block file info as below; note that this does not catch the case where the undo writes are keeping up
#     694                 :            :         // with the block writes (usually when a synced up node is getting newly mined blocks) -- this case is caught in
#     695                 :            :         // the FindBlockPos function
#     696 [ -  + ][ #  # ]:      60074 :         if (_pos.nFile < m_last_blockfile && static_cast<uint32_t>(pindex->nHeight) == m_blockfile_info[_pos.nFile].nHeightLast) {
#     697                 :          0 :             FlushUndoFile(_pos.nFile, true);
#     698                 :          0 :         }
#     699                 :            : 
#     700                 :            :         // update nUndoPos in block index
#     701                 :      60074 :         pindex->nUndoPos = _pos.nPos;
#     702                 :      60074 :         pindex->nStatus |= BLOCK_HAVE_UNDO;
#     703                 :      60074 :         m_dirty_blockindex.insert(pindex);
#     704                 :      60074 :     }
#     705                 :            : 
#     706                 :      61743 :     return true;
#     707                 :      61743 : }
#     708                 :            : 
#     709                 :            : bool ReadBlockFromDisk(CBlock& block, const FlatFilePos& pos, const Consensus::Params& consensusParams)
#     710                 :     126848 : {
#     711                 :     126848 :     block.SetNull();
#     712                 :            : 
#     713                 :            :     // Open history file to read
#     714                 :     126848 :     CAutoFile filein(OpenBlockFile(pos, true), SER_DISK, CLIENT_VERSION);
#     715         [ +  + ]:     126848 :     if (filein.IsNull()) {
#     716                 :        109 :         return error("ReadBlockFromDisk: OpenBlockFile failed for %s", pos.ToString());
#     717                 :        109 :     }
#     718                 :            : 
#     719                 :            :     // Read block
#     720                 :     126739 :     try {
#     721                 :     126739 :         filein >> block;
#     722                 :     126739 :     } catch (const std::exception& e) {
#     723                 :          0 :         return error("%s: Deserialize or I/O error - %s at %s", __func__, e.what(), pos.ToString());
#     724                 :          0 :     }
#     725                 :            : 
#     726                 :            :     // Check the header
#     727         [ -  + ]:     126739 :     if (!CheckProofOfWork(block.GetHash(), block.nBits, consensusParams)) {
#     728                 :          0 :         return error("ReadBlockFromDisk: Errors in block header at %s", pos.ToString());
#     729                 :          0 :     }
#     730                 :            : 
#     731                 :            :     // Signet only: check block solution
#     732 [ +  + ][ -  + ]:     126739 :     if (consensusParams.signet_blocks && !CheckSignetBlockSolution(block, consensusParams)) {
#     733                 :          0 :         return error("ReadBlockFromDisk: Errors in block solution at %s", pos.ToString());
#     734                 :          0 :     }
#     735                 :            : 
#     736                 :     126739 :     return true;
#     737                 :     126739 : }
#     738                 :            : 
#     739                 :            : bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex, const Consensus::Params& consensusParams)
#     740                 :     126607 : {
#     741                 :     126607 :     const FlatFilePos block_pos{WITH_LOCK(cs_main, return pindex->GetBlockPos())};
#     742                 :            : 
#     743         [ +  + ]:     126607 :     if (!ReadBlockFromDisk(block, block_pos, consensusParams)) {
#     744                 :        109 :         return false;
#     745                 :        109 :     }
#     746         [ -  + ]:     126498 :     if (block.GetHash() != pindex->GetBlockHash()) {
#     747                 :          0 :         return error("ReadBlockFromDisk(CBlock&, CBlockIndex*): GetHash() doesn't match index for %s at %s",
#     748                 :          0 :                      pindex->ToString(), block_pos.ToString());
#     749                 :          0 :     }
#     750                 :     126498 :     return true;
#     751                 :     126498 : }
#     752                 :            : 
#     753                 :            : bool ReadRawBlockFromDisk(std::vector<uint8_t>& block, const FlatFilePos& pos, const CMessageHeader::MessageStartChars& message_start)
#     754                 :       9829 : {
#     755                 :       9829 :     FlatFilePos hpos = pos;
#     756                 :       9829 :     hpos.nPos -= 8; // Seek back 8 bytes for meta header
#     757                 :       9829 :     CAutoFile filein(OpenBlockFile(hpos, true), SER_DISK, CLIENT_VERSION);
#     758         [ -  + ]:       9829 :     if (filein.IsNull()) {
#     759                 :          0 :         return error("%s: OpenBlockFile failed for %s", __func__, pos.ToString());
#     760                 :          0 :     }
#     761                 :            : 
#     762                 :       9829 :     try {
#     763                 :       9829 :         CMessageHeader::MessageStartChars blk_start;
#     764                 :       9829 :         unsigned int blk_size;
#     765                 :            : 
#     766                 :       9829 :         filein >> blk_start >> blk_size;
#     767                 :            : 
#     768         [ -  + ]:       9829 :         if (memcmp(blk_start, message_start, CMessageHeader::MESSAGE_START_SIZE)) {
#     769                 :          0 :             return error("%s: Block magic mismatch for %s: %s versus expected %s", __func__, pos.ToString(),
#     770                 :          0 :                          HexStr(blk_start),
#     771                 :          0 :                          HexStr(message_start));
#     772                 :          0 :         }
#     773                 :            : 
#     774         [ -  + ]:       9829 :         if (blk_size > MAX_SIZE) {
#     775                 :          0 :             return error("%s: Block data is larger than maximum deserialization size for %s: %s versus %s", __func__, pos.ToString(),
#     776                 :          0 :                          blk_size, MAX_SIZE);
#     777                 :          0 :         }
#     778                 :            : 
#     779                 :       9829 :         block.resize(blk_size); // Zeroing of memory is intentional here
#     780                 :       9829 :         filein.read(MakeWritableByteSpan(block));
#     781                 :       9829 :     } catch (const std::exception& e) {
#     782                 :          0 :         return error("%s: Read from block file failed: %s for %s", __func__, e.what(), pos.ToString());
#     783                 :          0 :     }
#     784                 :            : 
#     785                 :       9829 :     return true;
#     786                 :       9829 : }
#     787                 :            : 
#     788                 :            : /** Store block on disk. If dbp is non-nullptr, the file is known to already reside on disk */
#     789                 :            : FlatFilePos BlockManager::SaveBlockToDisk(const CBlock& block, int nHeight, CChain& active_chain, const CChainParams& chainparams, const FlatFilePos* dbp)
#     790                 :      64594 : {
#     791                 :      64594 :     unsigned int nBlockSize = ::GetSerializeSize(block, CLIENT_VERSION);
#     792                 :      64594 :     FlatFilePos blockPos;
#     793         [ +  + ]:      64594 :     if (dbp != nullptr) {
#     794                 :       1336 :         blockPos = *dbp;
#     795                 :       1336 :     }
#     796         [ -  + ]:      64594 :     if (!FindBlockPos(blockPos, nBlockSize + 8, nHeight, active_chain, block.GetBlockTime(), dbp != nullptr)) {
#     797                 :          0 :         error("%s: FindBlockPos failed", __func__);
#     798                 :          0 :         return FlatFilePos();
#     799                 :          0 :     }
#     800         [ +  + ]:      64594 :     if (dbp == nullptr) {
#     801         [ -  + ]:      63258 :         if (!WriteBlockToDisk(block, blockPos, chainparams.MessageStart())) {
#     802                 :          0 :             AbortNode("Failed to write block");
#     803                 :          0 :             return FlatFilePos();
#     804                 :          0 :         }
#     805                 :      63258 :     }
#     806                 :      64594 :     return blockPos;
#     807                 :      64594 : }
#     808                 :            : 
#     809                 :            : struct CImportingNow {
#     810                 :            :     CImportingNow()
#     811                 :        725 :     {
#     812                 :        725 :         assert(fImporting == false);
#     813                 :          0 :         fImporting = true;
#     814                 :        725 :     }
#     815                 :            : 
#     816                 :            :     ~CImportingNow()
#     817                 :        725 :     {
#     818                 :        725 :         assert(fImporting == true);
#     819                 :          0 :         fImporting = false;
#     820                 :        725 :     }
#     821                 :            : };
#     822                 :            : 
#     823                 :            : void ThreadImport(ChainstateManager& chainman, std::vector<fs::path> vImportFiles, const ArgsManager& args)
#     824                 :        725 : {
#     825                 :        725 :     SetSyscallSandboxPolicy(SyscallSandboxPolicy::INITIALIZATION_LOAD_BLOCKS);
#     826                 :        725 :     ScheduleBatchPriority();
#     827                 :            : 
#     828                 :        725 :     {
#     829                 :        725 :         CImportingNow imp;
#     830                 :            : 
#     831                 :            :         // -reindex
#     832         [ +  + ]:        725 :         if (fReindex) {
#     833                 :         10 :             int nFile = 0;
#     834                 :         19 :             while (true) {
#     835                 :         19 :                 FlatFilePos pos(nFile, 0);
#     836         [ +  + ]:         19 :                 if (!fs::exists(GetBlockPosFilename(pos))) {
#     837                 :         10 :                     break; // No block files left to reindex
#     838                 :         10 :                 }
#     839                 :          9 :                 FILE* file = OpenBlockFile(pos, true);
#     840         [ -  + ]:          9 :                 if (!file) {
#     841                 :          0 :                     break; // This error is logged in OpenBlockFile
#     842                 :          0 :                 }
#     843                 :          9 :                 LogPrintf("Reindexing block file blk%05u.dat...\n", (unsigned int)nFile);
#     844                 :          9 :                 chainman.ActiveChainstate().LoadExternalBlockFile(file, &pos);
#     845         [ -  + ]:          9 :                 if (ShutdownRequested()) {
#     846                 :          0 :                     LogPrintf("Shutdown requested. Exit %s\n", __func__);
#     847                 :          0 :                     return;
#     848                 :          0 :                 }
#     849                 :          9 :                 nFile++;
#     850                 :          9 :             }
#     851                 :         10 :             WITH_LOCK(::cs_main, chainman.m_blockman.m_block_tree_db->WriteReindexing(false));
#     852                 :         10 :             fReindex = false;
#     853                 :         10 :             LogPrintf("Reindexing finished\n");
#     854                 :            :             // To avoid ending up in a situation without genesis block, re-try initializing (no-op if reindexing worked):
#     855                 :         10 :             chainman.ActiveChainstate().LoadGenesisBlock();
#     856                 :         10 :         }
#     857                 :            : 
#     858                 :            :         // -loadblock=
#     859         [ +  + ]:        725 :         for (const fs::path& path : vImportFiles) {
#     860                 :          1 :             FILE* file = fsbridge::fopen(path, "rb");
#     861         [ +  - ]:          1 :             if (file) {
#     862                 :          1 :                 LogPrintf("Importing blocks file %s...\n", fs::PathToString(path));
#     863                 :          1 :                 chainman.ActiveChainstate().LoadExternalBlockFile(file);
#     864         [ -  + ]:          1 :                 if (ShutdownRequested()) {
#     865                 :          0 :                     LogPrintf("Shutdown requested. Exit %s\n", __func__);
#     866                 :          0 :                     return;
#     867                 :          0 :                 }
#     868                 :          1 :             } else {
#     869                 :          0 :                 LogPrintf("Warning: Could not open blocks file %s\n", fs::PathToString(path));
#     870                 :          0 :             }
#     871                 :          1 :         }
#     872                 :            : 
#     873                 :            :         // scan for better chains in the block chain database, that are not yet connected in the active best chain
#     874                 :            : 
#     875                 :            :         // We can't hold cs_main during ActivateBestChain even though we're accessing
#     876                 :            :         // the chainman unique_ptrs since ABC requires us not to be holding cs_main, so retrieve
#     877                 :            :         // the relevant pointers before the ABC call.
#     878         [ +  + ]:        725 :         for (CChainState* chainstate : WITH_LOCK(::cs_main, return chainman.GetAll())) {
#     879                 :        725 :             BlockValidationState state;
#     880         [ -  + ]:        725 :             if (!chainstate->ActivateBestChain(state, nullptr)) {
#     881                 :          0 :                 LogPrintf("Failed to connect best block (%s)\n", state.ToString());
#     882                 :          0 :                 StartShutdown();
#     883                 :          0 :                 return;
#     884                 :          0 :             }
#     885                 :        725 :         }
#     886                 :            : 
#     887         [ -  + ]:        725 :         if (args.GetBoolArg("-stopafterblockimport", DEFAULT_STOPAFTERBLOCKIMPORT)) {
#     888                 :          0 :             LogPrintf("Stopping after block import\n");
#     889                 :          0 :             StartShutdown();
#     890                 :          0 :             return;
#     891                 :          0 :         }
#     892                 :        725 :     } // End scope of CImportingNow
#     893                 :        725 :     chainman.ActiveChainstate().LoadMempool(args);
#     894                 :        725 : }
#     895                 :            : } // namespace node

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