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