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-04-02 01:23:23 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      630199 : CCoinsViewBacked::CCoinsViewBacked(CCoinsView* viewIn) : base(viewIn) {}
      34     1062510 : 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      150421 : uint256 CCoinsViewBacked::GetBestBlock() const { return base->GetBestBlock(); }
      37           0 : std::vector<uint256> CCoinsViewBacked::GetHeadBlocks() const { return base->GetHeadBlocks(); }
      38      514279 : void CCoinsViewBacked::SetBackend(CCoinsView& viewIn) { base = &viewIn; }
      39         965 : CCoinsViewCursor *CCoinsViewBacked::Cursor() const { return base->Cursor(); }
      40          98 : size_t CCoinsViewBacked::EstimateSize() const { return base->EstimateSize(); }
      41             : 
      42         799 : bool CCoinsViewBacked::BatchWrite(CCoinsMap& mapCoins,
      43             :                                   const uint256& hashBlock,
      44             :                                   const uint256& hashSaplingAnchor,
      45             :                                   CAnchorsSaplingMap& mapSaplingAnchors,
      46             :                                   CNullifiersMap& mapSaplingNullifiers)
      47         799 : { return base->BatchWrite(mapCoins, hashBlock, hashSaplingAnchor, mapSaplingAnchors, mapSaplingNullifiers); }
      48             : 
      49             : // Sapling
      50         466 : bool CCoinsViewBacked::GetSaplingAnchorAt(const uint256 &rt, SaplingMerkleTree &tree) const { return base->GetSaplingAnchorAt(rt, tree); }
      51         152 : bool CCoinsViewBacked::GetNullifier(const uint256 &nullifier) const { return base->GetNullifier(nullifier); }
      52         244 : uint256 CCoinsViewBacked::GetBestAnchor() const { return base->GetBestAnchor(); }
      53             : 
      54      374839 : SaltedOutpointHasher::SaltedOutpointHasher() : k0(GetRand(std::numeric_limits<uint64_t>::max())), k1(GetRand(std::numeric_limits<uint64_t>::max())) {}
      55      778278 : SaltedIdHasher::SaltedIdHasher() : k0(GetRand(std::numeric_limits<uint64_t>::max())), k1(GetRand(std::numeric_limits<uint64_t>::max())) {}
      56             : 
      57     1104021 : CCoinsViewCache::CCoinsViewCache(CCoinsView *baseIn) : CCoinsViewBacked(baseIn), cachedCoinsUsage(0) {}
      58             : 
      59      286476 : size_t CCoinsViewCache::DynamicMemoryUsage() const {
      60      286476 :     return memusage::DynamicUsage(cacheCoins) +
      61      286476 :            memusage::DynamicUsage(cacheSaplingAnchors) +
      62      286476 :            memusage::DynamicUsage(cacheSaplingNullifiers) +
      63      286476 :            cachedCoinsUsage;
      64             : }
      65             : 
      66    58476700 : CCoinsMap::iterator CCoinsViewCache::FetchCoin(const COutPoint& outpoint) const
      67             : {
      68    58476700 :     CCoinsMap::iterator it = cacheCoins.find(outpoint);
      69    58476700 :     if (it != cacheCoins.end())
      70    22217129 :         return it;
      71    94736200 :     Coin tmp;
      72    36259630 :     if (!base->GetCoin(outpoint, tmp))
      73    36259630 :         return cacheCoins.end();
      74     5512977 :     CCoinsMap::iterator ret = cacheCoins.emplace(std::piecewise_construct, std::forward_as_tuple(outpoint), std::forward_as_tuple(std::move(tmp))).first;
      75     5512977 :     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      280729 :         ret->second.flags = CCoinsCacheEntry::FRESH;
      79             :     }
      80     5512977 :     cachedCoinsUsage += memusage::DynamicUsage(ret->second.coin);
      81     5512977 :     return ret;
      82             : }
      83             : 
      84    22193390 : bool CCoinsViewCache::GetCoin(const COutPoint& outpoint, Coin& coin) const
      85             : {
      86    22193390 :     CCoinsMap::const_iterator it = FetchCoin(outpoint);
      87    22193390 :     if (it != cacheCoins.end()) {
      88     4961257 :         coin = it->second.coin;
      89     4961257 :         return true;
      90             :     }
      91             :     return false;
      92             : }
      93             : 
      94     5786517 : void CCoinsViewCache::AddCoin(const COutPoint& outpoint, Coin&& coin, bool possible_overwrite) {
      95     5786517 :     assert(!coin.IsSpent());
      96     5787941 :     if (coin.out.scriptPubKey.IsUnspendable()) return;
      97     5785093 :     if (coin.out.IsZerocoinMint()) return;
      98     5785093 :     CCoinsMap::iterator it;
      99     5785093 :     bool inserted;
     100     5785093 :     std::tie(it, inserted) = cacheCoins.emplace(std::piecewise_construct, std::forward_as_tuple(outpoint), std::tuple<>());
     101     5785093 :     bool fresh = false;
     102     5785093 :     if (!inserted) {
     103       48411 :         cachedCoinsUsage -= it->second.coin.DynamicMemoryUsage();
     104             :     }
     105     5785093 :     if (!possible_overwrite) {
     106     5728837 :         if (!it->second.coin.IsSpent()) {
     107          12 :             throw std::logic_error("Adding new coin that replaces non-pruned entry");
     108             :         }
     109     5728825 :         fresh = !(it->second.flags & CCoinsCacheEntry::DIRTY);
     110             :     }
     111     5785081 :     it->second.coin = std::move(coin);
     112     5785081 :     it->second.flags |= CCoinsCacheEntry::DIRTY | (fresh ? CCoinsCacheEntry::FRESH : 0);
     113     5785081 :     cachedCoinsUsage += it->second.coin.DynamicMemoryUsage();
     114             : }
     115             : 
     116     2971555 : void AddCoins(CCoinsViewCache& cache, const CTransaction& tx, int nHeight, bool check, bool fSkipInvalid)
     117             : {
     118     2971555 :     bool fCoinbase = tx.IsCoinBase();
     119     2971555 :     bool fCoinstake = tx.IsCoinStake();
     120     2971555 :     const uint256& txid = tx.GetHash();
     121     8613020 :     for (size_t i = 0; i < tx.vout.size(); ++i) {
     122     5641465 :         const COutPoint out(txid, i);
     123             :         // Don't add fraudulent/banned outputs
     124     5641465 :         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     5641465 :         bool overwrite = check && cache.HaveCoin(out);
     129    11282970 :         cache.AddCoin(out, Coin(tx.vout[i], nHeight, fCoinbase, fCoinstake), overwrite);
     130             :     }
     131     2971555 : }
     132             : 
     133     4319920 : void CCoinsViewCache::SpendCoin(const COutPoint& outpoint, Coin* moveout)
     134             : {
     135     4319920 :     CCoinsMap::iterator it = FetchCoin(outpoint);
     136     4319920 :     if (it == cacheCoins.end()) return;
     137     4303569 :     cachedCoinsUsage -= it->second.coin.DynamicMemoryUsage();
     138     4303569 :     if (moveout) {
     139     4266864 :         *moveout = std::move(it->second.coin);
     140             :     }
     141     4303569 :     if (it->second.flags & CCoinsCacheEntry::FRESH) {
     142      139160 :         cacheCoins.erase(it);
     143             :     } else {
     144     4164401 :         it->second.flags |= CCoinsCacheEntry::DIRTY;
     145     8467970 :         it->second.coin.Clear();
     146             :     }
     147             : }
     148             : 
     149             : static const Coin coinEmpty;
     150             : 
     151    21423420 : const Coin& CCoinsViewCache::AccessCoin(const COutPoint& outpoint) const
     152             : {
     153    21423420 :     CCoinsMap::const_iterator it = FetchCoin(outpoint);
     154    21423420 :     if (it == cacheCoins.end()) {
     155             :         return coinEmpty;
     156             :     } else {
     157     9048176 :         return it->second.coin;
     158             :     }
     159             : }
     160             : 
     161    10539970 : bool CCoinsViewCache::HaveCoin(const COutPoint& outpoint) const
     162             : {
     163    10539970 :     CCoinsMap::const_iterator it = FetchCoin(outpoint);
     164    10539970 :     return (it != cacheCoins.end() && !it->second.coin.IsSpent());
     165             : }
     166             : 
     167      898573 : bool CCoinsViewCache::HaveCoinInCache(const COutPoint& outpoint) const
     168             : {
     169      898573 :     CCoinsMap::const_iterator it = cacheCoins.find(outpoint);
     170      898573 :     return it != cacheCoins.end();
     171             : }
     172             : 
     173     3637224 : uint256 CCoinsViewCache::GetBestBlock() const
     174             : {
     175     7274448 :     if (hashBlock.IsNull())
     176      217080 :         hashBlock = base->GetBestBlock();
     177     3637224 :     return hashBlock;
     178             : }
     179             : 
     180       42654 : void CCoinsViewCache::SetBestBlock(const uint256& hashBlockIn)
     181             : {
     182       42654 :     hashBlock = hashBlockIn;
     183       42654 : }
     184             : 
     185             : template<typename Map, typename MapIterator, typename MapEntry>
     186       42193 : void BatchWriteAnchors(
     187             :         Map &mapAnchors,
     188             :         Map &cacheAnchors,
     189             :         size_t &cachedCoinsUsage
     190             : )
     191             : {
     192       83350 :     for (MapIterator child_it = mapAnchors.begin(); child_it != mapAnchors.end();)
     193             :     {
     194       41157 :         if (child_it->second.flags & MapEntry::DIRTY) {
     195         228 :             MapIterator parent_it = cacheAnchors.find(child_it->first);
     196             : 
     197         228 :             if (parent_it == cacheAnchors.end()) {
     198         218 :                 MapEntry& entry = cacheAnchors[child_it->first];
     199         218 :                 entry.entered = child_it->second.entered;
     200         218 :                 entry.tree = child_it->second.tree;
     201         218 :                 entry.flags = MapEntry::DIRTY;
     202             : 
     203         218 :                 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       41157 :         MapIterator itOld = child_it++;
     214       41157 :         mapAnchors.erase(itOld);
     215             :     }
     216       42193 : }
     217             : 
     218       42193 : void BatchWriteNullifiers(CNullifiersMap &mapNullifiers, CNullifiersMap &cacheNullifiers)
     219             : {
     220       42345 :     for (CNullifiersMap::iterator child_it = mapNullifiers.begin(); child_it != mapNullifiers.end();) {
     221         152 :         if (child_it->second.flags & CNullifiersCacheEntry::DIRTY) { // Ignore non-dirty entries (optimization).
     222         151 :             CNullifiersMap::iterator parent_it = cacheNullifiers.find(child_it->first);
     223             : 
     224         151 :             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         150 :                 if (parent_it->second.entered != child_it->second.entered) {
     230         150 :                     parent_it->second.entered = child_it->second.entered;
     231         150 :                     parent_it->second.flags |= CNullifiersCacheEntry::DIRTY;
     232             :                 }
     233             :             }
     234             :         }
     235         152 :         CNullifiersMap::iterator itOld = child_it++;
     236         152 :         mapNullifiers.erase(itOld);
     237             :     }
     238       42193 : }
     239             : 
     240       42201 : bool CCoinsViewCache::BatchWrite(CCoinsMap& mapCoins,
     241             :                                  const uint256& hashBlockIn,
     242             :                                  const uint256 &hashSaplingAnchorIn,
     243             :                                  CAnchorsSaplingMap& mapSaplingAnchors,
     244             :                                  CNullifiersMap& mapSaplingNullifiers)
     245             : {
     246     1407339 :     for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end(); it = mapCoins.erase(it)) {
     247             :         // Ignore non-dirty entries (optimization).
     248     1365146 :         if (!(it->second.flags & CCoinsCacheEntry::DIRTY)) {
     249      310615 :             continue;
     250             :         }
     251     1054531 :         CCoinsMap::iterator itUs = cacheCoins.find(it->first);
     252     1054531 :         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      584962 :             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      584961 :                 CCoinsCacheEntry& entry = cacheCoins[it->first];
     259      584961 :                 entry.coin = std::move(it->second.coin);
     260      584961 :                 cachedCoinsUsage += memusage::DynamicUsage(entry.coin);
     261      584961 :                 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      584961 :                 if (it->second.flags & CCoinsCacheEntry::FRESH) {
     266      558971 :                     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      469569 :             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      469561 :             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      114580 :                 cachedCoinsUsage -= memusage::DynamicUsage(itUs->second.coin);
     284      114580 :                 cacheCoins.erase(itUs);
     285             :             } else {
     286             :                 // A normal modification.
     287      354981 :                 cachedCoinsUsage -= memusage::DynamicUsage(itUs->second.coin);
     288      354981 :                 itUs->second.coin = std::move(it->second.coin);
     289      354981 :                 cachedCoinsUsage += memusage::DynamicUsage(itUs->second.coin);
     290      354981 :                 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       42193 :     ::BatchWriteAnchors<CAnchorsSaplingMap, CAnchorsSaplingMap::iterator, CAnchorsSaplingCacheEntry>(mapSaplingAnchors, cacheSaplingAnchors, cachedCoinsUsage);
     302       42193 :     ::BatchWriteNullifiers(mapSaplingNullifiers, cacheSaplingNullifiers);
     303       42193 :     hashSaplingAnchor = hashSaplingAnchorIn;
     304             : 
     305       42193 :     hashBlock = hashBlockIn;
     306       42193 :     return true;
     307             : }
     308             : 
     309       42948 : bool CCoinsViewCache::Flush()
     310             : {
     311       85896 :     bool fOk = base->BatchWrite(cacheCoins,
     312       42948 :             hashBlock,
     313       42948 :             hashSaplingAnchor,
     314       42948 :             cacheSaplingAnchors,
     315       42948 :             cacheSaplingNullifiers);
     316       42948 :     cacheCoins.clear();
     317       42948 :     cacheSaplingAnchors.clear();
     318       42948 :     cacheSaplingNullifiers.clear();
     319       42948 :     cachedCoinsUsage = 0;
     320       42948 :     return fOk;
     321             : }
     322             : 
     323       22550 : void CCoinsViewCache::Uncache(const COutPoint& outpoint)
     324             : {
     325       22550 :     CCoinsMap::iterator it = cacheCoins.find(outpoint);
     326       22550 :     if (it != cacheCoins.end() && it->second.flags == 0) {
     327         747 :         cachedCoinsUsage -= it->second.coin.DynamicMemoryUsage();
     328         747 :         cacheCoins.erase(it);
     329             :     }
     330       22550 : }
     331             : 
     332       42606 : unsigned int CCoinsViewCache::GetCacheSize() const
     333             : {
     334       42606 :     return cacheCoins.size();
     335             : }
     336             : 
     337      490456 : CAmount CCoinsViewCache::GetValueIn(const CTransaction& tx) const
     338             : {
     339      490456 :     if (tx.IsCoinBase())
     340             :         return 0;
     341             : 
     342      490456 :     CAmount nResult = 0;
     343     1395180 :     for (const CTxIn& in : tx.vin) {
     344      904721 :         if (in.IsZerocoinSpend() || in.IsZerocoinPublicSpend()) {
     345           0 :             nResult += in.nSequence * COIN;
     346             :         } else {
     347      904721 :             nResult += AccessCoin(in.prevout).out.nValue;
     348             :         }
     349             :     }
     350             : 
     351             :     // Sapling
     352      490456 :     nResult += tx.GetShieldedValueIn();
     353             : 
     354      490456 :     return nResult;
     355             : }
     356             : 
     357     3526757 : bool CCoinsViewCache::HaveInputs(const CTransaction& tx) const
     358             : {
     359     3526757 :     if (!tx.IsCoinBase() && !tx.HasZerocoinSpendInputs()) {
     360     8815467 :         for (unsigned int i = 0; i < tx.vin.size(); i++) {
     361     5300404 :             if (!HaveCoin(tx.vin[i].prevout)) {
     362             :                 return false;
     363             :             }
     364             :         }
     365             :     }
     366             :     return true;
     367             : }
     368             : 
     369         277 : int CCoinsViewCache::GetCoinDepthAtHeight(const COutPoint& output, int nHeight) const
     370             : {
     371         277 :     const Coin& coin = AccessCoin(output);
     372         277 :     if (!coin.IsSpent())
     373         277 :         return nHeight - coin.nHeight + 1;
     374             :     return -1;
     375             : }
     376             : 
     377         435 : CAmount CCoinsViewCache::GetTotalAmount() const
     378             : {
     379         435 :     CAmount nTotal = 0;
     380             : 
     381         435 :     std::unique_ptr<CCoinsViewCursor> pcursor(Cursor());
     382     3205077 :     while (pcursor->Valid()) {
     383     6409278 :         Coin coin;
     384     3204634 :         if (pcursor->GetValue(coin) && !coin.IsSpent()) {
     385     3204634 :             nTotal += coin.out.nValue;
     386             :         }
     387     3204634 :         pcursor->Next();
     388             :     }
     389             : 
     390         870 :     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          89 : const Coin& AccessByTxid(const CCoinsViewCache& view, const uint256& txid)
     410             : {
     411          89 :     COutPoint iter(txid, 0);
     412    11555600 :     while (iter.n < MAX_OUTPUTS_PER_BLOCK) {
     413    11555600 :         const Coin& alternate = view.AccessCoin(iter);
     414    11555600 :         if (!alternate.IsSpent()) return alternate;
     415    11555500 :         ++iter.n;
     416             :     }
     417             :     return coinEmpty;
     418             : }
     419             : 
     420             : // Sapling
     421             : 
     422      160033 : bool CCoinsViewCache::GetSaplingAnchorAt(const uint256 &rt, SaplingMerkleTree &tree) const {
     423             : 
     424      160033 :     CAnchorsSaplingMap::const_iterator it = cacheSaplingAnchors.find(rt);
     425      160033 :     if (it != cacheSaplingAnchors.end()) {
     426      103468 :         if (it->second.entered) {
     427      103464 :             tree = it->second.tree;
     428      103464 :             return true;
     429             :         } else {
     430             :             return false;
     431             :         }
     432             :     }
     433             : 
     434       56565 :     if (!base->GetSaplingAnchorAt(rt, tree)) {
     435             :         return false;
     436             :     }
     437             : 
     438      113128 :     CAnchorsSaplingMap::iterator ret = cacheSaplingAnchors.insert(std::make_pair(rt, CAnchorsSaplingCacheEntry())).first;
     439       56564 :     ret->second.entered = true;
     440       56564 :     ret->second.tree = tree;
     441       56564 :     cachedCoinsUsage += ret->second.tree.DynamicMemoryUsage();
     442             : 
     443       56564 :     return true;
     444             : }
     445             : 
     446        1531 : bool CCoinsViewCache::GetNullifier(const uint256 &nullifier) const {
     447        1531 :     CNullifiersMap* cacheToUse = &cacheSaplingNullifiers;
     448        1531 :     CNullifiersMap::iterator it = cacheToUse->find(nullifier);
     449        1531 :     if (it != cacheToUse->end())
     450         912 :         return it->second.entered;
     451             : 
     452         619 :     CNullifiersCacheEntry entry;
     453         619 :     bool tmp = base->GetNullifier(nullifier);
     454         619 :     entry.entered = tmp;
     455             : 
     456         619 :     cacheToUse->insert(std::make_pair(nullifier, entry));
     457         619 :     return tmp;
     458             : }
     459             : 
     460             : template<typename Tree, typename Cache, typename CacheIterator, typename CacheEntry>
     461       55914 : void CCoinsViewCache::AbstractPushAnchor(
     462             :         const Tree &tree,
     463             :         Cache &cacheAnchors,
     464             :         uint256 &hash
     465             : )
     466             : {
     467       55914 :     uint256 newrt = tree.root();
     468             : 
     469       55914 :     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       55914 :     if (currentRoot != newrt) {
     477         612 :         auto insertRet = cacheAnchors.insert(std::make_pair(newrt, CacheEntry()));
     478         306 :         CacheIterator ret = insertRet.first;
     479             : 
     480         306 :         ret->second.entered = true;
     481         306 :         ret->second.tree = tree;
     482         306 :         ret->second.flags = CacheEntry::DIRTY;
     483             : 
     484         306 :         if (insertRet.second) {
     485             :             // An insert took place
     486         306 :             cachedCoinsUsage += ret->second.tree.DynamicMemoryUsage();
     487             :         }
     488             : 
     489         306 :         hash = newrt;
     490             :     }
     491       55914 : }
     492             : 
     493       55914 : template<> void CCoinsViewCache::PushAnchor(const SaplingMerkleTree &tree)
     494             : {
     495       55914 :     AbstractPushAnchor<SaplingMerkleTree, CAnchorsSaplingMap, CAnchorsSaplingMap::iterator, CAnchorsSaplingCacheEntry>(
     496             :             tree,
     497       55914 :             cacheSaplingAnchors,
     498       55914 :             hashSaplingAnchor
     499             :     );
     500       55914 : }
     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        1411 : void CCoinsViewCache::AbstractPopAnchor(
     513             :         const uint256 &newrt,
     514             :         Cache &cacheAnchors,
     515             :         uint256 &hash
     516             : )
     517             : {
     518        1411 :     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        1411 :     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        1411 : }
     541             : 
     542        1411 : void CCoinsViewCache::PopAnchor(const uint256 &newrt) {
     543        1411 :     AbstractPopAnchor<SaplingMerkleTree, CAnchorsSaplingMap, CAnchorsSaplingCacheEntry>(
     544             :             newrt,
     545        1411 :             cacheSaplingAnchors,
     546        1411 :             hashSaplingAnchor
     547             :     );
     548        1411 : }
     549             : 
     550     3013820 : void CCoinsViewCache::SetNullifiers(const CTransaction& tx, bool spent) {
     551     3013820 :     if (tx.sapData) {
     552     3014152 :         for (const SpendDescription& spendDescription : tx.sapData->vShieldedSpend) {
     553         333 :             std::pair<CNullifiersMap::iterator, bool> ret = cacheSaplingNullifiers.insert(
     554         333 :                     std::make_pair(spendDescription.nullifier, CNullifiersCacheEntry()));
     555         333 :             ret.first->second.entered = spent;
     556         333 :             ret.first->second.flags |= CNullifiersCacheEntry::DIRTY;
     557             :         }
     558             :     }
     559     3013820 : }
     560             : 
     561      175070 : uint256 CCoinsViewCache::GetBestAnchor() const {
     562      350140 :     if (hashSaplingAnchor.IsNull())
     563       56614 :         hashSaplingAnchor = base->GetBestAnchor();
     564      175070 :     return hashSaplingAnchor;
     565             : }
     566             : 
     567     3646693 : bool CCoinsViewCache::HaveShieldedRequirements(const CTransaction& tx) const
     568             : {
     569     4166664 :     if (tx.IsShieldedTx()) {
     570      513185 :         for (const SpendDescription &spendDescription : tx.sapData->vShieldedSpend) {
     571         935 :             if (GetNullifier(spendDescription.nullifier)) // Prevent double spends
     572           2 :                 return false;
     573             : 
     574        1866 :             SaplingMerkleTree tree;
     575         933 :             if (!GetSaplingAnchorAt(spendDescription.anchor, tree)) {
     576           2 :                 return false;
     577             :             }
     578             :         }
     579             :     }
     580             : 
     581             :     return true;
     582             : }
     583             : 
     584        1801 : bool CCoinsViewCache::GetUTXOCoin(const COutPoint& outpoint, Coin& coin) const
     585             : {
     586        1801 :     return GetCoin(outpoint, coin) && !coin.IsSpent();
     587             : }

Generated by: LCOV version 1.14