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);
82 }
catch (
const std::logic_error& e) {
88 assert(e.what() == std::string{
"FRESH flag misapplied to coin that exists in parent cache"});
92 m_expected_snapshot = ComputeCacheCoinsSnapshot();
101 static const auto testing_setup = MakeNoLogFileContext<>();
106 bool good_data{
true};
121 Coin coin{random_coin};
123 const bool possible_overwrite{fuzzed_data_provider.ConsumeBool()};
125 coins_view_cache.AddCoin(outpoint, std::move(coin), possible_overwrite);
126 }
catch (
const std::logic_error& e) {
127 assert(e.what() == std::string{
"Attempted to overwrite an unspent coin (when possible_overwrite is false)"});
128 assert(!possible_overwrite);
138 coins_view_cache.
Sync();
143 if (is_db && best_block.IsNull()) best_block =
uint256::ONE;
153 if (best_block.IsNull()) {
165 coins_view_cache.
Uncache(random_out_point);
171 coins_view_cache.
SetBackend(backend_coins_view);
174 const std::optional<COutPoint> opt_out_point = ConsumeDeserializable<COutPoint>(
fuzzed_data_provider);
175 if (!opt_out_point) {
179 random_out_point = *opt_out_point;
187 random_coin = *opt_coin;
191 if (!opt_mutable_transaction) {
195 random_mutable_transaction = *opt_mutable_transaction;
199 sentinel.second.SelfRef(sentinel);
200 size_t dirty_count{0};
209 coins_cache_entry.
coin = random_coin;
216 coins_cache_entry.
coin = *opt_coin;
218 auto it{coins_map.emplace(random_out_point, std::move(coins_cache_entry)).first};
221 dirty_count += dirty;
223 bool expected_code_path =
false;
229 if (is_db && best_block.IsNull()) best_block =
uint256::ONE;
230 coins_view_cache.
BatchWrite(cursor, best_block);
231 expected_code_path =
true;
232 }
catch (
const std::logic_error& e) {
233 if (e.what() == std::string{
"FRESH flag misapplied to coin that exists in parent cache"}) {
234 expected_code_path =
true;
237 assert(expected_code_path);
242 bool expected_code_path =
false;
244 (void)coins_view_cache.Cursor();
245 }
catch (
const std::logic_error&) {
246 expected_code_path =
true;
248 assert(expected_code_path);
249 (void)coins_view_cache.DynamicMemoryUsage();
250 (void)coins_view_cache.EstimateSize();
251 (void)coins_view_cache.GetBestBlock();
252 (void)coins_view_cache.GetCacheSize();
253 (void)coins_view_cache.GetHeadBlocks();
254 (void)coins_view_cache.HaveInputs(
CTransaction{random_mutable_transaction});
259 std::unique_ptr<CCoinsViewCursor> coins_view_cursor = backend_coins_view.Cursor();
260 assert(!!coins_view_cursor);
262 (void)backend_coins_view.EstimateSize();
263 (void)backend_coins_view.GetBestBlock();
264 (void)backend_coins_view.GetHeadBlocks();
271 const CTransaction transaction{random_mutable_transaction};
272 bool is_spent =
false;
273 for (
const CTxOut& tx_out : transaction.vout) {
274 if (Coin{tx_out, 0, transaction.IsCoinBase()}.IsSpent()) {
283 bool expected_code_path =
false;
287 AddCoins(coins_view_cache, transaction, height, possible_overwrite);
288 expected_code_path =
true;
289 }
catch (
const std::logic_error& e) {
290 if (e.what() == std::string{
"Attempted to overwrite an unspent coin (when possible_overwrite is false)"}) {
291 assert(!possible_overwrite);
292 expected_code_path =
true;
295 assert(expected_code_path);
303 const CTransaction transaction{random_mutable_transaction};
319 const CTransaction transaction{random_mutable_transaction};
328 const CTransaction transaction{random_mutable_transaction};
335 if (!transaction.vin.empty() && (
flags & SCRIPT_VERIFY_WITNESS) != 0 && (
flags & SCRIPT_VERIFY_P2SH) == 0) {
348 const Coin& coin_using_access_coin = coins_view_cache.AccessCoin(random_out_point);
349 const bool exists_using_access_coin = !(coin_using_access_coin == EMPTY_COIN);
350 const bool exists_using_have_coin = coins_view_cache.HaveCoin(random_out_point);
351 const bool exists_using_have_coin_in_cache = coins_view_cache.HaveCoinInCache(random_out_point);
352 if (
auto coin{coins_view_cache.GetCoin(random_out_point)}) {
353 assert(*coin == coin_using_access_coin);
354 assert(exists_using_access_coin && exists_using_have_coin_in_cache && exists_using_have_coin);
356 assert(!exists_using_access_coin && !exists_using_have_coin_in_cache && !exists_using_have_coin);
359 const bool exists_using_have_coin_in_backend = backend_coins_view.HaveCoin(random_out_point);
360 if (!coin_using_access_coin.
IsSpent() && exists_using_have_coin_in_backend) {
361 assert(exists_using_have_coin);
363 if (
auto coin{backend_coins_view.GetCoin(random_out_point)}) {
364 assert(exists_using_have_coin_in_backend);
368 assert(!exists_using_have_coin_in_backend);
386 .cache_bytes = 1_MiB,
402 MutationGuardCoinsViewCache backend_cache{&backend_base_coins_view,
true};
bool MoneyRange(const CAmount &nValue)
int64_t CAmount
Amount in satoshis (Can be negative)
catch(const std::exception &e)
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 Flush(bool reallocate_cache=true)
Push the modifications applied to this cache to its base and wipe local state.
void Reset() noexcept
Discard all modifications made to this cache without flushing to the base view.
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).
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.
CoinsCachePair * NextAndMaybeErase(CoinsCachePair ¤t) noexcept
Return the next entry after current, possibly erasing current.
CoinsCachePair * Begin() const noexcept
CoinsCachePair * End() const noexcept
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