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 ¶ms,
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
|