fuzz: gate mempool entry based on weight
What changed, and why it matters
This is a small fix to a Bitcoin Core fuzz test (an automated testing harness, not production code). The test was using an outdated size check after the real mempool code switched from measuring transaction size in 'vsize' to measuring it in 'weight'. The change tightens a guard so the fuzzer stops adding transactions before hitting an internal integer limit. It does not change how real nodes handle transactions and is not a vulnerability in live Bitcoin Core.
No action required for operators or users. This is a test-only change. Developers can verify the fuzz harness now correctly respects the weight-based TxGraph/FeeFrac limits.
Security signals we found
Integer-limit guard in fuzz harness
Test-only code change
Guard against FeeFrac limit overflow in fuzzing input generation
Evidence from the diff
The commit modifies src/test/fuzz/rbf.cpp, the package_rbf fuzz target. After the mempool implementation moved to TxGraph with FeePerWeight (weight-based) entries, the fuzz harness’s running_vsize_total check became too permissive: GetTxSize() returns vsize, but the new code stores entries by weight, which is WITNESS_SCALE_FACTOR (4x) larger. The patch multiplies the running vsize total by WITNESS_SCALE_FACTOR before comparing against std::numeric_limits
Changed components
src/test/fuzz/rbf.cpppackage_rbf fuzz targetInspect captured patch +3 / −2
diff --git a/src/test/fuzz/rbf.cpp b/src/test/fuzz/rbf.cpp
index 02ec3cb0..c0595e1b 100644
--- a/src/test/fuzz/rbf.cpp
+++ b/src/test/fuzz/rbf.cpp
@@ -121,6 +121,7 @@ FUZZ_TARGET(package_rbf, .init = initialize_package_rbf)
CTransaction replacement_tx_final{*replacement_tx};
auto replacement_entry = ConsumeTxMemPoolEntry(fuzzed_data_provider, replacement_tx_final);
int32_t replacement_weight = replacement_entry.GetAdjustedWeight();
+ // Ensure that we don't hit FeeFrac limits, as we store TxGraph entries in terms of FeePerWeight
int64_t running_vsize_total{replacement_entry.GetTxSize()};
LOCK2(cs_main, pool.cs);
@@ -137,7 +138,7 @@ FUZZ_TARGET(package_rbf, .init = initialize_package_rbf)
mempool_txs.emplace_back(parent);
const auto parent_entry = ConsumeTxMemPoolEntry(fuzzed_data_provider, mempool_txs.back());
running_vsize_total += parent_entry.GetTxSize();
- if (running_vsize_total > std::numeric_limits<int32_t>::max()) {
+ if (running_vsize_total * WITNESS_SCALE_FACTOR > std::numeric_limits<int32_t>::max()) {
// We aren't adding this final tx to mempool, so we don't want to conflict with it
mempool_txs.pop_back();
break;
@@ -156,7 +157,7 @@ FUZZ_TARGET(package_rbf, .init = initialize_package_rbf)
mempool_txs.emplace_back(child);
const auto child_entry = ConsumeTxMemPoolEntry(fuzzed_data_provider, mempool_txs.back());
running_vsize_total += child_entry.GetTxSize();
- if (running_vsize_total > std::numeric_limits<int32_t>::max()) {
+ if (running_vsize_total * WITNESS_SCALE_FACTOR > std::numeric_limits<int32_t>::max()) {
// We aren't adding this final tx to mempool, so we don't want to conflict with it
mempool_txs.pop_back();
break;
Why this scored 17/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.