LCOV - code coverage report
Current view: top level - src/sapling - saplingscriptpubkeyman.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 580 720 80.6 %
Date: 2025-02-23 09:33:43 Functions: 55 64 85.9 %

          Line data    Source code
       1             : // Copyright (c) 2016-2020 The ZCash developers
       2             : // Copyright (c) 2021 The PIVX Core developers
       3             : // Distributed under the MIT software license, see the accompanying
       4             : // file COPYING or https://www.opensource.org/licenses/mit-license.php.
       5             : 
       6             : #include "sapling/saplingscriptpubkeyman.h"
       7             : 
       8             : #include "chain.h" // for CBlockIndex
       9             : #include "primitives/transaction.h"
      10             : #include "consensus/params.h"
      11             : #include "primitives/block.h"
      12             : #include "sapling/incrementalmerkletree.h"
      13             : #include "uint256.h"
      14             : #include "validation.h" // for ReadBlockFromDisk()
      15             : #include "wallet/wallet.h"
      16             : #include <algorithm>
      17             : #include <map>
      18             : #include <string>
      19             : #include <vector>
      20             : 
      21         144 : void SaplingScriptPubKeyMan::AddToSaplingSpends(const uint256& nullifier, const uint256& wtxid)
      22             : {
      23         144 :     AssertLockHeld(wallet->cs_wallet);
      24         144 :     mapTxSaplingNullifiers.emplace(nullifier, wtxid);
      25             : 
      26         144 :     std::pair<TxNullifiers::iterator, TxNullifiers::iterator> range;
      27         144 :     range = mapTxSaplingNullifiers.equal_range(nullifier);
      28         144 :     wallet->SyncMetaDataN(range);
      29         144 : }
      30             : 
      31           2 : bool SaplingScriptPubKeyMan::IsSaplingSpent(const SaplingOutPoint& op) const
      32             : {
      33           2 :     for (auto& i : mapSaplingNullifiersToNotes) {
      34           2 :         SaplingOutPoint iOp = i.second;
      35           2 :         if (iOp == op) {
      36           2 :             return IsSaplingSpent(i.first);
      37             :         }
      38             :     }
      39           0 :     return false;
      40             : }
      41             : 
      42        1215 : bool SaplingScriptPubKeyMan::IsSaplingSpent(const uint256& nullifier) const {
      43        2430 :     LOCK(wallet->cs_wallet); // future: move to AssertLockHeld()
      44        1215 :     std::pair<TxNullifiers::const_iterator, TxNullifiers::const_iterator> range;
      45        1215 :     range = mapTxSaplingNullifiers.equal_range(nullifier);
      46             : 
      47        1215 :     for (TxNullifiers::const_iterator it = range.first; it != range.second; ++it) {
      48         273 :         const uint256& wtxid = it->second;
      49         273 :         std::map<uint256, CWalletTx>::const_iterator mit = wallet->mapWallet.find(wtxid);
      50         273 :         if (mit != wallet->mapWallet.end() && mit->second.GetDepthInMainChain() >= 0) {
      51         273 :             return true; // Spent
      52             :         }
      53             :     }
      54         942 :     return false;
      55             : }
      56             : 
      57       42319 : void SaplingScriptPubKeyMan::UpdateSaplingNullifierNoteMapForBlock(const CBlock *pblock) {
      58       42319 :     LOCK(wallet->cs_wallet);
      59             : 
      60      344035 :     for (const auto& tx : pblock->vtx) {
      61      301716 :         auto it = wallet->mapWallet.find(tx->GetHash());
      62      301716 :         if (it != wallet->mapWallet.end()) {
      63      169767 :             UpdateSaplingNullifierNoteMapWithTx(it->second);
      64             :         }
      65             :     }
      66       42319 : }
      67             : 
      68             : // Updates noteData and mapSaplingNullifiersToNotes directly
      69         897 : void SaplingScriptPubKeyMan::UpdateSaplingNullifierNoteMap(SaplingNoteData& nd, const SaplingOutPoint& op, const Optional<uint256>& nullifier)
      70             : {
      71        1794 :     AssertLockHeld(wallet->cs_wallet);
      72         897 :     nd.nullifier = nullifier;
      73         897 :     if (nullifier) mapSaplingNullifiersToNotes[*nullifier] = op;
      74         897 : }
      75             : 
      76             : /**
      77             :  * Update mapSaplingNullifiersToNotes, computing the nullifier from a cached witness if necessary.
      78             :  */
      79      169769 : void SaplingScriptPubKeyMan::UpdateSaplingNullifierNoteMapWithTx(CWalletTx& wtx) {
      80      169769 :     LOCK(wallet->cs_wallet);
      81             : 
      82      170720 :     for (mapSaplingNoteData_t::value_type &item : wtx.mapSaplingNoteData) {
      83         951 :         const SaplingOutPoint& op = item.first;
      84         951 :         SaplingNoteData& nd = item.second;
      85             : 
      86        1848 :         if (nd.witnesses.empty() || !nd.IsMyNote()) {
      87             :             // If there are no witnesses, erase the nullifier and associated mapping.
      88          54 :             if (nd.nullifier) {
      89           0 :                 mapSaplingNullifiersToNotes.erase(item.second.nullifier.get());
      90             :             }
      91          54 :             nd.nullifier = nullopt;
      92             :         } else {
      93         897 :             const libzcash::SaplingIncomingViewingKey& ivk = *(nd.ivk);
      94         897 :             uint64_t position = nd.witnesses.front().position();
      95         897 :             auto extfvk = wallet->mapSaplingFullViewingKeys.at(ivk);
      96         897 :             OutputDescription output = wtx.tx->sapData->vShieldedOutput[op.n];
      97        1794 :             auto optPlaintext = libzcash::SaplingNotePlaintext::decrypt(output.encCiphertext, ivk, output.ephemeralKey, output.cmu);
      98         897 :             if (!optPlaintext) {
      99             :                 // An item in mapSaplingNoteData must have already been successfully decrypted,
     100             :                 // otherwise the item would not exist in the first place.
     101           0 :                 assert(false);
     102             :             }
     103        1794 :             auto optNote = optPlaintext.get().note(ivk);
     104         897 :             if (!optNote) {
     105           0 :                 assert(false);
     106             :             }
     107         897 :             auto optNullifier = optNote.get().nullifier(extfvk.fvk, position);
     108         897 :             if (!optNullifier) {
     109             :                 // This should not happen.  If it does, maybe the position has been corrupted or miscalculated?
     110           0 :                 assert(false);
     111             :             }
     112         897 :             UpdateSaplingNullifierNoteMap(nd, op, optNullifier.get());
     113             :         }
     114             :     }
     115      169769 : }
     116             : 
     117             : /**
     118             :  * Update mapSaplingNullifiersToNotes with the cached nullifiers in this tx.
     119             :  */
     120      403237 : void SaplingScriptPubKeyMan::UpdateNullifierNoteMapWithTx(const CWalletTx& wtx)
     121             : {
     122      403237 :     {
     123      403237 :         LOCK(wallet->cs_wallet);
     124      404381 :         for (const mapSaplingNoteData_t::value_type& item : wtx.mapSaplingNoteData) {
     125        1144 :             if (item.second.nullifier) {
     126          21 :                 mapSaplingNullifiersToNotes[*item.second.nullifier] = item.first;
     127             :             }
     128             :         }
     129             :     }
     130      403237 : }
     131             : 
     132             : template<typename NoteDataMap>
     133       24249 : void CopyPreviousWitnesses(NoteDataMap& noteDataMap, int indexHeight, int64_t nWitnessCacheSize)
     134             : {
     135       50767 :     for (auto& item : noteDataMap) {
     136       26518 :         auto* nd = &(item.second);
     137             :         // skip externally sent notes
     138       26518 :         if (!nd->IsMyNote()) continue;
     139             :         // Only increment witnesses that are behind the current height
     140       26207 :         if (nd->witnessHeight < indexHeight) {
     141             :             // Check the validity of the cache
     142             :             // The only time a note witnessed above the current height
     143             :             // would be invalid here is during a reindex when blocks
     144             :             // have been decremented, and we are incrementing the blocks
     145             :             // immediately after.
     146       12475 :             assert(nWitnessCacheSize >= (int64_t) nd->witnesses.size());
     147             :             // Witnesses being incremented should always be either -1
     148             :             // (never incremented or decremented) or one below indexHeight
     149       12475 :             assert((nd->witnessHeight == -1) || (nd->witnessHeight == indexHeight - 1));
     150             :             // Copy the witness for the previous block if we have one
     151       12475 :             if (nd->witnesses.size() > 0) {
     152        9668 :                 nd->witnesses.push_front(nd->witnesses.front());
     153             :             }
     154       12475 :             if (nd->witnesses.size() > WITNESS_CACHE_SIZE) {
     155       26856 :                 nd->witnesses.pop_back();
     156             :             }
     157             :         }
     158             :     }
     159       24249 : }
     160             : 
     161      831966 : void AppendNoteCommitment(SaplingNoteData* nd, int indexHeight, int64_t nWitnessCacheSize, const uint256& note_commitment)
     162             : {
     163             :     // skip externally sent notes
     164      831966 :     if (!nd->IsMyNote()) return;
     165             :     // No empty witnesses can reach here. Before any append, the note must be already witnessed.
     166      831606 :     if (nd->witnessHeight < indexHeight && nd->witnesses.size() > 0) {
     167             :         // Check the validity of the cache
     168             :         // See comment in CopyPreviousWitnesses about validity.
     169      199525 :         assert(nWitnessCacheSize >= (int64_t) nd->witnesses.size());
     170      199525 :         nd->witnesses.front().append(note_commitment);
     171             :     }
     172             : }
     173             : 
     174             : template<typename Witness>
     175        1177 : void WitnessNoteIfMine(SaplingNoteData* nd,
     176             :                        int indexHeight,
     177             :                        int64_t nWitnessCacheSize,
     178             :                        const Witness& witness)
     179             : {
     180        1177 :     assert(nd);
     181             :     // skip externally sent and already witnessed notes
     182        1177 :     if (!nd->IsMyNote() || nd->witnessHeight >= indexHeight) return;
     183         996 :     if (!nd->witnesses.empty()) {
     184             :         // We think this can happen because we write out the
     185             :         // witness cache state after every block increment or
     186             :         // decrement, but the block index itself is written in
     187             :         // batches. So if the node crashes in between these two
     188             :         // operations, it is possible for IncrementNoteWitnesses
     189             :         // to be called again on previously-cached blocks. This
     190             :         // doesn't affect existing cached notes because of the
     191             :         // NoteData::witnessHeight checks. See #1378 for details.
     192           0 :         LogPrintf("Inconsistent witness cache state found\n- Cache size: %d\n- Top (height %d): %s\n- New (height %d): %s\n",
     193           0 :                   nd->witnesses.size(), nd->witnessHeight,
     194           0 :                   nd->witnesses.front().root().GetHex(),
     195             :                   indexHeight,
     196           0 :                   witness.root().GetHex());
     197           0 :         nd->witnesses.clear();
     198             :     }
     199         996 :     nd->witnesses.push_front(witness);
     200             :     // Set height to one less than pindex so it gets incremented
     201         996 :     nd->witnessHeight = indexHeight - 1;
     202             :     // Check the validity of the cache
     203         996 :     assert(nWitnessCacheSize >= (int64_t) nd->witnesses.size());
     204             : }
     205             : 
     206             : template <typename NoteDataMap>
     207       25426 : void UpdateWitnessHeights(NoteDataMap& noteDataMap, int indexHeight, int64_t nWitnessCacheSize)
     208             : {
     209       54977 :     for (auto& item : noteDataMap) {
     210       29551 :         auto* nd = &(item.second);
     211             :         // skip externally sent notes
     212       29551 :         if (!nd->IsMyNote()) continue;
     213       29159 :         if (nd->witnessHeight < indexHeight) {
     214       13471 :             nd->witnessHeight = indexHeight;
     215             :             // Check the validity of the cache
     216             :             // See comment in CopyPreviousWitnesses about validity.
     217       13471 :             assert(nWitnessCacheSize >= (int64_t) nd->witnesses.size());
     218             :         }
     219             :     }
     220       25426 : }
     221             : 
     222           5 : bool SaplingScriptPubKeyMan::BuildWitnessChain(const CBlockIndex* pTargetBlock, const Consensus::Params& params, std::string& errorStr)
     223             : {
     224             :     // If V5 is not enforced building the witness cache is useless
     225           5 :     if (!params.NetworkUpgradeActive(chainActive.Height(), Consensus::UPGRADE_V5_0)) {
     226             :         return true;
     227             :     }
     228             : 
     229           7 :     LOCK2(cs_main, wallet->cs_wallet);
     230             :     // Target is the last block we want to invalidate
     231           1 :     rollbackTargetHeight = pTargetBlock->nHeight;
     232           1 :     cachedWitnessMap.clear();
     233             : 
     234             :     // Find the oldest sapling note
     235           1 :     int minHeight = INT_MAX;
     236         227 :     for (auto& it : wallet->mapWallet) {
     237         226 :         CWalletTx& wtx = it.second;
     238         226 :         if (wtx.mapSaplingNoteData.empty()) continue;
     239             :         // Skip abandoned and conflicted txs for which the block_height is not defined (more precisely it it set to 0 by default)
     240           0 :         if (wtx.m_confirm.status != CWalletTx::CONFIRMED) continue;
     241           0 :         minHeight = std::min(wtx.m_confirm.block_height, minHeight);
     242             :     }
     243             : 
     244             :     // Read blocks from the disk from chaintip to the minimum found height
     245           2 :     std::vector<CBlock> cblocks;
     246           1 :     const CBlockIndex* pIndex = GetChainTip();
     247           1 :     int currentHeight = GetChainTip()->nHeight;
     248           1 :     while (currentHeight >= minHeight) {
     249           0 :         CBlock cblock;
     250           0 :         ReadBlockFromDisk(cblock, pIndex);
     251           0 :         cblocks.insert(cblocks.begin(), cblock);
     252           0 :         pIndex = pIndex->pprev;
     253           0 :         currentHeight = pIndex->nHeight;
     254             :     }
     255             : 
     256           2 :     SaplingMerkleTree initialSaplingTree = SaplingMerkleTree();
     257             :     // Load the SaplingMerkleTree for the block before the oldest note (if the hash is zero then continue with an empty merkle tree)
     258           1 :     if (!(pIndex->hashFinalSaplingRoot == UINT256_ZERO) && !pcoinsTip->GetSaplingAnchorAt(pIndex->hashFinalSaplingRoot, initialSaplingTree)) {
     259           1 :         errorStr = "Cannot fetch the sapling anchor!";
     260             :         return false;
     261             :     }
     262             :     // Finally build the witness cache for each sapling note of your wallet
     263           1 :     int height = minHeight;
     264           1 :     for (CBlock& block : cblocks) {
     265             :         // Finally build the witness cache for each sapling note
     266           0 :         std::vector<uint256> noteCommitments;
     267           0 :         std::vector<SaplingNoteData*> inBlockArrivingNotes;
     268           0 :         for (const auto& tx : block.vtx) {
     269           0 :             const auto& hash = tx->GetHash();
     270           0 :             auto it = wallet->mapWallet.find(hash);
     271           0 :             bool txIsOurs = it != wallet->mapWallet.end();
     272             : 
     273           0 :             if (!tx->IsShieldedTx()) continue;
     274           0 :             for (uint32_t i = 0; i < tx->sapData->vShieldedOutput.size(); i++) {
     275           0 :                 const auto& cmu = tx->sapData->vShieldedOutput[i].cmu;
     276           0 :                 noteCommitments.emplace_back(cmu);
     277           0 :                 for (auto& item : inBlockArrivingNotes) {
     278           0 :                     item->witnesses.front().append(cmu);
     279             :                 }
     280           0 :                 initialSaplingTree.append(cmu);
     281           0 :                 if (txIsOurs) {
     282           0 :                     CWalletTx* wtx = &it->second;
     283           0 :                     auto ndIt = wtx->mapSaplingNoteData.find({hash, i});
     284           0 :                     if (ndIt != wtx->mapSaplingNoteData.end()) {
     285           0 :                         SaplingNoteData* nd = &ndIt->second;
     286           0 :                         nd->witnesses.push_front(initialSaplingTree.witness());
     287           0 :                         inBlockArrivingNotes.emplace_back(nd);
     288             :                     }
     289             :                 }
     290             :             }
     291             :         }
     292           0 :         for (auto& it2 : cachedWitnessMap) {
     293             :             // Don't duplicate if the block is too old
     294           0 :             if (height >= rollbackTargetHeight) {
     295           0 :                 it2.second.emplace_front(it2.second.front());
     296             :             }
     297           0 :             for (auto& noteComm : noteCommitments) {
     298           0 :                 it2.second.front().append(noteComm);
     299             :             }
     300             :         }
     301           0 :         for (auto nd : inBlockArrivingNotes) {
     302           0 :             if (nd->nullifier) {
     303           0 :                 std::list<SaplingWitness> witnesses;
     304           0 :                 witnesses.push_front(nd->witnesses.front());
     305           0 :                 cachedWitnessMap.emplace(*(nd->nullifier), witnesses);
     306             :             }
     307             :         }
     308           0 :         height++;
     309             :     }
     310           1 :     return true;
     311             : }
     312             : 
     313       42368 : void SaplingScriptPubKeyMan::IncrementNoteWitnesses(const CBlockIndex* pindex,
     314             :                                                     const CBlock* pblock,
     315             :                                                     SaplingMerkleTree& saplingTreeRes)
     316             : {
     317       42368 :     LOCK(wallet->cs_wallet);
     318       42368 :     int chainHeight = pindex->nHeight;
     319             : 
     320             :     // Set the update cache flag.
     321       42368 :     int64_t prevWitCacheSize = nWitnessCacheSize;
     322       42368 :     if (nWitnessCacheSize < WITNESS_CACHE_SIZE) {
     323       18755 :         nWitnessCacheSize += 1;
     324       18755 :         nWitnessCacheNeedsUpdate = true;
     325             :     }
     326             : 
     327             :     // 1) Loop over the block txs and gather the note commitments ordered.
     328             :     // If the wtx is from this wallet, witness it and append the following block note commitments on top.
     329       84736 :     std::vector<uint256> noteCommitments;
     330       42368 :     std::vector<std::pair<CWalletTx*, SaplingNoteData*>> inBlockArrivingNotes;
     331      344114 :     for (const auto& tx : pblock->vtx) {
     332      304379 :         if (!tx->IsShieldedTx()) continue;
     333             : 
     334        1807 :         const auto& hash = tx->GetHash();
     335        1807 :         auto it = wallet->mapWallet.find(hash);
     336        1807 :         bool txIsOurs = it != wallet->mapWallet.end();
     337             : 
     338        3853 :         for (uint32_t i = 0; i < tx->sapData->vShieldedOutput.size(); i++) {
     339        2046 :             const auto& cmu = tx->sapData->vShieldedOutput[i].cmu;
     340        2046 :             noteCommitments.emplace_back(cmu);
     341             : 
     342             :             // Append note commitment to the in-block wallet's notes.
     343             :             // This is processed here because we already looked for the wtx on
     344             :             // the WitnessNoteIfMine call and only need to append the follow-up block notes,
     345             :             // not every block note (check below).
     346      193053 :             for (auto& item : inBlockArrivingNotes) {
     347      191007 :                 ::AppendNoteCommitment(item.second, chainHeight, nWitnessCacheSize, cmu);
     348             :             }
     349             : 
     350             :             // If tx is from this wallet, try to witness the note for the first time (if exists).
     351             :             // And add it to the in-block arriving txs.
     352        2046 :             saplingTreeRes.append(cmu);
     353        2046 :             if (txIsOurs) {
     354        1226 :                 CWalletTx* wtx = &it->second;
     355        1226 :                 auto ndIt = wtx->mapSaplingNoteData.find({hash, i});
     356        1226 :                 if (ndIt != wtx->mapSaplingNoteData.end()) {
     357        1177 :                     SaplingNoteData* nd = &ndIt->second;
     358        1177 :                     ::WitnessNoteIfMine(nd, chainHeight, nWitnessCacheSize, saplingTreeRes.witness());
     359        1177 :                     inBlockArrivingNotes.emplace_back(std::make_pair(wtx, nd));
     360             :                 }
     361             :             }
     362             :         }
     363             :     }
     364             : 
     365             :     // 2) Mark already sync wtx, so we don't process them again.
     366       43545 :     for (auto& item : inBlockArrivingNotes) {
     367        1177 :         ::UpdateWitnessHeights(item.first->mapSaplingNoteData, chainHeight, nWitnessCacheSize);
     368             :     }
     369             : 
     370             :     // 3) Loop over the shield txs in the wallet's map (excluding the wtx arriving in this block) and for each tx:
     371             :     //    a) Copy the previous witness.
     372             :     //    b) Append all new notes commitments
     373             :     //    c) Update witness last processed height
     374    11236833 :     for (auto& it : wallet->mapWallet) {
     375    11194424 :         CWalletTx& wtx = it.second;
     376    11194424 :         if (!wtx.mapSaplingNoteData.empty()) {
     377             :             // Create copy of the previous witness (verifying pre-arriving block witness cache size)
     378       24249 :             ::CopyPreviousWitnesses(wtx.mapSaplingNoteData, chainHeight, prevWitCacheSize);
     379             : 
     380             :             // Append new notes commitments.
     381      661656 :             for (auto& noteComm : noteCommitments) {
     382     1278364 :                 for (auto& item : wtx.mapSaplingNoteData) {
     383      640959 :                     AppendNoteCommitment(&(item.second), chainHeight, nWitnessCacheSize, noteComm);
     384             :                 }
     385             :             }
     386             : 
     387             :             // Set last processed height.
     388       24249 :             ::UpdateWitnessHeights(wtx.mapSaplingNoteData, chainHeight, nWitnessCacheSize);
     389             :         }
     390             :     }
     391             : 
     392             :     // For performance reasons, we write out the witness cache in
     393             :     // CWallet::SetBestChain() (which also ensures that overall consistency
     394             :     // of the wallet.dat is maintained).
     395       42368 : }
     396             : /*
     397             :  * Clear and eventually reset each witness of noteDataMap with the corresponding front-value of cachedWitnessMap, indexHeight is the blockHeight being invalidated
     398             :  */
     399           0 : void ResetNoteWitnesses(std::map<SaplingOutPoint, SaplingNoteData>& noteDataMap, std::map<uint256, std::list<SaplingWitness>>& cachedWitnessMap, int indexHeight)
     400             : {
     401             :     // For each note that you own:
     402           0 :     for (auto& item : noteDataMap) {
     403           0 :         auto& nd = (item.second);
     404             :         // skip externally sent notes
     405           0 :         if (!nd.IsMyNote()) continue;
     406             :         // Clear the cache
     407           0 :         nd.witnesses.clear();
     408             :         // The withnessHeight must be EITHER -1 or equal to the block indexHeight
     409             :         // The case in which indexHeight > witnessHeight is due to conflicted notes, which are irrelevant
     410             :         // TODO: Allow invalidating blocks only if there are not conflicted txs?
     411           0 :         if (nd.witnessHeight <= indexHeight) {
     412           0 :             assert((nd.witnessHeight == -1) || (nd.witnessHeight == indexHeight));
     413             :         }
     414             :         // Decrease the witnessHeight
     415           0 :         nd.witnessHeight = indexHeight - 1;
     416           0 :         if (nd.nullifier && cachedWitnessMap.at(*nd.nullifier).size() > 0) {
     417             :             // Update the witness value with the cached one
     418           0 :             nd.witnesses.push_front(cachedWitnessMap.at(*nd.nullifier).front());
     419           0 :             cachedWitnessMap.at(*nd.nullifier).pop_front();
     420             :         }
     421             :     }
     422           0 : }
     423             : 
     424             : 
     425             : template<typename NoteDataMap>
     426        3893 : void DecrementNoteWitnesses(NoteDataMap& noteDataMap, int indexHeight, int64_t nWitnessCacheSize)
     427             : {
     428        4130 :     for (auto& item : noteDataMap) {
     429         237 :         auto* nd = &(item.second);
     430             :         // skip externally sent notes
     431         237 :         if (!nd->IsMyNote()) continue;
     432             :         // Only decrement witnesses that are not above the current height
     433         235 :         if (nd->witnessHeight <= indexHeight) {
     434             :             // Check the validity of the cache
     435             :             // See comment below (this would be invalid if there were a
     436             :             // prior decrement).
     437          13 :             assert(nWitnessCacheSize >= (int64_t) nd->witnesses.size());
     438             :             // Witnesses being decremented should always be either -1
     439             :             // (never incremented or decremented) or equal to the height
     440             :             // of the block being removed (indexHeight)
     441          13 :             assert((nd->witnessHeight == -1) || (nd->witnessHeight == indexHeight));
     442          13 :             if (nd->witnesses.size() > 0) {
     443          12 :                 nd->witnesses.pop_front();
     444             :             }
     445             :             // indexHeight is the height of the block being removed, so
     446             :             // the new witness cache height is one below it.
     447          13 :             nd->witnessHeight = indexHeight - 1;
     448             :         }
     449             :         // Check the validity of the cache
     450             :         // Technically if there are notes witnessed above the current
     451             :         // height, their cache will now be invalid (relative to the new
     452             :         // value of nWitnessCacheSize). However, this would only occur
     453             :         // during a reindex, and by the time the reindex reaches the tip
     454             :         // of the chain again, the existing witness caches will be valid
     455             :         // again.
     456             :         // We don't set nWitnessCacheSize to zero at the start of the
     457             :         // reindex because the on-disk blocks had already resulted in a
     458             :         // chain that didn't trigger the assertion below.
     459         235 :         if (nd->witnessHeight < indexHeight) {
     460             :             // Subtract 1 to compare to what nWitnessCacheSize will be after
     461             :             // decrementing.
     462          13 :             assert((nWitnessCacheSize - 1) >= (int64_t) nd->witnesses.size());
     463             :         }
     464             :     }
     465        3893 : }
     466             : 
     467         188 : void SaplingScriptPubKeyMan::DecrementNoteWitnesses(const CBlockIndex* pindex)
     468             : {
     469         188 :     assert(pindex);
     470         235 :     LOCK(wallet->cs_wallet);
     471         188 :     int nChainHeight = pindex->nHeight;
     472             :     // if the targetHeight is different from -1 we have a cache to use
     473         188 :     if (rollbackTargetHeight != -1) {
     474       31780 :         for (std::pair<const uint256, CWalletTx>& wtxItem : wallet->mapWallet) {
     475       31640 :             if (!wtxItem.second.mapSaplingNoteData.empty()) {
     476             :                 // For each sapling note that you own reset the current witness with the cached one
     477           0 :                 ResetNoteWitnesses(wtxItem.second.mapSaplingNoteData, cachedWitnessMap, nChainHeight);
     478             :             }
     479             :         }
     480         140 :         nWitnessCacheSize = 1;
     481         140 :         nWitnessCacheNeedsUpdate = true;
     482             :         // If we reached the target height empty the cache and reset the target height to -1
     483             :         // Remember that the targetHeight is indeed the last block we want to invalidate
     484         140 :         if (rollbackTargetHeight == pindex->nHeight) {
     485           1 :             cachedWitnessMap.clear();
     486           1 :             rollbackTargetHeight = -1;
     487             :         }
     488         280 :         return;
     489             :     }
     490             : 
     491        3941 :     for (std::pair<const uint256, CWalletTx>& wtxItem : wallet->mapWallet) {
     492        3893 :         ::DecrementNoteWitnesses(wtxItem.second.mapSaplingNoteData, nChainHeight, nWitnessCacheSize);
     493             :     }
     494          48 :     nWitnessCacheSize -= 1;
     495          48 :     nWitnessCacheNeedsUpdate = true;
     496             :     // TODO: If nWitnessCache is zero, we need to regenerate the caches (#1302)
     497          48 :     if (Params().IsRegTestNet()) { // throw an error in regtest to be able to catch it from the sapling_wallet_tests.cpp unit test.
     498          48 :         if (nWitnessCacheSize <= 0) throw std::runtime_error("nWitnessCacheSize > 0");
     499           0 :     } else assert(nWitnessCacheSize > 0);
     500             : 
     501             :     // For performance reasons, we write out the witness cache in
     502             :     // CWallet::SetBestChain() (which also ensures that overall consistency
     503             :     // of the wallet.dat is maintained).
     504             : }
     505             : 
     506             : /**
     507             :  * Finds all output notes in the given transaction that have been sent to
     508             :  * SaplingPaymentAddresses in this wallet.
     509             :  *
     510             :  * It should never be necessary to call this method with a CWalletTx, because
     511             :  * the result of FindMySaplingNotes (for the addresses available at the time) will
     512             :  * already have been cached in CWalletTx.mapSaplingNoteData.
     513             :  */
     514      647505 : std::pair<mapSaplingNoteData_t, SaplingIncomingViewingKeyMap> SaplingScriptPubKeyMan::FindMySaplingNotes(const CTransaction &tx) const
     515             : {
     516             :     // First check that this tx is a Shielded tx.
     517      647505 :     if (!tx.IsShieldedTx()) {
     518      643739 :         return {};
     519             :     }
     520             : 
     521      651271 :     LOCK(wallet->cs_KeyStore);
     522        3766 :     const uint256& hash = tx.GetHash();
     523             : 
     524        7532 :     mapSaplingNoteData_t noteData;
     525        3766 :     SaplingIncomingViewingKeyMap viewingKeysToAdd;
     526             : 
     527             :     // Protocol Spec: 4.19 Block Chain Scanning (Sapling)
     528        7944 :     for (uint32_t i = 0; i < tx.sapData->vShieldedOutput.size(); ++i) {
     529        4178 :         const OutputDescription output = tx.sapData->vShieldedOutput[i];
     530        8319 :         for (auto it = wallet->mapSaplingFullViewingKeys.begin(); it != wallet->mapSaplingFullViewingKeys.end(); ++it) {
     531        6197 :             libzcash::SaplingIncomingViewingKey ivk = it->first;
     532        6197 :             auto result = libzcash::SaplingNotePlaintext::decrypt(output.encCiphertext, ivk, output.ephemeralKey, output.cmu);
     533        6197 :             if (!result) {
     534        4141 :                 continue;
     535             :             }
     536             : 
     537             :             // Check if we already have it.
     538        4112 :             Optional<libzcash::SaplingPaymentAddress> address = ivk.address(result.get().d);
     539        4112 :             if (address && wallet->mapSaplingIncomingViewingKeys.count(address.get()) == 0) {
     540           0 :                 viewingKeysToAdd[address.get()] = ivk;
     541             :             }
     542             :             // We don't cache the nullifier here as computing it requires knowledge of the note position
     543             :             // in the commitment tree, which can only be determined when the transaction has been mined.
     544        2056 :             SaplingOutPoint op {hash, i};
     545        4112 :             SaplingNoteData nd;
     546        2056 :             nd.ivk = ivk;
     547        2056 :             nd.amount = result->value();
     548        2056 :             nd.address = address;
     549        2056 :             const auto& memo = result->memo();
     550             :             // don't save empty memo (starting with 0xF6)
     551        2056 :             if (memo[0] < 0xF6) {
     552          23 :                 nd.memo = memo;
     553             :             }
     554        4112 :             noteData.insert(std::make_pair(op, nd));
     555        2056 :             break;
     556             :         }
     557             :     }
     558             : 
     559        3766 :     return std::make_pair(noteData, viewingKeysToAdd);
     560             : }
     561             : 
     562          19 : std::vector<libzcash::SaplingPaymentAddress> SaplingScriptPubKeyMan::FindMySaplingAddresses(const CTransaction& tx) const
     563             : {
     564          38 :     LOCK(wallet->cs_KeyStore);
     565          19 :     std::vector<libzcash::SaplingPaymentAddress> ret;
     566          19 :     if (!tx.sapData) return ret;
     567             : 
     568             :     // Protocol Spec: 4.19 Block Chain Scanning (Sapling)
     569          39 :     for (const OutputDescription& output : tx.sapData->vShieldedOutput) {
     570         649 :         for (auto it = wallet->mapSaplingFullViewingKeys.begin(); it != wallet->mapSaplingFullViewingKeys.end(); ++it) {
     571         629 :             libzcash::SaplingIncomingViewingKey ivk = it->first;
     572         638 :             auto result = libzcash::SaplingNotePlaintext::decrypt(output.encCiphertext, ivk, output.ephemeralKey, output.cmu);
     573         629 :             if (!result) {
     574         620 :                 continue;
     575             :             }
     576          18 :             Optional<libzcash::SaplingPaymentAddress> address = ivk.address(result.get().d);
     577           9 :             if (address && wallet->mapSaplingIncomingViewingKeys.count(address.get()) != 0) {
     578           9 :                 ret.emplace_back(address.get());
     579             :             }
     580             :         }
     581             :     }
     582          19 :     return ret;
     583             : }
     584             : 
     585           1 : void SaplingScriptPubKeyMan::GetNotes(const std::vector<SaplingOutPoint>& saplingOutpoints,
     586             :                                       std::vector<SaplingNoteEntry>& saplingEntriesRet) const
     587             : {
     588           6 :     for (const auto& outpoint : saplingOutpoints) {
     589           5 :         const auto* wtx = wallet->GetWalletTx(outpoint.hash);
     590           5 :         if (!wtx) throw std::runtime_error("No transaction available for hash " + outpoint.hash.GetHex());
     591          15 :         const int depth = WITH_LOCK(wallet->cs_wallet, return wtx->GetDepthInMainChain(); );
     592           5 :         const auto& it = wtx->mapSaplingNoteData.find(outpoint);
     593           5 :         if (it != wtx->mapSaplingNoteData.end()) {
     594           5 :             const SaplingOutPoint& op = it->first;
     595           5 :             const SaplingNoteData& nd = it->second;
     596             : 
     597             :             // skip sent notes
     598           5 :             if (!nd.IsMyNote()) continue;
     599             : 
     600             :             // recover plaintext and address
     601          10 :             auto optNotePtAndAddress = wtx->DecryptSaplingNote(op);
     602           5 :             assert(static_cast<bool>(optNotePtAndAddress));
     603             : 
     604           5 :             const libzcash::SaplingIncomingViewingKey& ivk = *(nd.ivk);
     605           5 :             const libzcash::SaplingNotePlaintext& notePt = optNotePtAndAddress->first;
     606           5 :             const libzcash::SaplingPaymentAddress& pa = optNotePtAndAddress->second;
     607          10 :             auto note = notePt.note(ivk).get();
     608             : 
     609           5 :             saplingEntriesRet.emplace_back(op, pa, note, notePt.memo(), depth);
     610             :         }
     611             :     }
     612           1 : }
     613             : 
     614             : /**
     615             :  * Find notes in the wallet filtered by payment address, min depth and ability to spend and if the notes are locked.
     616             :  * These notes are decrypted and added to the output parameter vector, saplingEntries.
     617             :  */
     618         131 : void SaplingScriptPubKeyMan::GetFilteredNotes(
     619             :     std::vector<SaplingNoteEntry>& saplingEntries,
     620             :     Optional<libzcash::SaplingPaymentAddress>& address,
     621             :     int minDepth,
     622             :     bool ignoreSpent,
     623             :     bool requireSpendingKey,
     624             :     bool ignoreLocked) const
     625             : {
     626         131 :     std::set<libzcash::PaymentAddress> filterAddresses;
     627             : 
     628         231 :     if (address && IsValidPaymentAddress(*address)) {
     629         100 :         filterAddresses.insert(*address);
     630             :     }
     631             : 
     632         131 :     GetFilteredNotes(saplingEntries, filterAddresses, minDepth, INT_MAX, ignoreSpent, requireSpendingKey, ignoreLocked);
     633         131 : }
     634             : 
     635             : /**
     636             :  * Find notes in the wallet filtered by payment addresses, min depth, max depth,
     637             :  * if the note is spent, if a spending key is required, and if the notes are locked.
     638             :  * These notes are decrypted and added to the output parameter vector, saplingEntries.
     639             :  */
     640         142 : void SaplingScriptPubKeyMan::GetFilteredNotes(
     641             :         std::vector<SaplingNoteEntry>& saplingEntries,
     642             :         std::set<libzcash::PaymentAddress>& filterAddresses,
     643             :         int minDepth,
     644             :         int maxDepth,
     645             :         bool ignoreSpent,
     646             :         bool requireSpendingKey,
     647             :         bool ignoreLocked) const
     648             : {
     649         142 :     LOCK(wallet->cs_wallet);
     650             : 
     651       10725 :     for (auto& p : wallet->mapWallet) {
     652       10583 :         const CWalletTx& wtx = p.second;
     653             : 
     654             :         // Filter coinbase/coinstakes transactions that don't have Sapling outputs
     655       14043 :         if ((wtx.IsCoinBase() || wtx.IsCoinStake()) && wtx.mapSaplingNoteData.empty()) {
     656        9842 :             continue;
     657             :         }
     658             : 
     659             :         // Filter the transactions before checking for notes
     660         785 :         const int depth = wtx.GetDepthInMainChain();
     661         785 :         if (!IsFinalTx(wtx.tx, wallet->GetLastBlockHeight() + 1, GetAdjustedTime()) ||
     662         785 :             depth < minDepth || depth > maxDepth) {
     663          44 :             continue;
     664             :         }
     665             : 
     666        2054 :         for (const auto& it : wtx.mapSaplingNoteData) {
     667        1313 :             const SaplingOutPoint& op = it.first;
     668        1313 :             const SaplingNoteData& nd = it.second;
     669             :             // skip sent notes
     670        1608 :             if (!nd.IsMyNote()) continue;
     671             : 
     672             :             // recover plaintext and address
     673        2045 :             auto optNotePtAndAddress = wtx.DecryptSaplingNote(op);
     674        1170 :             assert(static_cast<bool>(optNotePtAndAddress));
     675             : 
     676        1170 :             const libzcash::SaplingIncomingViewingKey& ivk = *(nd.ivk);
     677        1170 :             const libzcash::SaplingNotePlaintext& notePt = optNotePtAndAddress->first;
     678        1170 :             const libzcash::SaplingPaymentAddress& pa = optNotePtAndAddress->second;
     679        3215 :             auto note = notePt.note(ivk).get();
     680             : 
     681             :             // skip notes which belong to a different payment address in the wallet
     682        2630 :             if (!(filterAddresses.empty() || filterAddresses.count(pa))) {
     683         295 :                 continue;
     684             :             }
     685             : 
     686        1122 :             if (ignoreSpent && nd.nullifier && IsSaplingSpent(*nd.nullifier)) {
     687         240 :                 continue;
     688             :             }
     689             : 
     690             :             // skip notes which cannot be spent
     691         882 :             if (requireSpendingKey && !HaveSpendingKeyForPaymentAddress(pa)) {
     692           5 :                 continue;
     693             :             }
     694             : 
     695             :             // skip locked notes.
     696         877 :             if (ignoreLocked && wallet->IsLockedNote(op)) {
     697           2 :                 continue;
     698             :             }
     699             : 
     700         875 :             saplingEntries.emplace_back(op, pa, note, notePt.memo(), depth);
     701             :         }
     702             :     }
     703         142 : }
     704             : 
     705             : /* Return list of available notes and locked notes grouped by sapling address. */
     706           0 : std::map<libzcash::SaplingPaymentAddress, std::vector<SaplingNoteEntry>> SaplingScriptPubKeyMan::ListNotes() const
     707             : {
     708           0 :     std::vector<SaplingNoteEntry> notes;
     709           0 :     Optional<libzcash::SaplingPaymentAddress> dummy = nullopt;
     710           0 :     GetFilteredNotes(notes, dummy, 1, true, true, false);
     711             : 
     712           0 :     std::map<libzcash::SaplingPaymentAddress, std::vector<SaplingNoteEntry>> result;
     713           0 :     for (const auto& note : notes) {
     714           0 :         result[note.address].emplace_back(std::move(note));
     715             :     }
     716           0 :     return result;
     717             : }
     718             : 
     719             : Optional<libzcash::SaplingPaymentAddress>
     720           0 : SaplingScriptPubKeyMan::GetAddressFromInputIfPossible(const uint256& txHash, int index) const
     721             : {
     722           0 :     const CWalletTx* wtx = wallet->GetWalletTx(txHash);
     723           0 :     if (!wtx) return nullopt;
     724           0 :     return GetAddressFromInputIfPossible(wtx, index);
     725             : }
     726             : 
     727             : Optional<libzcash::SaplingPaymentAddress>
     728           0 :         SaplingScriptPubKeyMan::GetAddressFromInputIfPossible(const CWalletTx* wtx, int index) const
     729             : {
     730           0 :     if (!wtx->tx->sapData || wtx->tx->sapData->vShieldedSpend.empty()) return nullopt;
     731             : 
     732           0 :     SpendDescription spendDesc = wtx->tx->sapData->vShieldedSpend.at(index);
     733           0 :     if (!IsSaplingNullifierFromMe(spendDesc.nullifier)) return nullopt;
     734             : 
     735             :     // Knowing that the spent note is from us, we can get the address from
     736           0 :     const SaplingOutPoint& outPoint = mapSaplingNullifiersToNotes.at(spendDesc.nullifier);
     737           0 :     const CWalletTx& txPrev = wallet->mapWallet.at(outPoint.hash);
     738           0 :     return txPrev.mapSaplingNoteData.at(outPoint).address;
     739             : }
     740             : 
     741         191 : bool SaplingScriptPubKeyMan::IsSaplingNullifierFromMe(const uint256& nullifier) const
     742             : {
     743         191 :     LOCK(wallet->cs_wallet);
     744         191 :     auto it = mapSaplingNullifiersToNotes.find(nullifier);
     745         191 :     return it != mapSaplingNullifiersToNotes.end() && wallet->mapWallet.count(it->second.hash);
     746             : }
     747             : 
     748          29 : std::set<std::pair<libzcash::PaymentAddress, uint256>> SaplingScriptPubKeyMan::GetNullifiersForAddresses(
     749             :         const std::set<libzcash::PaymentAddress> & addresses) const
     750             : {
     751          29 :     AssertLockHeld(wallet->cs_wallet);
     752          29 :     std::set<std::pair<libzcash::PaymentAddress, uint256>> nullifierSet;
     753             :     // Sapling ivk -> list of addrs map
     754             :     // (There may be more than one diversified address for a given ivk.)
     755          29 :     std::map<libzcash::SaplingIncomingViewingKey, std::vector<libzcash::SaplingPaymentAddress>> ivkMap;
     756         422 :     for (const auto& addr : addresses) {
     757         393 :         auto saplingAddr = boost::get<libzcash::SaplingPaymentAddress>(&addr);
     758         393 :         if (saplingAddr != nullptr) {
     759         393 :             libzcash::SaplingIncomingViewingKey ivk;
     760         393 :             if (wallet->GetSaplingIncomingViewingKey(*saplingAddr, ivk))
     761         392 :                 ivkMap[ivk].push_back(*saplingAddr);
     762             :         }
     763             :     }
     764        1059 :     for (const auto& txPair : wallet->mapWallet) {
     765        1491 :         for (const auto & noteDataPair : txPair.second.mapSaplingNoteData) {
     766         461 :             const auto& noteData = noteDataPair.second;
     767             : 
     768             :             // Skip sent notes
     769         461 :             if (!noteData.IsMyNote()) continue;
     770         428 :             const libzcash::SaplingIncomingViewingKey& ivk = *(noteData.ivk);
     771             : 
     772         428 :             const auto& nullifier = noteData.nullifier;
     773         431 :             if (nullifier && ivkMap.count(ivk)) {
     774         836 :                 for (const auto & addr : ivkMap[ivk]) {
     775         418 :                     nullifierSet.insert(std::make_pair(addr, nullifier.get()));
     776             :                 }
     777             :             }
     778             :         }
     779             :     }
     780          29 :     return nullifierSet;
     781             : }
     782             : 
     783           0 : Optional<libzcash::SaplingPaymentAddress> SaplingScriptPubKeyMan::GetOutPointAddress(const CWalletTx& tx, const SaplingOutPoint& op) const
     784             : {
     785           0 :     auto it = tx.mapSaplingNoteData.find(op);
     786           0 :     if (it == tx.mapSaplingNoteData.end()) {
     787           0 :         return nullopt;
     788             :     }
     789           0 :     return it->second.address;
     790             : }
     791             : 
     792           0 : CAmount SaplingScriptPubKeyMan::GetOutPointValue(const CWalletTx& tx, const SaplingOutPoint& op) const
     793             : {
     794           0 :     auto it = tx.mapSaplingNoteData.find(op);
     795           0 :     if (it == tx.mapSaplingNoteData.end()) {
     796             :         return 0;
     797             :     }
     798           0 :     return it->second.amount ? *(it->second.amount) : 0;
     799             : }
     800             : 
     801           0 : Optional<std::string> SaplingScriptPubKeyMan::GetOutPointMemo(const CWalletTx& tx, const SaplingOutPoint& op) const
     802             : {
     803           0 :     auto it = tx.mapSaplingNoteData.find(op);
     804           0 :     if (it == tx.mapSaplingNoteData.end() || !static_cast<bool>(it->second.memo))
     805           0 :         return nullopt;
     806           0 :     auto& memo = *(it->second.memo);
     807           0 :     auto end = FindFirstNonZero(memo.rbegin(), memo.rend());
     808           0 :     if (memo[0] <= 0xf4) {
     809           0 :         std::string memoStr(memo.begin(), end.base());
     810           0 :         if (IsValidUTF8(memoStr)) return memoStr;
     811             :     }
     812             :     // non UTF-8 memo. Return as hex encoded raw memo.
     813           0 :     return HexStr(std::vector<unsigned char>(memo.begin(), end.base()));
     814             : }
     815             : 
     816             : Optional<std::pair<
     817             :         libzcash::SaplingNotePlaintext,
     818             :         libzcash::SaplingPaymentAddress>>
     819          99 :         SaplingScriptPubKeyMan::TryToRecoverNote(const CWalletTx& tx, const SaplingOutPoint& op)
     820             : {
     821          99 :     const uint256& txId = tx.GetHash();
     822          99 :     assert(txId == op.hash);
     823             :     // Try to recover it with the ovks (either the common one, if t->shield tx, or the ones from the spends)
     824          99 :     std::set<uint256> ovks;
     825             :     // Get the common OVK for recovering t->shield outputs.
     826             :     // If not already databased, a new one will be generated from the HD seed (this throws an error if the
     827             :     // wallet is currently locked). As the ovk is created when the wallet is unlocked for sending a t->shield
     828             :     // tx for the first time, a failure to decode can happen only if this note was sent (from a t-addr)
     829             :     // using this wallet.dat on another computer (and never sent t->shield txes from this computer).
     830          99 :     if (!tx.tx->vin.empty()) {
     831          46 :         try {
     832          92 :             ovks.emplace(getCommonOVK());
     833           0 :         } catch (...) {
     834           0 :             LogPrintf("WARNING: No CommonOVK found. Some notes might not be correctly recovered. " /* Continued */
     835           0 :                       "Unlock the wallet and call 'viewshieldtransaction %s' to fix.\n", txId.ToString());
     836             :         }
     837             :     } else {
     838         134 :         for (const auto& spend : tx.tx->sapData->vShieldedSpend) {
     839          81 :             const auto& it = mapSaplingNullifiersToNotes.find(spend.nullifier);
     840          81 :             if (it != mapSaplingNullifiersToNotes.end()) {
     841          77 :                 const SaplingOutPoint& prevOut = it->second;
     842          77 :                 const CWalletTx* txPrev = wallet->GetWalletTx(prevOut.hash);
     843          77 :                 if (!txPrev) continue;
     844          77 :                 const auto& itPrev = txPrev->mapSaplingNoteData.find(prevOut);
     845          77 :                 if (itPrev != txPrev->mapSaplingNoteData.end()) {
     846          77 :                     const SaplingNoteData& noteData = itPrev->second;
     847          77 :                     if (!noteData.IsMyNote()) continue;
     848          77 :                     libzcash::SaplingExtendedFullViewingKey extfvk;
     849          77 :                     if (wallet->GetSaplingFullViewingKey(*(noteData.ivk), extfvk)) {
     850         154 :                         ovks.emplace(extfvk.fvk.ovk);
     851             :                     }
     852             :                 }
     853             :             }
     854             :         }
     855             :     }
     856         198 :     return tx.RecoverSaplingNote(op, ovks);
     857             : }
     858             : 
     859           0 : isminetype SaplingScriptPubKeyMan::IsMine(const CWalletTx& wtx, const SaplingOutPoint& op) const
     860             : {
     861           0 :     auto ndIt = wtx.mapSaplingNoteData.find(op);
     862           0 :     if (ndIt != wtx.mapSaplingNoteData.end() && ndIt->second.IsMyNote()) {
     863           0 :         const auto addr = ndIt->second.address;
     864           0 :         return (static_cast<bool>(addr) && HaveSpendingKeyForPaymentAddress(*addr)) ?
     865           0 :                ISMINE_SPENDABLE_SHIELDED : ISMINE_WATCH_ONLY_SHIELDED;
     866             :     }
     867             :     return ISMINE_NO;
     868             : }
     869             : 
     870       21370 : CAmount SaplingScriptPubKeyMan::GetCredit(const CWalletTx& tx, const isminefilter& filter, const bool fUnspent) const
     871             : {
     872             :     // If we are not filtering shield data, return
     873       21370 :     if (!(filter & ISMINE_WATCH_ONLY_SHIELDED || filter & ISMINE_SPENDABLE_SHIELDED)) {
     874             :         return 0;
     875             :     }
     876             : 
     877       21521 :     if (!tx.tx->IsShieldedTx() || tx.tx->sapData->vShieldedOutput.empty()) {
     878       21219 :         return 0;
     879             :     }
     880             :     CAmount nCredit = 0;
     881         330 :     for (int i = 0; i < (int) tx.tx->sapData->vShieldedOutput.size(); ++i) {
     882         179 :         SaplingOutPoint op(tx.GetHash(), i);
     883         179 :         if (tx.mapSaplingNoteData.find(op) == tx.mapSaplingNoteData.end()) {
     884          18 :             continue;
     885             :         }
     886             :         // Obtain the noteData and check if the nullifier has being spent or not
     887         268 :         SaplingNoteData noteData = tx.mapSaplingNoteData.at(op);
     888             : 
     889             :         // Skip externally sent notes
     890         233 :         if (!noteData.IsMyNote()) continue;
     891             : 
     892             :         // The nullifier could be null if the wallet was locked when the noteData was created.
     893         137 :         if (noteData.nullifier &&
     894         264 :             (fUnspent && IsSaplingSpent(*noteData.nullifier))) {
     895          30 :             continue; // only unspent
     896             :         }
     897             :         // If we are filtering watch only or we have spend authority add the amount
     898         107 :         if ((filter & ISMINE_WATCH_ONLY_SHIELDED) || (noteData.address && HaveSpendingKeyForPaymentAddress(*noteData.address))) {
     899         107 :             nCredit += noteData.amount ? *noteData.amount : 0;
     900             :         }
     901             :     }
     902             :     return nCredit;
     903             : }
     904             : 
     905        4786 : CAmount SaplingScriptPubKeyMan::GetDebit(const CTransaction& tx, const isminefilter& filter) const
     906             : {
     907             :     // If we are not filtering shield data, return
     908        4786 :     if (!(filter & ISMINE_WATCH_ONLY_SHIELDED || filter & ISMINE_SPENDABLE_SHIELDED)) {
     909             :         return 0;
     910             :     }
     911             : 
     912        9572 :     if (!tx.IsShieldedTx() || tx.sapData->vShieldedSpend.empty()) {
     913        4537 :         return 0;
     914             :     }
     915         249 :     CAmount nDebit = 0;
     916         595 :     for (const SpendDescription& spend : tx.sapData->vShieldedSpend) {
     917         346 :         const auto &it = mapSaplingNullifiersToNotes.find(spend.nullifier);
     918         346 :         if (it != mapSaplingNullifiersToNotes.end()) {
     919             :             // If we have the spend nullifier, it means that this input is ours.
     920             :             // The transaction (and decrypted note data) has been added to the wallet.
     921         151 :             const SaplingOutPoint& op = it->second;
     922         151 :             auto wit = wallet->mapWallet.find(op.hash);
     923         151 :             assert(wit != wallet->mapWallet.end());
     924         151 :             const auto& wtx = wit->second;
     925         151 :             auto nit = wtx.mapSaplingNoteData.find(op);
     926         151 :             assert(nit != wtx.mapSaplingNoteData.end());
     927         151 :             const auto& nd = nit->second;
     928         151 :             assert(nd.IsMyNote());
     929         151 :             assert(static_cast<bool>(nd.amount));
     930             :             // If we are filtering watch only or we have spend authority add the amount
     931         151 :             if ((filter & ISMINE_WATCH_ONLY_SHIELDED) || (nd.address && HaveSpendingKeyForPaymentAddress(*nd.address))) {
     932         151 :                 nDebit += *(nd.amount);
     933             :             }
     934         302 :             if (!Params().GetConsensus().MoneyRange(nDebit))
     935           0 :                 throw std::runtime_error("SaplingScriptPubKeyMan::GetDebit() : value out of range");
     936             :         }
     937             :     }
     938         249 :     return nDebit;
     939             : }
     940             : 
     941           3 : CAmount SaplingScriptPubKeyMan::GetShieldedChange(const CWalletTx& wtx) const
     942             : {
     943           6 :     if (!wtx.tx->IsShieldedTx() || wtx.tx->sapData->vShieldedOutput.empty()) {
     944           0 :         return 0;
     945             :     }
     946           3 :     const uint256& txHash = wtx.GetHash();
     947           3 :     CAmount nChange = 0;
     948           3 :     SaplingOutPoint op{txHash, 0};
     949           9 :     for (uint32_t pos = 0; pos < (uint32_t) wtx.tx->sapData->vShieldedOutput.size(); ++pos) {
     950           6 :         op.n = pos;
     951           6 :         auto it = wtx.mapSaplingNoteData.find(op);
     952           6 :         if (it == wtx.mapSaplingNoteData.end()) continue;
     953           4 :         const auto& nd = it->second;
     954           4 :         if (!nd.IsMyNote() || !static_cast<bool>(nd.address) || !static_cast<bool>(nd.amount)) continue;
     955           4 :         if (IsNoteSaplingChange(op, *(nd.address))) {
     956           2 :             nChange += *(nd.amount);
     957           6 :             if (!Params().GetConsensus().MoneyRange(nChange))
     958           0 :                 throw std::runtime_error("GetShieldedChange() : value out of range");
     959             :         }
     960             :     }
     961             :     return nChange;
     962             : }
     963             : 
     964           5 : bool SaplingScriptPubKeyMan::IsNoteSaplingChange(const SaplingOutPoint& op, libzcash::SaplingPaymentAddress address) const
     965             : {
     966          10 :     LOCK2(wallet->cs_wallet, wallet->cs_KeyStore);
     967          15 :     std::set<libzcash::PaymentAddress> shieldedAddresses = {address};
     968          10 :     std::set<std::pair<libzcash::PaymentAddress, uint256>> nullifierSet = GetNullifiersForAddresses(shieldedAddresses);
     969          10 :     return IsNoteSaplingChange(nullifierSet, address, op);
     970             : }
     971             : 
     972         381 : bool SaplingScriptPubKeyMan::IsNoteSaplingChange(const std::set<std::pair<libzcash::PaymentAddress, uint256>> & nullifierSet,
     973             :                                   const libzcash::PaymentAddress & address,
     974             :                                   const SaplingOutPoint & op) const
     975             : {
     976             :     // A Note is marked as "change" if the address that received it
     977             :     // also spent Notes in the same transaction. This will catch,
     978             :     // for instance:
     979             :     // - Change created by spending fractions of Notes (because
     980             :     //   shieldsendmany sends change to the originating shielded address).
     981             :     // - Notes sent from one address to itself.
     982         381 :     const auto& tx = wallet->mapWallet.at(op.hash);
     983         381 :     if (tx.tx->sapData) {
     984         437 :         for (const SpendDescription& spend : tx.tx->sapData->vShieldedSpend) {
     985         124 :             if (nullifierSet.count(std::make_pair(address, spend.nullifier))) {
     986           6 :                 return true;
     987             :             }
     988             :         }
     989             :     }
     990             :     return false;
     991             : }
     992             : 
     993         304 : void SaplingScriptPubKeyMan::GetSaplingNoteWitnesses(const std::vector<SaplingOutPoint>& notes,
     994             :                                       std::vector<Optional<SaplingWitness>>& witnesses,
     995             :                                       uint256& final_anchor) const
     996             : {
     997         304 :     LOCK(wallet->cs_wallet);
     998         304 :     witnesses.resize(notes.size());
     999         608 :     Optional<uint256> rt;
    1000         304 :     int i = 0;
    1001       19382 :     for (SaplingOutPoint note : notes) {
    1002       19078 :         auto it = wallet->mapWallet.find(note.hash);
    1003       19078 :         if (it != wallet->mapWallet.end()) {
    1004       19077 :             auto nit = it->second.mapSaplingNoteData.find(note);
    1005       19077 :             if (nit != it->second.mapSaplingNoteData.end() &&
    1006       19075 :                     nit->second.witnesses.size() > 0) {
    1007       19068 :                 witnesses[i] = nit->second.witnesses.front();
    1008       19068 :                 if (!rt) {
    1009         592 :                     rt = witnesses[i]->root();
    1010             :                 } else {
    1011       37544 :                     assert(*rt == witnesses[i]->root());
    1012             :                 }
    1013             :             }
    1014             :         }
    1015       19078 :         i++;
    1016             :     }
    1017             :     // All returned witnesses have the same anchor
    1018         304 :     if (rt) {
    1019         296 :         final_anchor = *rt;
    1020             :     }
    1021         304 : }
    1022             : 
    1023      277356 : bool SaplingScriptPubKeyMan::UpdatedNoteData(const CWalletTx& wtxIn, CWalletTx& wtx)
    1024             : {
    1025      277356 :     bool unchangedSaplingFlag = (wtxIn.mapSaplingNoteData.empty() || wtxIn.mapSaplingNoteData == wtx.mapSaplingNoteData);
    1026        1112 :     if (!unchangedSaplingFlag) {
    1027        2224 :         auto tmp = wtxIn.mapSaplingNoteData;
    1028             :         // Ensure we keep any cached witnesses we may already have
    1029             : 
    1030        1166 :         for (const std::pair <SaplingOutPoint, SaplingNoteData> nd : wtx.mapSaplingNoteData) {
    1031         108 :             if (tmp.count(nd.first) && nd.second.witnesses.size() > 0) {
    1032          21 :                 tmp.at(nd.first).witnesses.assign(
    1033             :                         nd.second.witnesses.cbegin(), nd.second.witnesses.cend());
    1034             :             }
    1035          54 :             tmp.at(nd.first).witnessHeight = nd.second.witnessHeight;
    1036             :         }
    1037             : 
    1038             :         // Now copy over the updated note data
    1039        1112 :         wtx.mapSaplingNoteData = tmp;
    1040             :     }
    1041             : 
    1042      277356 :     return !unchangedSaplingFlag;
    1043             : }
    1044             : 
    1045          12 : void SaplingScriptPubKeyMan::ClearNoteWitnessCache()
    1046             : {
    1047          12 :     LOCK(wallet->cs_wallet);
    1048         166 :     for (std::pair<const uint256, CWalletTx>& wtxItem : wallet->mapWallet) {
    1049         165 :         for (mapSaplingNoteData_t::value_type& item : wtxItem.second.mapSaplingNoteData) {
    1050          11 :             item.second.witnesses.clear();
    1051          11 :             item.second.witnessHeight = -1;
    1052             :         }
    1053             :     }
    1054          12 :     nWitnessCacheSize = 0;
    1055          12 :     nWitnessCacheNeedsUpdate = true;
    1056          12 : }
    1057             : 
    1058        1004 : Optional<libzcash::SaplingExtendedSpendingKey> SaplingScriptPubKeyMan::GetSpendingKeyForPaymentAddress(const libzcash::SaplingPaymentAddress &addr) const
    1059             : {
    1060        1004 :     libzcash::SaplingExtendedSpendingKey extsk;
    1061        1004 :     if (wallet->GetSaplingExtendedSpendingKey(addr, extsk)) {
    1062        1004 :         return extsk;
    1063             :     } else {
    1064           0 :         return nullopt;
    1065             :     }
    1066             : }
    1067             : 
    1068           3 : Optional<libzcash::SaplingExtendedFullViewingKey> SaplingScriptPubKeyMan::GetViewingKeyForPaymentAddress(
    1069             :         const libzcash::SaplingPaymentAddress &addr) const
    1070             : {
    1071           3 :     libzcash::SaplingIncomingViewingKey ivk;
    1072           3 :     libzcash::SaplingExtendedFullViewingKey extfvk;
    1073             : 
    1074           6 :     if (wallet->GetSaplingIncomingViewingKey(addr, ivk) &&
    1075           3 :         wallet->GetSaplingFullViewingKey(ivk, extfvk))
    1076             :     {
    1077           3 :         return extfvk;
    1078             :     } else {
    1079           0 :         return nullopt;
    1080             :     }
    1081             : }
    1082             : 
    1083             : //! TODO: Should be Sapling address format, SaplingPaymentAddress
    1084             : // Generate a new Sapling spending key and return its public payment address
    1085        1245 : libzcash::SaplingPaymentAddress SaplingScriptPubKeyMan::GenerateNewSaplingZKey()
    1086             : {
    1087        1245 :     LOCK(wallet->cs_wallet); // mapSaplingZKeyMetadata
    1088             : 
    1089             :     // Try to get the seed
    1090        2490 :     CKey seedKey;
    1091        1245 :     if (!wallet->GetKey(hdChain.GetID(), seedKey))
    1092           2 :         throw std::runtime_error(std::string(__func__) + ": HD seed not found");
    1093             : 
    1094        3733 :     HDSeed seed(seedKey.GetPrivKey());
    1095        1244 :     auto m = libzcash::SaplingExtendedSpendingKey::Master(seed);
    1096             : 
    1097             :     // We use a fixed keypath scheme of m/32'/coin_type'/account'
    1098             :     // Derive m/32'
    1099        1244 :     auto m_32h = m.Derive(32 | ZIP32_HARDENED_KEY_LIMIT);
    1100             :     // Derive m/32'/coin_type'
    1101        1244 :     auto m_32h_cth = m_32h.Derive(119 | ZIP32_HARDENED_KEY_LIMIT);
    1102             : 
    1103             :     // Derive account key at next index, skip keys already known to the wallet
    1104        1244 :     libzcash::SaplingExtendedSpendingKey xsk;
    1105        1244 :     do {
    1106        1244 :         xsk = m_32h_cth.Derive(hdChain.nExternalChainCounter | ZIP32_HARDENED_KEY_LIMIT);
    1107        1244 :         hdChain.nExternalChainCounter++; // Increment childkey index
    1108        1244 :     } while (wallet->HaveSaplingSpendingKey(xsk.ToXFVK()));
    1109             : 
    1110             :     // Update the chain model in the database
    1111        1244 :     if (!WalletBatch(wallet->GetDBHandle()).WriteHDChain(hdChain))
    1112           0 :         throw std::runtime_error(std::string(__func__) + ": Writing HD chain model failed");
    1113             : 
    1114             :     // Create new metadata
    1115        1244 :     int64_t nCreationTime = GetTime();
    1116        1244 :     auto ivk = xsk.expsk.full_viewing_key().in_viewing_key();
    1117        2488 :     CKeyMetadata metadata(nCreationTime);
    1118        1244 :     metadata.key_origin.path.push_back(32 | BIP32_HARDENED_KEY_LIMIT);
    1119        1244 :     metadata.key_origin.path.push_back(119 | BIP32_HARDENED_KEY_LIMIT);
    1120        1244 :     metadata.key_origin.path.push_back(hdChain.nExternalChainCounter | BIP32_HARDENED_KEY_LIMIT);
    1121        1244 :     metadata.hd_seed_id = hdChain.GetID();
    1122        1244 :     mapSaplingZKeyMetadata[ivk] = metadata;
    1123             : 
    1124        1244 :     if (!AddSaplingZKey(xsk)) {
    1125           0 :         throw std::runtime_error(std::string(__func__) + ": AddSaplingZKey failed");
    1126             :     }
    1127             :     // return default sapling payment address.
    1128        2488 :     return xsk.DefaultAddress();
    1129             : }
    1130             : 
    1131           0 : int64_t SaplingScriptPubKeyMan::GetKeyCreationTime(const libzcash::SaplingIncomingViewingKey& ivk)
    1132             : {
    1133           0 :     auto it = mapSaplingZKeyMetadata.find(ivk);
    1134           0 :     return it != mapSaplingZKeyMetadata.end() ? it->second.nCreateTime : 0;
    1135             : }
    1136             : 
    1137         395 : void SaplingScriptPubKeyMan::GetConflicts(const CWalletTx& wtx, std::set<uint256>& result) const
    1138             : {
    1139         395 :     AssertLockHeld(wallet->cs_wallet);
    1140         395 :     std::pair<TxNullifiers::const_iterator, TxNullifiers::const_iterator> range_o;
    1141             : 
    1142         395 :     if (wtx.tx->IsShieldedTx()) {
    1143           8 :         for (const SpendDescription& spend : wtx.tx->sapData->vShieldedSpend) {
    1144           2 :             const uint256& nullifier = spend.nullifier;
    1145           2 :             if (mapTxSaplingNullifiers.count(nullifier) <= 1) {
    1146           1 :                 continue;  // No conflict if zero or one spends
    1147             :             }
    1148           1 :             range_o = mapTxSaplingNullifiers.equal_range(nullifier);
    1149           3 :             for (TxNullifiers::const_iterator it = range_o.first; it != range_o.second; ++it) {
    1150           2 :                 result.insert(it->second);
    1151             :             }
    1152             :         }
    1153             :     }
    1154         395 : }
    1155             : 
    1156           3 : KeyAddResult SaplingScriptPubKeyMan::AddViewingKeyToWallet(const libzcash::SaplingExtendedFullViewingKey &extfvk) const {
    1157           3 :     if (wallet->HaveSaplingSpendingKey(extfvk)) {
    1158             :         return SpendingKeyExists;
    1159           3 :     } else if (wallet->HaveSaplingFullViewingKey(extfvk.fvk.in_viewing_key())) {
    1160             :         return KeyAlreadyExists;
    1161           3 :     } else if (wallet->AddSaplingFullViewingKey(extfvk)) {
    1162             :         return KeyAdded;
    1163             :     } else {
    1164           0 :         return KeyNotAdded;
    1165             :     }
    1166             : }
    1167             : 
    1168        1007 : KeyAddResult SaplingScriptPubKeyMan::AddSpendingKeyToWallet(
    1169             :         const Consensus::Params &params,
    1170             :         const libzcash::SaplingExtendedSpendingKey &sk,
    1171             :         int64_t nTime)
    1172             : {
    1173        1007 :     auto extfvk = sk.ToXFVK();
    1174        1007 :     auto ivk = extfvk.fvk.in_viewing_key();
    1175        1007 :     {
    1176             :         //LogPrint(BCLog::SAPLING, "Importing shielded addr %s...\n", KeyIO::EncodePaymentAddress(sk.DefaultAddress()));
    1177             :         // Don't throw error in case a key is already there
    1178        1007 :         if (wallet->HaveSaplingSpendingKey(extfvk)) {
    1179             :             return KeyAlreadyExists;
    1180             :         } else {
    1181        1006 :             if (!wallet-> AddSaplingZKey(sk)) {
    1182             :                 return KeyNotAdded;
    1183             :             }
    1184             : 
    1185        1006 :             int64_t nTimeToSet;
    1186             :             // Sapling addresses can't have been used in transactions prior to activation.
    1187        1006 :             if (params.vUpgrades[Consensus::UPGRADE_V5_0].nActivationHeight == Consensus::NetworkUpgrade::ALWAYS_ACTIVE) {
    1188           0 :                 nTimeToSet = nTime;
    1189             :             } else {
    1190             :                 // TODO: Update epoch before release v5.
    1191             :                 // 154051200 seconds from epoch is Friday, 26 October 2018 00:00:00 GMT - definitely before Sapling activates
    1192        1006 :                 nTimeToSet = std::max((int64_t) 154051200, nTime);
    1193             :             }
    1194             : 
    1195        2012 :             mapSaplingZKeyMetadata[ivk] = CKeyMetadata(nTimeToSet);
    1196        1006 :             return KeyAdded;
    1197             :         }
    1198             :     }
    1199             : }
    1200             : 
    1201             : // Add spending key to keystore
    1202        2264 : bool SaplingScriptPubKeyMan::AddSaplingZKey(
    1203             :         const libzcash::SaplingExtendedSpendingKey &sk)
    1204             : {
    1205        2264 :     AssertLockHeld(wallet->cs_wallet); // mapSaplingZKeyMetadata
    1206             : 
    1207        2264 :     if (!IsEnabled()) {
    1208           0 :         return error("%s: Sapling spkm not enabled", __func__ );
    1209             :     }
    1210             : 
    1211        2264 :     if (!AddSaplingSpendingKey(sk)) {
    1212             :         return false;
    1213             :     }
    1214             : 
    1215        2264 :     if (!wallet->IsCrypted()) {
    1216        2262 :         auto ivk = sk.expsk.full_viewing_key().in_viewing_key();
    1217        2262 :         return WalletBatch(wallet->GetDBHandle()).WriteSaplingZKey(ivk, sk, mapSaplingZKeyMetadata[ivk]);
    1218             :     }
    1219             : 
    1220             :     return true;
    1221             : }
    1222             : 
    1223        2264 : bool SaplingScriptPubKeyMan::AddSaplingSpendingKey(
    1224             :         const libzcash::SaplingExtendedSpendingKey &sk)
    1225             : {
    1226        2264 :     {
    1227        2264 :         LOCK(wallet->cs_KeyStore);
    1228        2264 :         if (!wallet->IsCrypted()) {
    1229        4524 :             return wallet->AddSaplingSpendingKey(sk); // keystore
    1230             :         }
    1231             : 
    1232           2 :         if (wallet->IsLocked()) {
    1233             :             return false;
    1234             :         }
    1235             : 
    1236           4 :         std::vector<unsigned char> vchCryptedSecret;
    1237           4 :         CSecureDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
    1238           2 :         ss << sk;
    1239           4 :         CKeyingMaterial vchSecret(ss.begin(), ss.end());
    1240           2 :         auto extfvk = sk.ToXFVK();
    1241           2 :         if (!EncryptSecret(wallet->GetEncryptionKey(), vchSecret, extfvk.fvk.GetFingerprint(), vchCryptedSecret)) {
    1242           0 :             return false;
    1243             :         }
    1244             : 
    1245           2 :         if (!AddCryptedSaplingSpendingKeyDB(extfvk, vchCryptedSecret)) {
    1246             :             return false;
    1247             :         }
    1248             :     }
    1249           2 :     return true;
    1250             : }
    1251             : 
    1252             : // Add payment address -> incoming viewing key map entry
    1253           1 : bool SaplingScriptPubKeyMan::AddSaplingIncomingViewingKey(
    1254             :         const libzcash::SaplingIncomingViewingKey &ivk,
    1255             :         const libzcash::SaplingPaymentAddress &addr)
    1256             : {
    1257           1 :     AssertLockHeld(wallet->cs_wallet); // mapSaplingZKeyMetadata
    1258             : 
    1259           1 :     if (!wallet->AddSaplingIncomingViewingKey(ivk, addr)) {
    1260             :         return false;
    1261             :     }
    1262             : 
    1263           1 :     if (!wallet->IsCrypted()) {
    1264           1 :         return WalletBatch(wallet->GetDBHandle()).WriteSaplingPaymentAddress(addr, ivk);
    1265             :     }
    1266             : 
    1267             :     return true;
    1268             : }
    1269             : 
    1270           7 : bool SaplingScriptPubKeyMan::EncryptSaplingKeys(CKeyingMaterial& vMasterKeyIn)
    1271             : {
    1272           7 :     AssertLockHeld(wallet->cs_wallet); // mapSaplingSpendingKeys
    1273             : 
    1274         109 :     for (SaplingSpendingKeyMap::value_type& mSaplingSpendingKey : wallet->mapSaplingSpendingKeys) {
    1275         102 :         const libzcash::SaplingExtendedSpendingKey &sk = mSaplingSpendingKey.second;
    1276         204 :         CSecureDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
    1277         102 :         ss << sk;
    1278         204 :         CKeyingMaterial vchSecret(ss.begin(), ss.end());
    1279         102 :         auto extfvk = sk.ToXFVK();
    1280         204 :         std::vector<unsigned char> vchCryptedSecret;
    1281         102 :         if (!EncryptSecret(vMasterKeyIn, vchSecret, extfvk.fvk.GetFingerprint(), vchCryptedSecret)) {
    1282           0 :             return false;
    1283             :         }
    1284         102 :         if (!AddCryptedSaplingSpendingKeyDB(extfvk, vchCryptedSecret)) {
    1285             :             return false;
    1286             :         }
    1287             :     }
    1288           7 :     wallet->mapSaplingSpendingKeys.clear();
    1289           7 :     return true;
    1290             : }
    1291             : 
    1292         104 : bool SaplingScriptPubKeyMan::AddCryptedSaplingSpendingKeyDB(const libzcash::SaplingExtendedFullViewingKey &extfvk,
    1293             :                                            const std::vector<unsigned char> &vchCryptedSecret)
    1294             : {
    1295         104 :     if (!wallet->AddCryptedSaplingSpendingKey(extfvk, vchCryptedSecret))
    1296             :         return false;
    1297         104 :     {
    1298         208 :         LOCK(wallet->cs_wallet);
    1299         104 :         if (wallet->encrypted_batch) {
    1300         102 :             return wallet->encrypted_batch->WriteCryptedSaplingZKey(extfvk,
    1301             :                                                                 vchCryptedSecret,
    1302         204 :                                                                 mapSaplingZKeyMetadata[extfvk.fvk.in_viewing_key()]);
    1303             :         } else {
    1304           6 :             return WalletBatch(wallet->GetDBHandle()).WriteCryptedSaplingZKey(extfvk,
    1305             :                                                                     vchCryptedSecret,
    1306           4 :                                                                     mapSaplingZKeyMetadata[extfvk.fvk.in_viewing_key()]);
    1307             :         }
    1308             :     }
    1309             :     return false;
    1310             : }
    1311             : 
    1312        4630 : bool SaplingScriptPubKeyMan::HaveSpendingKeyForPaymentAddress(const libzcash::SaplingPaymentAddress &zaddr) const
    1313             : {
    1314        4630 :     libzcash::SaplingIncomingViewingKey ivk;
    1315        4630 :     libzcash::SaplingExtendedFullViewingKey extfvk;
    1316             : 
    1317        9256 :     return wallet->GetSaplingIncomingViewingKey(zaddr, ivk) &&
    1318        9256 :            wallet->GetSaplingFullViewingKey(ivk, extfvk) &&
    1319        4626 :            wallet->HaveSaplingSpendingKey(extfvk);
    1320             : }
    1321             : 
    1322          15 : bool SaplingScriptPubKeyMan::PaymentAddressBelongsToWallet(const libzcash::SaplingPaymentAddress &zaddr) const
    1323             : {
    1324          15 :     libzcash::SaplingIncomingViewingKey ivk;
    1325             : 
    1326             :     // If we have a SaplingExtendedSpendingKey in the wallet, then we will
    1327             :     // also have the corresponding SaplingExtendedFullViewingKey.
    1328          29 :     return wallet->GetSaplingIncomingViewingKey(zaddr, ivk) &&
    1329          14 :            wallet->HaveSaplingFullViewingKey(ivk);
    1330             : }
    1331             : 
    1332             : ///////////////////// Load ////////////////////////////////////////
    1333             : 
    1334           2 : bool SaplingScriptPubKeyMan::LoadCryptedSaplingZKey(
    1335             :         const libzcash::SaplingExtendedFullViewingKey &extfvk,
    1336             :         const std::vector<unsigned char> &vchCryptedSecret)
    1337             : {
    1338           2 :     return wallet->AddCryptedSaplingSpendingKey(extfvk, vchCryptedSecret);
    1339             : }
    1340             : 
    1341          38 : bool SaplingScriptPubKeyMan::LoadSaplingZKeyMetadata(const libzcash::SaplingIncomingViewingKey &ivk, const CKeyMetadata &meta)
    1342             : {
    1343          38 :     AssertLockHeld(wallet->cs_wallet); // mapSaplingZKeyMetadata
    1344          38 :     mapSaplingZKeyMetadata[ivk] = meta;
    1345          38 :     return true;
    1346             : }
    1347             : 
    1348          36 : bool SaplingScriptPubKeyMan::LoadSaplingZKey(const libzcash::SaplingExtendedSpendingKey &key)
    1349             : {
    1350          36 :     return wallet->AddSaplingSpendingKey(key);
    1351             : }
    1352             : 
    1353           1 : bool SaplingScriptPubKeyMan::LoadSaplingPaymentAddress(
    1354             :         const libzcash::SaplingPaymentAddress &addr,
    1355             :         const libzcash::SaplingIncomingViewingKey &ivk)
    1356             : {
    1357           1 :     return wallet->AddSaplingIncomingViewingKey(ivk, addr);
    1358             : }
    1359             : 
    1360             : ///////////////////// Setup ///////////////////////////////////////
    1361             : 
    1362         237 : bool SaplingScriptPubKeyMan::SetupGeneration(const CKeyID& keyID, bool force, bool memonly)
    1363             : {
    1364         237 :     SetHDSeed(keyID, force, memonly);
    1365         237 :     return true;
    1366             : }
    1367             : 
    1368           4 : void SaplingScriptPubKeyMan::SetHDSeed(const CPubKey& seed, bool force, bool memonly)
    1369             : {
    1370           4 :     SetHDSeed(seed.GetID(), force, memonly);
    1371           4 : }
    1372             : 
    1373         241 : void SaplingScriptPubKeyMan::SetHDSeed(const CKeyID& keyID, bool force, bool memonly)
    1374             : {
    1375         241 :     if (!hdChain.IsNull() && !force)
    1376           0 :         throw std::runtime_error(std::string(__func__) + ": sapling trying to set a hd seed on an already created chain");
    1377             : 
    1378         241 :     LOCK(wallet->cs_wallet);
    1379             :     // store the keyid (hash160) together with
    1380             :     // the child index counter in the database
    1381             :     // as a hdChain object
    1382         241 :     CHDChain newHdChain(HDChain::ChainCounterType::Sapling);
    1383         241 :     if (!newHdChain.SetSeed(keyID) ) {
    1384           0 :         throw std::runtime_error(std::string(__func__) + ": set sapling hd seed failed");
    1385             :     }
    1386             : 
    1387         241 :     SetHDChain(newHdChain, memonly);
    1388             : 
    1389             :     // Update the commonOVK to recover t->shield notes
    1390         241 :     commonOVK = getCommonOVKFromSeed();
    1391         478 :     if (!memonly && !WalletBatch(wallet->GetDBHandle()).WriteSaplingCommonOVK(*commonOVK)) {
    1392           0 :         throw std::runtime_error(std::string(__func__) + ": writing sapling commonOVK failed");
    1393             :     }
    1394         241 : }
    1395             : 
    1396         400 : void SaplingScriptPubKeyMan::SetHDChain(CHDChain& chain, bool memonly)
    1397             : {
    1398         400 :     LOCK(wallet->cs_wallet);
    1399         400 :     if (chain.chainType != HDChain::ChainCounterType::Sapling)
    1400           0 :         throw std::runtime_error(std::string(__func__) + ": trying to store an invalid chain type");
    1401             : 
    1402         637 :     if (!memonly && !WalletBatch(wallet->GetDBHandle()).WriteHDChain(chain))
    1403           0 :         throw std::runtime_error(std::string(__func__) + ": writing sapling chain failed");
    1404             : 
    1405         400 :     hdChain = chain;
    1406             : 
    1407             :     // Sanity check
    1408         400 :     if (!wallet->HaveKey(hdChain.GetID()))
    1409           0 :         throw std::runtime_error(std::string(__func__) + ": Not found sapling seed in wallet");
    1410         400 : }
    1411             : 
    1412        2140 : uint256 SaplingScriptPubKeyMan::getCommonOVK()
    1413             : {
    1414             :     // If already loaded, return it
    1415        2140 :     if (commonOVK) return *commonOVK;
    1416             : 
    1417             :     // Else, look for it in the database
    1418           0 :     uint256 ovk;
    1419           0 :     if (WalletBatch(wallet->GetDBHandle()).ReadSaplingCommonOVK(ovk)) {
    1420           0 :         commonOVK = std::move(ovk);
    1421           0 :         return *commonOVK;
    1422             :     }
    1423             : 
    1424             :     // Otherwise create one. This throws if the wallet is encrypted.
    1425             :     // So we should always call this after unlocking the wallet during a spend
    1426             :     // from a transparent address, or when changing/setting the HD seed.
    1427           0 :     commonOVK = getCommonOVKFromSeed();
    1428           0 :     if (!WalletBatch(wallet->GetDBHandle()).WriteSaplingCommonOVK(*commonOVK)) {
    1429           0 :         throw std::runtime_error("Unable to write sapling Common OVK to database");
    1430             :     }
    1431           0 :     return *commonOVK;
    1432             : }
    1433             : 
    1434         241 : uint256 SaplingScriptPubKeyMan::getCommonOVKFromSeed() const
    1435             : {
    1436             :     // Sending from a t-address, which we don't have an ovk for. Instead,
    1437             :     // generate a common one from the HD seed. This ensures the data is
    1438             :     // recoverable, while keeping it logically separate from the ZIP 32
    1439             :     // Sapling key hierarchy, which the user might not be using.
    1440         241 :     CKey key;
    1441         241 :     if (!wallet->GetKey(GetHDChain().GetID(), key)) {
    1442           0 :         throw std::runtime_error("HD seed not found, wallet must be un-locked");
    1443             :     }
    1444         723 :     HDSeed seed{key.GetPrivKey()};
    1445         482 :     return ovkForShieldingFromTaddr(seed);
    1446             : }

Generated by: LCOV version 1.14