Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 39 additions & 7 deletions src/test/fuzz/coins_view.cpp
Original file line number Diff line number Diff line change
@@ -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
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

Expand All @@ -14,6 +14,7 @@
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
#include <test/util/setup_common.h>
#include <txdb.h>
#include <util/hasher.h>

#include <cassert>
Expand Down Expand Up @@ -41,13 +42,12 @@ void initialize_coins_view()
static const auto testing_setup = MakeNoLogFileContext<>();
}

FUZZ_TARGET(coins_view, .init = initialize_coins_view)
void TestCoinsView(FuzzedDataProvider& fuzzed_data_provider, CCoinsView& backend_coins_view, bool is_db)
{
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
bool good_data{true};

CCoinsView backend_coins_view;
CCoinsViewCache coins_view_cache{&backend_coins_view, /*deterministic=*/true};
if (is_db) coins_view_cache.SetBestBlock(uint256::ONE);
COutPoint random_out_point;
Coin random_coin;
CMutableTransaction random_mutable_transaction;
Expand All @@ -69,6 +69,12 @@ FUZZ_TARGET(coins_view, .init = initialize_coins_view)
if (e.what() == std::string{"Attempted to overwrite an unspent coin (when possible_overwrite is false)"}) {
assert(!possible_overwrite);
expected_code_path = true;
// AddCoin() decreases cachedCoinsUsage by the memory usage of the old coin at the beginning and
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still think this comment is way to verbose, we don't need that much context here.
Is this still needed after 327ee45 (#32313) where we might not get into the described situation anymore since cachedCoinsUsage update only happens after the mentioned exception now.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the comment makes sense here, even if it is a bit verbose. Happy to change it once a fix such as #32313 gets merged.

// increases it by the value of the new coin at the end. If it throws in the process, the value
// of cachedCoinsUsage would have been incorrectly decreased, leading to an underflow later on.
// To avoid this, use Flush() to reset the value of cachedCoinsUsage in sync with the cacheCoins
// mapping.
(void)coins_view_cache.Flush();
}
}
assert(expected_code_path);
Expand All @@ -80,7 +86,10 @@ FUZZ_TARGET(coins_view, .init = initialize_coins_view)
(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;
Expand Down Expand Up @@ -148,7 +157,11 @@ FUZZ_TARGET(coins_view, .init = initialize_coins_view)
bool expected_code_path = false;
try {
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;
} catch (const std::logic_error& e) {
if (e.what() == std::string{"FRESH flag misapplied to coin that exists in parent cache"}) {
Expand Down Expand Up @@ -202,7 +215,7 @@ FUZZ_TARGET(coins_view, .init = initialize_coins_view)

{
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.GetBestBlock();
(void)backend_coins_view.GetHeadBlocks();
Expand Down Expand Up @@ -288,3 +301,22 @@ FUZZ_TARGET(coins_view, .init = initialize_coins_view)
});
}
}

FUZZ_TARGET(coins_view, .init = initialize_coins_view)
{
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
CCoinsView 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);
}
Loading