mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-05-31 08:13:52 +02:00
coins: add explicit CoinsViewEmpty noop backend
Introduce `CoinsViewEmpty` as an explicit no-op `CCoinsView` implementation, and define its singleton accessor out of line in `coins.cpp` to avoid `-Wunique-object-duplication` in shared-library builds.` Use it at call sites that intentionally want a no-op backend instead of constructing anonymous placeholder views. `CCoinsViewTest` and `CoinsViewBottom` now inherit defaults from `CoinsViewEmpty` (e.g. the unused `EstimateSize()`, which now returns 0). Co-authored-by: Ryan Ofsky <ryan@ofsky.org>
This commit is contained in:
@@ -38,14 +38,14 @@ bool operator==(const Coin &a, const Coin &b) {
|
||||
a.out == b.out;
|
||||
}
|
||||
|
||||
class CCoinsViewTest : public CCoinsView
|
||||
class CCoinsViewTest : public CoinsViewEmpty
|
||||
{
|
||||
FastRandomContext& m_rng;
|
||||
uint256 hashBestBlock_;
|
||||
std::map<COutPoint, Coin> map_;
|
||||
|
||||
public:
|
||||
CCoinsViewTest(FastRandomContext& rng) : m_rng{rng} {}
|
||||
explicit CCoinsViewTest(FastRandomContext& rng) : m_rng{rng} {}
|
||||
|
||||
std::optional<Coin> GetCoin(const COutPoint& outpoint) const override
|
||||
{
|
||||
@@ -677,8 +677,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
CCoinsView root;
|
||||
CCoinsViewCacheTest base{&root};
|
||||
CCoinsViewCacheTest base{&CoinsViewEmpty::Get()};
|
||||
CCoinsViewCacheTest cache{&base};
|
||||
};
|
||||
|
||||
@@ -1087,8 +1086,7 @@ BOOST_AUTO_TEST_CASE(coins_resource_is_used)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(ccoins_addcoin_exception_keeps_usage_balanced)
|
||||
{
|
||||
CCoinsView root;
|
||||
CCoinsViewCacheTest cache{&root};
|
||||
CCoinsViewCacheTest cache{&CoinsViewEmpty::Get()};
|
||||
|
||||
const COutPoint outpoint{Txid::FromUint256(m_rng.rand256()), m_rng.rand32()};
|
||||
|
||||
@@ -1105,8 +1103,7 @@ BOOST_AUTO_TEST_CASE(ccoins_addcoin_exception_keeps_usage_balanced)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(ccoins_emplace_duplicate_keeps_usage_balanced)
|
||||
{
|
||||
CCoinsView root;
|
||||
CCoinsViewCacheTest cache{&root};
|
||||
CCoinsViewCacheTest cache{&CoinsViewEmpty::Get()};
|
||||
|
||||
const COutPoint outpoint{Txid::FromUint256(m_rng.rand256()), m_rng.rand32()};
|
||||
|
||||
|
||||
@@ -90,11 +90,11 @@ void initialize_coins_view()
|
||||
static const auto testing_setup = MakeNoLogFileContext<>();
|
||||
}
|
||||
|
||||
void TestCoinsView(FuzzedDataProvider& fuzzed_data_provider, CCoinsViewCache& coins_view_cache, CCoinsView* backend_coins_view, bool is_db)
|
||||
void TestCoinsView(FuzzedDataProvider& fuzzed_data_provider, CCoinsViewCache& coins_view_cache, CCoinsView* backend_coins_view)
|
||||
{
|
||||
const bool is_db{dynamic_cast<CCoinsViewDB*>(backend_coins_view) != nullptr};
|
||||
bool good_data{true};
|
||||
auto* original_backend{backend_coins_view};
|
||||
CCoinsView coins_view_empty{};
|
||||
|
||||
if (is_db) coins_view_cache.SetBestBlock(uint256::ONE);
|
||||
COutPoint random_out_point;
|
||||
@@ -158,7 +158,7 @@ void TestCoinsView(FuzzedDataProvider& fuzzed_data_provider, CCoinsViewCache& co
|
||||
// Reset() clears the best block; db backends require a non-null hash.
|
||||
if (is_db) coins_view_cache.SetBestBlock(uint256::ONE);
|
||||
}
|
||||
backend_coins_view = use_original_backend ? original_backend : &coins_view_empty;
|
||||
backend_coins_view = use_original_backend ? original_backend : &CoinsViewEmpty::Get();
|
||||
coins_view_cache.SetBackend(*backend_coins_view);
|
||||
},
|
||||
[&] {
|
||||
@@ -350,9 +350,8 @@ void TestCoinsView(FuzzedDataProvider& fuzzed_data_provider, CCoinsViewCache& co
|
||||
FUZZ_TARGET(coins_view, .init = initialize_coins_view)
|
||||
{
|
||||
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
|
||||
CCoinsView backend_coins_view;
|
||||
CCoinsViewCache coins_view_cache{&backend_coins_view, /*deterministic=*/true};
|
||||
TestCoinsView(fuzzed_data_provider, coins_view_cache, &backend_coins_view, /*is_db=*/false);
|
||||
CCoinsViewCache coins_view_cache{&CoinsViewEmpty::Get(), /*deterministic=*/true};
|
||||
TestCoinsView(fuzzed_data_provider, coins_view_cache, &CoinsViewEmpty::Get());
|
||||
}
|
||||
|
||||
FUZZ_TARGET(coins_view_db, .init = initialize_coins_view)
|
||||
@@ -365,7 +364,7 @@ FUZZ_TARGET(coins_view_db, .init = initialize_coins_view)
|
||||
};
|
||||
CCoinsViewDB backend_coins_view{std::move(db_params), CoinsViewOptions{}};
|
||||
CCoinsViewCache coins_view_cache{&backend_coins_view, /*deterministic=*/true};
|
||||
TestCoinsView(fuzzed_data_provider, coins_view_cache, &backend_coins_view, /*is_db=*/true);
|
||||
TestCoinsView(fuzzed_data_provider, coins_view_cache, &backend_coins_view);
|
||||
}
|
||||
|
||||
// Creates a CoinsViewOverlay and a MutationGuardCoinsViewCache as the base.
|
||||
@@ -375,8 +374,7 @@ FUZZ_TARGET(coins_view_db, .init = initialize_coins_view)
|
||||
FUZZ_TARGET(coins_view_overlay, .init = initialize_coins_view)
|
||||
{
|
||||
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
|
||||
CCoinsView backend_base_coins_view;
|
||||
MutationGuardCoinsViewCache backend_cache{&backend_base_coins_view, /*deterministic=*/true};
|
||||
MutationGuardCoinsViewCache backend_cache{&CoinsViewEmpty::Get(), /*deterministic=*/true};
|
||||
CoinsViewOverlay coins_view_cache{&backend_cache, /*deterministic=*/true};
|
||||
TestCoinsView(fuzzed_data_provider, coins_view_cache, &backend_cache, /*is_db=*/false);
|
||||
TestCoinsView(fuzzed_data_provider, coins_view_cache, &backend_cache);
|
||||
}
|
||||
|
||||
@@ -139,7 +139,7 @@ struct CacheLevel
|
||||
*
|
||||
* The initial state consists of the empty UTXO set.
|
||||
*/
|
||||
class CoinsViewBottom final : public CCoinsView
|
||||
class CoinsViewBottom final : public CoinsViewEmpty
|
||||
{
|
||||
std::map<COutPoint, Coin> m_data;
|
||||
|
||||
@@ -153,11 +153,6 @@ public:
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
uint256 GetBestBlock() const final { return {}; }
|
||||
std::vector<uint256> GetHeadBlocks() const final { return {}; }
|
||||
std::unique_ptr<CCoinsViewCursor> Cursor() const final { return {}; }
|
||||
size_t EstimateSize() const final { return m_data.size(); }
|
||||
|
||||
void BatchWrite(CoinsViewCacheCursor& cursor, const uint256&) final
|
||||
{
|
||||
for (auto it{cursor.Begin()}; it != cursor.End(); it = cursor.NextAndMaybeErase(*it)) {
|
||||
|
||||
@@ -86,8 +86,7 @@ FUZZ_TARGET(transaction, .init = initialize_transaction)
|
||||
(void)RecursiveDynamicUsage(tx);
|
||||
(void)SignalsOptInRBF(tx);
|
||||
|
||||
CCoinsView coins_view;
|
||||
const CCoinsViewCache coins_view_cache(&coins_view);
|
||||
const CCoinsViewCache coins_view_cache{&CoinsViewEmpty::Get()};
|
||||
(void)ValidateInputsStandardness(tx, coins_view_cache);
|
||||
(void)IsWitnessStandard(tx, coins_view_cache);
|
||||
|
||||
|
||||
@@ -277,8 +277,7 @@ BOOST_AUTO_TEST_CASE(switchover)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(ValidateInputsStandardness)
|
||||
{
|
||||
CCoinsView coinsDummy;
|
||||
CCoinsViewCache coins(&coinsDummy);
|
||||
CCoinsViewCache coins{&CoinsViewEmpty::Get()};
|
||||
FillableSigningProvider keystore;
|
||||
CKey key[6];
|
||||
for (int i = 0; i < 6; i++)
|
||||
|
||||
@@ -116,8 +116,7 @@ BOOST_AUTO_TEST_CASE(GetTxSigOpCost)
|
||||
CMutableTransaction spendingTx;
|
||||
|
||||
// Create utxo set
|
||||
CCoinsView coinsDummy;
|
||||
CCoinsViewCache coins(&coinsDummy);
|
||||
CCoinsViewCache coins{&CoinsViewEmpty::Get()};
|
||||
// Create key
|
||||
CKey key = GenerateRandomKey();
|
||||
CPubKey pubkey = key.GetPubKey();
|
||||
|
||||
@@ -392,8 +392,7 @@ BOOST_AUTO_TEST_CASE(basic_transaction_tests)
|
||||
BOOST_AUTO_TEST_CASE(test_Get)
|
||||
{
|
||||
FillableSigningProvider keystore;
|
||||
CCoinsView coinsDummy;
|
||||
CCoinsViewCache coins(&coinsDummy);
|
||||
CCoinsViewCache coins{&CoinsViewEmpty::Get()};
|
||||
std::vector<CMutableTransaction> dummyTransactions =
|
||||
SetupDummyInputs(keystore, coins, {11*CENT, 50*CENT, 21*CENT, 22*CENT});
|
||||
|
||||
@@ -749,8 +748,7 @@ BOOST_AUTO_TEST_CASE(test_witness)
|
||||
BOOST_AUTO_TEST_CASE(test_IsStandard)
|
||||
{
|
||||
FillableSigningProvider keystore;
|
||||
CCoinsView coinsDummy;
|
||||
CCoinsViewCache coins(&coinsDummy);
|
||||
CCoinsViewCache coins{&CoinsViewEmpty::Get()};
|
||||
std::vector<CMutableTransaction> dummyTransactions =
|
||||
SetupDummyInputs(keystore, coins, {11*CENT, 50*CENT, 21*CENT, 22*CENT});
|
||||
|
||||
@@ -1022,8 +1020,7 @@ BOOST_AUTO_TEST_CASE(test_IsStandard)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(max_standard_legacy_sigops)
|
||||
{
|
||||
CCoinsView coins_dummy;
|
||||
CCoinsViewCache coins(&coins_dummy);
|
||||
CCoinsViewCache coins{&CoinsViewEmpty::Get()};
|
||||
CKey key;
|
||||
key.MakeNewKey(true);
|
||||
|
||||
@@ -1132,8 +1129,7 @@ BOOST_AUTO_TEST_CASE(max_standard_legacy_sigops)
|
||||
BOOST_AUTO_TEST_CASE(checktxinputs_invalid_transactions_test)
|
||||
{
|
||||
auto check_invalid{[](CAmount input_value, CAmount output_value, bool coinbase, int spend_height, TxValidationResult expected_result, std::string_view expected_reason) {
|
||||
CCoinsView coins_dummy;
|
||||
CCoinsViewCache inputs(&coins_dummy);
|
||||
CCoinsViewCache inputs{&CoinsViewEmpty::Get()};
|
||||
|
||||
const COutPoint prevout{Txid::FromUint256(uint256::ONE), 0};
|
||||
inputs.AddCoin(prevout, Coin{{input_value, CScript() << OP_TRUE}, /*nHeightIn=*/1, coinbase}, /*possible_overwrite=*/false);
|
||||
@@ -1181,8 +1177,7 @@ BOOST_AUTO_TEST_CASE(getvalueout_out_of_range_throws)
|
||||
/** Sanity check the return value of SpendsNonAnchorWitnessProg for various output types. */
|
||||
BOOST_AUTO_TEST_CASE(spends_witness_prog)
|
||||
{
|
||||
CCoinsView coins_dummy;
|
||||
CCoinsViewCache coins(&coins_dummy);
|
||||
CCoinsViewCache coins{&CoinsViewEmpty::Get()};
|
||||
CKey key;
|
||||
key.MakeNewKey(true);
|
||||
const CPubKey pubkey{key.GetPubKey()};
|
||||
|
||||
@@ -465,8 +465,7 @@ std::pair<CMutableTransaction, CAmount> TestChain100Setup::CreateValidTransactio
|
||||
keystore.AddKey(input_signing_key);
|
||||
}
|
||||
// - Populate a CoinsViewCache with the unspent output
|
||||
CCoinsView coins_view;
|
||||
CCoinsViewCache coins_cache(&coins_view);
|
||||
CCoinsViewCache coins_cache{&CoinsViewEmpty::Get()};
|
||||
for (const auto& input_transaction : input_transactions) {
|
||||
AddCoins(coins_cache, *input_transaction.get(), input_height);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user