LCOV - code coverage report
Current view: top level - src/test - headers_sync_chainwork_tests.cpp (source / functions) Coverage Total Hit
Test: total_coverage.info Lines: 100.0 % 63 63
Test Date: 2024-11-04 05:10:19 Functions: 100.0 % 5 5
Branches: 50.8 % 246 125

             Branch data     Line data    Source code
       1                 :             : // Copyright (c) 2022 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 <chain.h>
       6                 :             : #include <chainparams.h>
       7                 :             : #include <consensus/params.h>
       8                 :             : #include <headerssync.h>
       9                 :             : #include <pow.h>
      10                 :             : #include <test/util/setup_common.h>
      11                 :             : #include <validation.h>
      12                 :             : #include <vector>
      13                 :             : 
      14                 :             : #include <boost/test/unit_test.hpp>
      15                 :             : 
      16                 :           3 : struct HeadersGeneratorSetup : public RegTestingSetup {
      17                 :             :     /** Search for a nonce to meet (regtest) proof of work */
      18                 :             :     void FindProofOfWork(CBlockHeader& starting_header);
      19                 :             :     /**
      20                 :             :      * Generate headers in a chain that build off a given starting hash, using
      21                 :             :      * the given nVersion, advancing time by 1 second from the starting
      22                 :             :      * prev_time, and with a fixed merkle root hash.
      23                 :             :      */
      24                 :             :     void GenerateHeaders(std::vector<CBlockHeader>& headers, size_t count,
      25                 :             :             const uint256& starting_hash, const int nVersion, int prev_time,
      26                 :             :             const uint256& merkle_root, const uint32_t nBits);
      27                 :             : };
      28                 :             : 
      29                 :       29997 : void HeadersGeneratorSetup::FindProofOfWork(CBlockHeader& starting_header)
      30                 :             : {
      31         [ +  + ]:       59957 :     while (!CheckProofOfWork(starting_header.GetHash(), starting_header.nBits, Params().GetConsensus())) {
      32                 :       29960 :         ++(starting_header.nNonce);
      33                 :             :     }
      34                 :       29997 : }
      35                 :             : 
      36                 :           2 : void HeadersGeneratorSetup::GenerateHeaders(std::vector<CBlockHeader>& headers,
      37                 :             :         size_t count, const uint256& starting_hash, const int nVersion, int prev_time,
      38                 :             :         const uint256& merkle_root, const uint32_t nBits)
      39                 :             : {
      40                 :           2 :     uint256 prev_hash = starting_hash;
      41                 :             : 
      42         [ +  + ]:       29999 :     while (headers.size() < count) {
      43                 :       29997 :         headers.emplace_back();
      44                 :       29997 :         CBlockHeader& next_header = headers.back();;
      45                 :       29997 :         next_header.nVersion = nVersion;
      46                 :       29997 :         next_header.hashPrevBlock = prev_hash;
      47                 :       29997 :         next_header.hashMerkleRoot = merkle_root;
      48                 :       29997 :         next_header.nTime = prev_time+1;
      49                 :       29997 :         next_header.nBits = nBits;
      50                 :             : 
      51                 :       29997 :         FindProofOfWork(next_header);
      52                 :       29997 :         prev_hash = next_header.GetHash();
      53                 :       29997 :         prev_time = next_header.nTime;
      54                 :             :     }
      55                 :           2 :     return;
      56                 :             : }
      57                 :             : 
      58                 :             : BOOST_FIXTURE_TEST_SUITE(headers_sync_chainwork_tests, HeadersGeneratorSetup)
      59                 :             : 
      60                 :             : // In this test, we construct two sets of headers from genesis, one with
      61                 :             : // sufficient proof of work and one without.
      62                 :             : // 1. We deliver the first set of headers and verify that the headers sync state
      63                 :             : //    updates to the REDOWNLOAD phase successfully.
      64                 :             : // 2. Then we deliver the second set of headers and verify that they fail
      65                 :             : //    processing (presumably due to commitments not matching).
      66                 :             : // 3. Finally, we verify that repeating with the first set of headers in both
      67                 :             : //    phases is successful.
      68   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(headers_sync_state)
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                      - ]
      69                 :             : {
      70                 :           1 :     std::vector<CBlockHeader> first_chain;
      71                 :           1 :     std::vector<CBlockHeader> second_chain;
      72                 :             : 
      73                 :           1 :     std::unique_ptr<HeadersSyncState> hss;
      74                 :             : 
      75                 :           1 :     const int target_blocks = 15000;
      76                 :           1 :     arith_uint256 chain_work = target_blocks*2;
      77                 :             : 
      78                 :             :     // Generate headers for two different chains (using differing merkle roots
      79                 :             :     // to ensure the headers are different).
      80   [ +  -  +  - ]:           1 :     GenerateHeaders(first_chain, target_blocks-1, Params().GenesisBlock().GetHash(),
      81   [ +  -  +  -  :           1 :             Params().GenesisBlock().nVersion, Params().GenesisBlock().nTime,
                   +  - ]
      82   [ +  -  +  - ]:           2 :             ArithToUint256(0), Params().GenesisBlock().nBits);
      83                 :             : 
      84   [ +  -  +  - ]:           1 :     GenerateHeaders(second_chain, target_blocks-2, Params().GenesisBlock().GetHash(),
      85   [ +  -  +  -  :           1 :             Params().GenesisBlock().nVersion, Params().GenesisBlock().nTime,
                   +  - ]
      86   [ +  -  +  - ]:           2 :             ArithToUint256(1), Params().GenesisBlock().nBits);
      87                 :             : 
      88   [ +  -  +  -  :           3 :     const CBlockIndex* chain_start = WITH_LOCK(::cs_main, return m_node.chainman->m_blockman.LookupBlockIndex(Params().GenesisBlock().GetHash()));
             +  -  +  - ]
      89                 :           1 :     std::vector<CBlockHeader> headers_batch;
      90                 :             : 
      91                 :             :     // Feed the first chain to HeadersSyncState, by delivering 1 header
      92                 :             :     // initially and then the rest.
      93         [ +  - ]:           1 :     headers_batch.insert(headers_batch.end(), std::next(first_chain.begin()), first_chain.end());
      94                 :             : 
      95   [ +  -  +  -  :           1 :     hss.reset(new HeadersSyncState(0, Params().GetConsensus(), chain_start, chain_work));
             +  -  -  + ]
      96   [ +  -  +  -  :           2 :     (void)hss->ProcessNextHeaders({first_chain.front()}, true);
                   +  - ]
      97                 :             :     // Pretend the first header is still "full", so we don't abort.
      98         [ +  - ]:           1 :     auto result = hss->ProcessNextHeaders(headers_batch, true);
      99                 :             : 
     100                 :             :     // This chain should look valid, and we should have met the proof-of-work
     101                 :             :     // requirement.
     102   [ +  -  +  -  :           2 :     BOOST_CHECK(result.success);
                   +  - ]
     103   [ +  -  +  -  :           2 :     BOOST_CHECK(result.request_more);
                   +  - ]
     104   [ +  -  +  -  :           2 :     BOOST_CHECK(hss->GetState() == HeadersSyncState::State::REDOWNLOAD);
                   +  - ]
     105                 :             : 
     106                 :             :     // Try to sneakily feed back the second chain.
     107         [ +  - ]:           2 :     result = hss->ProcessNextHeaders(second_chain, true);
     108   [ +  -  +  -  :           2 :     BOOST_CHECK(!result.success); // foiled!
                   +  - ]
     109   [ +  -  +  -  :           2 :     BOOST_CHECK(hss->GetState() == HeadersSyncState::State::FINAL);
                   +  - ]
     110                 :             : 
     111                 :             :     // Now try again, this time feeding the first chain twice.
     112   [ +  -  +  -  :           1 :     hss.reset(new HeadersSyncState(0, Params().GetConsensus(), chain_start, chain_work));
             +  -  +  - ]
     113         [ +  - ]:           1 :     (void)hss->ProcessNextHeaders(first_chain, true);
     114   [ +  -  +  -  :           2 :     BOOST_CHECK(hss->GetState() == HeadersSyncState::State::REDOWNLOAD);
                   +  - ]
     115                 :             : 
     116         [ +  - ]:           2 :     result = hss->ProcessNextHeaders(first_chain, true);
     117   [ +  -  +  -  :           2 :     BOOST_CHECK(result.success);
                   +  - ]
     118   [ +  -  +  -  :           2 :     BOOST_CHECK(!result.request_more);
                   +  - ]
     119                 :             :     // All headers should be ready for acceptance:
     120   [ +  -  +  -  :           2 :     BOOST_CHECK(result.pow_validated_headers.size() == first_chain.size());
                   +  - ]
     121                 :             :     // Nothing left for the sync logic to do:
     122   [ +  -  +  -  :           2 :     BOOST_CHECK(hss->GetState() == HeadersSyncState::State::FINAL);
                   +  - ]
     123                 :             : 
     124                 :             :     // Finally, verify that just trying to process the second chain would not
     125                 :             :     // succeed (too little work)
     126   [ +  -  +  -  :           1 :     hss.reset(new HeadersSyncState(0, Params().GetConsensus(), chain_start, chain_work));
             +  -  +  - ]
     127   [ +  -  +  -  :           2 :     BOOST_CHECK(hss->GetState() == HeadersSyncState::State::PRESYNC);
                   +  - ]
     128                 :             :      // Pretend just the first message is "full", so we don't abort.
     129   [ +  -  +  -  :           2 :     (void)hss->ProcessNextHeaders({second_chain.front()}, true);
                   +  - ]
     130   [ +  -  +  -  :           2 :     BOOST_CHECK(hss->GetState() == HeadersSyncState::State::PRESYNC);
                   +  - ]
     131                 :             : 
     132         [ +  - ]:           1 :     headers_batch.clear();
     133         [ +  - ]:           1 :     headers_batch.insert(headers_batch.end(), std::next(second_chain.begin(), 1), second_chain.end());
     134                 :             :     // Tell the sync logic that the headers message was not full, implying no
     135                 :             :     // more headers can be requested. For a low-work-chain, this should causes
     136                 :             :     // the sync to end with no headers for acceptance.
     137         [ +  - ]:           2 :     result = hss->ProcessNextHeaders(headers_batch, false);
     138   [ +  -  +  -  :           2 :     BOOST_CHECK(hss->GetState() == HeadersSyncState::State::FINAL);
                   +  - ]
     139   [ +  -  +  -  :           2 :     BOOST_CHECK(result.pow_validated_headers.empty());
                   +  - ]
     140   [ +  -  +  -  :           2 :     BOOST_CHECK(!result.request_more);
                   +  - ]
     141                 :             :     // Nevertheless, no validation errors should have been detected with the
     142                 :             :     // chain:
     143   [ +  -  +  - ]:           2 :     BOOST_CHECK(result.success);
     144                 :           1 : }
     145                 :             : 
     146                 :             : BOOST_AUTO_TEST_SUITE_END()
        

Generated by: LCOV version 2.0-1