fuzz: add a target for the coins database

It reuses the logic from the `coins_view` target, except it uses an
in-memory CCoinsViewDB as the backend.

Note `CCoinsViewDB` will assert the best block hash is never null, so we
slightly modify the coins_view fuzz logic to take care of this.
This commit is contained in:
Antoine Poinsot authored and marcofleon committed 2025-05-29 12:14:13 +01:00
1 parent 46e14630f7
commit cfc42ae5b7
1 file changed
+26 -6
+26 -6
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2020-2022 The Bitcoin Core developers // Copyright (c) 2020-present The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying // Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -42,11 +42,12 @@ void initialize_coins_view()
static const auto testing_setup = MakeNoLogFileContext<>(); static const auto testing_setup = MakeNoLogFileContext<>();
} }
void TestCoinsView(FuzzedDataProvider& fuzzed_data_provider, CCoinsView& backend_coins_view) void TestCoinsView(FuzzedDataProvider& fuzzed_data_provider, CCoinsView& backend_coins_view, bool is_db)
{ {
bool good_data{true}; bool good_data{true};
CCoinsViewCache coins_view_cache{&backend_coins_view, /*deterministic=*/true}; CCoinsViewCache coins_view_cache{&backend_coins_view, /*deterministic=*/true};
if (is_db) coins_view_cache.SetBestBlock(uint256::ONE);
COutPoint random_out_point; COutPoint random_out_point;
Coin random_coin; Coin random_coin;
CMutableTransaction random_mutable_transaction; CMutableTransaction random_mutable_transaction;
@@ -85,7 +86,10 @@ void TestCoinsView(FuzzedDataProvider& fuzzed_data_provider, CCoinsView& backend
(void)coins_view_cache.Sync(); (void)coins_view_cache.Sync();
}, },
[&] { [&] {
coins_view_cache.SetBestBlock(ConsumeUInt256(fuzzed_data_provider)); uint256 best_block{ConsumeUInt256(fuzzed_data_provider)};
// Set best block hash to non-null to satisfy the assertion in CCoinsViewDB::BatchWrite().
if (is_db && best_block.IsNull()) best_block = uint256::ONE;
coins_view_cache.SetBestBlock(best_block);
}, },
[&] { [&] {
Coin move_to; Coin move_to;
@@ -153,7 +157,11 @@ void TestCoinsView(FuzzedDataProvider& fuzzed_data_provider, CCoinsView& backend
bool expected_code_path = false; bool expected_code_path = false;
try { try {
auto cursor{CoinsViewCacheCursor(usage, sentinel, coins_map, /*will_erase=*/true)}; auto cursor{CoinsViewCacheCursor(usage, sentinel, coins_map, /*will_erase=*/true)};
coins_view_cache.BatchWrite(cursor, fuzzed_data_provider.ConsumeBool() ? ConsumeUInt256(fuzzed_data_provider) : coins_view_cache.GetBestBlock()); uint256 best_block{coins_view_cache.GetBestBlock()};
if (fuzzed_data_provider.ConsumeBool()) best_block = ConsumeUInt256(fuzzed_data_provider);
// Set best block hash to non-null to satisfy the assertion in CCoinsViewDB::BatchWrite().
if (is_db && best_block.IsNull()) best_block = uint256::ONE;
coins_view_cache.BatchWrite(cursor, best_block);
expected_code_path = true; expected_code_path = true;
} catch (const std::logic_error& e) { } catch (const std::logic_error& e) {
if (e.what() == std::string{"FRESH flag misapplied to coin that exists in parent cache"}) { if (e.what() == std::string{"FRESH flag misapplied to coin that exists in parent cache"}) {
@@ -207,7 +215,7 @@ void TestCoinsView(FuzzedDataProvider& fuzzed_data_provider, CCoinsView& backend
{ {
std::unique_ptr<CCoinsViewCursor> coins_view_cursor = backend_coins_view.Cursor(); std::unique_ptr<CCoinsViewCursor> coins_view_cursor = backend_coins_view.Cursor();
assert(!coins_view_cursor); assert(is_db == !!coins_view_cursor);
(void)backend_coins_view.EstimateSize(); (void)backend_coins_view.EstimateSize();
(void)backend_coins_view.GetBestBlock(); (void)backend_coins_view.GetBestBlock();
(void)backend_coins_view.GetHeadBlocks(); (void)backend_coins_view.GetHeadBlocks();
@@ -298,5 +306,17 @@ FUZZ_TARGET(coins_view, .init = initialize_coins_view)
{ {
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
CCoinsView backend_coins_view; CCoinsView backend_coins_view;
TestCoinsView(fuzzed_data_provider, backend_coins_view); TestCoinsView(fuzzed_data_provider, backend_coins_view, /*is_db=*/false);
}
FUZZ_TARGET(coins_view_db, .init = initialize_coins_view)
{
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
auto db_params = DBParams{
.path = "",
.cache_bytes = 1_MiB,
.memory_only = true,
};
CCoinsViewDB coins_db{std::move(db_params), CoinsViewOptions{}};
TestCoinsView(fuzzed_data_provider, coins_db, /*is_db=*/true);
} }