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(); 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;