From a0eaa4749fe0f755e113eee70dee1989bdc07ad5 Mon Sep 17 00:00:00 2001 From: marcofleon Date: Tue, 13 Aug 2024 11:42:59 +0100 Subject: Add FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION in PoW check To avoid PoW being a blocker for fuzz tests, `FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION` is used in fuzz builds to bypass the actual PoW validation in `CheckProofOfWork`. It's replaced with a check on the last byte of the hash, which allows the fuzzer to quickly generate (in)valid blocks by checking a single bit, rather than performing the full PoW computation. If PoW is the target of a fuzz test, then it should call `CheckProofOfWorkImpl`. --- src/pow.cpp | 11 +++++++++++ src/pow.h | 1 + src/test/fuzz/integer.cpp | 2 +- src/test/fuzz/pow.cpp | 2 +- 4 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/pow.cpp b/src/pow.cpp index 50de8946be..6c8e7e5d98 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -134,7 +134,18 @@ bool PermittedDifficultyTransition(const Consensus::Params& params, int64_t heig return true; } +// Bypasses the actual proof of work check during fuzz testing with a simplified validation checking whether +// the most signficant bit of the last byte of the hash is set. bool CheckProofOfWork(uint256 hash, unsigned int nBits, const Consensus::Params& params) +{ +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + return (hash.data()[31] & 0x80) == 0; +#else + return CheckProofOfWorkImpl(hash, nBits, params); +#endif +} + +bool CheckProofOfWorkImpl(uint256 hash, unsigned int nBits, const Consensus::Params& params) { bool fNegative; bool fOverflow; diff --git a/src/pow.h b/src/pow.h index ec03f318a4..2b28ade273 100644 --- a/src/pow.h +++ b/src/pow.h @@ -19,6 +19,7 @@ unsigned int CalculateNextWorkRequired(const CBlockIndex* pindexLast, int64_t nF /** Check whether a block hash satisfies the proof-of-work requirement specified by nBits */ bool CheckProofOfWork(uint256 hash, unsigned int nBits, const Consensus::Params&); +bool CheckProofOfWorkImpl(uint256 hash, unsigned int nBits, const Consensus::Params&); /** * Return false if the proof-of-work requirement specified by new_nbits at a diff --git a/src/test/fuzz/integer.cpp b/src/test/fuzz/integer.cpp index 02c6796d11..87838b7b39 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)); 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 hash = ConsumeDeserializable(fuzzed_data_provider); if (hash) { - (void)CheckProofOfWork(*hash, fuzzed_data_provider.ConsumeIntegral(), consensus_params); + (void)CheckProofOfWorkImpl(*hash, fuzzed_data_provider.ConsumeIntegral(), consensus_params); } } } -- cgit v1.2.3