/root/bitcoin/src/test/fuzz/headerssync.cpp
| Line | Count | Source | 
| 1 |  | // Copyright (c) 2022-present The Bitcoin Core developers | 
| 2 |  | // Distributed under the MIT software license, see the accompanying | 
| 3 |  | // file COPYING or https://opensource.org/license/mit. | 
| 4 |  |  | 
| 5 |  | #include <arith_uint256.h> | 
| 6 |  | #include <chain.h> | 
| 7 |  | #include <chainparams.h> | 
| 8 |  | #include <headerssync.h> | 
| 9 |  | #include <test/fuzz/fuzz.h> | 
| 10 |  | #include <test/fuzz/util.h> | 
| 11 |  | #include <test/util/setup_common.h> | 
| 12 |  | #include <uint256.h> | 
| 13 |  | #include <util/chaintype.h> | 
| 14 |  | #include <util/time.h> | 
| 15 |  | #include <validation.h> | 
| 16 |  |  | 
| 17 |  | #include <iterator> | 
| 18 |  | #include <vector> | 
| 19 |  |  | 
| 20 |  | static void initialize_headers_sync_state_fuzz() | 
| 21 | 0 | { | 
| 22 | 0 |     static const auto testing_setup = MakeNoLogFileContext<>( | 
| 23 | 0 |         /*chain_type=*/ChainType::MAIN); | 
| 24 | 0 | } | 
| 25 |  |  | 
| 26 |  | void MakeHeadersContinuous( | 
| 27 |  |     const CBlockHeader& genesis_header, | 
| 28 |  |     const std::vector<CBlockHeader>& all_headers, | 
| 29 |  |     std::vector<CBlockHeader>& new_headers) | 
| 30 | 0 | { | 
| 31 | 0 |     Assume(!new_headers.empty()); | 
| 32 |  | 
 | 
| 33 | 0 |     const CBlockHeader* prev_header{ | 
| 34 | 0 |         all_headers.empty() ? &genesis_header : &all_headers.back()}; | 
| 35 |  | 
 | 
| 36 | 0 |     for (auto& header : new_headers) { | 
| 37 | 0 |         header.hashPrevBlock = prev_header->GetHash(); | 
| 38 |  | 
 | 
| 39 | 0 |         prev_header = &header; | 
| 40 | 0 |     } | 
| 41 | 0 | } | 
| 42 |  |  | 
| 43 |  | class FuzzedHeadersSyncState : public HeadersSyncState | 
| 44 |  | { | 
| 45 |  | public: | 
| 46 |  |     FuzzedHeadersSyncState(const unsigned commit_offset, const CBlockIndex* chain_start, const arith_uint256& minimum_required_work) | 
| 47 | 0 |         : HeadersSyncState(/*id=*/0, Params().GetConsensus(), chain_start, minimum_required_work) | 
| 48 | 0 |     { | 
| 49 | 0 |         const_cast<unsigned&>(m_commit_offset) = commit_offset; | 
| 50 | 0 |     } | 
| 51 |  | }; | 
| 52 |  |  | 
| 53 |  | FUZZ_TARGET(headers_sync_state, .init = initialize_headers_sync_state_fuzz) | 
| 54 | 0 | { | 
| 55 | 0 |     SeedRandomStateForTest(SeedRand::ZEROS); | 
| 56 | 0 |     FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); | 
| 57 | 0 |     auto mock_time{ConsumeTime(fuzzed_data_provider)}; | 
| 58 |  | 
 | 
| 59 | 0 |     CBlockHeader genesis_header{Params().GenesisBlock()}; | 
| 60 | 0 |     CBlockIndex start_index(genesis_header); | 
| 61 |  | 
 | 
| 62 | 0 |     if (mock_time < start_index.GetMedianTimePast()) return; | 
| 63 | 0 |     SetMockTime(mock_time); | 
| 64 |  | 
 | 
| 65 | 0 |     const uint256 genesis_hash = genesis_header.GetHash(); | 
| 66 | 0 |     start_index.phashBlock = &genesis_hash; | 
| 67 |  | 
 | 
| 68 | 0 |     arith_uint256 min_work{UintToArith256(ConsumeUInt256(fuzzed_data_provider))}; | 
| 69 | 0 |     FuzzedHeadersSyncState headers_sync( | 
| 70 | 0 |         /*commit_offset=*/fuzzed_data_provider.ConsumeIntegralInRange<unsigned>(1, 1024), | 
| 71 | 0 |         /*chain_start=*/&start_index, | 
| 72 | 0 |         /*minimum_required_work=*/min_work); | 
| 73 |  |  | 
| 74 |  |     // Store headers for potential redownload phase. | 
| 75 | 0 |     std::vector<CBlockHeader> all_headers; | 
| 76 | 0 |     std::vector<CBlockHeader>::const_iterator redownloaded_it; | 
| 77 | 0 |     bool presync{true}; | 
| 78 | 0 |     bool requested_more{true}; | 
| 79 |  | 
 | 
| 80 | 0 |     while (requested_more) { | 
| 81 | 0 |         std::vector<CBlockHeader> headers; | 
| 82 |  |  | 
| 83 |  |         // Consume headers from fuzzer or maybe replay headers if we got to the | 
| 84 |  |         // redownload phase. | 
| 85 | 0 |         if (presync || fuzzed_data_provider.ConsumeBool()) { | 
| 86 | 0 |             auto deser_headers = ConsumeDeserializable<std::vector<CBlockHeader>>(fuzzed_data_provider); | 
| 87 | 0 |             if (!deser_headers || deser_headers->empty()) return; | 
| 88 |  |  | 
| 89 | 0 |             if (fuzzed_data_provider.ConsumeBool()) { | 
| 90 | 0 |                 MakeHeadersContinuous(genesis_header, all_headers, *deser_headers); | 
| 91 | 0 |             } | 
| 92 |  | 
 | 
| 93 | 0 |             headers.swap(*deser_headers); | 
| 94 | 0 |         } else if (auto num_headers_left{std::distance(redownloaded_it, all_headers.cend())}; num_headers_left > 0) { | 
| 95 |  |             // Consume some headers from the redownload buffer (At least one | 
| 96 |  |             // header is consumed). | 
| 97 | 0 |             auto begin_it{redownloaded_it}; | 
| 98 | 0 |             std::advance(redownloaded_it, fuzzed_data_provider.ConsumeIntegralInRange<int>(1, num_headers_left)); | 
| 99 | 0 |             headers.insert(headers.cend(), begin_it, redownloaded_it); | 
| 100 | 0 |         } | 
| 101 |  |  | 
| 102 | 0 |         if (headers.empty()) return; | 
| 103 | 0 |         auto result = headers_sync.ProcessNextHeaders(headers, fuzzed_data_provider.ConsumeBool()); | 
| 104 | 0 |         requested_more = result.request_more; | 
| 105 |  | 
 | 
| 106 | 0 |         if (result.request_more) { | 
| 107 | 0 |             if (presync) { | 
| 108 | 0 |                 all_headers.insert(all_headers.cend(), headers.cbegin(), headers.cend()); | 
| 109 |  | 
 | 
| 110 | 0 |                 if (headers_sync.GetState() == HeadersSyncState::State::REDOWNLOAD) { | 
| 111 | 0 |                     presync = false; | 
| 112 | 0 |                     redownloaded_it = all_headers.cbegin(); | 
| 113 |  |  | 
| 114 |  |                     // If we get to redownloading, the presynced headers need | 
| 115 |  |                     // to have the min amount of work on them. | 
| 116 | 0 |                     assert(CalculateClaimedHeadersWork(all_headers) >= min_work); | 
| 117 | 0 |                 } | 
| 118 | 0 |             } | 
| 119 |  |  | 
| 120 | 0 |             (void)headers_sync.NextHeadersRequestLocator(); | 
| 121 | 0 |         } | 
| 122 | 0 |     } | 
| 123 | 0 | } |