LCOV - code coverage report
Current view: top level - src/test - coinsviewoverlay_tests.cpp (source / functions) Coverage Total Hit
Test: test_bitcoin_coverage.info Lines: 94.4 % 196 185
Test Date: 2026-07-17 06:52:43 Functions: 100.0 % 22 22
Branches: 52.0 % 986 513

             Branch data     Line data    Source code
       1                 :             : // Copyright (c) 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 <coins.h>
       6                 :             : #include <kernel/chainstatemanager_opts.h>
       7                 :             : #include <primitives/block.h>
       8                 :             : #include <primitives/transaction.h>
       9                 :             : #include <primitives/transaction_identifier.h>
      10                 :             : #include <txdb.h>
      11                 :             : #include <uint256.h>
      12                 :             : #include <util/byte_units.h>
      13                 :             : #include <util/hasher.h>
      14                 :             : #include <util/threadpool.h>
      15                 :             : 
      16                 :             : #include <boost/test/unit_test.hpp>
      17                 :             : 
      18                 :             : #include <cstdint>
      19                 :             : #include <cstring>
      20                 :             : #include <memory>
      21                 :             : #include <ranges>
      22                 :             : #include <unordered_set>
      23                 :             : #include <vector>
      24                 :             : 
      25                 :             : namespace {
      26                 :             : 
      27                 :           7 : std::shared_ptr<ThreadPool> MakeStartedThreadPool()
      28                 :             : {
      29                 :           7 :     auto pool{std::make_shared<ThreadPool>("fetch_test")};
      30         [ +  - ]:           7 :     pool->Start(DEFAULT_PREVOUTFETCH_THREADS);
      31                 :           7 :     return pool;
      32                 :           0 : }
      33                 :             : 
      34                 :           8 : CBlock CreateBlock() noexcept
      35                 :             : {
      36                 :           8 :     static constexpr auto NUM_TXS{100};
      37                 :           8 :     CBlock block;
      38                 :           8 :     CMutableTransaction coinbase;
      39                 :           8 :     coinbase.vin.emplace_back();
      40         [ -  + ]:           8 :     block.vtx.push_back(MakeTransactionRef(coinbase));
      41                 :             : 
      42                 :           8 :     Txid prevhash{Txid::FromUint256(uint256{1})};
      43                 :             : 
      44         [ +  + ]:         800 :     for (const auto i : std::views::iota(1, NUM_TXS)) {
      45                 :         792 :         CMutableTransaction tx;
      46         [ +  + ]:         792 :         const Txid txid{i % 20 == 0 ? prevhash : Txid::FromUint256(uint256(i))};
      47                 :         792 :         tx.vin.emplace_back(txid, 0);
      48                 :         792 :         prevhash = tx.GetHash();
      49         [ -  + ]:         792 :         block.vtx.push_back(MakeTransactionRef(tx));
      50                 :         792 :     }
      51                 :             : 
      52                 :           8 :     return block;
      53                 :           8 : }
      54                 :             : 
      55                 :           8 : void PopulateView(const CBlock& block, CCoinsView& view, bool spent = false)
      56                 :             : {
      57                 :           8 :     CCoinsViewCache cache{&view};
      58         [ +  - ]:           8 :     cache.SetBestBlock(uint256::ONE);
      59                 :             : 
      60         [ +  - ]:           8 :     std::unordered_set<Txid, SaltedTxidHasher> txids{};
      61   [ -  +  +  - ]:           8 :     txids.reserve(block.vtx.size() - 1);
      62         [ +  + ]:         800 :     for (const auto& tx : block.vtx | std::views::drop(1)) {
      63         [ +  + ]:        1584 :         for (const auto& in : tx->vin) {
      64         [ +  + ]:         792 :             if (txids.contains(in.prevout.hash)) continue;
      65                 :         760 :             Coin coin{};
      66         [ +  + ]:         760 :             if (!spent) coin.out.nValue = 1;
      67         [ +  - ]:         760 :             cache.EmplaceCoinInternalDANGER(COutPoint{in.prevout}, std::move(coin));
      68                 :         760 :         }
      69         [ +  - ]:         792 :         txids.emplace(tx->GetHash());
      70                 :             :     }
      71                 :             : 
      72         [ +  - ]:           8 :     cache.Flush();
      73                 :           8 : }
      74                 :             : 
      75                 :           8 : void CheckCache(const CBlock& block, const CCoinsViewCache& cache)
      76                 :             : {
      77                 :           8 :     uint32_t counter{0};
      78                 :           8 :     std::unordered_set<Txid, SaltedTxidHasher> txids{};
      79   [ -  +  +  - ]:           8 :     txids.reserve(block.vtx.size() - 1);
      80                 :             : 
      81         [ +  + ]:         808 :     for (const auto& tx : block.vtx) {
      82         [ +  + ]:         800 :         if (tx->IsCoinBase()) {
      83   [ +  -  +  -  :          16 :             BOOST_CHECK(!cache.HaveCoinInCache(tx->vin[0].prevout));
             +  -  +  - ]
      84                 :             :         } else {
      85         [ +  + ]:        1584 :             for (const auto& in : tx->vin) {
      86                 :         792 :                 const auto& outpoint{in.prevout};
      87         [ +  - ]:         792 :                 const auto& first{cache.AccessCoin(outpoint)};
      88         [ +  - ]:         792 :                 const auto& second{cache.AccessCoin(outpoint)};
      89   [ +  -  +  - ]:         792 :                 BOOST_CHECK_EQUAL(&first, &second);
      90         [ +  - ]:         792 :                 const auto have{cache.HaveCoinInCache(outpoint)};
      91   [ +  -  +  - ]:         792 :                 BOOST_CHECK_NE(txids.contains(outpoint.hash), have);
      92                 :         792 :                 counter += have;
      93                 :             :             }
      94         [ +  - ]:         792 :             txids.emplace(tx->GetHash());
      95                 :             :         }
      96                 :             :     }
      97   [ +  -  +  -  :           8 :     BOOST_CHECK_EQUAL(cache.GetCacheSize(), counter);
                   +  - ]
      98                 :           8 : }
      99                 :             : 
     100                 :             : } // namespace
     101                 :             : 
     102                 :             : BOOST_AUTO_TEST_SUITE(coinsviewoverlay_tests)
     103                 :             : 
     104   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(fetch_inputs_from_db)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  -  +  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          -  +  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
     105                 :             : {
     106                 :           1 :     const auto block{CreateBlock()};
     107                 :           0 :     CCoinsViewDB db{{.path = "", .cache_bytes = 1_MiB, .memory_only = true}, {}};
     108         [ +  - ]:           1 :     PopulateView(block, db);
     109         [ +  - ]:           1 :     CCoinsViewCache main_cache{&db};
     110   [ +  -  -  + ]:           1 :     CoinsViewOverlay view{&main_cache, MakeStartedThreadPool()};
     111                 :           1 :     const auto reset_guard{view.StartFetching(block)};
     112         [ +  - ]:           1 :     const auto& outpoint{block.vtx[1]->vin[0].prevout};
     113                 :             : 
     114   [ +  -  +  -  :           2 :     BOOST_CHECK(view.HaveCoin(outpoint));
             +  -  +  - ]
     115   [ +  -  +  -  :           2 :     BOOST_CHECK(view.GetCoin(outpoint).has_value());
             +  -  +  - ]
     116   [ +  -  +  -  :           2 :     BOOST_CHECK(!main_cache.HaveCoinInCache(outpoint));
             +  -  +  - ]
     117                 :             : 
     118         [ +  - ]:           1 :     CheckCache(block, view);
     119                 :             :     // Check that no coins have been moved up to main cache from db
     120         [ +  + ]:         101 :     for (const auto& tx : block.vtx) {
     121         [ +  + ]:         200 :         for (const auto& in : tx->vin) {
     122   [ +  -  +  -  :         200 :             BOOST_CHECK(!main_cache.HaveCoinInCache(in.prevout));
                   +  - ]
     123                 :             :         }
     124                 :             :     }
     125                 :             : 
     126         [ +  - ]:           1 :     view.SetBestBlock(uint256::ONE);
     127   [ +  -  +  -  :           2 :     BOOST_CHECK(view.SpendCoin(outpoint));
             +  -  +  - ]
     128         [ +  - ]:           1 :     view.Flush();
     129   [ +  -  +  -  :           2 :     BOOST_CHECK(!main_cache.PeekCoin(outpoint).has_value());
                   +  - ]
     130   [ +  -  +  - ]:           2 : }
     131                 :             : 
     132   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(fetch_inputs_from_cache)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  -  +  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          -  +  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
     133                 :             : {
     134                 :           1 :     const auto block{CreateBlock()};
     135                 :           0 :     CCoinsViewDB db{{.path = "", .cache_bytes = 1_MiB, .memory_only = true}, {}};
     136         [ +  - ]:           1 :     CCoinsViewCache main_cache{&db};
     137         [ +  - ]:           1 :     PopulateView(block, main_cache);
     138   [ +  -  -  + ]:           1 :     CoinsViewOverlay view{&main_cache, MakeStartedThreadPool()};
     139                 :           1 :     const auto reset_guard{view.StartFetching(block)};
     140         [ +  - ]:           1 :     CheckCache(block, view);
     141                 :             : 
     142         [ +  - ]:           1 :     const auto& outpoint{block.vtx[1]->vin[0].prevout};
     143         [ +  - ]:           1 :     view.SetBestBlock(uint256::ONE);
     144   [ +  -  +  -  :           2 :     BOOST_CHECK(view.SpendCoin(outpoint));
             +  -  +  - ]
     145         [ +  - ]:           1 :     view.Flush();
     146   [ +  -  +  -  :           2 :     BOOST_CHECK(!main_cache.PeekCoin(outpoint).has_value());
                   +  - ]
     147   [ +  -  +  - ]:           2 : }
     148                 :             : 
     149                 :             : // Test for the case where a block spends coins that are spent in the cache, but
     150                 :             : // the spentness has not been flushed to the db.
     151   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(fetch_no_double_spend)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  -  +  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          -  +  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
     152                 :             : {
     153                 :           1 :     const auto block{CreateBlock()};
     154                 :           0 :     CCoinsViewDB db{{.path = "", .cache_bytes = 1_MiB, .memory_only = true}, {}};
     155         [ +  - ]:           1 :     PopulateView(block, db);
     156         [ +  - ]:           1 :     CCoinsViewCache main_cache{&db};
     157                 :             :     // Add all inputs as spent already in cache
     158         [ +  - ]:           1 :     PopulateView(block, main_cache, /*spent=*/true);
     159   [ +  -  -  + ]:           1 :     CoinsViewOverlay view{&main_cache, MakeStartedThreadPool()};
     160                 :           1 :     const auto reset_guard{view.StartFetching(block)};
     161         [ +  + ]:         101 :     for (const auto& tx : block.vtx) {
     162         [ +  + ]:         200 :         for (const auto& in : tx->vin) {
     163         [ +  - ]:         100 :             const auto& c{view.AccessCoin(in.prevout)};
     164   [ +  -  +  -  :         200 :             BOOST_CHECK(c.IsSpent());
                   +  - ]
     165   [ +  -  +  -  :         200 :             BOOST_CHECK(!view.HaveCoin(in.prevout));
             +  -  +  - ]
     166   [ +  -  +  -  :         200 :             BOOST_CHECK(!view.GetCoin(in.prevout));
                   +  - ]
     167                 :             :         }
     168                 :             :     }
     169                 :             :     // Coins are not added to the view, even though they exist unspent in the parent db
     170   [ +  -  +  -  :           1 :     BOOST_CHECK_EQUAL(view.GetCacheSize(), 0);
                   +  - ]
     171   [ +  -  +  - ]:           2 : }
     172                 :             : 
     173   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(fetch_no_inputs)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  -  +  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          -  +  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
     174                 :             : {
     175                 :           1 :     const auto block{CreateBlock()};
     176                 :           0 :     CCoinsViewDB db{{.path = "", .cache_bytes = 1_MiB, .memory_only = true}, {}};
     177         [ +  - ]:           1 :     CCoinsViewCache main_cache{&db};
     178   [ +  -  -  + ]:           1 :     CoinsViewOverlay view{&main_cache, MakeStartedThreadPool()};
     179                 :           1 :     const auto reset_guard{view.StartFetching(block)};
     180         [ +  + ]:         101 :     for (const auto& tx : block.vtx) {
     181         [ +  + ]:         200 :         for (const auto& in : tx->vin) {
     182         [ +  - ]:         100 :             const auto& c{view.AccessCoin(in.prevout)};
     183   [ +  -  +  -  :         200 :             BOOST_CHECK(c.IsSpent());
                   +  - ]
     184   [ +  -  +  -  :         200 :             BOOST_CHECK(!view.HaveCoin(in.prevout));
             +  -  +  - ]
     185   [ +  -  +  -  :         200 :             BOOST_CHECK(!view.GetCoin(in.prevout));
                   +  - ]
     186                 :             :         }
     187                 :             :     }
     188   [ +  -  +  -  :           1 :     BOOST_CHECK_EQUAL(view.GetCacheSize(), 0);
                   +  - ]
     189   [ +  -  +  - ]:           2 : }
     190                 :             : 
     191                 :             : // Access coins that are not block inputs
     192   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(access_non_input_coins)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  -  +  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          -  +  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
     193                 :             : {
     194                 :           1 :     CBlock block;
     195         [ +  - ]:           1 :     CMutableTransaction coinbase;
     196         [ +  - ]:           1 :     coinbase.vin.emplace_back();
     197   [ +  -  +  -  :           2 :     block.vtx.push_back(MakeTransactionRef(coinbase));
                   -  + ]
     198                 :           0 :     CCoinsViewDB db{{.path = "", .cache_bytes = 1_MiB, .memory_only = true}, {}};
     199         [ +  - ]:           1 :     CCoinsViewCache main_cache{&db};
     200                 :           1 :     Coin coin{};
     201                 :           1 :     coin.out.nValue = 1;
     202         [ +  - ]:           1 :     const COutPoint outpoint{Txid::FromUint256(uint256::ZERO), 0};
     203         [ +  - ]:           1 :     main_cache.EmplaceCoinInternalDANGER(COutPoint{outpoint}, std::move(coin));
     204                 :             : 
     205   [ +  -  -  + ]:           1 :     CoinsViewOverlay view{&main_cache, MakeStartedThreadPool()};
     206                 :           1 :     const auto reset_guard{view.StartFetching(block)};
     207                 :             : 
     208                 :             :     // Non-input fallback hit.
     209   [ +  -  +  -  :           2 :     BOOST_CHECK(!view.AccessCoin(outpoint).IsSpent());
             +  -  +  - ]
     210                 :             : 
     211                 :             :     // Non-input fallback miss.
     212         [ +  - ]:           1 :     const COutPoint missing_outpoint{Txid::FromUint256(uint256::ONE), 0};
     213   [ +  -  +  -  :           2 :     BOOST_CHECK(view.AccessCoin(missing_outpoint).IsSpent());
             +  -  +  - ]
     214   [ +  -  +  -  :           2 :     BOOST_CHECK(!view.HaveCoinInCache(missing_outpoint));
                   +  - ]
     215   [ +  -  +  - ]:           3 : }
     216                 :             : 
     217                 :             : // Access a fetched input out of order (i.e. not the next one in m_inputs).
     218                 :             : // FetchCoinFromBase must fall back to base->PeekCoin, and the coin must still
     219                 :             : // be inserted into the cache.
     220   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(fetch_out_of_order_input_uses_normal_lookup)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  -  +  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          -  +  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
     221                 :             : {
     222                 :           1 :     const auto block{CreateBlock()};
     223                 :           0 :     CCoinsViewDB db{{.path = "", .cache_bytes = 1_MiB, .memory_only = true}, {}};
     224         [ +  - ]:           1 :     CCoinsViewCache main_cache{&db};
     225         [ +  - ]:           1 :     PopulateView(block, main_cache);
     226                 :             : 
     227                 :           1 :     std::vector<COutPoint> fetched_inputs;
     228         [ +  - ]:           1 :     std::unordered_set<Txid, SaltedTxidHasher> txids;
     229   [ -  +  +  - ]:           1 :     txids.reserve(block.vtx.size() - 1);
     230         [ +  + ]:         100 :     for (const auto& tx : block.vtx | std::views::drop(1)) {
     231         [ +  + ]:         198 :         for (const auto& input : tx->vin) {
     232   [ +  +  +  - ]:          99 :             if (!txids.contains(input.prevout.hash)) fetched_inputs.push_back(input.prevout);
     233                 :             :         }
     234         [ +  - ]:          99 :         txids.emplace(tx->GetHash());
     235                 :             :     }
     236   [ +  -  -  +  :           1 :     BOOST_REQUIRE_GE(fetched_inputs.size(), 2U);
                   +  - ]
     237                 :             : 
     238   [ +  -  -  + ]:           1 :     CoinsViewOverlay view{&main_cache, MakeStartedThreadPool()};
     239                 :           1 :     const auto reset_guard{view.StartFetching(block)};
     240                 :             : 
     241         [ +  - ]:           1 :     const auto& out_of_order_input{fetched_inputs[1]};
     242   [ +  -  +  -  :           2 :     BOOST_CHECK(!view.HaveCoinInCache(out_of_order_input));
             +  -  +  - ]
     243   [ +  -  +  -  :           2 :     BOOST_CHECK(!view.AccessCoin(out_of_order_input).IsSpent());
             +  -  +  - ]
     244   [ +  -  +  -  :           2 :     BOOST_CHECK(view.HaveCoinInCache(out_of_order_input));
             +  -  +  - ]
     245                 :             : 
     246         [ +  - ]:           1 :     CheckCache(block, view);
     247   [ +  -  +  - ]:           2 : }
     248                 :             : 
     249                 :             : // The ResetGuard returned by StartFetching must clear all per-block state when
     250                 :             : // it goes out of scope, so the overlay can be reused for a subsequent block.
     251                 :             : // Flush must also clear all per-block state to be reused.
     252   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(fetch_state_is_reusable_after_teardown)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  -  +  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          -  +  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
     253                 :             : {
     254                 :           1 :     const auto block{CreateBlock()};
     255                 :           0 :     CCoinsViewDB db{{.path = "", .cache_bytes = 1_MiB, .memory_only = true}, {}};
     256         [ +  - ]:           1 :     CCoinsViewCache main_cache{&db};
     257         [ +  - ]:           1 :     PopulateView(block, main_cache);
     258   [ +  -  -  + ]:           1 :     CoinsViewOverlay view{&main_cache, MakeStartedThreadPool()};
     259                 :             : 
     260         [ +  + ]:           4 :     for (const bool use_flush : {false, true, false}) {
     261                 :           3 :         {
     262                 :           3 :             const auto reset_guard{view.StartFetching(block)};
     263         [ +  - ]:           3 :             CheckCache(block, view);
     264   [ +  -  +  -  :           3 :             BOOST_CHECK_GT(view.GetCacheSize(), 0U);
                   +  - ]
     265         [ +  + ]:           3 :             if (use_flush) {
     266         [ +  - ]:           1 :                 view.SetBestBlock(uint256::ONE);
     267         [ +  - ]:           1 :                 view.Flush();
     268                 :             :             }
     269                 :           0 :         }
     270   [ +  -  +  -  :           3 :         BOOST_CHECK_EQUAL(view.GetCacheSize(), 0U);
                   +  - ]
     271                 :             :     }
     272   [ +  -  +  - ]:           2 : }
     273                 :             : 
     274                 :             : BOOST_AUTO_TEST_SUITE_END()
     275                 :             : 
     276                 :             : BOOST_AUTO_TEST_SUITE(coinsviewoverlay_tests_noworkers)
     277                 :             : 
     278                 :             : // Test that disabled input fetching falls back to normal cache lookups via base->PeekCoin.
     279   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(fetch_unstarted_thread_pool)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  -  +  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          -  +  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
     280                 :             : {
     281                 :           1 :     const auto block{CreateBlock()};
     282                 :           0 :     CCoinsViewDB db{{.path = "", .cache_bytes = 1_MiB, .memory_only = true}, {}};
     283         [ +  - ]:           1 :     CCoinsViewCache main_cache{&db};
     284         [ +  - ]:           1 :     PopulateView(block, main_cache);
     285         [ +  - ]:           1 :     auto thread_pool{std::make_shared<ThreadPool>("fetch_none")};
     286   [ +  -  -  + ]:           2 :     CoinsViewOverlay view{&main_cache, thread_pool};
     287                 :           1 :     const auto reset_guard{view.StartFetching(block)};
     288         [ +  - ]:           1 :     CheckCache(block, view);
     289   [ +  -  +  -  :           3 : }
                   +  - ]
     290                 :             : 
     291                 :             : // Test that an interrupted thread pool falls back to normal cache lookups via base->PeekCoin.
     292   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(fetch_interrupted_thread_pool_uses_normal_lookup)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  -  +  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          -  +  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
     293                 :             : {
     294                 :           1 :     const auto block{CreateBlock()};
     295                 :           0 :     CCoinsViewDB db{{.path = "", .cache_bytes = 1_MiB, .memory_only = true}, {}};
     296         [ +  - ]:           1 :     CCoinsViewCache main_cache{&db};
     297         [ +  - ]:           1 :     PopulateView(block, main_cache);
     298                 :             : 
     299         [ +  - ]:           1 :     auto thread_pool{std::make_shared<ThreadPool>("fetch_intr")};
     300         [ +  - ]:           1 :     thread_pool->Start(DEFAULT_PREVOUTFETCH_THREADS);
     301         [ +  - ]:           1 :     thread_pool->Interrupt();
     302   [ +  -  -  + ]:           2 :     CoinsViewOverlay view{&main_cache, thread_pool};
     303                 :           1 :     const auto reset_guard{view.StartFetching(block)};
     304         [ +  - ]:           1 :     CheckCache(block, view);
     305   [ +  -  +  -  :           3 : }
                   +  - ]
     306                 :             : 
     307                 :             : BOOST_AUTO_TEST_SUITE_END()
        

Generated by: LCOV version 2.0-1