From fa327c77e34e0cfb7994842c23f539ab11bf5d3b Mon Sep 17 00:00:00 2001 From: marcofleon Date: Mon, 4 Nov 2024 11:32:23 +0000 Subject: [PATCH 1/2] util: Add ConsumeArithUInt256InRange fuzzing helper --- src/test/fuzz/util.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/test/fuzz/util.h b/src/test/fuzz/util.h index de097457301..8e2b8639c28 100644 --- a/src/test/fuzz/util.h +++ b/src/test/fuzz/util.h @@ -180,6 +180,22 @@ template return UintToArith256(ConsumeUInt256(fuzzed_data_provider)); } +[[nodiscard]] inline arith_uint256 ConsumeArithUInt256InRange(FuzzedDataProvider& fuzzed_data_provider, const arith_uint256& min, const arith_uint256& max) noexcept +{ + assert(min <= max); + const arith_uint256 range = max - min; + const arith_uint256 value = ConsumeArithUInt256(fuzzed_data_provider); + arith_uint256 result = value; + // Avoid division by 0, in case range + 1 results in overflow. + if (range != ~arith_uint256(0)) { + const arith_uint256 quotient = value / (range + 1); + result = value - (quotient * (range + 1)); + } + result += min; + assert(result >= min && result <= max); + return result; +} + [[nodiscard]] std::map ConsumeCoins(FuzzedDataProvider& fuzzed_data_provider) noexcept; [[nodiscard]] CTxDestination ConsumeTxDestination(FuzzedDataProvider& fuzzed_data_provider) noexcept; From a6ca8f324396522e9748c9a7bbefb3bf1c74a436 Mon Sep 17 00:00:00 2001 From: marcofleon Date: Mon, 4 Nov 2024 12:31:44 +0000 Subject: [PATCH 2/2] fuzz: Fix difficulty target generation in p2p_headers_presync The hardcoded nBits range would occasionally produce values for the difficulty target that were too low, causing the total work of the test chain to exceed MinimumChainWork. This fix uses ConsumeArithUInt256InRange to properly generate targets that will produce header chains with less work than MinimumChainWork. --- src/test/fuzz/p2p_headers_presync.cpp | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/test/fuzz/p2p_headers_presync.cpp b/src/test/fuzz/p2p_headers_presync.cpp index 2670aa8ee4e..5c9ce8723df 100644 --- a/src/test/fuzz/p2p_headers_presync.cpp +++ b/src/test/fuzz/p2p_headers_presync.cpp @@ -1,3 +1,4 @@ +#include #include #include #include @@ -89,10 +90,23 @@ CBlockHeader ConsumeHeader(FuzzedDataProvider& fuzzed_data_provider, const uint2 { 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(0x17058EBE, 0x1D00FFFF); + // Either use the previous difficulty or let the fuzzer choose. The upper target in the + // range comes from the bits value of the genesis block, which is 0x1d00ffff. The lower + // target comes from the bits value of mainnet block 840000, which is 0x17034219. + // Calling lower_target.SetCompact(0x17034219) and upper_target.SetCompact(0x1d00ffff) + // should return the values below. + // + // RPC commands to verify: + // getblockheader 000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f + // getblockheader 0000000000000000000320283a032748cef8227873ff4872689bf23f1cda83a5 + if (fuzzed_data_provider.ConsumeBool()) { + header.nBits = prev_nbits; + } else { + arith_uint256 lower_target = UintToArith256(uint256{"0000000000000000000342190000000000000000000000000000000000000000"}); + arith_uint256 upper_target = UintToArith256(uint256{"00000000ffff0000000000000000000000000000000000000000000000000000"}); + arith_uint256 target = ConsumeArithUInt256InRange(fuzzed_data_provider, lower_target, upper_target); + header.nBits = target.GetCompact(); + } header.nTime = ConsumeTime(fuzzed_data_provider); header.hashPrevBlock = prev_hash; header.nVersion = fuzzed_data_provider.ConsumeIntegral();