fuzz: don't bypass_limits for most mempool harnesses
What changed, and why it matters
This change only modifies Bitcoin Core's internal fuzz testing code, not the production mempool logic. It adjusts how test harnesses feed random data into the mempool acceptance routine so that most harnesses no longer skip standard policy limits. The patch improves test coverage for a new transaction type (TRUC) but does not fix a security bug in live software.
No action required for production deployments. Treat as a routine test-quality improvement. Reviewers may verify that the remaining bypass_limits usage in the tx_pool fuzz target still provides adequate coverage for reorg-only paths.
Security signals we found
No production code changed
Fuzz-test harness adjustment only
No input validation, cryptography, or network logic modified
No memory safety, resource exhaustion, or consensus code touched
Evidence from the diff
The commit updates three fuzz targets in src/test/fuzz/package_eval.cpp and src/test/fuzz/tx_pool.cpp. It replaces fuzzer-controlled bypass_limits booleans with false in ephemeral_package_eval and tx_pool_standard, and in the tx_pool target it tracks whether limits were ever bypassed so that CheckMempoolTRUCInvariants is skipped only when bypass_limits was actually used. AcceptToMemoryPool’s real behavior is unchanged; only the test scaffolding is altered.
Changed components
src/test/fuzz/package_eval.cppsrc/test/fuzz/tx_pool.cppInspect captured patch +11 / −5
diff --git a/src/test/fuzz/package_eval.cpp b/src/test/fuzz/package_eval.cpp
index 23ea9d1f..50f4c416 100644
--- a/src/test/fuzz/package_eval.cpp
+++ b/src/test/fuzz/package_eval.cpp
@@ -325,7 +325,7 @@ FUZZ_TARGET(ephemeral_package_eval, .init = initialize_tx_pool)
return ProcessNewPackage(chainstate, tx_pool, txs, /*test_accept=*/single_submit, /*client_maxfeerate=*/{}));
const auto res = WITH_LOCK(::cs_main, return AcceptToMemoryPool(chainstate, txs.back(), GetTime(),
- /*bypass_limits=*/fuzzed_data_provider.ConsumeBool(), /*test_accept=*/!single_submit));
+ /*bypass_limits=*/false, /*test_accept=*/!single_submit));
if (!single_submit && result_package.m_state.GetResult() != PackageValidationResult::PCKG_POLICY) {
// We don't know anything about the validity since transactions were randomly generated, so
diff --git a/src/test/fuzz/tx_pool.cpp b/src/test/fuzz/tx_pool.cpp
index 90155d38..c728485d 100644
--- a/src/test/fuzz/tx_pool.cpp
+++ b/src/test/fuzz/tx_pool.cpp
@@ -296,7 +296,6 @@ FUZZ_TARGET(tx_pool_standard, .init = initialize_tx_pool)
std::set<CTransactionRef> added;
auto txr = std::make_shared<TransactionsDelta>(removed, added);
node.validation_signals->RegisterSharedValidationInterface(txr);
- const bool bypass_limits = fuzzed_data_provider.ConsumeBool();
// Make sure ProcessNewPackage on one transaction works.
// The result is not guaranteed to be the same as what is returned by ATMP.
@@ -311,7 +310,7 @@ FUZZ_TARGET(tx_pool_standard, .init = initialize_tx_pool)
it->second.m_result_type == MempoolAcceptResult::ResultType::INVALID);
}
- const auto res = WITH_LOCK(::cs_main, return AcceptToMemoryPool(chainstate, tx, GetTime(), bypass_limits, /*test_accept=*/false));
+ const auto res = WITH_LOCK(::cs_main, return AcceptToMemoryPool(chainstate, tx, GetTime(), /*bypass_limits=*/false, /*test_accept=*/false));
const bool accepted = res.m_result_type == MempoolAcceptResult::ResultType::VALID;
node.validation_signals->SyncWithValidationInterfaceQueue();
node.validation_signals->UnregisterSharedValidationInterface(txr);
@@ -394,6 +393,9 @@ FUZZ_TARGET(tx_pool, .init = initialize_tx_pool)
chainstate.SetMempool(&tx_pool);
+ // If we ever bypass limits, do not do TRUC invariants checks
+ bool ever_bypassed_limits{false};
+
LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 300)
{
const auto mut_tx = ConsumeTransaction(fuzzed_data_provider, txids);
@@ -412,13 +414,17 @@ FUZZ_TARGET(tx_pool, .init = initialize_tx_pool)
tx_pool.PrioritiseTransaction(txid, delta);
}
+ const bool bypass_limits{fuzzed_data_provider.ConsumeBool()};
+ ever_bypassed_limits |= bypass_limits;
+
const auto tx = MakeTransactionRef(mut_tx);
- const bool bypass_limits = fuzzed_data_provider.ConsumeBool();
const auto res = WITH_LOCK(::cs_main, return AcceptToMemoryPool(chainstate, tx, GetTime(), bypass_limits, /*test_accept=*/false));
const bool accepted = res.m_result_type == MempoolAcceptResult::ResultType::VALID;
if (accepted) {
txids.push_back(tx->GetHash());
- CheckMempoolTRUCInvariants(tx_pool);
+ if (!ever_bypassed_limits) {
+ CheckMempoolTRUCInvariants(tx_pool);
+ }
}
}
Finish(fuzzed_data_provider, tx_pool, chainstate);
Why this scored 16/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.