LCOV - code coverage report
Current view: top level - src - coins.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 277 299 92.6 %
Date: 2025-02-23 09:33:43 Functions: 47 58 81.0 %

          Line data    Source code
       1             : // Copyright (c) 2012-2014 The Bitcoin developers
       2             : // Copyright (c) 2015-2021 The PIVX Core developers
       3             : // Distributed under the MIT software license, see the accompanying
       4             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       5             : 
       6             : #include "coins.h"
       7             : 
       8             : #include "consensus/consensus.h"
       9             : #include "invalid.h"
      10             : #include "logging.h"
      11             : #include "random.h"
      12             : #include "version.h"
      13             : 
      14             : #include <assert.h>
      15             : 
      16          25 : bool CCoinsView::GetCoin(const COutPoint& outpoint, Coin& coin) const { return false; }
      17           0 : bool CCoinsView::HaveCoin(const COutPoint& outpoint) const { return false; }
      18           0 : uint256 CCoinsView::GetBestBlock() const { return UINT256_ZERO; }
      19           0 : std::vector<uint256> CCoinsView::GetHeadBlocks() const { return std::vector<uint256>(); }
      20           0 : CCoinsViewCursor *CCoinsView::Cursor() const { return 0; }
      21             : 
      22           0 : bool CCoinsView::BatchWrite(CCoinsMap& mapCoins,
      23             :                             const uint256& hashBlock,
      24             :                             const uint256& hashSaplingAnchor,
      25             :                             CAnchorsSaplingMap& mapSaplingAnchors,
      26           0 :                             CNullifiersMap& mapSaplingNullifiers) { return false; }
      27             : 
      28             : // Sapling
      29           0 : bool CCoinsView::GetSaplingAnchorAt(const uint256 &rt, SaplingMerkleTree &tree) const { return false; }
      30           0 : bool CCoinsView::GetNullifier(const uint256 &nullifier) const { return false; }
      31           0 : uint256 CCoinsView::GetBestAnchor() const { return uint256(); };
      32             : 
      33      669111 : CCoinsViewBacked::CCoinsViewBacked(CCoinsView* viewIn) : base(viewIn) {}
      34     1307110 : bool CCoinsViewBacked::GetCoin(const COutPoint& outpoint, Coin& coin) const { return base->GetCoin(outpoint, coin); }
      35           0 : bool CCoinsViewBacked::HaveCoin(const COutPoint& outpoint) const { return base->HaveCoin(outpoint); }
      36      171907 : uint256 CCoinsViewBacked::GetBestBlock() const { return base->GetBestBlock(); }
      37           0 : std::vector<uint256> CCoinsViewBacked::GetHeadBlocks() const { return base->GetHeadBlocks(); }
      38      554757 : void CCoinsViewBacked::SetBackend(CCoinsView& viewIn) { base = &viewIn; }
      39         975 : CCoinsViewCursor *CCoinsViewBacked::Cursor() const { return base->Cursor(); }
      40          98 : size_t CCoinsViewBacked::EstimateSize() const { return base->EstimateSize(); }
      41             : 
      42         804 : bool CCoinsViewBacked::BatchWrite(CCoinsMap& mapCoins,
      43             :                                   const uint256& hashBlock,
      44             :                                   const uint256& hashSaplingAnchor,
      45             :                                   CAnchorsSaplingMap& mapSaplingAnchors,
      46             :                                   CNullifiersMap& mapSaplingNullifiers)
      47         804 : { return base->BatchWrite(mapCoins, hashBlock, hashSaplingAnchor, mapSaplingAnchors, mapSaplingNullifiers); }
      48             : 
      49             : // Sapling
      50         464 : bool CCoinsViewBacked::GetSaplingAnchorAt(const uint256 &rt, SaplingMerkleTree &tree) const { return base->GetSaplingAnchorAt(rt, tree); }
      51         149 : bool CCoinsViewBacked::GetNullifier(const uint256 &nullifier) const { return base->GetNullifier(nullifier); }
      52         242 : uint256 CCoinsViewBacked::GetBestAnchor() const { return base->GetBestAnchor(); }
      53             : 
      54      394906 : SaltedOutpointHasher::SaltedOutpointHasher() : k0(GetRand(std::numeric_limits<uint64_t>::max())), k1(GetRand(std::numeric_limits<uint64_t>::max())) {}
      55      818417 : SaltedIdHasher::SaltedIdHasher() : k0(GetRand(std::numeric_limits<uint64_t>::max())), k1(GetRand(std::numeric_limits<uint64_t>::max())) {}
      56             : 
      57     1163789 : CCoinsViewCache::CCoinsViewCache(CCoinsView *baseIn) : CCoinsViewBacked(baseIn), cachedCoinsUsage(0) {}
      58             : 
      59      306500 : size_t CCoinsViewCache::DynamicMemoryUsage() const {
      60      306500 :     return memusage::DynamicUsage(cacheCoins) +
      61      306500 :            memusage::DynamicUsage(cacheSaplingAnchors) +
      62      306500 :            memusage::DynamicUsage(cacheSaplingNullifiers) +
      63      306500 :            cachedCoinsUsage;
      64             : }
      65             : 
      66    59025300 : CCoinsMap::iterator CCoinsViewCache::FetchCoin(const COutPoint& outpoint) const
      67             : {
      68    59025300 :     CCoinsMap::iterator it = cacheCoins.find(outpoint);
      69    59025300 :     if (it != cacheCoins.end())
      70    27289522 :         return it;
      71    90761000 :     Coin tmp;
      72    31735730 :     if (!base->GetCoin(outpoint, tmp))
      73    31735730 :         return cacheCoins.end();
      74     6825780 :     CCoinsMap::iterator ret = cacheCoins.emplace(std::piecewise_construct, std::forward_as_tuple(outpoint), std::forward_as_tuple(std::move(tmp))).first;
      75     6825780 :     if (ret->second.coin.IsSpent()) {
      76             :         // The parent only has an empty entry for this outpoint; we can consider our
      77             :         // version as fresh.
      78      285066 :         ret->second.flags = CCoinsCacheEntry::FRESH;
      79             :     }
      80     6825780 :     cachedCoinsUsage += memusage::DynamicUsage(ret->second.coin);
      81     6825780 :     return ret;
      82             : }
      83             : 
      84    21235220 : bool CCoinsViewCache::GetCoin(const COutPoint& outpoint, Coin& coin) const
      85             : {
      86    21235220 :     CCoinsMap::const_iterator it = FetchCoin(outpoint);
      87    21235220 :     if (it != cacheCoins.end()) {
      88     6168778 :         coin = it->second.coin;
      89     6168778 :         return true;
      90             :     }
      91             :     return false;
      92             : }
      93             : 
      94     7325393 : void CCoinsViewCache::AddCoin(const COutPoint& outpoint, Coin&& coin, bool possible_overwrite) {
      95     7325393 :     assert(!coin.IsSpent());
      96     7326813 :     if (coin.out.scriptPubKey.IsUnspendable()) return;
      97     7323963 :     if (coin.out.IsZerocoinMint()) return;
      98     7323963 :     CCoinsMap::iterator it;
      99     7323963 :     bool inserted;
     100     7323963 :     std::tie(it, inserted) = cacheCoins.emplace(std::piecewise_construct, std::forward_as_tuple(outpoint), std::tuple<>());
     101     7323963 :     bool fresh = false;
     102     7323963 :     if (!inserted) {
     103       83196 :         cachedCoinsUsage -= it->second.coin.DynamicMemoryUsage();
     104             :     }
     105     7323963 :     if (!possible_overwrite) {
     106     7273200 :         if (!it->second.coin.IsSpent()) {
     107          12 :             throw std::logic_error("Adding new coin that replaces non-pruned entry");
     108             :         }
     109     7273188 :         fresh = !(it->second.flags & CCoinsCacheEntry::DIRTY);
     110             :     }
     111     7323951 :     it->second.coin = std::move(coin);
     112     7323951 :     it->second.flags |= CCoinsCacheEntry::DIRTY | (fresh ? CCoinsCacheEntry::FRESH : 0);
     113     7323951 :     cachedCoinsUsage += it->second.coin.DynamicMemoryUsage();
     114             : }
     115             : 
     116     3622926 : void AddCoins(CCoinsViewCache& cache, const CTransaction& tx, int nHeight, bool check, bool fSkipInvalid)
     117             : {
     118     3622926 :     bool fCoinbase = tx.IsCoinBase();
     119     3622926 :     bool fCoinstake = tx.IsCoinStake();
     120     3622926 :     const uint256& txid = tx.GetHash();
     121    10703083 :     for (size_t i = 0; i < tx.vout.size(); ++i) {
     122     7080117 :         const COutPoint out(txid, i);
     123             :         // Don't add fraudulent/banned outputs
     124     7080117 :         if (fSkipInvalid && invalid_out::ContainsOutPoint(out)) {
     125           0 :             cache.SpendCoin(out);   // no-op if the coin is not in the cache
     126           0 :             continue;
     127             :         }
     128     7080117 :         bool overwrite = check && cache.HaveCoin(out);
     129    14160214 :         cache.AddCoin(out, Coin(tx.vout[i], nHeight, fCoinbase, fCoinstake), overwrite);
     130             :     }
     131     3622926 : }
     132             : 
     133     5476193 : void CCoinsViewCache::SpendCoin(const COutPoint& outpoint, Coin* moveout)
     134             : {
     135     5476193 :     CCoinsMap::iterator it = FetchCoin(outpoint);
     136     5476193 :     if (it == cacheCoins.end()) return;
     137     5462462 :     cachedCoinsUsage -= it->second.coin.DynamicMemoryUsage();
     138     5462462 :     if (moveout) {
     139     5408863 :         *moveout = std::move(it->second.coin);
     140             :     }
     141     5462462 :     if (it->second.flags & CCoinsCacheEntry::FRESH) {
     142      182580 :         cacheCoins.erase(it);
     143             :     } else {
     144     5279879 :         it->second.flags |= CCoinsCacheEntry::DIRTY;
     145    10742381 :         it->second.coin.Clear();
     146             :     }
     147             : }
     148             : 
     149             : static const Coin coinEmpty;
     150             : 
     151    19502440 : const Coin& CCoinsViewCache::AccessCoin(const COutPoint& outpoint) const
     152             : {
     153    19502440 :     CCoinsMap::const_iterator it = FetchCoin(outpoint);
     154    19502440 :     if (it == cacheCoins.end()) {
     155             :         return coinEmpty;
     156             :     } else {
     157    10918175 :         return it->second.coin;
     158             :     }
     159             : }
     160             : 
     161    12811445 : bool CCoinsViewCache::HaveCoin(const COutPoint& outpoint) const
     162             : {
     163    12811445 :     CCoinsMap::const_iterator it = FetchCoin(outpoint);
     164    12811445 :     return (it != cacheCoins.end() && !it->second.coin.IsSpent());
     165             : }
     166             : 
     167     1006628 : bool CCoinsViewCache::HaveCoinInCache(const COutPoint& outpoint) const
     168             : {
     169     1006628 :     CCoinsMap::const_iterator it = cacheCoins.find(outpoint);
     170     1006628 :     return it != cacheCoins.end();
     171             : }
     172             : 
     173     4374561 : uint256 CCoinsViewCache::GetBestBlock() const
     174             : {
     175     8749122 :     if (hashBlock.IsNull())
     176      239231 :         hashBlock = base->GetBestBlock();
     177     4374561 :     return hashBlock;
     178             : }
     179             : 
     180       43028 : void CCoinsViewCache::SetBestBlock(const uint256& hashBlockIn)
     181             : {
     182       43028 :     hashBlock = hashBlockIn;
     183       43028 : }
     184             : 
     185             : template<typename Map, typename MapIterator, typename MapEntry>
     186       42553 : void BatchWriteAnchors(
     187             :         Map &mapAnchors,
     188             :         Map &cacheAnchors,
     189             :         size_t &cachedCoinsUsage
     190             : )
     191             : {
     192       84029 :     for (MapIterator child_it = mapAnchors.begin(); child_it != mapAnchors.end();)
     193             :     {
     194       41476 :         if (child_it->second.flags & MapEntry::DIRTY) {
     195         226 :             MapIterator parent_it = cacheAnchors.find(child_it->first);
     196             : 
     197         226 :             if (parent_it == cacheAnchors.end()) {
     198         216 :                 MapEntry& entry = cacheAnchors[child_it->first];
     199         216 :                 entry.entered = child_it->second.entered;
     200         216 :                 entry.tree = child_it->second.tree;
     201         216 :                 entry.flags = MapEntry::DIRTY;
     202             : 
     203         216 :                 cachedCoinsUsage += entry.tree.DynamicMemoryUsage();
     204             :             } else {
     205          10 :                 if (parent_it->second.entered != child_it->second.entered) {
     206             :                     // The parent may have removed the entry.
     207          10 :                     parent_it->second.entered = child_it->second.entered;
     208          10 :                     parent_it->second.flags |= MapEntry::DIRTY;
     209             :                 }
     210             :             }
     211             :         }
     212             : 
     213       41476 :         MapIterator itOld = child_it++;
     214       41476 :         mapAnchors.erase(itOld);
     215             :     }
     216       42553 : }
     217             : 
     218       42553 : void BatchWriteNullifiers(CNullifiersMap &mapNullifiers, CNullifiersMap &cacheNullifiers)
     219             : {
     220       42703 :     for (CNullifiersMap::iterator child_it = mapNullifiers.begin(); child_it != mapNullifiers.end();) {
     221         150 :         if (child_it->second.flags & CNullifiersCacheEntry::DIRTY) { // Ignore non-dirty entries (optimization).
     222         149 :             CNullifiersMap::iterator parent_it = cacheNullifiers.find(child_it->first);
     223             : 
     224         149 :             if (parent_it == cacheNullifiers.end()) {
     225           1 :                 CNullifiersCacheEntry& entry = cacheNullifiers[child_it->first];
     226           1 :                 entry.entered = child_it->second.entered;
     227           1 :                 entry.flags = CNullifiersCacheEntry::DIRTY;
     228             :             } else {
     229         148 :                 if (parent_it->second.entered != child_it->second.entered) {
     230         148 :                     parent_it->second.entered = child_it->second.entered;
     231         148 :                     parent_it->second.flags |= CNullifiersCacheEntry::DIRTY;
     232             :                 }
     233             :             }
     234             :         }
     235         150 :         CNullifiersMap::iterator itOld = child_it++;
     236         150 :         mapNullifiers.erase(itOld);
     237             :     }
     238       42553 : }
     239             : 
     240       42561 : bool CCoinsViewCache::BatchWrite(CCoinsMap& mapCoins,
     241             :                                  const uint256& hashBlockIn,
     242             :                                  const uint256 &hashSaplingAnchorIn,
     243             :                                  CAnchorsSaplingMap& mapSaplingAnchors,
     244             :                                  CNullifiersMap& mapSaplingNullifiers)
     245             : {
     246     1929411 :     for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end(); it = mapCoins.erase(it)) {
     247             :         // Ignore non-dirty entries (optimization).
     248     1886864 :         if (!(it->second.flags & CCoinsCacheEntry::DIRTY)) {
     249      276806 :             continue;
     250             :         }
     251     1610054 :         CCoinsMap::iterator itUs = cacheCoins.find(it->first);
     252     1610054 :         if (itUs == cacheCoins.end()) {
     253             :             // The parent cache does not have an entry, while the child does
     254             :             // We can ignore it if it's both FRESH and pruned in the child
     255      791740 :             if (!(it->second.flags & CCoinsCacheEntry::FRESH && it->second.coin.IsSpent())) {
     256             :                 // Otherwise we will need to create it in the parent
     257             :                 // and move the data up and mark it as dirty
     258      791739 :                 CCoinsCacheEntry& entry = cacheCoins[it->first];
     259      791739 :                 entry.coin = std::move(it->second.coin);
     260      791739 :                 cachedCoinsUsage += memusage::DynamicUsage(entry.coin);
     261      791739 :                 entry.flags = CCoinsCacheEntry::DIRTY;
     262             :                 // We can mark it FRESH in the parent if it was FRESH in the child
     263             :                 // Otherwise it might have just been flushed from the parent's cache
     264             :                 // and already exist in the grandparent
     265      791739 :                 if (it->second.flags & CCoinsCacheEntry::FRESH) {
     266      757974 :                     entry.flags |= CCoinsCacheEntry::FRESH;
     267             :                 }
     268             :             }
     269             :         } else {
     270             :             // Assert that the child cache entry was not marked FRESH if the
     271             :             // parent cache entry has unspent outputs. If this ever happens,
     272             :             // it means the FRESH flag was misapplied and there is a logic
     273             :             // error in the calling code.
     274      818313 :             if ((it->second.flags & CCoinsCacheEntry::FRESH) && !itUs->second.coin.IsSpent()) {
     275           8 :                 throw std::logic_error("FRESH flag misapplied to cache entry for base transaction with spendable outputs");
     276             :             }
     277             : 
     278             :             // Found the entry in the parent cache
     279      818305 :             if ((itUs->second.flags & CCoinsCacheEntry::FRESH) && it->second.coin.IsSpent()) {
     280             :                 // The grandparent does not have an entry, and the child is
     281             :                 // modified and being pruned. This means we can just delete
     282             :                 // it from the parent.
     283      208911 :                 cachedCoinsUsage -= memusage::DynamicUsage(itUs->second.coin);
     284      208911 :                 cacheCoins.erase(itUs);
     285             :             } else {
     286             :                 // A normal modification.
     287      609394 :                 cachedCoinsUsage -= memusage::DynamicUsage(itUs->second.coin);
     288      609394 :                 itUs->second.coin = std::move(it->second.coin);
     289      609394 :                 cachedCoinsUsage += memusage::DynamicUsage(itUs->second.coin);
     290      609394 :                 itUs->second.flags |= CCoinsCacheEntry::DIRTY;
     291             :                 // NOTE: It is possible the child has a FRESH flag here in
     292             :                 // the event the entry we found in the parent is pruned. But
     293             :                 // we must not copy that FRESH flag to the parent as that
     294             :                 // pruned state likely still needs to be communicated to the
     295             :                 // grandparent.
     296             :             }
     297             :         }
     298             :     }
     299             : 
     300             :     // Sapling
     301       42553 :     ::BatchWriteAnchors<CAnchorsSaplingMap, CAnchorsSaplingMap::iterator, CAnchorsSaplingCacheEntry>(mapSaplingAnchors, cacheSaplingAnchors, cachedCoinsUsage);
     302       42553 :     ::BatchWriteNullifiers(mapSaplingNullifiers, cacheSaplingNullifiers);
     303       42553 :     hashSaplingAnchor = hashSaplingAnchorIn;
     304             : 
     305       42553 :     hashBlock = hashBlockIn;
     306       42553 :     return true;
     307             : }
     308             : 
     309       43306 : bool CCoinsViewCache::Flush()
     310             : {
     311       86612 :     bool fOk = base->BatchWrite(cacheCoins,
     312       43306 :             hashBlock,
     313       43306 :             hashSaplingAnchor,
     314       43306 :             cacheSaplingAnchors,
     315       43306 :             cacheSaplingNullifiers);
     316       43306 :     cacheCoins.clear();
     317       43306 :     cacheSaplingAnchors.clear();
     318       43306 :     cacheSaplingNullifiers.clear();
     319       43306 :     cachedCoinsUsage = 0;
     320       43306 :     return fOk;
     321             : }
     322             : 
     323       14754 : void CCoinsViewCache::Uncache(const COutPoint& outpoint)
     324             : {
     325       14754 :     CCoinsMap::iterator it = cacheCoins.find(outpoint);
     326       14754 :     if (it != cacheCoins.end() && it->second.flags == 0) {
     327         789 :         cachedCoinsUsage -= it->second.coin.DynamicMemoryUsage();
     328         789 :         cacheCoins.erase(it);
     329             :     }
     330       14754 : }
     331             : 
     332       42990 : unsigned int CCoinsViewCache::GetCacheSize() const
     333             : {
     334       42990 :     return cacheCoins.size();
     335             : }
     336             : 
     337      600063 : CAmount CCoinsViewCache::GetValueIn(const CTransaction& tx) const
     338             : {
     339      600063 :     if (tx.IsCoinBase())
     340             :         return 0;
     341             : 
     342      600063 :     CAmount nResult = 0;
     343     1723730 :     for (const CTxIn& in : tx.vin) {
     344     1123663 :         if (in.IsZerocoinSpend() || in.IsZerocoinPublicSpend()) {
     345           0 :             nResult += in.nSequence * COIN;
     346             :         } else {
     347     1123663 :             nResult += AccessCoin(in.prevout).out.nValue;
     348             :         }
     349             :     }
     350             : 
     351             :     // Sapling
     352      600063 :     nResult += tx.GetShieldedValueIn();
     353             : 
     354      600063 :     return nResult;
     355             : }
     356             : 
     357     4313367 : bool CCoinsViewCache::HaveInputs(const CTransaction& tx) const
     358             : {
     359     4313367 :     if (!tx.IsCoinBase() && !tx.HasZerocoinSpendInputs()) {
     360    10888537 :         for (unsigned int i = 0; i < tx.vin.size(); i++) {
     361     6580954 :             if (!HaveCoin(tx.vin[i].prevout)) {
     362             :                 return false;
     363             :             }
     364             :         }
     365             :     }
     366             :     return true;
     367             : }
     368             : 
     369         284 : int CCoinsViewCache::GetCoinDepthAtHeight(const COutPoint& output, int nHeight) const
     370             : {
     371         284 :     const Coin& coin = AccessCoin(output);
     372         284 :     if (!coin.IsSpent())
     373         284 :         return nHeight - coin.nHeight + 1;
     374             :     return -1;
     375             : }
     376             : 
     377         440 : CAmount CCoinsViewCache::GetTotalAmount() const
     378             : {
     379         440 :     CAmount nTotal = 0;
     380             : 
     381         440 :     std::unique_ptr<CCoinsViewCursor> pcursor(Cursor());
     382     3579797 :     while (pcursor->Valid()) {
     383     7158708 :         Coin coin;
     384     3579354 :         if (pcursor->GetValue(coin) && !coin.IsSpent()) {
     385     3579354 :             nTotal += coin.out.nValue;
     386             :         }
     387     3579354 :         pcursor->Next();
     388             :     }
     389             : 
     390         880 :     return nTotal;
     391             : }
     392             : 
     393           0 : bool CCoinsViewCache::PruneInvalidEntries()
     394             : {
     395             :     // Prune zerocoin Mints and fraudulent/frozen outputs
     396           0 :     bool loaded = invalid_out::LoadOutpoints();
     397           0 :     assert(loaded);
     398           0 :     for (const COutPoint& out: invalid_out::setInvalidOutPoints) {
     399           0 :         if (HaveCoin(out)) {
     400           0 :             LogPrintf("Pruning invalid output %s\n", out.ToString());
     401           0 :             SpendCoin(out);
     402             :         }
     403             :     }
     404           0 :     return Flush();
     405             : }
     406             : 
     407             : static const size_t MAX_OUTPUTS_PER_BLOCK = MAX_BLOCK_SIZE_CURRENT /  ::GetSerializeSize(CTxOut(), PROTOCOL_VERSION); // TODO: merge with similar definition in undo.h.
     408             : 
     409          86 : const Coin& AccessByTxid(const CCoinsViewCache& view, const uint256& txid)
     410             : {
     411          86 :     COutPoint iter(txid, 0);
     412     7777860 :     while (iter.n < MAX_OUTPUTS_PER_BLOCK) {
     413     7777820 :         const Coin& alternate = view.AccessCoin(iter);
     414     7777820 :         if (!alternate.IsSpent()) return alternate;
     415     7777770 :         ++iter.n;
     416             :     }
     417             :     return coinEmpty;
     418             : }
     419             : 
     420             : // Sapling
     421             : 
     422      161385 : bool CCoinsViewCache::GetSaplingAnchorAt(const uint256 &rt, SaplingMerkleTree &tree) const {
     423             : 
     424      161385 :     CAnchorsSaplingMap::const_iterator it = cacheSaplingAnchors.find(rt);
     425      161385 :     if (it != cacheSaplingAnchors.end()) {
     426      104304 :         if (it->second.entered) {
     427      104300 :             tree = it->second.tree;
     428      104300 :             return true;
     429             :         } else {
     430             :             return false;
     431             :         }
     432             :     }
     433             : 
     434       57081 :     if (!base->GetSaplingAnchorAt(rt, tree)) {
     435             :         return false;
     436             :     }
     437             : 
     438      114160 :     CAnchorsSaplingMap::iterator ret = cacheSaplingAnchors.insert(std::make_pair(rt, CAnchorsSaplingCacheEntry())).first;
     439       57080 :     ret->second.entered = true;
     440       57080 :     ret->second.tree = tree;
     441       57080 :     cachedCoinsUsage += ret->second.tree.DynamicMemoryUsage();
     442             : 
     443       57080 :     return true;
     444             : }
     445             : 
     446        1511 : bool CCoinsViewCache::GetNullifier(const uint256 &nullifier) const {
     447        1511 :     CNullifiersMap* cacheToUse = &cacheSaplingNullifiers;
     448        1511 :     CNullifiersMap::iterator it = cacheToUse->find(nullifier);
     449        1511 :     if (it != cacheToUse->end())
     450         901 :         return it->second.entered;
     451             : 
     452         610 :     CNullifiersCacheEntry entry;
     453         610 :     bool tmp = base->GetNullifier(nullifier);
     454         610 :     entry.entered = tmp;
     455             : 
     456         610 :     cacheToUse->insert(std::make_pair(nullifier, entry));
     457         610 :     return tmp;
     458             : }
     459             : 
     460             : template<typename Tree, typename Cache, typename CacheIterator, typename CacheEntry>
     461       56433 : void CCoinsViewCache::AbstractPushAnchor(
     462             :         const Tree &tree,
     463             :         Cache &cacheAnchors,
     464             :         uint256 &hash
     465             : )
     466             : {
     467       56433 :     uint256 newrt = tree.root();
     468             : 
     469       56433 :     auto currentRoot = GetBestAnchor();
     470             : 
     471             :     // We don't want to overwrite an anchor we already have.
     472             :     // This occurs when a block doesn't modify mapAnchors at all,
     473             :     // because there are no joinsplits. We could get around this a
     474             :     // different way (make all blocks modify mapAnchors somehow)
     475             :     // but this is simpler to reason about.
     476       56433 :     if (currentRoot != newrt) {
     477         606 :         auto insertRet = cacheAnchors.insert(std::make_pair(newrt, CacheEntry()));
     478         303 :         CacheIterator ret = insertRet.first;
     479             : 
     480         303 :         ret->second.entered = true;
     481         303 :         ret->second.tree = tree;
     482         303 :         ret->second.flags = CacheEntry::DIRTY;
     483             : 
     484         303 :         if (insertRet.second) {
     485             :             // An insert took place
     486         303 :             cachedCoinsUsage += ret->second.tree.DynamicMemoryUsage();
     487             :         }
     488             : 
     489         303 :         hash = newrt;
     490             :     }
     491       56433 : }
     492             : 
     493       56433 : template<> void CCoinsViewCache::PushAnchor(const SaplingMerkleTree &tree)
     494             : {
     495       56433 :     AbstractPushAnchor<SaplingMerkleTree, CAnchorsSaplingMap, CAnchorsSaplingMap::iterator, CAnchorsSaplingCacheEntry>(
     496             :             tree,
     497       56433 :             cacheSaplingAnchors,
     498       56433 :             hashSaplingAnchor
     499             :     );
     500       56433 : }
     501             : 
     502             : template<>
     503          48 : void CCoinsViewCache::BringBestAnchorIntoCache(
     504             :         const uint256 &currentRoot,
     505             :         SaplingMerkleTree &tree
     506             : )
     507             : {
     508          48 :     assert(GetSaplingAnchorAt(currentRoot, tree));
     509          48 : }
     510             : 
     511             : template<typename Tree, typename Cache, typename CacheEntry>
     512        1464 : void CCoinsViewCache::AbstractPopAnchor(
     513             :         const uint256 &newrt,
     514             :         Cache &cacheAnchors,
     515             :         uint256 &hash
     516             : )
     517             : {
     518        1464 :     auto currentRoot = GetBestAnchor();
     519             : 
     520             :     // Blocks might not change the commitment tree, in which
     521             :     // case restoring the "old" anchor during a reorg must
     522             :     // have no effect.
     523        1464 :     if (currentRoot != newrt) {
     524             :         // Bring the current best anchor into our local cache
     525             :         // so that its tree exists in memory.
     526             :         {
     527          48 :             Tree tree;
     528          48 :             BringBestAnchorIntoCache(currentRoot, tree);
     529             :         }
     530             : 
     531             :         // Mark the anchor as unentered, removing it from view
     532          48 :         cacheAnchors[currentRoot].entered = false;
     533             : 
     534             :         // Mark the cache entry as dirty so it's propagated
     535          48 :         cacheAnchors[currentRoot].flags = CacheEntry::DIRTY;
     536             : 
     537             :         // Mark the new root as the best anchor
     538          48 :         hash = newrt;
     539             :     }
     540        1464 : }
     541             : 
     542        1464 : void CCoinsViewCache::PopAnchor(const uint256 &newrt) {
     543        1464 :     AbstractPopAnchor<SaplingMerkleTree, CAnchorsSaplingMap, CAnchorsSaplingCacheEntry>(
     544             :             newrt,
     545        1464 :             cacheSaplingAnchors,
     546        1464 :             hashSaplingAnchor
     547             :     );
     548        1464 : }
     549             : 
     550     3708861 : void CCoinsViewCache::SetNullifiers(const CTransaction& tx, bool spent) {
     551     3708861 :     if (tx.sapData) {
     552     3709193 :         for (const SpendDescription& spendDescription : tx.sapData->vShieldedSpend) {
     553         329 :             std::pair<CNullifiersMap::iterator, bool> ret = cacheSaplingNullifiers.insert(
     554         329 :                     std::make_pair(spendDescription.nullifier, CNullifiersCacheEntry()));
     555         329 :             ret.first->second.entered = spent;
     556         329 :             ret.first->second.flags |= CNullifiersCacheEntry::DIRTY;
     557             :         }
     558             :     }
     559     3708861 : }
     560             : 
     561      176847 : uint256 CCoinsViewCache::GetBestAnchor() const {
     562      353694 :     if (hashSaplingAnchor.IsNull())
     563       57178 :         hashSaplingAnchor = base->GetBestAnchor();
     564      176847 :     return hashSaplingAnchor;
     565             : }
     566             : 
     567     4448913 : bool CCoinsViewCache::HaveShieldedRequirements(const CTransaction& tx) const
     568             : {
     569     4968914 :     if (tx.IsShieldedTx()) {
     570      513172 :         for (const SpendDescription &spendDescription : tx.sapData->vShieldedSpend) {
     571         922 :             if (GetNullifier(spendDescription.nullifier)) // Prevent double spends
     572           2 :                 return false;
     573             : 
     574        1840 :             SaplingMerkleTree tree;
     575         920 :             if (!GetSaplingAnchorAt(spendDescription.anchor, tree)) {
     576           2 :                 return false;
     577             :             }
     578             :         }
     579             :     }
     580             : 
     581             :     return true;
     582             : }
     583             : 
     584        1820 : bool CCoinsViewCache::GetUTXOCoin(const COutPoint& outpoint, Coin& coin) const
     585             : {
     586        1820 :     return GetCoin(outpoint, coin) && !coin.IsSpent();
     587             : }

Generated by: LCOV version 1.14