LCOV - code coverage report
Current view: top level - src/sapling - saplingscriptpubkeyman.h (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 31 31 100.0 %
Date: 2025-02-23 09:33:43 Functions: 5 5 100.0 %

          Line data    Source code
       1             : // Copyright (c) 2020-2021 The PIVX Core developers
       2             : // Distributed under the MIT software license, see the accompanying
       3             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       4             : 
       5             : #ifndef PIVX_SAPLING_SAPLINGSCRIPTPUBKEYMAN_H
       6             : #define PIVX_SAPLING_SAPLINGSCRIPTPUBKEYMAN_H
       7             : 
       8             : #include "consensus/consensus.h"
       9             : #include "sapling/incrementalmerkletree.h"
      10             : #include "sapling/note.h"
      11             : #include "uint256.h"
      12             : #include "wallet/hdchain.h"
      13             : #include "wallet/scriptpubkeyman.h"
      14             : #include "wallet/wallet.h"
      15             : #include "wallet/walletdb.h"
      16             : #include <map>
      17             : 
      18             : //! Size of witness cache
      19             : //  Should be large enough that we can expect not to reorg beyond our cache
      20             : //  unless there is some exceptional network disruption.
      21             : static const unsigned int WITNESS_CACHE_SIZE = DEFAULT_MAX_REORG_DEPTH + 1;
      22             : 
      23             : class CBlock;
      24             : class CBlockIndex;
      25             : 
      26             : /** Sapling note, its location in a transaction, and number of confirmations. */
      27        1895 : struct SaplingNoteEntry
      28             : {
      29         880 :     explicit SaplingNoteEntry(const SaplingOutPoint& _op,
      30             :                               const libzcash::SaplingPaymentAddress& _addr,
      31             :                               const libzcash::SaplingNote& _note,
      32             :                               const std::array<unsigned char, ZC_MEMO_SIZE>& _memo,
      33         880 :                               const int _conf) :
      34             :                               op(_op), address(_addr), note(_note), memo(_memo),
      35         880 :                               confirmations(_conf) { }
      36             :     SaplingOutPoint op;
      37             :     libzcash::SaplingPaymentAddress address;
      38             :     libzcash::SaplingNote note;
      39             :     std::array<unsigned char, ZC_MEMO_SIZE> memo;
      40             :     int confirmations;
      41             : };
      42             : 
      43       19059 : class SaplingNoteData
      44             : {
      45             : public:
      46             : 
      47        4319 :     SaplingNoteData() : nullifier() { }
      48             :     explicit SaplingNoteData(const libzcash::SaplingIncomingViewingKey& _ivk) : ivk {_ivk}, nullifier() { }
      49             :     SaplingNoteData(const libzcash::SaplingIncomingViewingKey& _ivk, const uint256& n) : ivk {_ivk}, nullifier(n) { }
      50             : 
      51             :     /* witnesses/ivk: only for own (received) outputs */
      52             :     std::list<SaplingWitness> witnesses;
      53             : 
      54             :     Optional<libzcash::SaplingIncomingViewingKey> ivk {nullopt};
      55      893720 :     inline bool IsMyNote() const { return ivk != nullopt; }
      56             : 
      57             :     /**
      58             :      * Cached note amount.
      59             :      * It will be loaded the first time that the note is decrypted (when the tx is added to the wallet).
      60             :      */
      61             :     Optional<CAmount> amount{nullopt};
      62             : 
      63             :     /**
      64             :      * Cached shielded address
      65             :      * It will be loaded the first time that the note is decrypted (when the tx is added to the wallet)
      66             :      */
      67             :      Optional<libzcash::SaplingPaymentAddress> address{nullopt};
      68             : 
      69             :      /**
      70             :       * Cached note memo (only for non-empty memo)
      71             :       * It will be loaded the first time that the note is decrypted (when the tx is added to the wallet)
      72             :       */
      73             :      Optional<std::array<unsigned char, ZC_MEMO_SIZE>> memo{nullopt};
      74             : 
      75             :     /**
      76             :      * Block height corresponding to the most current witness.
      77             :      *
      78             :      * When we first create a SaplingNoteData in SaplingScriptPubKeyMan::FindMySaplingNotes, this is set to
      79             :      * -1 as a placeholder. The next time CWallet::BlockConnected/CWallet::BlockDisconnected is called, we can
      80             :      * determine what height the witness cache for this note is valid for (even
      81             :      * if no witnesses were cached), and so can set the correct value in
      82             :      * SaplingScriptPubKeyMan::IncrementNoteWitnesses and SaplingScriptPubKeyMan::DecrementNoteWitnesses.
      83             :      */
      84             :     int witnessHeight{-1};
      85             : 
      86             :     /**
      87             :      * Cached note nullifier. May not be set if the wallet was not unlocked when
      88             :      * this SaplingNoteData was created. If not set, we always assume that the
      89             :      * note has not been spent.
      90             :      *
      91             :      * It's okay to cache the nullifier in the wallet, because we are storing
      92             :      * the spending key there too, which could be used to derive this.
      93             :      * If the wallet is encrypted, this means that someone with access to the
      94             :      * locked wallet cannot spend notes, but can connect received notes to the
      95             :      * transactions they are spent in. This is the same security semantics as
      96             :      * for transparent addresses.
      97             :      */
      98             :     Optional<uint256> nullifier;
      99             : 
     100        4556 :     SERIALIZE_METHODS(SaplingNoteData, obj)
     101             :     {
     102        2278 :         int nVersion = s.GetVersion();
     103        2278 :         if (!(s.GetType() & SER_GETHASH)) {
     104        2278 :             READWRITE(nVersion);
     105             :         }
     106        2278 :         READWRITE(obj.ivk);
     107        2278 :         READWRITE(obj.nullifier);
     108        2278 :         READWRITE(obj.witnesses);
     109        2278 :         READWRITE(obj.witnessHeight);
     110        2278 :         READWRITE(obj.amount);
     111        2278 :         READWRITE(obj.address);
     112        2278 :         READWRITE(obj.memo);
     113        2278 :     }
     114             : 
     115         850 :     friend bool operator==(const SaplingNoteData& a, const SaplingNoteData& b) {
     116        1694 :         return (a.ivk == b.ivk &&
     117         844 :                 a.nullifier == b.nullifier &&
     118         833 :                 a.witnessHeight == b.witnessHeight &&
     119        1612 :                 a.amount == b.amount &&
     120        2462 :                 a.address == b.address &&
     121         806 :                 a.memo == b.memo);
     122             :     }
     123             : 
     124             :     friend bool operator!=(const SaplingNoteData& a, const SaplingNoteData& b) {
     125             :         return !(a == b);
     126             :     }
     127             : };
     128             : 
     129             : enum KeyAddResult {
     130             :     SpendingKeyExists,
     131             :     KeyAlreadyExists,
     132             :     KeyAdded,
     133             :     KeyNotAdded,
     134             : };
     135             : 
     136             : typedef std::map<SaplingOutPoint, SaplingNoteData> mapSaplingNoteData_t;
     137             : 
     138             : /*
     139             :  * Sapling keys manager
     140             :  * A class implementing SaplingScriptPubKeyMan manages all sapling keys and Notes used in a wallet.
     141             :  * It is responsible for the decryption of notes and caching metadata.
     142             :  * A SaplingScriptPubKeyMan will be able to give out notes to be used, as well as marking
     143             :  * when a note has been used. It also handles when and how to store a sapling OutputDescription
     144             :  * and its related keys, including encryption.
     145             :  * A ScriptPubKeyMan will also update notes witnesses, and keep track of nullifiers.
     146             :  */
     147             : class SaplingScriptPubKeyMan {
     148             : 
     149             : public:
     150        1010 :     explicit SaplingScriptPubKeyMan(CWallet *parent) : wallet(parent) {}
     151             : 
     152         504 :     ~SaplingScriptPubKeyMan() {};
     153             : 
     154             :     /**
     155             :      * Keep track of the used nullifier.
     156             :      */
     157             :     void AddToSaplingSpends(const uint256& nullifier, const uint256& wtxid);
     158             :     bool IsSaplingSpent(const SaplingOutPoint& op) const;
     159             :     bool IsSaplingSpent(const uint256& nullifier) const;
     160             : 
     161             :     /**
     162             :      * Build the old witness chain.
     163             :      */
     164             :     bool BuildWitnessChain(const CBlockIndex* pTargetBlock, const Consensus::Params& params, std::string& errorStr);
     165             : 
     166             :     /**
     167             :      * pindex is the new tip being connected.
     168             :      */
     169             :     void IncrementNoteWitnesses(const CBlockIndex* pindex,
     170             :                                 const CBlock* pblock,
     171             :                                 SaplingMerkleTree& saplingTree);
     172             :     /**
     173             :      * pindex is the old tip being disconnected.
     174             :      */
     175             :     void DecrementNoteWitnesses(const CBlockIndex* pindex);
     176             : 
     177             :     /**
     178             :      * Update mapSaplingNullifiersToNotes
     179             :      * with the cached nullifiers in this tx.
     180             :      */
     181             :     void UpdateNullifierNoteMapWithTx(const CWalletTx& wtx);
     182             : 
     183             :     /**
     184             :      *  Update mapSaplingNullifiersToNotes, and NoteData of a specific outpoint,
     185             :      *  directly with nullifier provided by the caller.
     186             :      */
     187             :     void UpdateSaplingNullifierNoteMap(SaplingNoteData& nd, const SaplingOutPoint& op, const Optional<uint256>& nullifier);
     188             : 
     189             :     /**
     190             :      *  Update mapSaplingNullifiersToNotes, computing the nullifier
     191             :      *  from a cached witness if necessary.
     192             :      */
     193             :     void UpdateSaplingNullifierNoteMapWithTx(CWalletTx& wtx);
     194             : 
     195             :     /**
     196             :      * Iterate over transactions in a block and update the cached Sapling nullifiers
     197             :      * for transactions which belong to the wallet.
     198             :      */
     199             :     void UpdateSaplingNullifierNoteMapForBlock(const CBlock* pblock);
     200             : 
     201             :     /**
     202             :      * Set and initialize the Sapling HD chain.
     203             :      */
     204             :     bool SetupGeneration(const CKeyID& keyID, bool force = false, bool memonly = false);
     205     1547433 :     bool IsEnabled() const { return !hdChain.IsNull(); };
     206             : 
     207             :     /* Set the current HD seed (will reset the chain child index counters)
     208             :       Sets the seed's version based on the current wallet version (so the
     209             :       caller must ensure the current wallet version is correct before calling
     210             :       this function). */
     211             :     void SetHDSeed(const CPubKey& key, bool force = false, bool memonly = false);
     212             :     void SetHDSeed(const CKeyID& keyID, bool force = false, bool memonly = false);
     213             : 
     214             :     /* Set the HD chain model (chain child index counters) */
     215             :     void SetHDChain(CHDChain& chain, bool memonly);
     216         241 :     const CHDChain& GetHDChain() const { return hdChain; }
     217             : 
     218             :     /* Get cached sapling commonOVK
     219             :      * If nullopt, read it from the database, and save it.
     220             :      * If not found in the database, create a new one from the HD seed (throw
     221             :      * if the wallet is locked), write it to database, and save it.
     222             :      */
     223             :     uint256 getCommonOVK();
     224         318 :     void setCommonOVK(const uint256& ovk) { commonOVK = ovk; }
     225             : 
     226             :     /* Encrypt Sapling keys */
     227             :     bool EncryptSaplingKeys(CKeyingMaterial& vMasterKeyIn);
     228             : 
     229             :     void GetConflicts(const CWalletTx& wtx, std::set<uint256>& result) const;
     230             : 
     231             :     // Get the ivk creation time (we are only using the ivk's default address)
     232             :     int64_t GetKeyCreationTime(const libzcash::SaplingIncomingViewingKey& ivk);
     233             : 
     234             :     // Add full viewing key if it's not already in the wallet
     235             :     KeyAddResult AddViewingKeyToWallet(const libzcash::SaplingExtendedFullViewingKey &extfvk) const;
     236             : 
     237             :     // Add spending key if it's not already in the wallet
     238             :     KeyAddResult AddSpendingKeyToWallet(
     239             :             const Consensus::Params &params,
     240             :             const libzcash::SaplingExtendedSpendingKey &sk,
     241             :             int64_t nTime);
     242             : 
     243             :     //! Generates new Sapling key
     244             :     libzcash::SaplingPaymentAddress GenerateNewSaplingZKey();
     245             :     //! Adds Sapling spending key to the store, and saves it to disk
     246             :     bool AddSaplingZKey(const libzcash::SaplingExtendedSpendingKey &key);
     247             :     bool AddSaplingIncomingViewingKey(
     248             :             const libzcash::SaplingIncomingViewingKey &ivk,
     249             :             const libzcash::SaplingPaymentAddress &addr);
     250             :     bool AddCryptedSaplingSpendingKeyDB(
     251             :             const libzcash::SaplingExtendedFullViewingKey &extfvk,
     252             :             const std::vector<unsigned char> &vchCryptedSecret);
     253             :     //! Returns true if the wallet contains the spending key
     254             :     bool HaveSpendingKeyForPaymentAddress(const libzcash::SaplingPaymentAddress &zaddr) const;
     255             :     //! Returns true if the wallet contains the spending and viewing key for the shielded address
     256             :     bool PaymentAddressBelongsToWallet(const libzcash::SaplingPaymentAddress &zaddr) const;
     257             : 
     258             :     //! Adds spending key to the store, without saving it to disk (used by LoadWallet)
     259             :     bool LoadSaplingZKey(const libzcash::SaplingExtendedSpendingKey &key);
     260             :     //! Load spending key metadata (used by LoadWallet)
     261             :     bool LoadSaplingZKeyMetadata(const libzcash::SaplingIncomingViewingKey &ivk, const CKeyMetadata &meta);
     262             :     //! Adds an encrypted spending key to the store, without saving it to disk (used by LoadWallet)
     263             :     bool LoadCryptedSaplingZKey(const libzcash::SaplingExtendedFullViewingKey &extfvk,
     264             :                                 const std::vector<unsigned char> &vchCryptedSecret);
     265             :     //! Adds a Sapling payment address -> incoming viewing key map entry,
     266             :     //! without saving it to disk (used by LoadWallet)
     267             :     bool LoadSaplingPaymentAddress(
     268             :             const libzcash::SaplingPaymentAddress &addr,
     269             :             const libzcash::SaplingIncomingViewingKey &ivk);
     270             :     bool AddSaplingSpendingKey(const libzcash::SaplingExtendedSpendingKey &sk);
     271             : 
     272             :     //! Return the full viewing key for the shielded address
     273             :     Optional<libzcash::SaplingExtendedFullViewingKey> GetViewingKeyForPaymentAddress(
     274             :             const libzcash::SaplingPaymentAddress &addr) const;
     275             : 
     276             :     //! Return the spending key for the payment address (nullopt if the wallet has no spending key for such address)
     277             :     Optional<libzcash::SaplingExtendedSpendingKey> GetSpendingKeyForPaymentAddress(const libzcash::SaplingPaymentAddress &addr) const;
     278             : 
     279             :     //! Finds all output notes in the given tx that have been sent to a
     280             :     //! SaplingPaymentAddress in this wallet
     281             :     std::pair<mapSaplingNoteData_t, SaplingIncomingViewingKeyMap> FindMySaplingNotes(const CTransaction& tx) const;
     282             : 
     283             :     //! Find all of the addresses in the given tx that have been sent to a SaplingPaymentAddress in this wallet.
     284             :     std::vector<libzcash::SaplingPaymentAddress> FindMySaplingAddresses(const CTransaction& tx) const;
     285             : 
     286             :     //! Find notes for the outpoints
     287             :     void GetNotes(const std::vector<SaplingOutPoint>& saplingOutpoints,
     288             :                   std::vector<SaplingNoteEntry>& saplingEntriesRet) const;
     289             : 
     290             :     /* Find notes filtered by payment address, min depth, ability to spend and if they are locked */
     291             :     void GetFilteredNotes(std::vector<SaplingNoteEntry>& saplingEntries,
     292             :         Optional<libzcash::SaplingPaymentAddress>& address,
     293             :         int minDepth = 1,
     294             :         bool ignoreSpent = true,
     295             :         bool requireSpendingKey = true,
     296             :         bool ignoreLocked = true) const;
     297             : 
     298             :     /* Find notes filtered by payment addresses, min depth, max depth, if they are spent,
     299             :        if a spending key is required, and if they are locked */
     300             :     void GetFilteredNotes(std::vector<SaplingNoteEntry>& saplingEntries,
     301             :                           std::set<libzcash::PaymentAddress>& filterAddresses,
     302             :                           int minDepth=1,
     303             :                           int maxDepth=INT_MAX,
     304             :                           bool ignoreSpent=true,
     305             :                           bool requireSpendingKey=true,
     306             :                           bool ignoreLocked=true) const;
     307             : 
     308             :     /* Return list of available notes grouped by sapling address. */
     309             :     std::map<libzcash::SaplingPaymentAddress, std::vector<SaplingNoteEntry>> ListNotes() const;
     310             : 
     311             :     //! Return the address from where the shielded spend is taking the funds from (if possible)
     312             :     Optional<libzcash::SaplingPaymentAddress> GetAddressFromInputIfPossible(const CWalletTx* wtx, int index) const;
     313             :     Optional<libzcash::SaplingPaymentAddress> GetAddressFromInputIfPossible(const uint256& txHash, int index) const;
     314             : 
     315             :     //! Whether the nullifier is from this wallet
     316             :     bool IsSaplingNullifierFromMe(const uint256& nullifier) const;
     317             : 
     318             :     //! Return all of the witnesses for the input notes
     319             :     void GetSaplingNoteWitnesses(
     320             :             const std::vector<SaplingOutPoint>& notes,
     321             :             std::vector<Optional<SaplingWitness>>& witnesses,
     322             :             uint256& final_anchor) const;
     323             : 
     324             :     std::set<std::pair<libzcash::PaymentAddress, uint256>> GetNullifiersForAddresses(const std::set<libzcash::PaymentAddress> & addresses) const;
     325             :     bool IsNoteSaplingChange(const std::set<std::pair<libzcash::PaymentAddress, uint256>>& nullifierSet, const libzcash::PaymentAddress& address, const SaplingOutPoint& entry) const;
     326             : 
     327             :     //! Try to recover the note using the wallet's ovks (mostly used when the outpoint is a debit)
     328             :     Optional<std::pair<
     329             :             libzcash::SaplingNotePlaintext,
     330             :             libzcash::SaplingPaymentAddress>> TryToRecoverNote(const CWalletTx& tx, const SaplingOutPoint& op);
     331             : 
     332             :     //! Return true if the wallet can decrypt & spend the shielded output.
     333             :     isminetype IsMine(const CWalletTx& wtx, const SaplingOutPoint& op) const;
     334             :     //! Return the shielded address of a specific outpoint of wallet transaction
     335             :     Optional<libzcash::SaplingPaymentAddress> GetOutPointAddress(const CWalletTx& tx, const SaplingOutPoint& op) const;
     336             :     //! Return the shielded value of a specific outpoint of wallet transaction
     337             :     CAmount GetOutPointValue(const CWalletTx& tx, const SaplingOutPoint& op) const;
     338             :     //! Return the memo value of a specific outpoint of wallet transaction
     339             :     Optional<std::string> GetOutPointMemo(const CWalletTx& tx, const SaplingOutPoint& op) const;
     340             :     //! Return the shielded credit of the tx
     341             :     CAmount GetCredit(const CWalletTx& tx, const isminefilter& filter, const bool fUnspent = false) const;
     342             :     //! Return the shielded debit of the tx.
     343             :     CAmount GetDebit(const CTransaction& tx, const isminefilter& filter) const;
     344             :     //! Return the shielded change of the tx
     345             :     CAmount GetShieldedChange(const CWalletTx& wtx) const;
     346             : 
     347             :     //! Check whether an specific output is change or not.
     348             :     bool IsNoteSaplingChange(const SaplingOutPoint& op, libzcash::SaplingPaymentAddress address) const;
     349             : 
     350             :     //! Update note data if is needed
     351             :     bool UpdatedNoteData(const CWalletTx& wtxIn, CWalletTx& wtx);
     352             : 
     353             :     //! Clear every notesData from every wallet tx and reset the witness cache size
     354             :     void ClearNoteWitnessCache();
     355             : 
     356             :     // Sapling metadata
     357             :     std::map<libzcash::SaplingIncomingViewingKey, CKeyMetadata> mapSaplingZKeyMetadata;
     358             : 
     359             :     /*
     360             :      * Size of the incremental witness cache for the notes in our wallet.
     361             :      * This will always be greater than or equal to the size of the largest
     362             :      * incremental witness cache in any transaction in mapWallet.
     363             :      */
     364             :     int64_t nWitnessCacheSize{0};
     365             :     bool nWitnessCacheNeedsUpdate{false};
     366             : 
     367             :     /**
     368             :      * The reverse mapping of nullifiers to notes.
     369             :      *
     370             :      * The mapping cannot be updated while an encrypted wallet is locked,
     371             :      * because we need the SpendingKey to create the nullifier (zcash#1502). This has
     372             :      * several implications for transactions added to the wallet while locked:
     373             :      *
     374             :      * - Parent transactions can't be marked dirty when a child transaction that
     375             :      *   spends their output notes is updated.
     376             :      *
     377             :      *   - We currently don't cache any note values, so this is not a problem,
     378             :      *     yet.
     379             :      *
     380             :      * - GetFilteredNotes can't filter out spent notes.
     381             :      *
     382             :      *   - Per the comment in SaplingNoteData, we assume that if we don't have a
     383             :      *     cached nullifier, the note is not spent.
     384             :      *
     385             :      * Another more problematic implication is that the wallet can fail to
     386             :      * detect transactions on the blockchain that spend our notes. There are two
     387             :      * possible cases in which this could happen:
     388             :      *
     389             :      * - We receive a note when the wallet is locked, and then spend it using a
     390             :      *   different wallet client.
     391             :      *
     392             :      * - We spend from a PaymentAddress we control, then we export the
     393             :      *   SpendingKey and import it into a new wallet, and reindex/rescan to find
     394             :      *   the old transactions.
     395             :      *
     396             :      * The wallet will only miss "pure" spends - transactions that are only
     397             :      * linked to us by the fact that they contain notes we spent. If it also
     398             :      * sends notes to us, or interacts with our transparent addresses, we will
     399             :      * detect the transaction and add it to the wallet (again without caching
     400             :      * nullifiers for new notes). As by default JoinSplits send change back to
     401             :      * the origin PaymentAddress, the wallet should rarely miss transactions.
     402             :      *
     403             :      * To work around these issues, whenever the wallet is unlocked, we scan all
     404             :      * cached notes, and cache any missing nullifiers. Since the wallet must be
     405             :      * unlocked in order to spend notes, this means that GetFilteredNotes will
     406             :      * always behave correctly within that context (and any other uses will give
     407             :      * correct responses afterwards), for the transactions that the wallet was
     408             :      * able to detect. Any missing transactions can be rediscovered by:
     409             :      *
     410             :      * - Unlocking the wallet (to fill all nullifier caches).
     411             :      *
     412             :      * - Restarting the node with -reindex (which operates on a locked wallet
     413             :      *   but with the now-cached nullifiers).
     414             :      */
     415             : 
     416             :     std::map<uint256, SaplingOutPoint> mapSaplingNullifiersToNotes;
     417             : 
     418             : private:
     419             :     /* Map hash nullifiers, list Sapling Witness*/
     420             :     std::map<uint256, std::list<SaplingWitness>> cachedWitnessMap;
     421             :     int rollbackTargetHeight = -1;
     422             :     /* Parent wallet */
     423             :     CWallet* wallet{nullptr};
     424             :     /* the HD chain data model (external/internal chain counters) */
     425             :     CHDChain hdChain;
     426             :     /* cached common OVK for sapling spends from t addresses */
     427             :     Optional<uint256> commonOVK;
     428             :     uint256 getCommonOVKFromSeed() const;
     429             : 
     430             : 
     431             :     /**
     432             :      * Used to keep track of spent Notes, and
     433             :      * detect and report conflicts (double-spends).
     434             :      */
     435             :     typedef std::multimap<uint256, uint256> TxNullifiers;
     436             :     TxNullifiers mapTxSaplingNullifiers;
     437             : };
     438             : 
     439             : #endif // PIVX_SAPLING_SAPLINGSCRIPTPUBKEYMAN_H

Generated by: LCOV version 1.14