Branch data Line data Source code
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 : 1 : static void initialize_headers_sync_state_fuzz()
21 : : {
22 : 1 : static const auto testing_setup = MakeNoLogFileContext<>(
23 [ + - + - ]: 2 : /*chain_type=*/ChainType::MAIN);
24 [ + - ]: 2 : }
25 : :
26 : 172587 : void MakeHeadersContinuous(
27 : : const CBlockHeader& genesis_header,
28 : : const std::vector<CBlockHeader>& all_headers,
29 : : std::vector<CBlockHeader>& new_headers)
30 : : {
31 : 172587 : Assume(!new_headers.empty());
32 : :
33 : 172587 : const CBlockHeader* prev_header{
34 [ + + ]: 172587 : all_headers.empty() ? &genesis_header : &all_headers.back()};
35 : :
36 [ + + ]: 355767 : for (auto& header : new_headers) {
37 : 183180 : header.hashPrevBlock = prev_header->GetHash();
38 : :
39 : 183180 : prev_header = &header;
40 : : }
41 : 172587 : }
42 : :
43 : 0 : class FuzzedHeadersSyncState : public HeadersSyncState
44 : : {
45 : : public:
46 : 215 : FuzzedHeadersSyncState(const unsigned commit_offset, const CBlockIndex* chain_start, const arith_uint256& minimum_required_work)
47 : 215 : : HeadersSyncState(/*id=*/0, Params().GetConsensus(), chain_start, minimum_required_work)
48 : : {
49 : 215 : const_cast<unsigned&>(m_commit_offset) = commit_offset;
50 : 215 : }
51 : : };
52 : :
53 [ + - ]: 662 : FUZZ_TARGET(headers_sync_state, .init = initialize_headers_sync_state_fuzz)
54 : : {
55 : 220 : SeedRandomStateForTest(SeedRand::ZEROS);
56 : 220 : FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
57 : 220 : auto mock_time{ConsumeTime(fuzzed_data_provider)};
58 : :
59 : 220 : CBlockHeader genesis_header{Params().GenesisBlock()};
60 : 220 : CBlockIndex start_index(genesis_header);
61 : :
62 [ + + ]: 220 : if (mock_time < start_index.GetMedianTimePast()) return;
63 : 215 : SetMockTime(mock_time);
64 : :
65 : 215 : const uint256 genesis_hash = genesis_header.GetHash();
66 : 215 : start_index.phashBlock = &genesis_hash;
67 : :
68 : 215 : arith_uint256 min_work{UintToArith256(ConsumeUInt256(fuzzed_data_provider))};
69 : 215 : FuzzedHeadersSyncState headers_sync(
70 : : /*commit_offset=*/fuzzed_data_provider.ConsumeIntegralInRange<unsigned>(1, 1024),
71 : : /*chain_start=*/&start_index,
72 : 215 : /*minimum_required_work=*/min_work);
73 : :
74 : : // Store headers for potential redownload phase.
75 : 215 : std::vector<CBlockHeader> all_headers;
76 : 215 : std::vector<CBlockHeader>::const_iterator redownloaded_it;
77 : 215 : bool presync{true};
78 : 215 : bool requested_more{true};
79 : :
80 [ + + ]: 172982 : while (requested_more) {
81 : 172852 : std::vector<CBlockHeader> headers;
82 : :
83 : : // Consume headers from fuzzer or maybe replay headers if we got to the
84 : : // redownload phase.
85 [ + + + + ]: 173023 : if (presync || fuzzed_data_provider.ConsumeBool()) {
86 : 172709 : auto deser_headers = ConsumeDeserializable<std::vector<CBlockHeader>>(fuzzed_data_provider);
87 [ + + + + ]: 172709 : if (!deser_headers || deser_headers->empty()) return;
88 : :
89 [ + + ]: 172624 : if (fuzzed_data_provider.ConsumeBool()) {
90 [ + - ]: 172587 : MakeHeadersContinuous(genesis_header, all_headers, *deser_headers);
91 : : }
92 : :
93 : 172624 : headers.swap(*deser_headers);
94 [ + - ]: 172852 : } 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 : 143 : auto begin_it{redownloaded_it};
98 : 143 : std::advance(redownloaded_it, fuzzed_data_provider.ConsumeIntegralInRange<int>(1, num_headers_left));
99 [ + - ]: 143 : headers.insert(headers.cend(), begin_it, redownloaded_it);
100 : : }
101 : :
102 [ + - ]: 172767 : if (headers.empty()) return;
103 [ + - ]: 172767 : auto result = headers_sync.ProcessNextHeaders(headers, fuzzed_data_provider.ConsumeBool());
104 : 172767 : requested_more = result.request_more;
105 : :
106 [ + + ]: 172767 : if (result.request_more) {
107 [ + + ]: 172637 : if (presync) {
108 [ + - ]: 172540 : all_headers.insert(all_headers.cend(), headers.cbegin(), headers.cend());
109 : :
110 [ + + ]: 172540 : if (headers_sync.GetState() == HeadersSyncState::State::REDOWNLOAD) {
111 : 74 : presync = false;
112 [ + - ]: 74 : 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 [ + - + - : 74 : assert(CalculateClaimedHeadersWork(all_headers) >= min_work);
- + ]
117 : : }
118 : : }
119 : :
120 [ + - ]: 345274 : (void)headers_sync.NextHeadersRequestLocator();
121 : : }
122 : 172852 : }
123 : 430 : }
|