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

Generated by: LCOV version 2.0-1