aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormarcofleon <marleo23@proton.me>2024-08-13 11:42:59 +0100
committermarcofleon <marleo23@proton.me>2024-09-02 15:43:33 +0100
commita0eaa4749fe0f755e113eee70dee1989bdc07ad5 (patch)
tree357c337218bc1b39c6490ca111358c736c55acbc
parenta3f6f5acd89f2f5bb136ec247f259d212e8944d0 (diff)
downloadbitcoin-a0eaa4749fe0f755e113eee70dee1989bdc07ad5.tar.xz
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`.
-rw-r--r--src/pow.cpp11
-rw-r--r--src/pow.h1
-rw-r--r--src/test/fuzz/integer.cpp2
-rw-r--r--src/test/fuzz/pow.cpp2
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,8 +134,19 @@ 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;
arith_uint256 bnTarget;
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<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);
}
}
}