mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-01-19 06:43:45 +01:00
This commit effectively moves the definition of these constants out of the chainparamsbase to their own file. Using the ChainType enums provides better type safety compared to passing around strings. The commit is part of an ongoing effort to decouple the libbitcoinkernel library from the ArgsManager and other functionality that should not be part of the kernel library.
119 lines
4.1 KiB
C++
119 lines
4.1 KiB
C++
#include <arith_uint256.h>
|
|
#include <chain.h>
|
|
#include <chainparams.h>
|
|
#include <headerssync.h>
|
|
#include <test/fuzz/fuzz.h>
|
|
#include <test/fuzz/util.h>
|
|
#include <test/util/setup_common.h>
|
|
#include <uint256.h>
|
|
#include <util/chaintype.h>
|
|
#include <util/time.h>
|
|
#include <validation.h>
|
|
|
|
#include <iterator>
|
|
#include <vector>
|
|
|
|
static void initialize_headers_sync_state_fuzz()
|
|
{
|
|
static const auto testing_setup = MakeNoLogFileContext<>(
|
|
/*chain_type=*/ChainType::MAIN);
|
|
}
|
|
|
|
void MakeHeadersContinuous(
|
|
const CBlockHeader& genesis_header,
|
|
const std::vector<CBlockHeader>& all_headers,
|
|
std::vector<CBlockHeader>& new_headers)
|
|
{
|
|
Assume(!new_headers.empty());
|
|
|
|
const CBlockHeader* prev_header{
|
|
all_headers.empty() ? &genesis_header : &all_headers.back()};
|
|
|
|
for (auto& header : new_headers) {
|
|
header.hashPrevBlock = prev_header->GetHash();
|
|
|
|
prev_header = &header;
|
|
}
|
|
}
|
|
|
|
class FuzzedHeadersSyncState : public HeadersSyncState
|
|
{
|
|
public:
|
|
FuzzedHeadersSyncState(const unsigned commit_offset, const CBlockIndex* chain_start, const arith_uint256& minimum_required_work)
|
|
: HeadersSyncState(/*id=*/0, Params().GetConsensus(), chain_start, minimum_required_work)
|
|
{
|
|
const_cast<unsigned&>(m_commit_offset) = commit_offset;
|
|
}
|
|
};
|
|
|
|
FUZZ_TARGET_INIT(headers_sync_state, initialize_headers_sync_state_fuzz)
|
|
{
|
|
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
|
|
auto mock_time{ConsumeTime(fuzzed_data_provider)};
|
|
|
|
CBlockHeader genesis_header{Params().GenesisBlock()};
|
|
CBlockIndex start_index(genesis_header);
|
|
|
|
if (mock_time < start_index.GetMedianTimePast()) return;
|
|
SetMockTime(mock_time);
|
|
|
|
const uint256 genesis_hash = genesis_header.GetHash();
|
|
start_index.phashBlock = &genesis_hash;
|
|
|
|
arith_uint256 min_work{UintToArith256(ConsumeUInt256(fuzzed_data_provider))};
|
|
FuzzedHeadersSyncState headers_sync(
|
|
/*commit_offset=*/fuzzed_data_provider.ConsumeIntegralInRange<unsigned>(1, 1024),
|
|
/*chain_start=*/&start_index,
|
|
/*minimum_required_work=*/min_work);
|
|
|
|
// Store headers for potential redownload phase.
|
|
std::vector<CBlockHeader> all_headers;
|
|
std::vector<CBlockHeader>::const_iterator redownloaded_it;
|
|
bool presync{true};
|
|
bool requested_more{true};
|
|
|
|
while (requested_more) {
|
|
std::vector<CBlockHeader> headers;
|
|
|
|
// Consume headers from fuzzer or maybe replay headers if we got to the
|
|
// redownload phase.
|
|
if (presync || fuzzed_data_provider.ConsumeBool()) {
|
|
auto deser_headers = ConsumeDeserializable<std::vector<CBlockHeader>>(fuzzed_data_provider);
|
|
if (!deser_headers || deser_headers->empty()) return;
|
|
|
|
if (fuzzed_data_provider.ConsumeBool()) {
|
|
MakeHeadersContinuous(genesis_header, all_headers, *deser_headers);
|
|
}
|
|
|
|
headers.swap(*deser_headers);
|
|
} else if (auto num_headers_left{std::distance(redownloaded_it, all_headers.cend())}; num_headers_left > 0) {
|
|
// Consume some headers from the redownload buffer (At least one
|
|
// header is consumed).
|
|
auto begin_it{redownloaded_it};
|
|
std::advance(redownloaded_it, fuzzed_data_provider.ConsumeIntegralInRange<int>(1, num_headers_left));
|
|
headers.insert(headers.cend(), begin_it, redownloaded_it);
|
|
}
|
|
|
|
if (headers.empty()) return;
|
|
auto result = headers_sync.ProcessNextHeaders(headers, fuzzed_data_provider.ConsumeBool());
|
|
requested_more = result.request_more;
|
|
|
|
if (result.request_more) {
|
|
if (presync) {
|
|
all_headers.insert(all_headers.cend(), headers.cbegin(), headers.cend());
|
|
|
|
if (headers_sync.GetState() == HeadersSyncState::State::REDOWNLOAD) {
|
|
presync = false;
|
|
redownloaded_it = all_headers.cbegin();
|
|
|
|
// If we get to redownloading, the presynced headers need
|
|
// to have the min amount of work on them.
|
|
assert(CalculateHeadersWork(all_headers) >= min_work);
|
|
}
|
|
}
|
|
|
|
(void)headers_sync.NextHeadersRequestLocator();
|
|
}
|
|
}
|
|
}
|