aboutsummaryrefslogtreecommitdiff
path: root/src/test/fuzz
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/fuzz')
-rw-r--r--src/test/fuzz/CMakeLists.txt147
-rw-r--r--src/test/fuzz/addrman.cpp40
-rw-r--r--src/test/fuzz/autofile.cpp1
-rw-r--r--src/test/fuzz/banman.cpp8
-rw-r--r--src/test/fuzz/bip324.cpp7
-rw-r--r--src/test/fuzz/buffered_file.cpp4
-rw-r--r--src/test/fuzz/cluster_linearize.cpp88
-rw-r--r--src/test/fuzz/connman.cpp16
-rw-r--r--src/test/fuzz/crypto.cpp8
-rw-r--r--src/test/fuzz/crypto_chacha20.cpp9
-rw-r--r--src/test/fuzz/crypto_chacha20poly1305.cpp2
-rw-r--r--src/test/fuzz/cuckoocache.cpp4
-rw-r--r--src/test/fuzz/descriptor_parse.cpp30
-rw-r--r--src/test/fuzz/fuzz.cpp4
-rw-r--r--src/test/fuzz/hex.cpp15
-rw-r--r--src/test/fuzz/integer.cpp4
-rw-r--r--src/test/fuzz/message.cpp4
-rw-r--r--src/test/fuzz/miniscript.cpp4
-rw-r--r--src/test/fuzz/p2p_handshake.cpp2
-rw-r--r--src/test/fuzz/p2p_headers_presync.cpp200
-rw-r--r--src/test/fuzz/p2p_transport_serialization.cpp7
-rw-r--r--src/test/fuzz/policy_estimator.cpp13
-rw-r--r--src/test/fuzz/poolresource.cpp2
-rw-r--r--src/test/fuzz/pow.cpp2
-rw-r--r--src/test/fuzz/prevector.cpp33
-rw-r--r--src/test/fuzz/script_format.cpp4
-rw-r--r--src/test/fuzz/script_interpreter.cpp10
-rw-r--r--src/test/fuzz/script_sign.cpp9
-rw-r--r--src/test/fuzz/secp256k1_ec_seckey_import_export_der.cpp2
-rw-r--r--src/test/fuzz/socks5.cpp8
-rw-r--r--src/test/fuzz/span.cpp6
-rw-r--r--src/test/fuzz/system.cpp18
-rw-r--r--src/test/fuzz/util/CMakeLists.txt23
-rw-r--r--src/test/fuzz/util/net.cpp12
-rw-r--r--src/test/fuzz/utxo_snapshot.cpp4
35 files changed, 639 insertions, 111 deletions
diff --git a/src/test/fuzz/CMakeLists.txt b/src/test/fuzz/CMakeLists.txt
new file mode 100644
index 0000000000..1c7b0d5c25
--- /dev/null
+++ b/src/test/fuzz/CMakeLists.txt
@@ -0,0 +1,147 @@
+# Copyright (c) 2023-present The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or https://opensource.org/license/mit/.
+
+add_subdirectory(util)
+
+add_executable(fuzz
+ addition_overflow.cpp
+ addrman.cpp
+ asmap.cpp
+ asmap_direct.cpp
+ autofile.cpp
+ banman.cpp
+ base_encode_decode.cpp
+ bech32.cpp
+ bip324.cpp
+ bitdeque.cpp
+ bitset.cpp
+ block.cpp
+ block_header.cpp
+ block_index.cpp
+ blockfilter.cpp
+ bloom_filter.cpp
+ buffered_file.cpp
+ chain.cpp
+ checkqueue.cpp
+ cluster_linearize.cpp
+ coins_view.cpp
+ coinscache_sim.cpp
+ connman.cpp
+ crypto.cpp
+ crypto_aes256.cpp
+ crypto_aes256cbc.cpp
+ crypto_chacha20.cpp
+ crypto_chacha20poly1305.cpp
+ crypto_common.cpp
+ crypto_diff_fuzz_chacha20.cpp
+ crypto_hkdf_hmac_sha256_l32.cpp
+ crypto_poly1305.cpp
+ cuckoocache.cpp
+ decode_tx.cpp
+ descriptor_parse.cpp
+ deserialize.cpp
+ eval_script.cpp
+ feefrac.cpp
+ fee_rate.cpp
+ feeratediagram.cpp
+ fees.cpp
+ flatfile.cpp
+ float.cpp
+ golomb_rice.cpp
+ headerssync.cpp
+ hex.cpp
+ http_request.cpp
+ i2p.cpp
+ integer.cpp
+ key.cpp
+ key_io.cpp
+ kitchen_sink.cpp
+ load_external_block_file.cpp
+ locale.cpp
+ merkleblock.cpp
+ message.cpp
+ miniscript.cpp
+ minisketch.cpp
+ mini_miner.cpp
+ muhash.cpp
+ multiplication_overflow.cpp
+ net.cpp
+ net_permissions.cpp
+ netaddress.cpp
+ netbase_dns_lookup.cpp
+ node_eviction.cpp
+ p2p_handshake.cpp
+ p2p_headers_presync.cpp
+ p2p_transport_serialization.cpp
+ package_eval.cpp
+ parse_hd_keypath.cpp
+ parse_numbers.cpp
+ parse_script.cpp
+ parse_univalue.cpp
+ partially_downloaded_block.cpp
+ policy_estimator.cpp
+ policy_estimator_io.cpp
+ poolresource.cpp
+ pow.cpp
+ prevector.cpp
+ primitives_transaction.cpp
+ process_message.cpp
+ process_messages.cpp
+ protocol.cpp
+ psbt.cpp
+ random.cpp
+ rbf.cpp
+ rolling_bloom_filter.cpp
+ rpc.cpp
+ script.cpp
+ script_assets_test_minimizer.cpp
+ script_descriptor_cache.cpp
+ script_flags.cpp
+ script_format.cpp
+ script_interpreter.cpp
+ script_ops.cpp
+ script_parsing.cpp
+ script_sigcache.cpp
+ script_sign.cpp
+ scriptnum_ops.cpp
+ secp256k1_ec_seckey_import_export_der.cpp
+ secp256k1_ecdsa_signature_parse_der_lax.cpp
+ signature_checker.cpp
+ signet.cpp
+ socks5.cpp
+ span.cpp
+ string.cpp
+ strprintf.cpp
+ system.cpp
+ timeoffsets.cpp
+ torcontrol.cpp
+ transaction.cpp
+ tx_in.cpp
+ tx_out.cpp
+ tx_pool.cpp
+ txorphan.cpp
+ txrequest.cpp
+ utxo_snapshot.cpp
+ utxo_total_supply.cpp
+ validation_load_mempool.cpp
+ vecdeque.cpp
+ versionbits.cpp
+)
+target_link_libraries(fuzz
+ core_interface
+ test_fuzz
+ bitcoin_cli
+ bitcoin_common
+ bitcoin_util
+ minisketch
+ leveldb
+ univalue
+ secp256k1
+ Boost::headers
+ $<TARGET_NAME_IF_EXISTS:libevent::libevent>
+)
+
+if(ENABLE_WALLET)
+ add_subdirectory(${PROJECT_SOURCE_DIR}/src/wallet/test/fuzz wallet)
+endif()
diff --git a/src/test/fuzz/addrman.cpp b/src/test/fuzz/addrman.cpp
index dbec2bc858..593086af21 100644
--- a/src/test/fuzz/addrman.cpp
+++ b/src/test/fuzz/addrman.cpp
@@ -250,19 +250,30 @@ FUZZ_TARGET(addrman, .init = initialize_addrman)
LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 10000) {
addresses.push_back(ConsumeAddress(fuzzed_data_provider));
}
- addr_man.Add(addresses, ConsumeNetAddr(fuzzed_data_provider), std::chrono::seconds{ConsumeTime(fuzzed_data_provider, 0, 100000000)});
+ auto net_addr = ConsumeNetAddr(fuzzed_data_provider);
+ auto time_penalty = std::chrono::seconds{ConsumeTime(fuzzed_data_provider, 0, 100000000)};
+ addr_man.Add(addresses, net_addr, time_penalty);
},
[&] {
- addr_man.Good(ConsumeService(fuzzed_data_provider), NodeSeconds{std::chrono::seconds{ConsumeTime(fuzzed_data_provider)}});
+ auto addr = ConsumeService(fuzzed_data_provider);
+ auto time = NodeSeconds{std::chrono::seconds{ConsumeTime(fuzzed_data_provider)}};
+ addr_man.Good(addr, time);
},
[&] {
- addr_man.Attempt(ConsumeService(fuzzed_data_provider), fuzzed_data_provider.ConsumeBool(), NodeSeconds{std::chrono::seconds{ConsumeTime(fuzzed_data_provider)}});
+ auto addr = ConsumeService(fuzzed_data_provider);
+ auto count_failure = fuzzed_data_provider.ConsumeBool();
+ auto time = NodeSeconds{std::chrono::seconds{ConsumeTime(fuzzed_data_provider)}};
+ addr_man.Attempt(addr, count_failure, time);
},
[&] {
- addr_man.Connected(ConsumeService(fuzzed_data_provider), NodeSeconds{std::chrono::seconds{ConsumeTime(fuzzed_data_provider)}});
+ auto addr = ConsumeService(fuzzed_data_provider);
+ auto time = NodeSeconds{std::chrono::seconds{ConsumeTime(fuzzed_data_provider)}};
+ addr_man.Connected(addr, time);
},
[&] {
- addr_man.SetServices(ConsumeService(fuzzed_data_provider), ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS));
+ auto addr = ConsumeService(fuzzed_data_provider);
+ auto n_services = ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS);
+ addr_man.SetServices(addr, n_services);
});
}
const AddrMan& const_addr_man{addr_man};
@@ -270,12 +281,19 @@ FUZZ_TARGET(addrman, .init = initialize_addrman)
if (fuzzed_data_provider.ConsumeBool()) {
network = fuzzed_data_provider.PickValueInArray(ALL_NETWORKS);
}
- (void)const_addr_man.GetAddr(
- /*max_addresses=*/fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096),
- /*max_pct=*/fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096),
- network,
- /*filtered=*/fuzzed_data_provider.ConsumeBool());
- (void)const_addr_man.Select(fuzzed_data_provider.ConsumeBool(), network);
+ auto max_addresses = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096);
+ auto max_pct = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096);
+ auto filtered = fuzzed_data_provider.ConsumeBool();
+ (void)const_addr_man.GetAddr(max_addresses, max_pct, network, filtered);
+
+ std::unordered_set<Network> nets;
+ for (const auto& net : ALL_NETWORKS) {
+ if (fuzzed_data_provider.ConsumeBool()) {
+ nets.insert(net);
+ }
+ }
+ (void)const_addr_man.Select(fuzzed_data_provider.ConsumeBool(), nets);
+
std::optional<bool> in_new;
if (fuzzed_data_provider.ConsumeBool()) {
in_new = fuzzed_data_provider.ConsumeBool();
diff --git a/src/test/fuzz/autofile.cpp b/src/test/fuzz/autofile.cpp
index 45316b6b21..81761c7bf9 100644
--- a/src/test/fuzz/autofile.cpp
+++ b/src/test/fuzz/autofile.cpp
@@ -56,7 +56,6 @@ FUZZ_TARGET(autofile)
WriteToStream(fuzzed_data_provider, auto_file);
});
}
- (void)auto_file.Get();
(void)auto_file.IsNull();
if (fuzzed_data_provider.ConsumeBool()) {
FILE* f = auto_file.release();
diff --git a/src/test/fuzz/banman.cpp b/src/test/fuzz/banman.cpp
index b26151f63c..4165cc6b2c 100644
--- a/src/test/fuzz/banman.cpp
+++ b/src/test/fuzz/banman.cpp
@@ -78,7 +78,9 @@ FUZZ_TARGET(banman, .init = initialize_banman)
contains_invalid = true;
}
}
- ban_man.Ban(net_addr, ConsumeBanTimeOffset(fuzzed_data_provider), fuzzed_data_provider.ConsumeBool());
+ auto ban_time_offset = ConsumeBanTimeOffset(fuzzed_data_provider);
+ auto since_unix_epoch = fuzzed_data_provider.ConsumeBool();
+ ban_man.Ban(net_addr, ban_time_offset, since_unix_epoch);
},
[&] {
CSubNet subnet{ConsumeSubNet(fuzzed_data_provider)};
@@ -86,7 +88,9 @@ FUZZ_TARGET(banman, .init = initialize_banman)
if (!subnet.IsValid()) {
contains_invalid = true;
}
- ban_man.Ban(subnet, ConsumeBanTimeOffset(fuzzed_data_provider), fuzzed_data_provider.ConsumeBool());
+ auto ban_time_offset = ConsumeBanTimeOffset(fuzzed_data_provider);
+ auto since_unix_epoch = fuzzed_data_provider.ConsumeBool();
+ ban_man.Ban(subnet, ban_time_offset, since_unix_epoch);
},
[&] {
ban_man.ClearBanned();
diff --git a/src/test/fuzz/bip324.cpp b/src/test/fuzz/bip324.cpp
index 9892e7a81c..f1fa15d8a3 100644
--- a/src/test/fuzz/bip324.cpp
+++ b/src/test/fuzz/bip324.cpp
@@ -10,6 +10,7 @@
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
+#include <algorithm>
#include <cstdint>
#include <vector>
@@ -59,9 +60,9 @@ FUZZ_TARGET(bip324_cipher_roundtrip, .init=Initialize)
InsecureRandomContext rng(provider.ConsumeIntegral<uint64_t>());
// Compare session IDs and garbage terminators.
- assert(initiator.GetSessionID() == responder.GetSessionID());
- assert(initiator.GetSendGarbageTerminator() == responder.GetReceiveGarbageTerminator());
- assert(initiator.GetReceiveGarbageTerminator() == responder.GetSendGarbageTerminator());
+ assert(std::ranges::equal(initiator.GetSessionID(), responder.GetSessionID()));
+ assert(std::ranges::equal(initiator.GetSendGarbageTerminator(), responder.GetReceiveGarbageTerminator()));
+ assert(std::ranges::equal(initiator.GetReceiveGarbageTerminator(), responder.GetSendGarbageTerminator()));
LIMITED_WHILE(provider.remaining_bytes(), 1000) {
// Mode:
diff --git a/src/test/fuzz/buffered_file.cpp b/src/test/fuzz/buffered_file.cpp
index e30c19b265..a6a042a25c 100644
--- a/src/test/fuzz/buffered_file.cpp
+++ b/src/test/fuzz/buffered_file.cpp
@@ -25,7 +25,9 @@ FUZZ_TARGET(buffered_file)
ConsumeRandomLengthByteVector<std::byte>(fuzzed_data_provider),
};
try {
- opt_buffered_file.emplace(fuzzed_file, fuzzed_data_provider.ConsumeIntegralInRange<uint64_t>(0, 4096), fuzzed_data_provider.ConsumeIntegralInRange<uint64_t>(0, 4096));
+ auto n_buf_size = fuzzed_data_provider.ConsumeIntegralInRange<uint64_t>(0, 4096);
+ auto n_rewind_in = fuzzed_data_provider.ConsumeIntegralInRange<uint64_t>(0, 4096);
+ opt_buffered_file.emplace(fuzzed_file, n_buf_size, n_rewind_in);
} catch (const std::ios_base::failure&) {
}
if (opt_buffered_file && !fuzzed_file.IsNull()) {
diff --git a/src/test/fuzz/cluster_linearize.cpp b/src/test/fuzz/cluster_linearize.cpp
index 2dfdfbb41d..d91f85d867 100644
--- a/src/test/fuzz/cluster_linearize.cpp
+++ b/src/test/fuzz/cluster_linearize.cpp
@@ -165,6 +165,23 @@ std::pair<std::vector<ClusterIndex>, bool> SimpleLinearize(const DepGraph<SetTyp
return {std::move(linearization), optimal};
}
+/** Stitch connected components together in a DepGraph, guaranteeing its corresponding cluster is connected. */
+template<typename BS>
+void MakeConnected(DepGraph<BS>& depgraph)
+{
+ auto todo = BS::Fill(depgraph.TxCount());
+ auto comp = depgraph.FindConnectedComponent(todo);
+ Assume(depgraph.IsConnected(comp));
+ todo -= comp;
+ while (todo.Any()) {
+ auto nextcomp = depgraph.FindConnectedComponent(todo);
+ Assume(depgraph.IsConnected(nextcomp));
+ depgraph.AddDependency(comp.Last(), nextcomp.First());
+ todo -= nextcomp;
+ comp = nextcomp;
+ }
+}
+
/** Given a dependency graph, and a todo set, read a topological subset of todo from reader. */
template<typename SetType>
SetType ReadTopologicalSet(const DepGraph<SetType>& depgraph, const SetType& todo, SpanReader& reader)
@@ -369,6 +386,20 @@ FUZZ_TARGET(clusterlin_components)
assert(depgraph.FindConnectedComponent(todo).None());
}
+FUZZ_TARGET(clusterlin_make_connected)
+{
+ // Verify that MakeConnected makes graphs connected.
+
+ SpanReader reader(buffer);
+ DepGraph<TestBitSet> depgraph;
+ try {
+ reader >> Using<DepGraphFormatter>(depgraph);
+ } catch (const std::ios_base::failure&) {}
+ MakeConnected(depgraph);
+ SanityCheck(depgraph);
+ assert(depgraph.IsConnected());
+}
+
FUZZ_TARGET(clusterlin_chunking)
{
// Verify the correctness of the ChunkLinearization function.
@@ -398,7 +429,7 @@ FUZZ_TARGET(clusterlin_chunking)
SetInfo<TestBitSet> accumulator, best;
for (ClusterIndex idx : linearization) {
if (todo[idx]) {
- accumulator |= SetInfo(depgraph, idx);
+ accumulator.Set(depgraph, idx);
if (best.feerate.IsEmpty() || accumulator.feerate >> best.feerate) {
best = accumulator;
}
@@ -427,6 +458,7 @@ FUZZ_TARGET(clusterlin_ancestor_finder)
while (todo.Any()) {
// Call the ancestor finder's FindCandidateSet for what remains of the graph.
assert(!anc_finder.AllDone());
+ assert(todo.Count() == anc_finder.NumRemaining());
auto best_anc = anc_finder.FindCandidateSet();
// Sanity check the result.
assert(best_anc.transactions.Any());
@@ -458,6 +490,7 @@ FUZZ_TARGET(clusterlin_ancestor_finder)
anc_finder.MarkDone(del_set);
}
assert(anc_finder.AllDone());
+ assert(anc_finder.NumRemaining() == 0);
}
static constexpr auto MAX_SIMPLE_ITERATIONS = 300000;
@@ -468,13 +501,17 @@ FUZZ_TARGET(clusterlin_search_finder)
// and comparing with the results from SimpleCandidateFinder, ExhaustiveCandidateFinder, and
// AncestorCandidateFinder.
- // Retrieve an RNG seed and a depgraph from the fuzz input.
+ // Retrieve an RNG seed, a depgraph, and whether to make it connected, from the fuzz input.
SpanReader reader(buffer);
DepGraph<TestBitSet> depgraph;
uint64_t rng_seed{0};
+ uint8_t make_connected{1};
try {
- reader >> Using<DepGraphFormatter>(depgraph) >> rng_seed;
+ reader >> Using<DepGraphFormatter>(depgraph) >> rng_seed >> make_connected;
} catch (const std::ios_base::failure&) {}
+ // The most complicated graphs are connected ones (other ones just split up). Optionally force
+ // the graph to be connected.
+ if (make_connected) MakeConnected(depgraph);
// Instantiate ALL the candidate finders.
SearchCandidateFinder src_finder(depgraph, rng_seed);
@@ -488,6 +525,7 @@ FUZZ_TARGET(clusterlin_search_finder)
assert(!smp_finder.AllDone());
assert(!exh_finder.AllDone());
assert(!anc_finder.AllDone());
+ assert(anc_finder.NumRemaining() == todo.Count());
// For each iteration, read an iteration count limit from the fuzz input.
uint64_t max_iterations = 1;
@@ -513,9 +551,17 @@ FUZZ_TARGET(clusterlin_search_finder)
assert(found.transactions.IsSupersetOf(depgraph.Ancestors(i) & todo));
}
- // At most 2^N-1 iterations can be required: the number of non-empty subsets a graph with N
- // transactions has.
- assert(iterations_done <= ((uint64_t{1} << todo.Count()) - 1));
+ // At most 2^(N-1) iterations can be required: the maximum number of non-empty topological
+ // subsets a (connected) cluster with N transactions can have. Even when the cluster is no
+ // longer connected after removing certain transactions, this holds, because the connected
+ // components are searched separately.
+ assert(iterations_done <= (uint64_t{1} << (todo.Count() - 1)));
+ // Additionally, test that no more than sqrt(2^N)+1 iterations are required. This is just
+ // an empirical bound that seems to hold, without proof. Still, add a test for it so we
+ // can learn about counterexamples if they exist.
+ if (iterations_done >= 1 && todo.Count() <= 63) {
+ Assume((iterations_done - 1) * (iterations_done - 1) <= uint64_t{1} << todo.Count());
+ }
// Perform quality checks only if SearchCandidateFinder claims an optimal result.
if (iterations_done < max_iterations) {
@@ -562,6 +608,7 @@ FUZZ_TARGET(clusterlin_search_finder)
assert(smp_finder.AllDone());
assert(exh_finder.AllDone());
assert(anc_finder.AllDone());
+ assert(anc_finder.NumRemaining() == 0);
}
FUZZ_TARGET(clusterlin_linearization_chunking)
@@ -621,7 +668,7 @@ FUZZ_TARGET(clusterlin_linearization_chunking)
SetInfo<TestBitSet> accumulator, best;
for (auto j : linearization) {
if (todo[j] && !combined[j]) {
- accumulator |= SetInfo(depgraph, j);
+ accumulator.Set(depgraph, j);
if (best.feerate.IsEmpty() || accumulator.feerate > best.feerate) {
best = accumulator;
}
@@ -685,14 +732,19 @@ FUZZ_TARGET(clusterlin_linearize)
{
// Verify the behavior of Linearize().
- // Retrieve an RNG seed, an iteration count, and a depgraph from the fuzz input.
+ // Retrieve an RNG seed, an iteration count, a depgraph, and whether to make it connected from
+ // the fuzz input.
SpanReader reader(buffer);
DepGraph<TestBitSet> depgraph;
uint64_t rng_seed{0};
uint64_t iter_count{0};
+ uint8_t make_connected{1};
try {
- reader >> VARINT(iter_count) >> Using<DepGraphFormatter>(depgraph) >> rng_seed;
+ reader >> VARINT(iter_count) >> Using<DepGraphFormatter>(depgraph) >> rng_seed >> make_connected;
} catch (const std::ios_base::failure&) {}
+ // The most complicated graphs are connected ones (other ones just split up). Optionally force
+ // the graph to be connected.
+ if (make_connected) MakeConnected(depgraph);
// Optionally construct an old linearization for it.
std::vector<ClusterIndex> old_linearization;
@@ -721,12 +773,24 @@ FUZZ_TARGET(clusterlin_linearize)
}
// If the iteration count is sufficiently high, an optimal linearization must be found.
- // Each linearization step can use up to 2^k iterations, with steps k=1..n. That sum is
- // 2 * (2^n - 1)
+ // Each linearization step can use up to 2^(k-1) iterations, with steps k=1..n. That sum is
+ // 2^n - 1.
const uint64_t n = depgraph.TxCount();
- if (n <= 18 && iter_count > 2U * ((uint64_t{1} << n) - 1U)) {
+ if (n <= 19 && iter_count > (uint64_t{1} << n)) {
assert(optimal);
}
+ // Additionally, if the assumption of sqrt(2^k)+1 iterations per step holds, plus ceil(k/4)
+ // start-up cost per step, plus ceil(n^2/64) start-up cost overall, we can compute the upper
+ // bound for a whole linearization (summing for k=1..n) using the Python expression
+ // [sum((k+3)//4 + int(math.sqrt(2**k)) + 1 for k in range(1, n + 1)) + (n**2 + 63) // 64 for n in range(0, 35)]:
+ static constexpr uint64_t MAX_OPTIMAL_ITERS[] = {
+ 0, 4, 8, 12, 18, 26, 37, 51, 70, 97, 133, 182, 251, 346, 480, 666, 927, 1296, 1815, 2545,
+ 3576, 5031, 7087, 9991, 14094, 19895, 28096, 39690, 56083, 79263, 112041, 158391, 223936,
+ 316629, 447712
+ };
+ if (n < std::size(MAX_OPTIMAL_ITERS) && iter_count >= MAX_OPTIMAL_ITERS[n]) {
+ Assume(optimal);
+ }
// If Linearize claims optimal result, run quality tests.
if (optimal) {
diff --git a/src/test/fuzz/connman.cpp b/src/test/fuzz/connman.cpp
index 8f5f6a6071..beefc9d82e 100644
--- a/src/test/fuzz/connman.cpp
+++ b/src/test/fuzz/connman.cpp
@@ -91,17 +91,15 @@ FUZZ_TARGET(connman, .init = initialize_connman)
(void)connman.ForNode(fuzzed_data_provider.ConsumeIntegral<NodeId>(), [&](auto) { return fuzzed_data_provider.ConsumeBool(); });
},
[&] {
- (void)connman.GetAddresses(
- /*max_addresses=*/fuzzed_data_provider.ConsumeIntegral<size_t>(),
- /*max_pct=*/fuzzed_data_provider.ConsumeIntegral<size_t>(),
- /*network=*/std::nullopt,
- /*filtered=*/fuzzed_data_provider.ConsumeBool());
+ auto max_addresses = fuzzed_data_provider.ConsumeIntegral<size_t>();
+ auto max_pct = fuzzed_data_provider.ConsumeIntegral<size_t>();
+ auto filtered = fuzzed_data_provider.ConsumeBool();
+ (void)connman.GetAddresses(max_addresses, max_pct, /*network=*/std::nullopt, filtered);
},
[&] {
- (void)connman.GetAddresses(
- /*requestor=*/random_node,
- /*max_addresses=*/fuzzed_data_provider.ConsumeIntegral<size_t>(),
- /*max_pct=*/fuzzed_data_provider.ConsumeIntegral<size_t>());
+ auto max_addresses = fuzzed_data_provider.ConsumeIntegral<size_t>();
+ auto max_pct = fuzzed_data_provider.ConsumeIntegral<size_t>();
+ (void)connman.GetAddresses(/*requestor=*/random_node, max_addresses, max_pct);
},
[&] {
(void)connman.GetDeterministicRandomizer(fuzzed_data_provider.ConsumeIntegral<uint64_t>());
diff --git a/src/test/fuzz/crypto.cpp b/src/test/fuzz/crypto.cpp
index ca8c1cd033..aa478277e3 100644
--- a/src/test/fuzz/crypto.cpp
+++ b/src/test/fuzz/crypto.cpp
@@ -22,7 +22,9 @@ FUZZ_TARGET(crypto)
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
std::vector<uint8_t> data = ConsumeRandomLengthByteVector(fuzzed_data_provider);
if (data.empty()) {
- data.resize(fuzzed_data_provider.ConsumeIntegralInRange<size_t>(1, 4096), fuzzed_data_provider.ConsumeIntegral<uint8_t>());
+ auto new_size = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(1, 4096);
+ auto x = fuzzed_data_provider.ConsumeIntegral<uint8_t>();
+ data.resize(new_size, x);
}
CHash160 hash160;
@@ -44,7 +46,9 @@ FUZZ_TARGET(crypto)
if (fuzzed_data_provider.ConsumeBool()) {
data = ConsumeRandomLengthByteVector(fuzzed_data_provider);
if (data.empty()) {
- data.resize(fuzzed_data_provider.ConsumeIntegralInRange<size_t>(1, 4096), fuzzed_data_provider.ConsumeIntegral<uint8_t>());
+ auto new_size = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(1, 4096);
+ auto x = fuzzed_data_provider.ConsumeIntegral<uint8_t>();
+ data.resize(new_size, x);
}
}
diff --git a/src/test/fuzz/crypto_chacha20.cpp b/src/test/fuzz/crypto_chacha20.cpp
index d115a2b7e1..fe47f18923 100644
--- a/src/test/fuzz/crypto_chacha20.cpp
+++ b/src/test/fuzz/crypto_chacha20.cpp
@@ -28,11 +28,10 @@ FUZZ_TARGET(crypto_chacha20)
chacha20.SetKey(key);
},
[&] {
- chacha20.Seek(
- {
- fuzzed_data_provider.ConsumeIntegral<uint32_t>(),
- fuzzed_data_provider.ConsumeIntegral<uint64_t>()
- }, fuzzed_data_provider.ConsumeIntegral<uint32_t>());
+ ChaCha20::Nonce96 nonce{
+ fuzzed_data_provider.ConsumeIntegral<uint32_t>(),
+ fuzzed_data_provider.ConsumeIntegral<uint64_t>()};
+ chacha20.Seek(nonce, fuzzed_data_provider.ConsumeIntegral<uint32_t>());
},
[&] {
std::vector<uint8_t> output(fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096));
diff --git a/src/test/fuzz/crypto_chacha20poly1305.cpp b/src/test/fuzz/crypto_chacha20poly1305.cpp
index 2b39a06094..5e62e6f3df 100644
--- a/src/test/fuzz/crypto_chacha20poly1305.cpp
+++ b/src/test/fuzz/crypto_chacha20poly1305.cpp
@@ -130,7 +130,7 @@ FUZZ_TARGET(crypto_fschacha20poly1305)
// data).
InsecureRandomContext rng(provider.ConsumeIntegral<uint64_t>());
- LIMITED_WHILE(provider.ConsumeBool(), 10000)
+ LIMITED_WHILE(provider.ConsumeBool(), 100)
{
// Mode:
// - Bit 0: whether to use single-plain Encrypt/Decrypt; otherwise use a split at prefix.
diff --git a/src/test/fuzz/cuckoocache.cpp b/src/test/fuzz/cuckoocache.cpp
index 50a71ee03f..f8a5bde3e6 100644
--- a/src/test/fuzz/cuckoocache.cpp
+++ b/src/test/fuzz/cuckoocache.cpp
@@ -41,7 +41,9 @@ FUZZ_TARGET(cuckoocache)
if (fuzzed_data_provider.ConsumeBool()) {
cuckoo_cache.insert(fuzzed_data_provider.ConsumeBool());
} else {
- cuckoo_cache.contains(fuzzed_data_provider.ConsumeBool(), fuzzed_data_provider.ConsumeBool());
+ auto e = fuzzed_data_provider.ConsumeBool();
+ auto erase = fuzzed_data_provider.ConsumeBool();
+ cuckoo_cache.contains(e, erase);
}
}
fuzzed_data_provider_ptr = nullptr;
diff --git a/src/test/fuzz/descriptor_parse.cpp b/src/test/fuzz/descriptor_parse.cpp
index 6a3f4d6dfe..765daa3db7 100644
--- a/src/test/fuzz/descriptor_parse.cpp
+++ b/src/test/fuzz/descriptor_parse.cpp
@@ -15,14 +15,24 @@
MockedDescriptorConverter MOCKED_DESC_CONVERTER;
/** Test a successfully parsed descriptor. */
-static void TestDescriptor(const Descriptor& desc, FlatSigningProvider& sig_provider, std::string& dummy)
+static void TestDescriptor(const Descriptor& desc, FlatSigningProvider& sig_provider, std::string& dummy, std::optional<bool>& is_ranged, std::optional<bool>& is_solvable)
{
// Trivial helpers.
(void)desc.IsRange();
- const bool is_solvable{desc.IsSolvable()};
(void)desc.IsSingleType();
(void)desc.GetOutputType();
+ if (is_ranged.has_value()) {
+ assert(desc.IsRange() == *is_ranged);
+ } else {
+ is_ranged = desc.IsRange();
+ }
+ if (is_solvable.has_value()) {
+ assert(desc.IsSolvable() == *is_solvable);
+ } else {
+ is_solvable = desc.IsSolvable();
+ }
+
// Serialization to string representation.
(void)desc.ToString();
(void)desc.ToPrivateString(sig_provider, dummy);
@@ -48,7 +58,7 @@ static void TestDescriptor(const Descriptor& desc, FlatSigningProvider& sig_prov
const auto max_sat_nonmaxsig{desc.MaxSatisfactionWeight(true)};
const auto max_elems{desc.MaxSatisfactionElems()};
// We must be able to estimate the max satisfaction size for any solvable descriptor (but combo).
- const bool is_nontop_or_nonsolvable{!is_solvable || !desc.GetOutputType()};
+ const bool is_nontop_or_nonsolvable{!*is_solvable || !desc.GetOutputType()};
const bool is_input_size_info_set{max_sat_maxsig && max_sat_nonmaxsig && max_elems};
assert(is_input_size_info_set || is_nontop_or_nonsolvable);
}
@@ -85,7 +95,12 @@ FUZZ_TARGET(mocked_descriptor_parse, .init = initialize_mocked_descriptor_parse)
FlatSigningProvider signing_provider;
std::string error;
const auto desc = Parse(*descriptor, signing_provider, error);
- if (desc) TestDescriptor(*desc, signing_provider, error);
+ std::optional<bool> is_ranged;
+ std::optional<bool> is_solvable;
+ for (const auto& d : desc) {
+ assert(d);
+ TestDescriptor(*d, signing_provider, error, is_ranged, is_solvable);
+ }
}
}
@@ -101,6 +116,11 @@ FUZZ_TARGET(descriptor_parse, .init = initialize_descriptor_parse)
std::string error;
for (const bool require_checksum : {true, false}) {
const auto desc = Parse(descriptor, signing_provider, error, require_checksum);
- if (desc) TestDescriptor(*desc, signing_provider, error);
+ std::optional<bool> is_ranged;
+ std::optional<bool> is_solvable;
+ for (const auto& d : desc) {
+ assert(d);
+ TestDescriptor(*d, signing_provider, error, is_ranged, is_solvable);
+ }
}
}
diff --git a/src/test/fuzz/fuzz.cpp b/src/test/fuzz/fuzz.cpp
index 96283a3e15..bba2dd8e3a 100644
--- a/src/test/fuzz/fuzz.cpp
+++ b/src/test/fuzz/fuzz.cpp
@@ -49,7 +49,7 @@ static std::vector<const char*> g_args;
static void SetArgs(int argc, char** argv) {
for (int i = 1; i < argc; ++i) {
// Only take into account arguments that start with `--`. The others are for the fuzz engine:
- // `fuzz -runs=1 fuzz_seed_corpus/address_deserialize_v2 --checkaddrman=5`
+ // `fuzz -runs=1 fuzz_corpora/address_deserialize_v2 --checkaddrman=5`
if (strlen(argv[i]) > 2 && argv[i][0] == '-' && argv[i][1] == '-') {
g_args.push_back(argv[i]);
}
@@ -106,7 +106,7 @@ void initialize()
// randomness during the fuzz test, except:
// - GetStrongRandBytes(), which is used for the creation of private key material.
// - Creating a BasicTestingSetup or derived class will switch to a random seed.
- SeedRandomForTest(SeedRand::ZEROS);
+ SeedRandomStateForTest(SeedRand::ZEROS);
// Terminate immediately if a fuzzing harness ever tries to create a socket.
// Individual tests can override this by pointing CreateSock to a mocked alternative.
diff --git a/src/test/fuzz/hex.cpp b/src/test/fuzz/hex.cpp
index ebe30c3c1a..3dcf1ed3d5 100644
--- a/src/test/fuzz/hex.cpp
+++ b/src/test/fuzz/hex.cpp
@@ -12,6 +12,7 @@
#include <util/strencodings.h>
#include <util/transaction_identifier.h>
+#include <algorithm>
#include <cassert>
#include <cstdint>
#include <string>
@@ -22,18 +23,26 @@ FUZZ_TARGET(hex)
const std::string random_hex_string(buffer.begin(), buffer.end());
const std::vector<unsigned char> data = ParseHex(random_hex_string);
const std::vector<std::byte> bytes{ParseHex<std::byte>(random_hex_string)};
- assert(AsBytes(Span{data}) == Span{bytes});
+ assert(std::ranges::equal(AsBytes(Span{data}), bytes));
const std::string hex_data = HexStr(data);
if (IsHex(random_hex_string)) {
assert(ToLower(random_hex_string) == hex_data);
}
- (void)IsHexNumber(random_hex_string);
if (uint256::FromHex(random_hex_string)) {
assert(random_hex_string.length() == 64);
assert(Txid::FromHex(random_hex_string));
assert(Wtxid::FromHex(random_hex_string));
+ assert(uint256::FromUserHex(random_hex_string));
+ }
+ if (const auto result{uint256::FromUserHex(random_hex_string)}) {
+ const auto result_string{result->ToString()}; // ToString() returns a fixed-length string without "0x" prefix
+ assert(result_string.length() == 64);
+ assert(IsHex(result_string));
+ assert(TryParseHex(result_string));
+ assert(Txid::FromHex(result_string));
+ assert(Wtxid::FromHex(result_string));
+ assert(uint256::FromHex(result_string));
}
- (void)uint256S(random_hex_string);
try {
(void)HexToPubKey(random_hex_string);
} catch (const UniValue&) {
diff --git a/src/test/fuzz/integer.cpp b/src/test/fuzz/integer.cpp
index 02c6796d11..b9e3154106 100644
--- a/src/test/fuzz/integer.cpp
+++ b/src/test/fuzz/integer.cpp
@@ -69,7 +69,7 @@ FUZZ_TARGET(integer, .init = initialize_integer)
const bool b = fuzzed_data_provider.ConsumeBool();
const Consensus::Params& consensus_params = Params().GetConsensus();
- (void)CheckProofOfWork(u256, u32, consensus_params);
+ (void)CheckProofOfWorkImpl(u256, u32, consensus_params);
if (u64 <= MAX_MONEY) {
const uint64_t compressed_money_amount = CompressAmount(u64);
assert(u64 == DecompressAmount(compressed_money_amount));
@@ -140,7 +140,7 @@ FUZZ_TARGET(integer, .init = initialize_integer)
const arith_uint256 au256 = UintToArith256(u256);
assert(ArithToUint256(au256) == u256);
- assert(uint256S(au256.GetHex()) == u256);
+ assert(uint256::FromHex(au256.GetHex()).value() == u256);
(void)au256.bits();
(void)au256.GetCompact(/* fNegative= */ false);
(void)au256.GetCompact(/* fNegative= */ true);
diff --git a/src/test/fuzz/message.cpp b/src/test/fuzz/message.cpp
index 6763206f72..99bbad6591 100644
--- a/src/test/fuzz/message.cpp
+++ b/src/test/fuzz/message.cpp
@@ -39,7 +39,9 @@ FUZZ_TARGET(message, .init = initialize_message)
}
{
(void)MessageHash(random_message);
- (void)MessageVerify(fuzzed_data_provider.ConsumeRandomLengthString(1024), fuzzed_data_provider.ConsumeRandomLengthString(1024), random_message);
+ auto address = fuzzed_data_provider.ConsumeRandomLengthString(1024);
+ auto signature = fuzzed_data_provider.ConsumeRandomLengthString(1024);
+ (void)MessageVerify(address, signature, random_message);
(void)SigningResultString(fuzzed_data_provider.PickValueInArray({SigningResult::OK, SigningResult::PRIVATE_KEY_NOT_AVAILABLE, SigningResult::SIGNING_FAILED}));
}
}
diff --git a/src/test/fuzz/miniscript.cpp b/src/test/fuzz/miniscript.cpp
index 1f9ed9a064..5b9e168856 100644
--- a/src/test/fuzz/miniscript.cpp
+++ b/src/test/fuzz/miniscript.cpp
@@ -13,6 +13,8 @@
#include <test/fuzz/util.h>
#include <util/strencodings.h>
+#include <algorithm>
+
namespace {
using Fragment = miniscript::Fragment;
@@ -293,7 +295,7 @@ const struct CheckerContext: BaseSignatureChecker {
XOnlyPubKey pk{pubkey};
auto it = TEST_DATA.schnorr_sigs.find(pk);
if (it == TEST_DATA.schnorr_sigs.end()) return false;
- return it->second.first == sig;
+ return std::ranges::equal(it->second.first, sig);
}
bool CheckLockTime(const CScriptNum& nLockTime) const override { return nLockTime.GetInt64() & 1; }
bool CheckSequence(const CScriptNum& nSequence) const override { return nSequence.GetInt64() & 1; }
diff --git a/src/test/fuzz/p2p_handshake.cpp b/src/test/fuzz/p2p_handshake.cpp
index 217655ab70..6c1ed11d45 100644
--- a/src/test/fuzz/p2p_handshake.cpp
+++ b/src/test/fuzz/p2p_handshake.cpp
@@ -74,7 +74,7 @@ FUZZ_TARGET(p2p_handshake, .init = ::initialize)
{
CNode& connection = *PickValue(fuzzed_data_provider, peers);
if (connection.fDisconnect || connection.fSuccessfullyConnected) {
- // Skip if the the connection was disconnected or if the version
+ // Skip if the connection was disconnected or if the version
// handshake was already completed.
continue;
}
diff --git a/src/test/fuzz/p2p_headers_presync.cpp b/src/test/fuzz/p2p_headers_presync.cpp
new file mode 100644
index 0000000000..b86d03442d
--- /dev/null
+++ b/src/test/fuzz/p2p_headers_presync.cpp
@@ -0,0 +1,200 @@
+#include <blockencodings.h>
+#include <net.h>
+#include <net_processing.h>
+#include <netmessagemaker.h>
+#include <node/peerman_args.h>
+#include <pow.h>
+#include <test/fuzz/FuzzedDataProvider.h>
+#include <test/fuzz/fuzz.h>
+#include <test/fuzz/util.h>
+#include <test/util/net.h>
+#include <test/util/script.h>
+#include <test/util/setup_common.h>
+#include <validation.h>
+
+namespace {
+constexpr uint32_t FUZZ_MAX_HEADERS_RESULTS{16};
+
+class HeadersSyncSetup : public TestingSetup
+{
+ std::vector<CNode*> m_connections;
+
+public:
+ HeadersSyncSetup(const ChainType chain_type = ChainType::MAIN,
+ TestOpts opts = {})
+ : TestingSetup(chain_type, opts)
+ {
+ PeerManager::Options peerman_opts;
+ node::ApplyArgsManOptions(*m_node.args, peerman_opts);
+ peerman_opts.max_headers_result = FUZZ_MAX_HEADERS_RESULTS;
+ m_node.peerman = PeerManager::make(*m_node.connman, *m_node.addrman,
+ m_node.banman.get(), *m_node.chainman,
+ *m_node.mempool, *m_node.warnings, peerman_opts);
+
+ CConnman::Options options;
+ options.m_msgproc = m_node.peerman.get();
+ m_node.connman->Init(options);
+ }
+
+ void ResetAndInitialize() EXCLUSIVE_LOCKS_REQUIRED(NetEventsInterface::g_msgproc_mutex);
+ void SendMessage(FuzzedDataProvider& fuzzed_data_provider, CSerializedNetMsg&& msg)
+ EXCLUSIVE_LOCKS_REQUIRED(NetEventsInterface::g_msgproc_mutex);
+};
+
+void HeadersSyncSetup::ResetAndInitialize()
+{
+ m_connections.clear();
+ auto& connman = static_cast<ConnmanTestMsg&>(*m_node.connman);
+ connman.StopNodes();
+
+ NodeId id{0};
+ std::vector<ConnectionType> conn_types = {
+ ConnectionType::OUTBOUND_FULL_RELAY,
+ ConnectionType::BLOCK_RELAY,
+ ConnectionType::INBOUND
+ };
+
+ for (auto conn_type : conn_types) {
+ CAddress addr{};
+ m_connections.push_back(new CNode(id++, nullptr, addr, 0, 0, addr, "", conn_type, false));
+ CNode& p2p_node = *m_connections.back();
+
+ connman.Handshake(
+ /*node=*/p2p_node,
+ /*successfully_connected=*/true,
+ /*remote_services=*/ServiceFlags(NODE_NETWORK | NODE_WITNESS),
+ /*local_services=*/ServiceFlags(NODE_NETWORK | NODE_WITNESS),
+ /*version=*/PROTOCOL_VERSION,
+ /*relay_txs=*/true);
+
+ connman.AddTestNode(p2p_node);
+ }
+}
+
+void HeadersSyncSetup::SendMessage(FuzzedDataProvider& fuzzed_data_provider, CSerializedNetMsg&& msg)
+{
+ auto& connman = static_cast<ConnmanTestMsg&>(*m_node.connman);
+ CNode& connection = *PickValue(fuzzed_data_provider, m_connections);
+
+ connman.FlushSendBuffer(connection);
+ (void)connman.ReceiveMsgFrom(connection, std::move(msg));
+ connection.fPauseSend = false;
+ try {
+ connman.ProcessMessagesOnce(connection);
+ } catch (const std::ios_base::failure&) {
+ }
+ m_node.peerman->SendMessages(&connection);
+}
+
+CBlockHeader ConsumeHeader(FuzzedDataProvider& fuzzed_data_provider, const uint256& prev_hash, uint32_t prev_nbits)
+{
+ CBlockHeader header;
+ header.nNonce = 0;
+ // Either use the previous difficulty or let the fuzzer choose
+ header.nBits = fuzzed_data_provider.ConsumeBool() ?
+ prev_nbits :
+ fuzzed_data_provider.ConsumeIntegralInRange<uint32_t>(0x17058EBE, 0x1D00FFFF);
+ header.nTime = ConsumeTime(fuzzed_data_provider);
+ header.hashPrevBlock = prev_hash;
+ header.nVersion = fuzzed_data_provider.ConsumeIntegral<int32_t>();
+ return header;
+}
+
+CBlock ConsumeBlock(FuzzedDataProvider& fuzzed_data_provider, const uint256& prev_hash, uint32_t prev_nbits)
+{
+ auto header = ConsumeHeader(fuzzed_data_provider, prev_hash, prev_nbits);
+ // In order to reach the headers acceptance logic, the block is
+ // constructed in a way that will pass the mutation checks.
+ CBlock block{header};
+ CMutableTransaction tx;
+ tx.vin.resize(1);
+ tx.vout.resize(1);
+ tx.vout[0].nValue = 0;
+ tx.vin[0].scriptSig.resize(2);
+ block.vtx.push_back(MakeTransactionRef(tx));
+ block.hashMerkleRoot = block.vtx[0]->GetHash();
+ return block;
+}
+
+void FinalizeHeader(CBlockHeader& header)
+{
+ while (!CheckProofOfWork(header.GetHash(), header.nBits, Params().GetConsensus())) {
+ ++(header.nNonce);
+ }
+}
+
+// Global setup works for this test as state modification (specifically in the
+// block index) would indicate a bug.
+HeadersSyncSetup* g_testing_setup;
+
+void initialize()
+{
+ static auto setup = MakeNoLogFileContext<HeadersSyncSetup>(ChainType::MAIN, {.extra_args = {"-checkpoints=0"}});
+ g_testing_setup = setup.get();
+}
+} // namespace
+
+FUZZ_TARGET(p2p_headers_presync, .init = initialize)
+{
+ ChainstateManager& chainman = *g_testing_setup->m_node.chainman;
+
+ LOCK(NetEventsInterface::g_msgproc_mutex);
+
+ g_testing_setup->ResetAndInitialize();
+
+ FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
+
+ CBlockHeader base{Params().GenesisBlock()};
+ SetMockTime(base.nTime);
+
+ // The chain is just a single block, so this is equal to 1
+ size_t original_index_size{WITH_LOCK(cs_main, return chainman.m_blockman.m_block_index.size())};
+
+ LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 100)
+ {
+ auto finalized_block = [&]() {
+ CBlock block = ConsumeBlock(fuzzed_data_provider, base.GetHash(), base.nBits);
+ FinalizeHeader(block);
+ return block;
+ };
+
+ // Send low-work headers, compact blocks, and blocks
+ CallOneOf(
+ fuzzed_data_provider,
+ [&]() NO_THREAD_SAFETY_ANALYSIS {
+ // Send FUZZ_MAX_HEADERS_RESULTS headers
+ std::vector<CBlock> headers;
+ headers.resize(FUZZ_MAX_HEADERS_RESULTS);
+ for (CBlock& header : headers) {
+ header = ConsumeHeader(fuzzed_data_provider, base.GetHash(), base.nBits);
+ FinalizeHeader(header);
+ base = header;
+ }
+
+ auto headers_msg = NetMsg::Make(NetMsgType::HEADERS, TX_WITH_WITNESS(headers));
+ g_testing_setup->SendMessage(fuzzed_data_provider, std::move(headers_msg));
+ },
+ [&]() NO_THREAD_SAFETY_ANALYSIS {
+ // Send a compact block
+ auto block = finalized_block();
+ CBlockHeaderAndShortTxIDs cmpct_block{block, fuzzed_data_provider.ConsumeIntegral<uint64_t>()};
+
+ auto headers_msg = NetMsg::Make(NetMsgType::CMPCTBLOCK, TX_WITH_WITNESS(cmpct_block));
+ g_testing_setup->SendMessage(fuzzed_data_provider, std::move(headers_msg));
+ },
+ [&]() NO_THREAD_SAFETY_ANALYSIS {
+ // Send a block
+ auto block = finalized_block();
+
+ auto headers_msg = NetMsg::Make(NetMsgType::BLOCK, TX_WITH_WITNESS(block));
+ g_testing_setup->SendMessage(fuzzed_data_provider, std::move(headers_msg));
+ });
+ }
+
+ // The headers/blocks sent in this test should never be stored, as the chains don't have the work required
+ // to meet the anti-DoS work threshold. So, if at any point the block index grew in size, then there's a bug
+ // in the headers pre-sync logic.
+ assert(WITH_LOCK(cs_main, return chainman.m_blockman.m_block_index.size()) == original_index_size);
+
+ g_testing_setup->m_node.validation_signals->SyncWithValidationInterfaceQueue();
+}
diff --git a/src/test/fuzz/p2p_transport_serialization.cpp b/src/test/fuzz/p2p_transport_serialization.cpp
index 93f77b6e5b..cf3ef45c0a 100644
--- a/src/test/fuzz/p2p_transport_serialization.cpp
+++ b/src/test/fuzz/p2p_transport_serialization.cpp
@@ -12,6 +12,7 @@
#include <test/fuzz/util.h>
#include <util/chaintype.h>
+#include <algorithm>
#include <cassert>
#include <cstdint>
#include <limits>
@@ -185,12 +186,12 @@ void SimulationTest(Transport& initiator, Transport& responder, R& rng, FuzzedDa
// Compare with expected more.
if (expect_more[side].has_value()) assert(!bytes.empty() == *expect_more[side]);
// Verify consistency between the two results.
- assert(bytes == bytes_next);
+ assert(std::ranges::equal(bytes, bytes_next));
assert(msg_type == msg_type_next);
if (more_nonext) assert(more_next);
// Compare with previously reported output.
assert(to_send[side].size() <= bytes.size());
- assert(to_send[side] == Span{bytes}.first(to_send[side].size()));
+ assert(std::ranges::equal(to_send[side], Span{bytes}.first(to_send[side].size())));
to_send[side].resize(bytes.size());
std::copy(bytes.begin(), bytes.end(), to_send[side].begin());
// Remember 'more' results.
@@ -278,7 +279,7 @@ void SimulationTest(Transport& initiator, Transport& responder, R& rng, FuzzedDa
// The m_type must match what is expected.
assert(received.m_type == expected[side].front().m_type);
// The data must match what is expected.
- assert(MakeByteSpan(received.m_recv) == MakeByteSpan(expected[side].front().data));
+ assert(std::ranges::equal(received.m_recv, MakeByteSpan(expected[side].front().data)));
expected[side].pop_front();
progress = true;
}
diff --git a/src/test/fuzz/policy_estimator.cpp b/src/test/fuzz/policy_estimator.cpp
index a4e1947b9f..2942740395 100644
--- a/src/test/fuzz/policy_estimator.cpp
+++ b/src/test/fuzz/policy_estimator.cpp
@@ -85,9 +85,18 @@ FUZZ_TARGET(policy_estimator, .init = initialize_policy_estimator)
});
(void)block_policy_estimator.estimateFee(fuzzed_data_provider.ConsumeIntegral<int>());
EstimationResult result;
- (void)block_policy_estimator.estimateRawFee(fuzzed_data_provider.ConsumeIntegral<int>(), fuzzed_data_provider.ConsumeFloatingPoint<double>(), fuzzed_data_provider.PickValueInArray(ALL_FEE_ESTIMATE_HORIZONS), fuzzed_data_provider.ConsumeBool() ? &result : nullptr);
+ auto conf_target = fuzzed_data_provider.ConsumeIntegral<int>();
+ auto success_threshold = fuzzed_data_provider.ConsumeFloatingPoint<double>();
+ auto horizon = fuzzed_data_provider.PickValueInArray(ALL_FEE_ESTIMATE_HORIZONS);
+ auto* result_ptr = fuzzed_data_provider.ConsumeBool() ? &result : nullptr;
+ (void)block_policy_estimator.estimateRawFee(conf_target, success_threshold, horizon, result_ptr);
+
FeeCalculation fee_calculation;
- (void)block_policy_estimator.estimateSmartFee(fuzzed_data_provider.ConsumeIntegral<int>(), fuzzed_data_provider.ConsumeBool() ? &fee_calculation : nullptr, fuzzed_data_provider.ConsumeBool());
+ conf_target = fuzzed_data_provider.ConsumeIntegral<int>();
+ auto* fee_calc_ptr = fuzzed_data_provider.ConsumeBool() ? &fee_calculation : nullptr;
+ auto conservative = fuzzed_data_provider.ConsumeBool();
+ (void)block_policy_estimator.estimateSmartFee(conf_target, fee_calc_ptr, conservative);
+
(void)block_policy_estimator.HighestTargetTracked(fuzzed_data_provider.PickValueInArray(ALL_FEE_ESTIMATE_HORIZONS));
}
{
diff --git a/src/test/fuzz/poolresource.cpp b/src/test/fuzz/poolresource.cpp
index 28bf7175c0..dd8d5b07e5 100644
--- a/src/test/fuzz/poolresource.cpp
+++ b/src/test/fuzz/poolresource.cpp
@@ -78,7 +78,7 @@ public:
{
std::vector<std::byte> expect(entry.span.size());
InsecureRandomContext(entry.seed).fillrand(expect);
- assert(entry.span == expect);
+ assert(std::ranges::equal(entry.span, expect));
}
void Deallocate(const Entry& entry)
diff --git a/src/test/fuzz/pow.cpp b/src/test/fuzz/pow.cpp
index 05cdb740e4..dba999ce4f 100644
--- a/src/test/fuzz/pow.cpp
+++ b/src/test/fuzz/pow.cpp
@@ -80,7 +80,7 @@ FUZZ_TARGET(pow, .init = initialize_pow)
{
const std::optional<uint256> hash = ConsumeDeserializable<uint256>(fuzzed_data_provider);
if (hash) {
- (void)CheckProofOfWork(*hash, fuzzed_data_provider.ConsumeIntegral<unsigned int>(), consensus_params);
+ (void)CheckProofOfWorkImpl(*hash, fuzzed_data_provider.ConsumeIntegral<unsigned int>(), consensus_params);
}
}
}
diff --git a/src/test/fuzz/prevector.cpp b/src/test/fuzz/prevector.cpp
index aeceb38a58..fffa099391 100644
--- a/src/test/fuzz/prevector.cpp
+++ b/src/test/fuzz/prevector.cpp
@@ -210,15 +210,20 @@ FUZZ_TARGET(prevector)
LIMITED_WHILE(prov.remaining_bytes(), 3000)
{
switch (prov.ConsumeIntegralInRange<int>(0, 13 + 3 * (test.size() > 0))) {
- case 0:
- test.insert(prov.ConsumeIntegralInRange<size_t>(0, test.size()), prov.ConsumeIntegral<int>());
- break;
+ case 0: {
+ auto position = prov.ConsumeIntegralInRange<size_t>(0, test.size());
+ auto value = prov.ConsumeIntegral<int>();
+ test.insert(position, value);
+ } break;
case 1:
test.resize(std::max(0, std::min(30, (int)test.size() + prov.ConsumeIntegralInRange<int>(0, 4) - 2)));
break;
- case 2:
- test.insert(prov.ConsumeIntegralInRange<size_t>(0, test.size()), 1 + prov.ConsumeBool(), prov.ConsumeIntegral<int>());
- break;
+ case 2: {
+ auto position = prov.ConsumeIntegralInRange<size_t>(0, test.size());
+ auto count = 1 + prov.ConsumeBool();
+ auto value = prov.ConsumeIntegral<int>();
+ test.insert(position, count, value);
+ } break;
case 3: {
int del = prov.ConsumeIntegralInRange<int>(0, test.size());
int beg = prov.ConsumeIntegralInRange<int>(0, test.size() - del);
@@ -255,9 +260,11 @@ FUZZ_TARGET(prevector)
case 9:
test.clear();
break;
- case 10:
- test.assign(prov.ConsumeIntegralInRange<size_t>(0, 32767), prov.ConsumeIntegral<int>());
- break;
+ case 10: {
+ auto n = prov.ConsumeIntegralInRange<size_t>(0, 32767);
+ auto value = prov.ConsumeIntegral<int>();
+ test.assign(n, value);
+ } break;
case 11:
test.swap();
break;
@@ -267,9 +274,11 @@ FUZZ_TARGET(prevector)
case 13:
test.move();
break;
- case 14:
- test.update(prov.ConsumeIntegralInRange<size_t>(0, test.size() - 1), prov.ConsumeIntegral<int>());
- break;
+ case 14: {
+ auto pos = prov.ConsumeIntegralInRange<size_t>(0, test.size() - 1);
+ auto value = prov.ConsumeIntegral<int>();
+ test.update(pos, value);
+ } break;
case 15:
test.erase(prov.ConsumeIntegralInRange<size_t>(0, test.size() - 1));
break;
diff --git a/src/test/fuzz/script_format.cpp b/src/test/fuzz/script_format.cpp
index 10150dcd7f..e26c42ae38 100644
--- a/src/test/fuzz/script_format.cpp
+++ b/src/test/fuzz/script_format.cpp
@@ -30,5 +30,7 @@ FUZZ_TARGET(script_format, .init = initialize_script_format)
(void)ScriptToAsmStr(script, /*fAttemptSighashDecode=*/fuzzed_data_provider.ConsumeBool());
UniValue o1(UniValue::VOBJ);
- ScriptToUniv(script, /*out=*/o1, /*include_hex=*/fuzzed_data_provider.ConsumeBool(), /*include_address=*/fuzzed_data_provider.ConsumeBool());
+ auto include_hex = fuzzed_data_provider.ConsumeBool();
+ auto include_address = fuzzed_data_provider.ConsumeBool();
+ ScriptToUniv(script, /*out=*/o1, include_hex, include_address);
}
diff --git a/src/test/fuzz/script_interpreter.cpp b/src/test/fuzz/script_interpreter.cpp
index 5e76443abe..9e3ad02b2e 100644
--- a/src/test/fuzz/script_interpreter.cpp
+++ b/src/test/fuzz/script_interpreter.cpp
@@ -25,12 +25,18 @@ FUZZ_TARGET(script_interpreter)
const CTransaction tx_to{*mtx};
const unsigned int in = fuzzed_data_provider.ConsumeIntegral<unsigned int>();
if (in < tx_to.vin.size()) {
- (void)SignatureHash(script_code, tx_to, in, fuzzed_data_provider.ConsumeIntegral<int>(), ConsumeMoney(fuzzed_data_provider), fuzzed_data_provider.PickValueInArray({SigVersion::BASE, SigVersion::WITNESS_V0}), nullptr);
+ auto n_hash_type = fuzzed_data_provider.ConsumeIntegral<int>();
+ auto amount = ConsumeMoney(fuzzed_data_provider);
+ auto sigversion = fuzzed_data_provider.PickValueInArray({SigVersion::BASE, SigVersion::WITNESS_V0});
+ (void)SignatureHash(script_code, tx_to, in, n_hash_type, amount, sigversion, nullptr);
const std::optional<CMutableTransaction> mtx_precomputed = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider, TX_WITH_WITNESS);
if (mtx_precomputed) {
const CTransaction tx_precomputed{*mtx_precomputed};
const PrecomputedTransactionData precomputed_transaction_data{tx_precomputed};
- (void)SignatureHash(script_code, tx_to, in, fuzzed_data_provider.ConsumeIntegral<int>(), ConsumeMoney(fuzzed_data_provider), fuzzed_data_provider.PickValueInArray({SigVersion::BASE, SigVersion::WITNESS_V0}), &precomputed_transaction_data);
+ n_hash_type = fuzzed_data_provider.ConsumeIntegral<int>();
+ amount = ConsumeMoney(fuzzed_data_provider);
+ sigversion = fuzzed_data_provider.PickValueInArray({SigVersion::BASE, SigVersion::WITNESS_V0});
+ (void)SignatureHash(script_code, tx_to, in, n_hash_type, amount, sigversion, &precomputed_transaction_data);
}
}
}
diff --git a/src/test/fuzz/script_sign.cpp b/src/test/fuzz/script_sign.cpp
index 4695bc611b..7725ee699c 100644
--- a/src/test/fuzz/script_sign.cpp
+++ b/src/test/fuzz/script_sign.cpp
@@ -111,7 +111,10 @@ FUZZ_TARGET(script_sign, .init = initialize_script_sign)
}
if (n_in < script_tx_to.vin.size()) {
SignatureData empty;
- (void)SignSignature(provider, ConsumeScript(fuzzed_data_provider), script_tx_to, n_in, ConsumeMoney(fuzzed_data_provider), fuzzed_data_provider.ConsumeIntegral<int>(), empty);
+ auto from_pub_key = ConsumeScript(fuzzed_data_provider);
+ auto amount = ConsumeMoney(fuzzed_data_provider);
+ auto n_hash_type = fuzzed_data_provider.ConsumeIntegral<int>();
+ (void)SignSignature(provider, from_pub_key, script_tx_to, n_in, amount, n_hash_type, empty);
MutableTransactionSignatureCreator signature_creator{tx_to, n_in, ConsumeMoney(fuzzed_data_provider), fuzzed_data_provider.ConsumeIntegral<int>()};
std::vector<unsigned char> vch_sig;
CKeyID address;
@@ -122,7 +125,9 @@ FUZZ_TARGET(script_sign, .init = initialize_script_sign)
} else {
address = CKeyID{ConsumeUInt160(fuzzed_data_provider)};
}
- (void)signature_creator.CreateSig(provider, vch_sig, address, ConsumeScript(fuzzed_data_provider), fuzzed_data_provider.PickValueInArray({SigVersion::BASE, SigVersion::WITNESS_V0}));
+ auto script_code = ConsumeScript(fuzzed_data_provider);
+ auto sigversion = fuzzed_data_provider.PickValueInArray({SigVersion::BASE, SigVersion::WITNESS_V0});
+ (void)signature_creator.CreateSig(provider, vch_sig, address, script_code, sigversion);
}
std::map<COutPoint, Coin> coins{ConsumeCoins(fuzzed_data_provider)};
std::map<int, bilingual_str> input_errors;
diff --git a/src/test/fuzz/secp256k1_ec_seckey_import_export_der.cpp b/src/test/fuzz/secp256k1_ec_seckey_import_export_der.cpp
index 0435626356..9f84ac9713 100644
--- a/src/test/fuzz/secp256k1_ec_seckey_import_export_der.cpp
+++ b/src/test/fuzz/secp256k1_ec_seckey_import_export_der.cpp
@@ -17,7 +17,7 @@ int ec_seckey_export_der(const secp256k1_context* ctx, unsigned char* seckey, si
FUZZ_TARGET(secp256k1_ec_seckey_import_export_der)
{
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
- secp256k1_context* secp256k1_context_sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
+ secp256k1_context* secp256k1_context_sign = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
{
std::vector<uint8_t> out32(32);
(void)ec_seckey_import_der(secp256k1_context_sign, out32.data(), ConsumeFixedLengthByteVector(fuzzed_data_provider, CKey::SIZE).data(), CKey::SIZE);
diff --git a/src/test/fuzz/socks5.cpp b/src/test/fuzz/socks5.cpp
index af81fcb593..17d1787586 100644
--- a/src/test/fuzz/socks5.cpp
+++ b/src/test/fuzz/socks5.cpp
@@ -41,8 +41,8 @@ FUZZ_TARGET(socks5, .init = initialize_socks5)
FuzzedSock fuzzed_sock = ConsumeSock(fuzzed_data_provider);
// This Socks5(...) fuzzing harness would have caught CVE-2017-18350 within
// a few seconds of fuzzing.
- (void)Socks5(fuzzed_data_provider.ConsumeRandomLengthString(512),
- fuzzed_data_provider.ConsumeIntegral<uint16_t>(),
- fuzzed_data_provider.ConsumeBool() ? &proxy_credentials : nullptr,
- fuzzed_sock);
+ auto str_dest = fuzzed_data_provider.ConsumeRandomLengthString(512);
+ auto port = fuzzed_data_provider.ConsumeIntegral<uint16_t>();
+ auto* auth = fuzzed_data_provider.ConsumeBool() ? &proxy_credentials : nullptr;
+ (void)Socks5(str_dest, port, auth, fuzzed_sock);
}
diff --git a/src/test/fuzz/span.cpp b/src/test/fuzz/span.cpp
index 8f753948df..cd436d582f 100644
--- a/src/test/fuzz/span.cpp
+++ b/src/test/fuzz/span.cpp
@@ -30,10 +30,4 @@ FUZZ_TARGET(span)
(void)span.subspan(idx, span.size() - idx);
(void)span[idx];
}
-
- std::string another_str = fuzzed_data_provider.ConsumeBytesAsString(32);
- const Span<const char> another_span{another_str};
- assert((span <= another_span) != (span > another_span));
- assert((span == another_span) != (span != another_span));
- assert((span >= another_span) != (span < another_span));
}
diff --git a/src/test/fuzz/system.cpp b/src/test/fuzz/system.cpp
index 73ae89b52a..2ab5b7ed39 100644
--- a/src/test/fuzz/system.cpp
+++ b/src/test/fuzz/system.cpp
@@ -44,23 +44,31 @@ FUZZ_TARGET(system, .init = initialize_system)
args_manager.SelectConfigNetwork(fuzzed_data_provider.ConsumeRandomLengthString(16));
},
[&] {
- args_manager.SoftSetArg(fuzzed_data_provider.ConsumeRandomLengthString(16), fuzzed_data_provider.ConsumeRandomLengthString(16));
+ auto str_arg = fuzzed_data_provider.ConsumeRandomLengthString(16);
+ auto str_value = fuzzed_data_provider.ConsumeRandomLengthString(16);
+ args_manager.SoftSetArg(str_arg, str_value);
},
[&] {
- args_manager.ForceSetArg(fuzzed_data_provider.ConsumeRandomLengthString(16), fuzzed_data_provider.ConsumeRandomLengthString(16));
+ auto str_arg = fuzzed_data_provider.ConsumeRandomLengthString(16);
+ auto str_value = fuzzed_data_provider.ConsumeRandomLengthString(16);
+ args_manager.ForceSetArg(str_arg, str_value);
},
[&] {
- args_manager.SoftSetBoolArg(fuzzed_data_provider.ConsumeRandomLengthString(16), fuzzed_data_provider.ConsumeBool());
+ auto str_arg = fuzzed_data_provider.ConsumeRandomLengthString(16);
+ auto f_value = fuzzed_data_provider.ConsumeBool();
+ args_manager.SoftSetBoolArg(str_arg, f_value);
},
[&] {
- const OptionsCategory options_category = fuzzed_data_provider.PickValueInArray<OptionsCategory>({OptionsCategory::OPTIONS, OptionsCategory::CONNECTION, OptionsCategory::WALLET, OptionsCategory::WALLET_DEBUG_TEST, OptionsCategory::ZMQ, OptionsCategory::DEBUG_TEST, OptionsCategory::CHAINPARAMS, OptionsCategory::NODE_RELAY, OptionsCategory::BLOCK_CREATION, OptionsCategory::RPC, OptionsCategory::GUI, OptionsCategory::COMMANDS, OptionsCategory::REGISTER_COMMANDS, OptionsCategory::HIDDEN});
+ const OptionsCategory options_category = fuzzed_data_provider.PickValueInArray<OptionsCategory>({OptionsCategory::OPTIONS, OptionsCategory::CONNECTION, OptionsCategory::WALLET, OptionsCategory::WALLET_DEBUG_TEST, OptionsCategory::ZMQ, OptionsCategory::DEBUG_TEST, OptionsCategory::CHAINPARAMS, OptionsCategory::NODE_RELAY, OptionsCategory::BLOCK_CREATION, OptionsCategory::RPC, OptionsCategory::GUI, OptionsCategory::COMMANDS, OptionsCategory::REGISTER_COMMANDS, OptionsCategory::CLI_COMMANDS, OptionsCategory::IPC, OptionsCategory::HIDDEN});
// Avoid hitting:
// common/args.cpp:563: void ArgsManager::AddArg(const std::string &, const std::string &, unsigned int, const OptionsCategory &): Assertion `ret.second' failed.
const std::string argument_name = GetArgumentName(fuzzed_data_provider.ConsumeRandomLengthString(16));
if (args_manager.GetArgFlags(argument_name) != std::nullopt) {
return;
}
- args_manager.AddArg(argument_name, fuzzed_data_provider.ConsumeRandomLengthString(16), fuzzed_data_provider.ConsumeIntegral<unsigned int>() & ~ArgsManager::COMMAND, options_category);
+ auto help = fuzzed_data_provider.ConsumeRandomLengthString(16);
+ auto flags = fuzzed_data_provider.ConsumeIntegral<unsigned int>() & ~ArgsManager::COMMAND;
+ args_manager.AddArg(argument_name, help, flags, options_category);
},
[&] {
// Avoid hitting:
diff --git a/src/test/fuzz/util/CMakeLists.txt b/src/test/fuzz/util/CMakeLists.txt
new file mode 100644
index 0000000000..f73a1a83c2
--- /dev/null
+++ b/src/test/fuzz/util/CMakeLists.txt
@@ -0,0 +1,23 @@
+# Copyright (c) 2023-present The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or https://opensource.org/license/mit/.
+
+add_library(test_fuzz STATIC EXCLUDE_FROM_ALL
+ descriptor.cpp
+ mempool.cpp
+ net.cpp
+ ../fuzz.cpp
+ ../util.cpp
+)
+
+target_link_libraries(test_fuzz
+ PRIVATE
+ core_interface
+ test_util
+ bitcoin_node
+ Boost::headers
+)
+
+if(NOT FUZZ_BINARY_LINKS_WITHOUT_MAIN_FUNCTION)
+ target_compile_definitions(test_fuzz PRIVATE PROVIDE_FUZZ_MAIN_FUNCTION)
+endif()
diff --git a/src/test/fuzz/util/net.cpp b/src/test/fuzz/util/net.cpp
index ca0fd65cae..b02c4edbad 100644
--- a/src/test/fuzz/util/net.cpp
+++ b/src/test/fuzz/util/net.cpp
@@ -414,10 +414,10 @@ bool FuzzedSock::IsConnected(std::string& errmsg) const
void FillNode(FuzzedDataProvider& fuzzed_data_provider, ConnmanTestMsg& connman, CNode& node) noexcept
{
- connman.Handshake(node,
- /*successfully_connected=*/fuzzed_data_provider.ConsumeBool(),
- /*remote_services=*/ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS),
- /*local_services=*/ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS),
- /*version=*/fuzzed_data_provider.ConsumeIntegralInRange<int32_t>(MIN_PEER_PROTO_VERSION, std::numeric_limits<int32_t>::max()),
- /*relay_txs=*/fuzzed_data_provider.ConsumeBool());
+ auto successfully_connected = fuzzed_data_provider.ConsumeBool();
+ auto remote_services = ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS);
+ auto local_services = ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS);
+ auto version = fuzzed_data_provider.ConsumeIntegralInRange<int32_t>(MIN_PEER_PROTO_VERSION, std::numeric_limits<int32_t>::max());
+ auto relay_txs = fuzzed_data_provider.ConsumeBool();
+ connman.Handshake(node, successfully_connected, remote_services, local_services, version, relay_txs);
}
diff --git a/src/test/fuzz/utxo_snapshot.cpp b/src/test/fuzz/utxo_snapshot.cpp
index 21c305e222..1241bba8be 100644
--- a/src/test/fuzz/utxo_snapshot.cpp
+++ b/src/test/fuzz/utxo_snapshot.cpp
@@ -58,7 +58,7 @@ void initialize_chain()
auto& chainman{*setup->m_node.chainman};
for (const auto& block : chain) {
BlockValidationState dummy;
- bool processed{chainman.ProcessNewBlockHeaders({*block}, true, dummy)};
+ bool processed{chainman.ProcessNewBlockHeaders({{block->GetBlockHeader()}}, true, dummy)};
Assert(processed);
const auto* index{WITH_LOCK(::cs_main, return chainman.m_blockman.LookupBlockIndex(block->GetHash()))};
Assert(index);
@@ -137,7 +137,7 @@ void utxo_snapshot_fuzz(FuzzBufferType buffer)
if constexpr (!INVALID) {
for (const auto& block : *g_chain) {
BlockValidationState dummy;
- bool processed{chainman.ProcessNewBlockHeaders({*block}, true, dummy)};
+ bool processed{chainman.ProcessNewBlockHeaders({{block->GetBlockHeader()}}, true, dummy)};
Assert(processed);
const auto* index{WITH_LOCK(::cs_main, return chainman.m_blockman.LookupBlockIndex(block->GetHash()))};
Assert(index);