mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-02-03 09:56:38 -05:00
[fuzz] Add HeadersSyncState target
This commit is contained in:
parent
53552affca
commit
3153e7d779
2 changed files with 118 additions and 0 deletions
|
@ -269,6 +269,7 @@ test_fuzz_fuzz_SOURCES = \
|
||||||
test/fuzz/flatfile.cpp \
|
test/fuzz/flatfile.cpp \
|
||||||
test/fuzz/float.cpp \
|
test/fuzz/float.cpp \
|
||||||
test/fuzz/golomb_rice.cpp \
|
test/fuzz/golomb_rice.cpp \
|
||||||
|
test/fuzz/headerssync.cpp \
|
||||||
test/fuzz/hex.cpp \
|
test/fuzz/hex.cpp \
|
||||||
test/fuzz/http_request.cpp \
|
test/fuzz/http_request.cpp \
|
||||||
test/fuzz/i2p.cpp \
|
test/fuzz/i2p.cpp \
|
||||||
|
|
117
src/test/fuzz/headerssync.cpp
Normal file
117
src/test/fuzz/headerssync.cpp
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
#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/time.h>
|
||||||
|
#include <validation.h>
|
||||||
|
|
||||||
|
#include <iterator>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
static void initialize_headers_sync_state_fuzz()
|
||||||
|
{
|
||||||
|
static const auto testing_setup = MakeNoLogFileContext<>(
|
||||||
|
/*chain_name=*/CBaseChainParams::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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue