16#include <unordered_set>
31 return it->second.coin.IsSpent() ? std::nullopt : std::optional{it->second.coin};
53 const auto [
ret, inserted] =
cacheCoins.try_emplace(outpoint);
56 ret->second.coin = std::move(*coin);
69 if (
auto it{
FetchCoin(outpoint)}; it !=
cacheCoins.end() && !it->second.coin.IsSpent())
return it->second.coin;
75 if (coin.out.scriptPubKey.IsUnspendable())
return;
76 CCoinsMap::iterator it;
78 std::tie(it, inserted) =
cacheCoins.emplace(std::piecewise_construct, std::forward_as_tuple(outpoint), std::tuple<>());
80 if (!possible_overwrite) {
81 if (!it->second.coin.IsSpent()) {
82 throw std::logic_error(
"Attempted to overwrite an unspent coin (when possible_overwrite is false)");
97 fresh = !it->second.IsDirty();
103 it->second.coin = std::move(coin);
110 (uint32_t)outpoint.
n,
111 (uint32_t)it->second.coin.nHeight,
112 (int64_t)it->second.coin.out.nValue,
113 (
bool)it->second.coin.IsCoinBase());
117 const auto mem_usage{coin.DynamicMemoryUsage()};
118 auto [it, inserted] =
cacheCoins.try_emplace(std::move(outpoint), std::move(coin));
129 for (
size_t i = 0; i < tx.
vout.size(); ++i) {
130 bool overwrite = check_for_overwrite ? cache.
HaveCoin(
COutPoint(txid, i)) : fCoinbase;
138 CCoinsMap::iterator it =
FetchCoin(outpoint);
144 (uint32_t)outpoint.
n,
145 (uint32_t)it->second.coin.nHeight,
146 (int64_t)it->second.coin.out.nValue,
147 (
bool)it->second.coin.IsCoinBase());
149 *moveout = std::move(it->second.coin);
151 if (it->second.IsFresh()) {
156 it->second.coin.Clear();
164 CCoinsMap::const_iterator it =
FetchCoin(outpoint);
168 return it->second.coin;
174 CCoinsMap::const_iterator it =
FetchCoin(outpoint);
175 return (it !=
cacheCoins.end() && !it->second.coin.IsSpent());
179 CCoinsMap::const_iterator it =
cacheCoins.find(outpoint);
180 return (it !=
cacheCoins.end() && !it->second.coin.IsSpent());
197 if (!it->second.IsDirty()) {
200 auto [itUs, inserted]{
cacheCoins.try_emplace(it->first)};
202 if (it->second.IsFresh() && it->second.coin.IsSpent()) {
208 assert(entry.coin.DynamicMemoryUsage() == 0);
212 entry.coin = std::move(it->second.coin);
214 entry.coin = it->second.coin;
226 if (it->second.IsFresh() && !itUs->second.coin.IsSpent()) {
231 throw std::logic_error(
"FRESH flag misapplied to coin that exists in parent cache");
234 if (itUs->second.IsFresh() && it->second.coin.IsSpent()) {
246 itUs->second.coin = std::move(it->second.coin);
248 itUs->second.coin = it->second.coin;
251 if (!itUs->second.IsDirty()) {
271 if (reallocate_cache) {
284 throw std::logic_error(
"Not all unspent flagged entries were cleared");
298 CCoinsMap::iterator it =
cacheCoins.find(hash);
299 if (it !=
cacheCoins.end() && !it->second.IsDirty()) {
304 (uint32_t)it->second.coin.nHeight,
305 (int64_t)it->second.coin.out.nValue,
306 (
bool)it->second.coin.IsCoinBase());
318 for (
unsigned int i = 0; i < tx.
vin.size(); i++) {
339 size_t recomputed_usage = 0;
340 size_t count_dirty = 0;
342 if (entry.coin.IsSpent()) {
343 assert(entry.IsDirty() && !entry.IsFresh());
345 assert(entry.IsDirty() || !entry.IsFresh());
349 recomputed_usage += entry.coin.DynamicMemoryUsage();
352 if (entry.IsDirty()) ++count_dirty;
355 size_t count_linked = 0;
358 assert(it->second.Next()->second.Prev() == it);
359 assert(it->second.Prev()->second.Next() == it);
361 assert(it->second.IsDirty());
371 Assert(m_futures.empty());
373 Assert(m_input_head.load(std::memory_order_relaxed) == 0);
374 Assert(m_input_tail == 0);
375 if (
const auto workers_count{m_thread_pool->WorkersCount()}; workers_count > 0) {
379 std::unordered_set<Txid, SaltedTxidHasher> earlier_txids;
380 earlier_txids.reserve(block.vtx.size());
381 for (
const auto& tx : block.vtx | std::views::drop(1)) {
382 for (
const auto& input : tx->vin) {
383 if (!earlier_txids.contains(input.prevout.hash)) m_inputs.emplace_back(input.prevout);
385 earlier_txids.emplace(tx->GetHash());
388 if (m_inputs.size()) {
389 std::vector<std::function<void()>>
tasks(workers_count, [
this] {
390 while (ProcessInput()) {}
392 if (
auto futures{m_thread_pool->Submit(std::move(
tasks))}) {
393 m_futures = std::move(*
futures);
398 LogWarning(
"Failed to submit prevout fetch tasks; falling back to single-threaded fetching for this block.");
404 return CreateResetGuard();
415 if (!alternate.
IsSpent())
return alternate;
421template <
typename ReturnType,
typename Func>
426 }
catch(
const std::runtime_error& e) {
427 for (
const auto& f : err_callbacks) {
430 LogError(
"Error reading from database: %s\n", e.what());
#define Assert(val)
Identity function.
#define Assume(val)
Assume is the identity function.
CCoinsView backed by another CCoinsView.
bool HaveCoin(const COutPoint &outpoint) const override
Just check whether a given outpoint is unspent.
std::optional< Coin > PeekCoin(const COutPoint &outpoint) const override
Retrieve the Coin (unspent transaction output) for a given outpoint, without caching results.
std::optional< Coin > GetCoin(const COutPoint &outpoint) const override
Retrieve the Coin (unspent transaction output) for a given outpoint.
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 (...
const bool m_deterministic
CCoinsMapMemoryResource m_cache_coins_memory_resource
bool SpendCoin(const COutPoint &outpoint, Coin *moveto=nullptr)
Spend a coin.
uint256 m_block_hash
Make mutable so that we can "fill the cache" even from Get-methods declared as "const".
void Uncache(const COutPoint &outpoint)
Removes the UTXO with the given outpoint from the cache, if it is not modified.
bool HaveInputs(const CTransaction &tx) const
Check whether all prevouts of the transaction are present in the UTXO set represented by this view.
void AddCoin(const COutPoint &outpoint, Coin &&coin, bool possible_overwrite)
Add a coin.
virtual std::optional< Coin > FetchCoinFromBase(const COutPoint &outpoint) const
CCoinsViewCache(CCoinsView *in_base, bool deterministic=false)
virtual void Flush(bool reallocate_cache=true)
Push the modifications applied to this cache to its base and wipe local state.
void SetBestBlock(const uint256 &block_hash)
virtual void Reset() noexcept
Discard all modifications made to this cache without flushing to the base view.
unsigned int GetCacheSize() const
Size of the cache (in number of transaction outputs)
uint256 GetBestBlock() const override
Retrieve the block hash whose state this CCoinsView currently represents.
CCoinsMap::iterator FetchCoin(const COutPoint &outpoint) const
bool HaveCoinInCache(const COutPoint &outpoint) const
Check if we have the given utxo already loaded in this cache.
CoinsCachePair m_sentinel
size_t DynamicMemoryUsage() const
Calculate the size of the cache (in bytes)
void BatchWrite(CoinsViewCacheCursor &cursor, const uint256 &block_hash) 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.
bool HaveCoin(const COutPoint &outpoint) const override
Just check whether a given outpoint is unspent.
void SanityCheck() const
Run an internal sanity check on the cache data structure. */.
std::optional< Coin > GetCoin(const COutPoint &outpoint) const override
Retrieve the Coin (unspent transaction output) for a given outpoint.
const Coin & AccessCoin(const COutPoint &output) const
Return a reference to Coin in the cache, or coinEmpty if not found.
void ReallocateCache()
Force a reallocation of the cache map.
std::optional< Coin > GetCoin(const COutPoint &outpoint) const override
Retrieve the Coin (unspent transaction output) for a given outpoint.
std::vector< std::function< void()> > m_err_callbacks
A list of callbacks to execute upon leveldb read error.
bool HaveCoin(const COutPoint &outpoint) const override
Just check whether a given outpoint is unspent.
std::optional< Coin > PeekCoin(const COutPoint &outpoint) const override
Retrieve the Coin (unspent transaction output) for a given outpoint, without caching results.
Pure abstract view on the open txout dataset.
virtual std::optional< Coin > PeekCoin(const COutPoint &outpoint) const =0
Retrieve the Coin (unspent transaction output) for a given outpoint, without caching results.
virtual std::optional< Coin > GetCoin(const COutPoint &outpoint) const =0
Retrieve the Coin (unspent transaction output) for a given outpoint.
virtual void BatchWrite(CoinsViewCacheCursor &cursor, const uint256 &block_hash)=0
Do a bulk modification (multiple Coin changes + BestBlock change).
virtual uint256 GetBestBlock() const =0
Retrieve the block hash whose state this CCoinsView currently represents.
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.
const std::vector< CTxOut > vout
const Txid & GetHash() const LIFETIMEBOUND
const std::vector< CTxIn > vin
An output of a transaction.
bool IsSpent() const
Either this coin never existed (see e.g.
static CoinsViewEmpty & Get()
ResetGuard StartFetching(const CBlock &block LIFETIMEBOUND) noexcept
Start fetching inputs from block.
constexpr bool IsNull() const
constexpr const std::byte * data() const
static const uint256 ZERO
static const Coin coinEmpty
TRACEPOINT_SEMAPHORE(utxocache, add)
static const uint64_t MAX_OUTPUTS_PER_BLOCK
static const uint64_t MIN_TRANSACTION_OUTPUT_WEIGHT
static ReturnType ExecuteBackedWrapper(Func func, const std::vector< std::function< void()> > &err_callbacks)
const Coin & AccessByTxid(const CCoinsViewCache &view, const Txid &txid)
Utility function to find any unspent output with a given txid.
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::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
static const unsigned int MAX_BLOCK_WEIGHT
The maximum allowed weight for a block, see BIP 141 (network rule)
static const int WITNESS_SCALE_FACTOR
static size_t DynamicUsage(const int8_t &v)
Dynamic memory usage for built-in types is zero.
bool Func(const std::string &str, std::span< const char > &sp)
Parse a function call.
constexpr bool TrySub(T &i, const U j) noexcept
uint64_t GetSerializeSize(const T &t)
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
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.
bool WillErase(CoinsCachePair ¤t) const noexcept
CoinsCachePair * Begin() const noexcept
CoinsCachePair * End() const noexcept
std::vector< std::function< void()> > tasks(MAX_READ_WORKERS)
#define TRACEPOINT(context,...)
consteval auto _(util::TranslatedLiteral str)