LCOV - code coverage report
Current view: top level - src/test - validation_chainstate_tests.cpp (source / functions) Coverage Total Hit
Test: total_coverage.info Lines: 96.0 % 75 72
Test Date: 2026-02-25 05:45:00 Functions: 100.0 % 12 12
Branches: 50.2 % 448 225

             Branch data     Line data    Source code
       1                 :             : // Copyright (c) 2020-present 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 <chainparams.h>
       6                 :             : #include <consensus/amount.h>
       7                 :             : #include <consensus/validation.h>
       8                 :             : #include <node/kernel_notifications.h>
       9                 :             : #include <random.h>
      10                 :             : #include <rpc/blockchain.h>
      11                 :             : #include <script/script.h>
      12                 :             : #include <sync.h>
      13                 :             : #include <test/util/chainstate.h>
      14                 :             : #include <test/util/coins.h>
      15                 :             : #include <test/util/random.h>
      16                 :             : #include <test/util/setup_common.h>
      17                 :             : #include <uint256.h>
      18                 :             : #include <util/check.h>
      19                 :             : #include <validation.h>
      20                 :             : 
      21                 :             : #include <vector>
      22                 :             : 
      23                 :             : #include <boost/test/unit_test.hpp>
      24                 :             : 
      25                 :             : BOOST_FIXTURE_TEST_SUITE(validation_chainstate_tests, ChainTestingSetup)
      26                 :             : 
      27                 :             : //! Test resizing coins-related Chainstate caches during runtime.
      28                 :             : //!
      29   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(validation_chainstate_resize_caches)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
      30                 :             : {
      31   [ -  +  -  + ]:           1 :     ChainstateManager& manager = *Assert(m_node.chainman);
      32         [ -  + ]:           1 :     CTxMemPool& mempool = *Assert(m_node.mempool);
      33   [ +  -  +  - ]:           3 :     Chainstate& c1 = WITH_LOCK(cs_main, return manager.InitializeChainstate(&mempool));
      34                 :           1 :     c1.InitCoinsDB(
      35                 :             :         /*cache_size_bytes=*/1 << 23, /*in_memory=*/true, /*should_wipe=*/false);
      36         [ +  - ]:           3 :     WITH_LOCK(::cs_main, c1.InitCoinsCache(1 << 23));
      37   [ +  -  +  - ]:           2 :     BOOST_REQUIRE(c1.LoadGenesisBlock()); // Need at least one block loaded to be able to flush caches
      38                 :             : 
      39                 :             :     // Add a coin to the in-memory cache, upsize once, then downsize.
      40                 :           1 :     {
      41                 :           1 :         LOCK(::cs_main);
      42   [ +  -  +  - ]:           1 :         const auto outpoint = AddTestCoin(m_rng, c1.CoinsTip());
      43                 :             : 
      44                 :             :         // Set a meaningless bestblock value in the coinsview cache - otherwise we won't
      45                 :             :         // flush during ResizecoinsCaches() and will subsequently hit an assertion.
      46   [ +  -  +  - ]:           1 :         c1.CoinsTip().SetBestBlock(m_rng.rand256());
      47                 :             : 
      48   [ +  -  +  -  :           2 :         BOOST_CHECK(c1.CoinsTip().HaveCoinInCache(outpoint));
          +  -  +  -  +  
                      - ]
      49                 :             : 
      50         [ +  - ]:           1 :         c1.ResizeCoinsCaches(
      51                 :             :             1 << 24,  // upsizing the coinsview cache
      52                 :             :             1 << 22  // downsizing the coinsdb cache
      53                 :             :         );
      54                 :             : 
      55                 :             :         // View should still have the coin cached, since we haven't destructed the cache on upsize.
      56   [ +  -  +  -  :           2 :         BOOST_CHECK(c1.CoinsTip().HaveCoinInCache(outpoint));
          +  -  +  -  +  
                      - ]
      57                 :             : 
      58         [ +  - ]:           1 :         c1.ResizeCoinsCaches(
      59                 :             :             1 << 22,  // downsizing the coinsview cache
      60                 :             :             1 << 23  // upsizing the coinsdb cache
      61                 :             :         );
      62                 :             : 
      63                 :             :         // The view cache should be empty since we had to destruct to downsize.
      64   [ +  -  +  -  :           2 :         BOOST_CHECK(!c1.CoinsTip().HaveCoinInCache(outpoint));
          +  -  +  -  +  
                      - ]
      65                 :           1 :     }
      66                 :           1 : }
      67                 :             : 
      68   [ +  -  +  -  :           7 : BOOST_FIXTURE_TEST_CASE(connect_tip_does_not_cache_inputs_on_failed_connect, TestChain100Setup)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
      69                 :             : {
      70         [ -  + ]:           1 :     Chainstate& chainstate{Assert(m_node.chainman)->ActiveChainstate()};
      71                 :             : 
      72                 :           1 :     COutPoint outpoint;
      73                 :           1 :     {
      74                 :           1 :         LOCK(cs_main);
      75   [ +  -  +  - ]:           1 :         outpoint = AddTestCoin(m_rng, chainstate.CoinsTip());
      76   [ +  -  +  - ]:           1 :         chainstate.CoinsTip().Flush(/*reallocate_cache=*/false);
      77                 :           0 :     }
      78                 :             : 
      79                 :           1 :     CMutableTransaction tx;
      80         [ +  - ]:           1 :     tx.vin.emplace_back(outpoint);
      81   [ +  -  +  - ]:           1 :     tx.vout.emplace_back(MAX_MONEY, CScript{} << OP_TRUE);
      82                 :             : 
      83   [ +  +  +  - ]:           3 :     const auto tip{WITH_LOCK(cs_main, return chainstate.m_chain.Tip()->GetBlockHash())};
      84   [ +  -  +  -  :           3 :     const CBlock block{CreateBlock({tx}, CScript{} << OP_TRUE, chainstate)};
          +  -  +  +  -  
                      - ]
      85   [ +  -  -  +  :           3 :     BOOST_CHECK(Assert(m_node.chainman)->ProcessNewBlock(std::make_shared<CBlock>(block), true, true, nullptr));
          +  -  +  -  +  
          -  +  -  -  +  
                   +  - ]
      86                 :             : 
      87         [ +  - ]:           1 :     LOCK(cs_main);
      88   [ +  -  -  +  :           2 :     BOOST_CHECK_EQUAL(tip, chainstate.m_chain.Tip()->GetBlockHash()); // block rejected
                   +  - ]
      89   [ +  -  +  -  :           2 :     BOOST_CHECK(!chainstate.CoinsTip().HaveCoinInCache(outpoint));    // input not cached
          +  -  +  -  +  
                      - ]
      90         [ +  - ]:           3 : }
      91                 :             : 
      92                 :             : //! Test UpdateTip behavior for both active and background chainstates.
      93                 :             : //!
      94                 :             : //! When run on the background chainstate, UpdateTip should do a subset
      95                 :             : //! of what it does for the active chainstate.
      96   [ +  -  +  -  :           7 : BOOST_FIXTURE_TEST_CASE(chainstate_update_tip, TestChain100Setup)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
      97                 :             : {
      98         [ -  + ]:           1 :     ChainstateManager& chainman = *Assert(m_node.chainman);
      99                 :           7 :     const auto get_notify_tip{[&]() {
     100                 :           6 :         LOCK(m_node.notifications->m_tip_block_mutex);
     101   [ +  -  +  -  :          12 :         BOOST_REQUIRE(m_node.notifications->TipBlock());
             +  -  +  - ]
     102   [ +  -  +  - ]:           6 :         return *m_node.notifications->TipBlock();
     103                 :           7 :     }};
     104                 :           1 :     uint256 curr_tip = get_notify_tip();
     105                 :             : 
     106                 :             :     // Mine 10 more blocks, putting at us height 110 where a valid assumeutxo value can
     107                 :             :     // be found.
     108                 :           1 :     mineBlocks(10);
     109                 :             : 
     110                 :             :     // After adding some blocks to the tip, best block should have changed.
     111   [ +  -  +  - ]:           2 :     BOOST_CHECK(get_notify_tip() != curr_tip);
     112                 :             : 
     113                 :             :     // Grab block 1 from disk; we'll add it to the background chain later.
     114                 :           1 :     std::shared_ptr<CBlock> pblockone = std::make_shared<CBlock>();
     115                 :           1 :     {
     116         [ +  - ]:           1 :         LOCK(::cs_main);
     117   [ +  -  -  +  :           2 :         chainman.m_blockman.ReadBlock(*pblockone, *chainman.ActiveChain()[1]);
                   +  - ]
     118                 :           0 :     }
     119                 :             : 
     120   [ +  -  +  -  :           2 :     BOOST_REQUIRE(CreateAndActivateUTXOSnapshot(
             +  -  +  - ]
     121                 :             :         this, NoMalleation, /*reset_chainstate=*/ true));
     122                 :             : 
     123                 :             :     // Ensure our active chain is the snapshot chainstate.
     124   [ +  -  +  -  :           3 :     BOOST_CHECK(WITH_LOCK(::cs_main, return chainman.CurrentChainstate().m_from_snapshot_blockhash));
             +  -  +  - ]
     125                 :             : 
     126         [ +  - ]:           1 :     curr_tip = get_notify_tip();
     127                 :             : 
     128                 :             :     // Mine a new block on top of the activated snapshot chainstate.
     129         [ +  - ]:           1 :     mineBlocks(1);  // Defined in TestChain100Setup.
     130                 :             : 
     131                 :             :     // After adding some blocks to the snapshot tip, best block should have changed.
     132   [ +  -  +  -  :           2 :     BOOST_CHECK(get_notify_tip() != curr_tip);
             +  -  +  - ]
     133                 :             : 
     134         [ +  - ]:           1 :     curr_tip = get_notify_tip();
     135                 :             : 
     136   [ +  -  -  + ]:           2 :     Chainstate& background_cs{*Assert(WITH_LOCK(::cs_main, return chainman.HistoricalChainstate()))};
     137                 :             : 
     138                 :             :     // Append the first block to the background chain.
     139         [ +  - ]:           1 :     BlockValidationState state;
     140                 :           1 :     CBlockIndex* pindex = nullptr;
     141         [ +  - ]:           1 :     const CChainParams& chainparams = Params();
     142                 :           1 :     bool newblock = false;
     143                 :             : 
     144                 :             :     // TODO: much of this is inlined from ProcessNewBlock(); just reuse PNB()
     145                 :             :     // once it is changed to support multiple chainstates.
     146                 :           1 :     {
     147         [ +  - ]:           1 :         LOCK(::cs_main);
     148         [ +  - ]:           1 :         bool checked = CheckBlock(*pblockone, state, chainparams.GetConsensus());
     149   [ +  -  +  -  :           2 :         BOOST_CHECK(checked);
                   +  - ]
     150   [ +  -  +  - ]:           2 :         bool accepted = chainman.AcceptBlock(
     151         [ +  - ]:           1 :             pblockone, state, &pindex, true, nullptr, &newblock, true);
     152   [ +  -  +  -  :           2 :         BOOST_CHECK(accepted);
                   +  - ]
     153                 :           0 :     }
     154                 :             : 
     155                 :             :     // UpdateTip is called here
     156   [ +  -  +  -  :           2 :     bool block_added = background_cs.ActivateBestChain(state, pblockone);
                   +  - ]
     157                 :             : 
     158                 :             :     // Ensure tip is as expected
     159   [ +  -  +  -  :           2 :     BOOST_CHECK_EQUAL(background_cs.m_chain.Tip()->GetBlockHash(), pblockone->GetHash());
             -  +  +  - ]
     160                 :             : 
     161                 :             :     // get_notify_tip() should be unchanged after adding a block to the background
     162                 :             :     // validation chain.
     163   [ +  -  +  -  :           2 :     BOOST_CHECK(block_added);
                   +  - ]
     164   [ +  -  +  -  :           1 :     BOOST_CHECK_EQUAL(curr_tip, get_notify_tip());
                   +  - ]
     165         [ +  - ]:           2 : }
     166                 :             : 
     167                 :             : BOOST_AUTO_TEST_SUITE_END()
        

Generated by: LCOV version 2.0-1