34 const Coin EMPTY_COIN{};
52 struct CacheCoinSnapshot {
57 bool operator==(
const CacheCoinSnapshot&)
const =
default;
60 std::vector<CacheCoinSnapshot> ComputeCacheCoinsSnapshot()
const 62 std::vector<CacheCoinSnapshot> snapshot;
63 snapshot.reserve(cacheCoins.size());
65 for (
const auto& [outpoint, entry] : cacheCoins) {
66 snapshot.emplace_back(outpoint, entry.IsDirty(), entry.IsFresh(), entry.coin);
69 std::ranges::sort(snapshot, std::less<>{}, &CacheCoinSnapshot::outpoint);
73 mutable std::vector<CacheCoinSnapshot> m_expected_snapshot{ComputeCacheCoinsSnapshot()};
79 assert(ComputeCacheCoinsSnapshot() == m_expected_snapshot);
81 m_expected_snapshot = ComputeCacheCoinsSnapshot();
90 static const auto testing_setup = MakeNoLogFileContext<>();
104 fuzzed_data_provider, 106 if (random_coin.IsSpent()) { 109 COutPoint outpoint{random_out_point}; 110 Coin coin{random_coin}; 111 if (fuzzed_data_provider.ConsumeBool()) { 112 // We can only skip the check if no unspent coin exists for this outpoint. 113 const bool possible_overwrite{coins_view_cache.PeekCoin(outpoint) || fuzzed_data_provider.ConsumeBool()}; 114 coins_view_cache.AddCoin(outpoint, std::move(coin), possible_overwrite); 116 coins_view_cache.EmplaceCoinInternalDANGER(std::move(outpoint), std::move(coin)); 120 coins_view_cache.Flush(/*reallocate_cache=*/fuzzed_data_provider.ConsumeBool()); 123 coins_view_cache.Sync(); 126 uint256 best_block{ConsumeUInt256(fuzzed_data_provider)}; 127 // Set best block hash to non-null to satisfy the assertion in CCoinsViewDB::BatchWrite(). 128 if (is_db && best_block.IsNull()) best_block = uint256::ONE; 129 coins_view_cache.SetBestBlock(best_block); 133 const auto reset_guard{coins_view_cache.CreateResetGuard()}; 135 // Set best block hash to non-null to satisfy the assertion in CCoinsViewDB::BatchWrite(). 137 const uint256 best_block{ConsumeUInt256(fuzzed_data_provider)}; 138 if (best_block.IsNull()) { 142 coins_view_cache.SetBestBlock(best_block); 147 (void)coins_view_cache.SpendCoin(random_out_point, fuzzed_data_provider.ConsumeBool() ? &move_to : nullptr); 150 coins_view_cache.Uncache(random_out_point); 153 if (fuzzed_data_provider.ConsumeBool()) { 154 backend_coins_view = CCoinsView{}; 156 coins_view_cache.SetBackend(backend_coins_view); 159 const std::optional<COutPoint> opt_out_point = ConsumeDeserializable<COutPoint>(fuzzed_data_provider); 160 if (!opt_out_point) { 164 random_out_point = *opt_out_point; 167 const std::optional<Coin> opt_coin = ConsumeDeserializable<Coin>(fuzzed_data_provider); 172 random_coin = *opt_coin; 175 const std::optional<CMutableTransaction> opt_mutable_transaction = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider, TX_WITH_WITNESS); 176 if (!opt_mutable_transaction) { 180 random_mutable_transaction = *opt_mutable_transaction; 183 CoinsCachePair sentinel{}; 184 sentinel.second.SelfRef(sentinel); 185 size_t dirty_count{0}; 186 CCoinsMapMemoryResource resource; 187 CCoinsMap coins_map{0, SaltedOutpointHasher{/*deterministic=*/true}, CCoinsMap::key_equal{}, &resource}; 188 LIMITED_WHILE(good_data && fuzzed_data_provider.ConsumeBool(), 10'000)
192 coins_cache_entry.
coin = random_coin;
199 coins_cache_entry.
coin = *opt_coin;
204 auto it{coins_map.emplace(random_out_point, std::move(coins_cache_entry)).first};
207 dirty_count += dirty;
213 if (is_db && best_block.IsNull()) best_block =
uint256::ONE;
214 coins_view_cache.
BatchWrite(cursor, best_block);
219 bool expected_code_path =
false;
221 (void)coins_view_cache.Cursor();
222 }
catch (
const std::logic_error&) {
223 expected_code_path =
true;
225 assert(expected_code_path);
226 (void)coins_view_cache.DynamicMemoryUsage();
227 (void)coins_view_cache.EstimateSize();
228 (void)coins_view_cache.GetBestBlock();
229 (void)coins_view_cache.GetCacheSize();
230 (void)coins_view_cache.GetHeadBlocks();
231 (void)coins_view_cache.HaveInputs(
CTransaction{random_mutable_transaction});
236 std::unique_ptr<CCoinsViewCursor> coins_view_cursor = backend_coins_view.Cursor();
237 assert(!!coins_view_cursor);
239 (void)backend_coins_view.EstimateSize();
240 (void)backend_coins_view.GetBestBlock();
241 (void)backend_coins_view.GetHeadBlocks();
248 const CTransaction transaction{random_mutable_transaction};
249 bool is_spent =
false;
250 for (
const CTxOut& tx_out : transaction.vout) {
251 if (Coin{tx_out, 0, transaction.IsCoinBase()}.IsSpent()) {
261 const bool check_for_overwrite{transaction.IsCoinBase() || [&] {
262 for (uint32_t i{0}; i < transaction.vout.size(); ++i) {
263 if (coins_view_cache.PeekCoin(
COutPoint{transaction.GetHash(), i}))
return true;
267 AddCoins(coins_view_cache, transaction, height, check_for_overwrite);
275 const CTransaction transaction{random_mutable_transaction};
291 const CTransaction transaction{random_mutable_transaction};
300 const CTransaction transaction{random_mutable_transaction};
320 const Coin& coin_using_access_coin = coins_view_cache.AccessCoin(random_out_point);
321 const bool exists_using_access_coin = !(coin_using_access_coin == EMPTY_COIN);
322 const bool exists_using_have_coin = coins_view_cache.HaveCoin(random_out_point);
323 const bool exists_using_have_coin_in_cache = coins_view_cache.HaveCoinInCache(random_out_point);
324 if (
auto coin{coins_view_cache.GetCoin(random_out_point)}) {
325 assert(*coin == coin_using_access_coin);
326 assert(exists_using_access_coin && exists_using_have_coin_in_cache && exists_using_have_coin);
328 assert(!exists_using_access_coin && !exists_using_have_coin_in_cache && !exists_using_have_coin);
331 const bool exists_using_have_coin_in_backend = backend_coins_view.HaveCoin(random_out_point);
332 if (!coin_using_access_coin.
IsSpent() && exists_using_have_coin_in_backend) {
333 assert(exists_using_have_coin);
335 if (
auto coin{backend_coins_view.GetCoin(random_out_point)}) {
336 assert(exists_using_have_coin_in_backend);
340 assert(!exists_using_have_coin_in_backend);
358 .cache_bytes = 1_MiB,
374 MutationGuardCoinsViewCache backend_cache{&backend_base_coins_view,
true};
FUZZ_TARGET(coins_view,.init=initialize_coins_view)
CCoinsViewCache(CCoinsView *baseIn, bool deterministic=false)
bool IsSpent() const
Either this coin never existed (see e.g.
fs::path path
Location in the filesystem where leveldb data will be stored.
bool CheckTxInputs(const CTransaction &tx, TxValidationState &state, const CCoinsViewCache &inputs, int nSpendHeight, CAmount &txfee)
Check whether all inputs of this transaction are valid (no double spends and amounts) This does not m...
A Coin in one level of the coins database caching hierarchy.
bool operator==(const CNetAddr &a, const CNetAddr &b)
bool MoneyRange(const CAmount &nValue)
CTxOut out
unspent transaction output
unsigned int fCoinBase
whether containing transaction was a coinbase
#define LIMITED_WHILE(condition, limit)
Can be used to limit a theoretically unbounded loop.
CCoinsViewCache overlay that avoids populating/mutating parent cache layers on cache misses...
User-controlled performance and debug options.
std::optional< Coin > PeekCoin(const COutPoint &outpoint) const override
Retrieve the Coin (unspent transaction output) for a given outpoint, without caching results...
int64_t GetTransactionSigOpCost(const CTransaction &tx, const CCoinsViewCache &inputs, script_verify_flags flags)
Compute total signature operation cost of a transaction.
void initialize_coins_view()
bool IsWitnessStandard(const CTransaction &tx, const CCoinsViewCache &mapInputs)
Check if the transaction is over standard P2WSH resources limit: 3600bytes witnessScript size...
int64_t CAmount
Amount in satoshis (Can be negative)
void SetBestBlock(const uint256 &hashBlock)
bool AreInputsStandard(const CTransaction &tx, const CCoinsViewCache &mapInputs)
Check transaction inputs.
void AddCoins(CCoinsViewCache &cache, const CTransaction &tx, int nHeight, bool check_for_overwrite)
Utility function to add all of a transaction's outputs to a cache.
uint32_t nHeight
at which height this containing transaction was included in the active block chain ...
Abstract view on the open txout dataset.
Cursor for iterating over the linked list of flagged entries in CCoinsViewCache.
bool ContainsSpentInput(const CTransaction &tx, const CCoinsViewCache &inputs) noexcept
An output of a transaction.
An outpoint - a combination of a transaction hash and an index n into its vout.
uint256 GetBestBlock() const override
Retrieve the block hash whose state this CCoinsView currently represents.
void TestCoinsView(FuzzedDataProvider &fuzzed_data_provider, CCoinsViewCache &coins_view_cache, CCoinsView &backend_coins_view, bool is_db)
static constexpr script_verify_flags from_int(value_type f)
static void SetDirty(CoinsCachePair &pair, CoinsCachePair &sentinel) noexcept
CCoinsView backed by the coin database (chainstate/)
FuzzedDataProvider & fuzzed_data_provider
unsigned int GetP2SHSigOpCount(const CTransaction &tx, const CCoinsViewCache &inputs)
Count ECDSA signature operations in pay-to-script-hash inputs.
Application-specific storage settings.
A mutable version of CTransaction.
size_t CallOneOf(FuzzedDataProvider &fuzzed_data_provider, Callables... callables)
The basic transaction that is broadcasted on the network and contained in blocks. ...
T ConsumeIntegralInRange(T min, T max)
CCoinsView that adds a memory cache for transactions to another CCoinsView.
static void SetFresh(CoinsCachePair &pair, CoinsCachePair &sentinel) noexcept
uint256 ConsumeUInt256(FuzzedDataProvider &fuzzed_data_provider) noexcept
bool CheckTransaction(const CTransaction &tx, TxValidationState &state)
void BatchWrite(CoinsViewCacheCursor &cursor, const uint256 &hashBlock) override
Do a bulk modification (multiple Coin changes + BestBlock change).