16#include <unordered_set>
38 return it->second.coin.IsSpent() ? std::nullopt : std::optional{it->second.coin};
60 const auto [
ret, inserted] =
cacheCoins.try_emplace(outpoint);
63 ret->second.coin = std::move(*coin);
76 if (
auto it{
FetchCoin(outpoint)}; it !=
cacheCoins.end() && !it->second.coin.IsSpent())
return it->second.coin;
82 if (coin.out.scriptPubKey.IsUnspendable())
return;
83 CCoinsMap::iterator it;
85 std::tie(it, inserted) =
cacheCoins.emplace(std::piecewise_construct, std::forward_as_tuple(outpoint), std::tuple<>());
87 if (!possible_overwrite) {
88 if (!it->second.coin.IsSpent()) {
89 throw std::logic_error(
"Attempted to overwrite an unspent coin (when possible_overwrite is false)");
104 fresh = !it->second.IsDirty();
110 it->second.coin = std::move(coin);
117 (uint32_t)outpoint.
n,
118 (uint32_t)it->second.coin.nHeight,
119 (int64_t)it->second.coin.out.nValue,
120 (
bool)it->second.coin.IsCoinBase());
124 const auto mem_usage{coin.DynamicMemoryUsage()};
125 auto [it, inserted] =
cacheCoins.try_emplace(outpoint, std::move(coin));
136 for (
size_t i = 0; i < tx.
vout.size(); ++i) {
137 bool overwrite = check_for_overwrite ? cache.
HaveCoin(
COutPoint(txid, i)) : fCoinbase;
145 CCoinsMap::iterator it =
FetchCoin(outpoint);
151 (uint32_t)outpoint.
n,
152 (uint32_t)it->second.coin.nHeight,
153 (int64_t)it->second.coin.out.nValue,
154 (
bool)it->second.coin.IsCoinBase());
156 *moveout = std::move(it->second.coin);
158 if (it->second.IsFresh()) {
163 it->second.coin.Clear();
171 CCoinsMap::const_iterator it =
FetchCoin(outpoint);
175 return it->second.coin;
181 CCoinsMap::const_iterator it =
FetchCoin(outpoint);
182 return (it !=
cacheCoins.end() && !it->second.coin.IsSpent());
186 CCoinsMap::const_iterator it =
cacheCoins.find(outpoint);
187 return (it !=
cacheCoins.end() && !it->second.coin.IsSpent());
204 if (!it->second.IsDirty()) {
207 auto [itUs, inserted]{
cacheCoins.try_emplace(it->first)};
209 if (it->second.IsFresh() && it->second.coin.IsSpent()) {
219 entry.
coin = std::move(it->second.coin);
221 entry.
coin = it->second.coin;
233 if (it->second.IsFresh() && !itUs->second.coin.IsSpent()) {
238 throw std::logic_error(
"FRESH flag misapplied to coin that exists in parent cache");
241 if (itUs->second.IsFresh() && it->second.coin.IsSpent()) {
253 itUs->second.coin = std::move(it->second.coin);
255 itUs->second.coin = it->second.coin;
258 if (!itUs->second.IsDirty()) {
278 if (reallocate_cache) {
291 throw std::logic_error(
"Not all unspent flagged entries were cleared");
305 CCoinsMap::iterator it =
cacheCoins.find(hash);
306 if (it !=
cacheCoins.end() && !it->second.IsDirty()) {
311 (uint32_t)it->second.coin.nHeight,
312 (int64_t)it->second.coin.out.nValue,
313 (
bool)it->second.coin.IsCoinBase());
325 for (
unsigned int i = 0; i < tx.
vin.size(); i++) {
346 size_t recomputed_usage = 0;
347 size_t count_dirty = 0;
349 if (entry.coin.IsSpent()) {
350 assert(entry.IsDirty() && !entry.IsFresh());
352 assert(entry.IsDirty() || !entry.IsFresh());
356 recomputed_usage += entry.coin.DynamicMemoryUsage();
359 if (entry.IsDirty()) ++count_dirty;
362 size_t count_linked = 0;
365 assert(it->second.Next()->second.Prev() == it);
366 assert(it->second.Prev()->second.Next() == it);
368 assert(it->second.IsDirty());
382 if (
const auto workers_count{
m_thread_pool->WorkersCount()}; workers_count > 0 && block.vtx.size() > 1) {
386 std::unordered_set<Txid, SaltedCoinsCacheHasher> earlier_txids;
387 earlier_txids.reserve(block.vtx.size());
388 earlier_txids.emplace(block.vtx[0]->GetHash());
389 for (
const auto& tx : block.vtx | std::views::drop(1)) {
390 for (
const auto& input : tx->vin) {
391 if (!earlier_txids.contains(input.prevout.hash))
m_inputs.emplace_back(input.prevout);
393 earlier_txids.emplace(tx->GetHash());
397 std::vector<std::function<void()>>
tasks(workers_count, [
this] {
423 if (!alternate.
IsSpent())
return alternate;
429template <
typename ReturnType,
typename Func>
434 }
catch(
const std::runtime_error& e) {
435 for (
const auto& f : err_callbacks) {
438 LogError(
"Error reading from database: %s\n", e.what());
#define Assert(val)
Identity function.
#define Assume(val)
Assume is the identity function.
bool HaveCoin(const COutPoint &outpoint) const override
std::optional< Coin > PeekCoin(const COutPoint &outpoint) const override
CCoinsViewBacked(CCoinsView *in_view)
std::optional< Coin > GetCoin(const COutPoint &outpoint) const override
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".
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 EmplaceCoinInternalDANGER(const COutPoint &outpoint, Coin &&coin)
Emplace a coin into cacheCoins without performing any checks, marking the emplaced coin as dirty.
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
std::optional< Coin > PeekCoin(const COutPoint &outpoint) const override
bool HaveCoin(const COutPoint &outpoint) const override
void SanityCheck() const
Run an internal sanity check on the cache data structure. */.
std::optional< Coin > GetCoin(const COutPoint &outpoint) const override
const Coin & AccessCoin(const COutPoint &output) const
Return a reference to Coin in the cache, or coinEmpty if not found.
std::optional< Coin > GetCoin(const COutPoint &outpoint) const override
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
std::optional< Coin > PeekCoin(const COutPoint &outpoint) const override
Pure abstract view on the open txout dataset.
virtual std::optional< Coin > PeekCoin(const COutPoint &outpoint) const =0
virtual std::optional< Coin > GetCoin(const COutPoint &outpoint) const =0
virtual void BatchWrite(CoinsViewCacheCursor &cursor, const uint256 &block_hash)=0
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
bool IsSpent() const
Either this coin never existed (see e.g.
size_t DynamicMemoryUsage() const
static CoinsViewEmpty & Get()
uint32_t m_input_tail
The latest input not yet accessed by a consumer. Only the main thread increments this.
void StopFetching() noexcept
std::vector< std::future< void > > m_futures
std::atomic_uint32_t m_input_head
The latest input not yet being fetched. Workers atomically increment this when fetching.
std::shared_ptr< ThreadPool > m_thread_pool
Non-null. May have zero workers when input fetching is disabled.
bool ProcessInput() noexcept
Claim and fetch the next input in the queue.
ResetGuard StartFetching(const CBlock &block LIFETIMEBOUND) noexcept
Start fetching inputs from block.
std::vector< InputToFetch > m_inputs
Must only be mutated when m_futures is empty. Elements may be mutated when m_futures is not empty.
SipHash-1-3-UJ based hasher for the coins cache and related coins containers.
const SipHasher13UJ m_hasher
SaltedCoinsCacheHasher(bool deterministic=false)
constexpr bool IsNull() const
constexpr const std::byte * data() const
static const uint256 ZERO
static const Coin coinEmpty
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)
void AddCoins(CCoinsViewCache &cache, const CTransaction &tx, int nHeight, bool check_for_overwrite)
std::unordered_map< COutPoint, CCoinsCacheEntry, SaltedCoinsCacheHasher, 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
constexpr unsigned int MAX_BLOCK_WEIGHT
The maximum allowed weight for a block, see BIP 141 (network rule).
constexpr int WITNESS_SCALE_FACTOR
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
CoinsViewCacheCursor(size_t &dirty_count LIFETIMEBOUND, CoinsCachePair &sentinel LIFETIMEBOUND, CCoinsMap &map LIFETIMEBOUND, bool will_erase) noexcept
CoinsCachePair * End() const noexcept
std::vector< std::function< void()> > tasks(MAX_READ_WORKERS)
constexpr std::string_view SubmitErrorString(const ThreadPool::SubmitError err) noexcept
#define TRACEPOINT(context,...)
#define TRACEPOINT_SEMAPHORE(context, event)
transaction_identifier< false > Txid
Txid commits to all transaction fields except the witness.
consteval auto _(util::TranslatedLiteral str)