Bitcoin Core 30.99.0
P2P Digital Currency
headerssync.cpp
Go to the documentation of this file.
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>
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
21{
22 static const auto testing_setup = MakeNoLogFileContext<>(
23 /*chain_type=*/ChainType::MAIN);
24}
25
27 const CBlockHeader& genesis_header,
28 const std::vector<CBlockHeader>& all_headers,
29 std::vector<CBlockHeader>& new_headers)
30{
31 Assume(!new_headers.empty());
32
33 const CBlockHeader* prev_header{
34 all_headers.empty() ? &genesis_header : &all_headers.back()};
35
36 for (auto& header : new_headers) {
37 header.hashPrevBlock = prev_header->GetHash();
38
39 prev_header = &header;
40 }
41}
42
44{
45public:
46 FuzzedHeadersSyncState(const HeadersSyncParams& sync_params, const size_t commit_offset,
47 const CBlockIndex* chain_start, const arith_uint256& minimum_required_work)
48 : HeadersSyncState(/*id=*/0, Params().GetConsensus(), sync_params, chain_start, minimum_required_work)
49 {
50 const_cast<size_t&>(m_commit_offset) = commit_offset;
51 }
52};
53
55{
57 FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
58 auto mock_time{ConsumeTime(fuzzed_data_provider)};
59
60 CBlockHeader genesis_header{Params().GenesisBlock()};
61 CBlockIndex start_index(genesis_header);
62
63 if (mock_time < start_index.GetMedianTimePast()) return;
64 SetMockTime(mock_time);
65
66 const uint256 genesis_hash = genesis_header.GetHash();
67 start_index.phashBlock = &genesis_hash;
68
69 const HeadersSyncParams params{
71 .redownload_buffer_size = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, Params().HeadersSync().redownload_buffer_size * 2),
72 };
74 FuzzedHeadersSyncState headers_sync(
75 params,
76 /*commit_offset=*/fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, params.commitment_period - 1),
77 /*chain_start=*/&start_index,
78 /*minimum_required_work=*/min_work);
79
80 // Store headers for potential redownload phase.
81 std::vector<CBlockHeader> all_headers;
82 std::vector<CBlockHeader>::const_iterator redownloaded_it;
83 bool presync{true};
84 bool requested_more{true};
85
86 while (requested_more) {
87 std::vector<CBlockHeader> headers;
88
89 // Consume headers from fuzzer or maybe replay headers if we got to the
90 // redownload phase.
91 if (presync || fuzzed_data_provider.ConsumeBool()) {
92 auto deser_headers = ConsumeDeserializable<std::vector<CBlockHeader>>(fuzzed_data_provider);
93 if (!deser_headers || deser_headers->empty()) return;
94
96 MakeHeadersContinuous(genesis_header, all_headers, *deser_headers);
97 }
98
99 headers.swap(*deser_headers);
100 } else if (auto num_headers_left{std::distance(redownloaded_it, all_headers.cend())}; num_headers_left > 0) {
101 // Consume some headers from the redownload buffer (At least one
102 // header is consumed).
103 auto begin_it{redownloaded_it};
104 std::advance(redownloaded_it, fuzzed_data_provider.ConsumeIntegralInRange<int>(1, num_headers_left));
105 headers.insert(headers.cend(), begin_it, redownloaded_it);
106 }
107
108 if (headers.empty()) return;
109 auto result = headers_sync.ProcessNextHeaders(headers, fuzzed_data_provider.ConsumeBool());
110 requested_more = result.request_more;
111
112 if (result.request_more) {
113 if (presync) {
114 all_headers.insert(all_headers.cend(), headers.cbegin(), headers.cend());
115
116 if (headers_sync.GetState() == HeadersSyncState::State::REDOWNLOAD) {
117 presync = false;
118 redownloaded_it = all_headers.cbegin();
119
120 // If we get to redownloading, the presynced headers need
121 // to have the min amount of work on them.
122 assert(CalculateClaimedHeadersWork(all_headers) >= min_work);
123 }
124 }
125
126 (void)headers_sync.NextHeadersRequestLocator();
127 }
128 }
129}
arith_uint256 UintToArith256(const uint256 &a)
const CChainParams & Params()
Return the currently selected parameters.
#define Assume(val)
Assume is the identity function.
Definition: check.h:127
Nodes collect new transactions into a block, hash them into a hash tree, and scan through nonce value...
Definition: block.h:22
uint256 hashPrevBlock
Definition: block.h:26
The block chain is a tree shaped structure starting with the genesis block at the root,...
Definition: chain.h:144
int64_t GetMedianTimePast() const
Definition: chain.h:283
const uint256 * phashBlock
pointer to the hash of the block, if any. Memory is owned by this CBlockIndex
Definition: chain.h:147
const CBlock & GenesisBlock() const
Definition: chainparams.h:95
const HeadersSyncParams & HeadersSync() const
Definition: chainparams.h:118
T ConsumeIntegralInRange(T min, T max)
FuzzedHeadersSyncState(const HeadersSyncParams &sync_params, const size_t commit_offset, const CBlockIndex *chain_start, const arith_uint256 &minimum_required_work)
Definition: headerssync.cpp:46
HeadersSyncState:
Definition: headerssync.h:101
@ REDOWNLOAD
REDOWNLOAD means the peer has given us a high-enough-work chain, and now we're redownloading the head...
ProcessingResult ProcessNextHeaders(std::span< const CBlockHeader > received_headers, bool full_headers_message)
Process a batch of headers, once a sync via this mechanism has started.
Definition: headerssync.cpp:65
State GetState() const
Return the current state of our download.
Definition: headerssync.h:119
const size_t m_commit_offset
The (secret) offset on the heights for which to create commitments.
Definition: headerssync.h:184
CBlockLocator NextHeadersRequestLocator() const
Issue the next GETHEADERS message to our peer.
256-bit unsigned big integer.
256-bit opaque blob.
Definition: uint256.h:196
Configuration for headers sync memory usage.
Definition: chainparams.h:65
size_t redownload_buffer_size
Minimum number of validated headers to accumulate in the redownload buffer before feeding them into t...
Definition: chainparams.h:70
size_t commitment_period
Distance in blocks between header commitments.
Definition: chainparams.h:67
static void initialize_headers_sync_state_fuzz()
Definition: headerssync.cpp:20
FUZZ_TARGET(headers_sync_state,.init=initialize_headers_sync_state_fuzz)
Definition: headerssync.cpp:54
void MakeHeadersContinuous(const CBlockHeader &genesis_header, const std::vector< CBlockHeader > &all_headers, std::vector< CBlockHeader > &new_headers)
Definition: headerssync.cpp:26
int64_t ConsumeTime(FuzzedDataProvider &fuzzed_data_provider, const std::optional< int64_t > &min, const std::optional< int64_t > &max) noexcept
Definition: util.cpp:34
uint256 ConsumeUInt256(FuzzedDataProvider &fuzzed_data_provider) noexcept
Definition: util.h:171
void SeedRandomStateForTest(SeedRand seedtype)
Seed the global RNG state for testing and log the seed value.
Definition: random.cpp:19
@ ZEROS
Seed with a compile time constant of zeros.
void SetMockTime(int64_t nMockTimeIn)
DEPRECATED Use SetMockTime with chrono type.
Definition: time.cpp:40
arith_uint256 CalculateClaimedHeadersWork(std::span< const CBlockHeader > headers)
Return the sum of the claimed work on a given set of headers.
assert(!tx.IsCoinBase())
FuzzedDataProvider & fuzzed_data_provider
Definition: fees.cpp:38