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