LCOV - code coverage report
Current view: top level - src/test - chain_tests.cpp (source / functions) Coverage Total Hit
Test: test_bitcoin_coverage.info Lines: 100.0 % 106 106
Test Date: 2026-04-27 06:44:50 Functions: 100.0 % 12 12
Branches: 54.7 % 430 235

             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 <boost/test/unit_test.hpp>
       6                 :             : 
       7                 :             : #include <chain.h>
       8                 :             : #include <test/util/setup_common.h>
       9                 :             : 
      10                 :             : #include <array>
      11                 :             : #include <memory>
      12                 :             : 
      13                 :             : BOOST_FIXTURE_TEST_SUITE(chain_tests, BasicTestingSetup)
      14                 :             : 
      15                 :             : namespace {
      16                 :             : 
      17                 :      100000 : const CBlockIndex* NaiveGetAncestor(const CBlockIndex* a, int height)
      18                 :             : {
      19         [ +  + ]:     6430303 :     while (a->nHeight > height) {
      20                 :     6330303 :         a = a->pprev;
      21                 :             :     }
      22         [ +  - ]:      100000 :     BOOST_REQUIRE_EQUAL(a->nHeight, height);
      23                 :      100000 :     return a;
      24                 :             : }
      25                 :             : 
      26                 :      100000 : const CBlockIndex* NaiveLastCommonAncestor(const CBlockIndex* a, const CBlockIndex* b)
      27                 :             : {
      28         [ +  + ]:     3449857 :     while (a->nHeight > b->nHeight) {
      29                 :     3349857 :         a = a->pprev;
      30                 :             :     }
      31         [ +  + ]:     3446839 :     while (b->nHeight > a->nHeight) {
      32                 :     3346839 :         b = b->pprev;
      33                 :             :     }
      34         [ +  + ]:     5852581 :     while (a != b) {
      35         [ +  - ]:     5752581 :         BOOST_REQUIRE_EQUAL(a->nHeight, b->nHeight);
      36                 :     5752581 :         a = a->pprev;
      37                 :     5752581 :         b = b->pprev;
      38                 :             :     }
      39         [ +  - ]:      100000 :     BOOST_REQUIRE_EQUAL(a, b);
      40                 :      100000 :     return a;
      41                 :             : }
      42                 :             : 
      43                 :             : } // namespace
      44                 :             : 
      45   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(basic_tests)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
      46                 :             : {
      47                 :             :     // An empty chain
      48                 :           1 :     const CChain chain_0;
      49                 :             :     // A chain with 2 blocks
      50                 :           1 :     CChain chain_2;
      51                 :             : 
      52                 :           1 :     CBlockIndex genesis;
      53                 :           1 :     genesis.nHeight = 0;
      54         [ +  - ]:           1 :     chain_2.SetTip(genesis);
      55                 :             : 
      56                 :           1 :     CBlockIndex bi1;
      57                 :           1 :     bi1.pprev = &genesis;
      58                 :           1 :     bi1.nHeight = 1;
      59         [ +  - ]:           1 :     chain_2.SetTip(bi1);
      60                 :             : 
      61   [ +  -  -  +  :           1 :     BOOST_CHECK_EQUAL(chain_0.Height(), -1);
                   +  - ]
      62   [ +  -  -  +  :           1 :     BOOST_CHECK_EQUAL(chain_2.Height(), 1);
                   +  - ]
      63                 :             : 
      64   [ +  -  -  +  :           2 :     BOOST_CHECK_EQUAL(chain_0.Tip(), nullptr);
                   +  - ]
      65   [ +  -  -  +  :           2 :     BOOST_CHECK_EQUAL(chain_2.Tip(), &bi1);
                   +  - ]
      66                 :             : 
      67                 :             :     // Indexer accessor: call with valid and invalid (low & high) values
      68   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(chain_2[-1], nullptr);
      69   [ +  -  -  +  :           2 :     BOOST_CHECK_EQUAL(chain_2[0], &genesis);
                   +  - ]
      70   [ +  -  -  +  :           2 :     BOOST_CHECK_EQUAL(chain_2[1], &bi1);
                   +  - ]
      71   [ +  -  -  +  :           2 :     BOOST_CHECK_EQUAL(chain_2[2], nullptr);
                   +  - ]
      72                 :             : 
      73                 :             :     // Contains: call with contained & non-contained blocks
      74   [ +  -  +  -  :           2 :     BOOST_CHECK(chain_2.Contains(genesis));
                   +  - ]
      75   [ +  -  +  -  :           2 :     BOOST_CHECK(chain_2.Contains(bi1));
                   +  - ]
      76   [ +  -  +  -  :           2 :     BOOST_CHECK(!chain_0.Contains(genesis));
                   +  - ]
      77                 :             : 
      78                 :             :     // Call with non-tip & tip blocks
      79   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(chain_2.Next(genesis), &bi1);
      80   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(chain_2.Next(bi1), nullptr);
      81   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(chain_0.Next(genesis), nullptr);
      82                 :             : 
      83   [ +  -  -  +  :           3 :     BOOST_CHECK_EQUAL(chain_2.Genesis(), &genesis);
             +  -  +  - ]
      84   [ +  -  -  +  :           2 :     BOOST_CHECK_EQUAL(chain_0.Genesis(), nullptr);
                   +  - ]
      85                 :           1 : }
      86                 :             : 
      87   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(findfork_tests)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
      88                 :             : {
      89                 :             :     // Create a forking chain
      90                 :           1 :     const auto init_branch{[](auto& blocks, CBlockIndex* parent, int start_height) {
      91   [ +  +  +  +  :          28 :         for (size_t i{0}; i < blocks.size(); ++i) {
                   +  + ]
      92   [ +  +  +  +  :          25 :             blocks[i].pprev = i == 0 ? parent : &blocks[i - 1];
                   +  + ]
      93                 :          25 :             blocks[i].nHeight = start_height + i;
      94                 :             :         }
      95                 :             :     }};
      96                 :             : 
      97                 :           5 :     const auto check_same{[](const CChain& chain, const auto& blocks) {
      98         [ +  + ]:          39 :         for (const auto& block : blocks) {
      99         [ +  - ]:          35 :             BOOST_CHECK_EQUAL(chain.FindFork(block), &block);
     100                 :             :         }
     101                 :           4 :     }};
     102                 :             : 
     103                 :           3 :     const auto check_fork_point{[](const CChain& chain, const auto& blocks, const CBlockIndex& fork_point) {
     104         [ +  + ]:          17 :         for (const auto& block : blocks) {
     105         [ +  - ]:          15 :             BOOST_CHECK_EQUAL(chain.FindFork(block), &fork_point);
     106                 :             :         }
     107                 :           2 :     }};
     108                 :             : 
     109         [ +  + ]:           9 :     std::array<CBlockIndex, 10> blocks_common;
     110                 :           1 :     init_branch(blocks_common, nullptr, 0);
     111                 :             : 
     112         [ +  + ]:           9 :     std::array<CBlockIndex, 10> blocks_long;
     113                 :           1 :     init_branch(blocks_long, &blocks_common.back(), blocks_common.size());
     114                 :             : 
     115         [ +  + ]:           4 :     std::array<CBlockIndex, 5> blocks_short;
     116                 :           1 :     init_branch(blocks_short, &blocks_common.back(), blocks_common.size());
     117                 :             : 
     118                 :             :     // Create a chain with the longer fork
     119                 :           1 :     CChain chain_long;
     120         [ +  - ]:           1 :     chain_long.SetTip(blocks_long.back());
     121   [ +  -  -  +  :           1 :     BOOST_CHECK_EQUAL(chain_long.Height(), 10 + 10 - 1);
                   +  - ]
     122                 :             :     // Test the blocks in the common part -> result should be the same
     123         [ +  - ]:           1 :     check_same(chain_long, blocks_common);
     124                 :             :     // Test the blocks on the longer fork -> result should be the same
     125         [ +  - ]:           1 :     check_same(chain_long, blocks_long);
     126                 :             :     // Test the blocks on the other shorter fork -> result should be the fork point
     127         [ +  - ]:           1 :     check_fork_point(chain_long, blocks_short, blocks_common.back());
     128                 :             : 
     129                 :             :     // Create a chain with the shorter fork
     130                 :           1 :     CChain chain_short;
     131         [ +  - ]:           1 :     chain_short.SetTip(blocks_short.back());
     132   [ +  -  -  +  :           1 :     BOOST_CHECK_EQUAL(chain_short.Height(), 10 + 5 - 1);
                   +  - ]
     133                 :             :     // Test the blocks in the common part -> result should be the same
     134         [ +  - ]:           1 :     check_same(chain_short, blocks_common);
     135                 :             :     // Test the blocks on the shorter fork -> result should be the same
     136         [ +  - ]:           1 :     check_same(chain_short, blocks_short);
     137                 :             :     // Test the blocks on the other longer fork -> result should be the fork point
     138         [ +  - ]:           1 :     check_fork_point(chain_short, blocks_long, blocks_common.back());
     139                 :             : 
     140                 :             :     // Invalid test case. Mixing chains is not supported
     141                 :           1 :     CBlockIndex block_on_unrelated_chain;
     142   [ +  -  +  -  :           1 :     BOOST_CHECK_EQUAL(chain_long.FindFork(block_on_unrelated_chain), nullptr);
                   +  - ]
     143                 :           1 : }
     144                 :             : 
     145   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(chain_test)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
     146                 :             : {
     147                 :           1 :     FastRandomContext ctx;
     148                 :           1 :     std::vector<std::unique_ptr<CBlockIndex>> block_index;
     149                 :             :     // Run 10 iterations of the whole test.
     150         [ +  + ]:          11 :     for (int i = 0; i < 10; ++i) {
     151                 :          10 :         block_index.clear();
     152                 :             :         // Create genesis block.
     153         [ +  - ]:          10 :         auto genesis = std::make_unique<CBlockIndex>();
     154         [ +  - ]:          10 :         genesis->nHeight = 0;
     155         [ +  - ]:          10 :         block_index.push_back(std::move(genesis));
     156                 :             :         // Create 10000 more blocks.
     157         [ +  + ]:      100010 :         for (int b = 0; b < 10000; ++b) {
     158         [ +  - ]:      100000 :             auto new_index = std::make_unique<CBlockIndex>();
     159                 :             :             // 95% of blocks build on top of the last block; the others fork off randomly.
     160         [ +  + ]:      100000 :             if (ctx.randrange(20) != 0) {
     161                 :       95000 :                 new_index->pprev = block_index.back().get();
     162                 :             :             } else {
     163         [ -  + ]:        5000 :                 new_index->pprev = block_index[ctx.randrange(block_index.size())].get();
     164                 :             :             }
     165         [ +  - ]:      100000 :             new_index->nHeight = new_index->pprev->nHeight + 1;
     166         [ +  - ]:      100000 :             new_index->BuildSkip();
     167         [ +  - ]:      100000 :             block_index.push_back(std::move(new_index));
     168                 :      100000 :         }
     169                 :             :         // Run 10000 random GetAncestor queries.
     170         [ +  + ]:      100010 :         for (int q = 0; q < 10000; ++q) {
     171         [ -  + ]:      100000 :             const CBlockIndex* block = block_index[ctx.randrange(block_index.size())].get();
     172                 :      100000 :             unsigned height = ctx.randrange<unsigned>(block->nHeight + 1);
     173         [ +  - ]:      100000 :             const CBlockIndex* result = block->GetAncestor(height);
     174   [ +  -  +  -  :      200000 :             BOOST_CHECK(result == NaiveGetAncestor(block, height));
                   +  - ]
     175                 :             :         }
     176                 :             :         // Run 10000 random LastCommonAncestor queries.
     177         [ +  + ]:      100010 :         for (int q = 0; q < 10000; ++q) {
     178   [ -  +  -  + ]:      100000 :             const CBlockIndex* block1 = block_index[ctx.randrange(block_index.size())].get();
     179   [ -  +  +  - ]:      100000 :             const CBlockIndex* block2 = block_index[ctx.randrange(block_index.size())].get();
     180         [ +  - ]:      100000 :             const CBlockIndex* result = LastCommonAncestor(block1, block2);
     181   [ +  -  +  -  :      200000 :             BOOST_CHECK(result == NaiveLastCommonAncestor(block1, block2));
                   +  - ]
     182                 :             :         }
     183                 :          10 :     }
     184                 :           1 : }
     185                 :             : 
     186                 :             : BOOST_AUTO_TEST_SUITE_END()
        

Generated by: LCOV version 2.0-1