fuzz: avoid invalid `AddCoin` overwrites
What changed, and why it matters
This commit fixes a fuzz test (an automated random-input testing harness) so it no longer violates an internal rule of the coin cache. It does not change production Bitcoin node code, so it cannot directly affect real users or the network. The change makes the test harness follow the same contract as real callers of AddCoin.
No production action required. Treat as a test-quality improvement. Reviewers may optionally verify that the fuzzer now matches the documented AddCoin contract and that no other fuzz targets have similar invalid-call patterns.
Security signals we found
Fixes a fuzz-harness contract violation, not a runtime vulnerability
No change to consensus, net, wallet, or mempool code
No attacker-controlled input path in production code
No CVE or security advisory referenced in commit
Evidence from the diff
In src/test/fuzz/coins_view.cpp, the fuzzer previously chose possible_overwrite randomly and caught the resulting logic_error when it was false but the outpoint already existed unspent. The patch derives possible_overwrite from PeekCoin(outpoint) || random_bool, ensuring AddCoin is only called with possible_overwrite=false when the outpoint is actually absent. This aligns the fuzzer with the AddCoin caller contract and removes the try/catch assertion. The change is confined to test/fuzz code.
Changed components
src/test/fuzz/coins_view.cppInspect captured patch +3 / −7
diff --git a/src/test/fuzz/coins_view.cpp b/src/test/fuzz/coins_view.cpp
index d4bdb8a1..011b660e 100644
--- a/src/test/fuzz/coins_view.cpp
+++ b/src/test/fuzz/coins_view.cpp
@@ -120,13 +120,9 @@ void TestCoinsView(FuzzedDataProvider& fuzzed_data_provider, CCoinsViewCache& co
COutPoint outpoint{random_out_point};
Coin coin{random_coin};
if (fuzzed_data_provider.ConsumeBool()) {
- const bool possible_overwrite{fuzzed_data_provider.ConsumeBool()};
- try {
- coins_view_cache.AddCoin(outpoint, std::move(coin), possible_overwrite);
- } catch (const std::logic_error& e) {
- assert(e.what() == std::string{"Attempted to overwrite an unspent coin (when possible_overwrite is false)"});
- assert(!possible_overwrite);
- }
+ // We can only skip the check if no unspent coin exists for this outpoint.
+ const bool possible_overwrite{coins_view_cache.PeekCoin(outpoint) || fuzzed_data_provider.ConsumeBool()};
+ coins_view_cache.AddCoin(outpoint, std::move(coin), possible_overwrite);
} else {
coins_view_cache.EmplaceCoinInternalDANGER(std::move(outpoint), std::move(coin));
}
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.