34const 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<>();
110 Coin coin{random_coin};
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);
123 coins_view_cache.
Sync();
128 if (is_db && best_block.IsNull()) best_block =
uint256::ONE;
138 if (best_block.IsNull()) {
150 coins_view_cache.
Uncache(random_out_point);
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;
172 random_coin = *opt_coin;
176 if (!opt_mutable_transaction) {
180 random_mutable_transaction = *opt_mutable_transaction;
184 sentinel.second.SelfRef(sentinel);
185 size_t dirty_count{0};
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};
307 if (!transaction.vin.empty() && (
flags & SCRIPT_VERIFY_WITNESS) != 0 && (
flags & SCRIPT_VERIFY_P2SH) == 0) {
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};
bool MoneyRange(const CAmount &nValue)
int64_t CAmount
Amount in satoshis (Can be negative)
void SetBackend(CCoinsView &viewIn)
CCoinsView that adds a memory cache for transactions to another CCoinsView.
void Sync()
Push the modifications applied to this cache to its base while retaining the contents of this cache (...
CCoinsViewCache(CCoinsView *baseIn, bool deterministic=false)
bool SpendCoin(const COutPoint &outpoint, Coin *moveto=nullptr)
Spend a coin.
ResetGuard CreateResetGuard() noexcept
Create a scoped guard that will call Reset() on this cache when it goes out of scope.
void Uncache(const COutPoint &outpoint)
Removes the UTXO with the given outpoint from the cache, if it is not modified.
void AddCoin(const COutPoint &outpoint, Coin &&coin, bool possible_overwrite)
Add a coin.
void Flush(bool reallocate_cache=true)
Push the modifications applied to this cache to its base and wipe local state.
uint256 GetBestBlock() const override
Retrieve the block hash whose state this CCoinsView currently represents.
void SetBestBlock(const uint256 &hashBlock)
void BatchWrite(CoinsViewCacheCursor &cursor, const uint256 &hashBlock) override
Do a bulk modification (multiple Coin changes + BestBlock change).
std::optional< Coin > PeekCoin(const COutPoint &outpoint) const override
Retrieve the Coin (unspent transaction output) for a given outpoint, without caching results.
void EmplaceCoinInternalDANGER(COutPoint &&outpoint, Coin &&coin)
Emplace a coin into cacheCoins without performing any checks, marking the emplaced coin as dirty.
CCoinsView backed by the coin database (chainstate/)
Abstract view on the open txout dataset.
An outpoint - a combination of a transaction hash and an index n into its vout.
The basic transaction that is broadcasted on the network and contained in blocks.
An output of a transaction.
CTxOut out
unspent transaction output
bool IsSpent() const
Either this coin never existed (see e.g.
uint32_t nHeight
at which height this containing transaction was included in the active block chain
unsigned int fCoinBase
whether containing transaction was a coinbase
CCoinsViewCache overlay that avoids populating/mutating parent cache layers on cache misses.
T ConsumeIntegralInRange(T min, T max)
static constexpr script_verify_flags from_int(value_type f)
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.
std::pair< const COutPoint, CCoinsCacheEntry > CoinsCachePair
std::unordered_map< COutPoint, CCoinsCacheEntry, SaltedOutpointHasher, std::equal_to< COutPoint >, PoolAllocator< CoinsCachePair, sizeof(CoinsCachePair)+sizeof(void *) *4 > > CCoinsMap
PoolAllocator's MAX_BLOCK_SIZE_BYTES parameter here uses sizeof the data, and adds the size of 4 poin...
CCoinsMap::allocator_type::ResourceType CCoinsMapMemoryResource
FUZZ_TARGET(coins_view,.init=initialize_coins_view)
void initialize_coins_view()
void TestCoinsView(FuzzedDataProvider &fuzzed_data_provider, CCoinsViewCache &coins_view_cache, CCoinsView &backend_coins_view, bool is_db)
#define LIMITED_WHILE(condition, limit)
Can be used to limit a theoretically unbounded loop.
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...
bool operator==(const CNetAddr &a, const CNetAddr &b)
bool AreInputsStandard(const CTransaction &tx, const CCoinsViewCache &mapInputs)
Check transaction inputs.
bool IsWitnessStandard(const CTransaction &tx, const CCoinsViewCache &mapInputs)
Check if the transaction is over standard P2WSH resources limit: 3600bytes witnessScript size,...
static constexpr TransactionSerParams TX_WITH_WITNESS
A Coin in one level of the coins database caching hierarchy.
static void SetFresh(CoinsCachePair &pair, CoinsCachePair &sentinel) noexcept
static void SetDirty(CoinsCachePair &pair, CoinsCachePair &sentinel) noexcept
A mutable version of CTransaction.
Cursor for iterating over the linked list of flagged entries in CCoinsViewCache.
User-controlled performance and debug options.
Application-specific storage settings.
fs::path path
Location in the filesystem where leveldb data will be stored.
bool ContainsSpentInput(const CTransaction &tx, const CCoinsViewCache &inputs) noexcept
uint256 ConsumeUInt256(FuzzedDataProvider &fuzzed_data_provider) noexcept
size_t CallOneOf(FuzzedDataProvider &fuzzed_data_provider, Callables... callables)
bool CheckTransaction(const CTransaction &tx, TxValidationState &state)
int64_t GetTransactionSigOpCost(const CTransaction &tx, const CCoinsViewCache &inputs, script_verify_flags flags)
Compute total signature operation cost of a transaction.
unsigned int GetP2SHSigOpCount(const CTransaction &tx, const CCoinsViewCache &inputs)
Count ECDSA signature operations in pay-to-script-hash inputs.
FuzzedDataProvider & fuzzed_data_provider