From 780f460635af86b91c4215e761b6895be762ed3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C5=91rinc?= Date: Sun, 22 Feb 2026 13:42:37 +0100 Subject: [PATCH] fuzz: avoid invalid `AddCoin` overwrites The coins view fuzzer can call `AddCoin` with `possible_overwrite=false` for an outpoint that already exists unspent in the view, which violates the `AddCoin` caller contract. Derive `possible_overwrite` from `PeekCoin` so `possible_overwrite=false` is only used when the outpoint is absent. This matches the approach used by the `coinscache_sim` fuzzer, which derives the overwrite flag from simulated state. --- src/test/fuzz/coins_view.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/test/fuzz/coins_view.cpp b/src/test/fuzz/coins_view.cpp index d4bdb8a1d1b..011b660eeea 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)); }