]> Git Repo - VerusCoin.git/blob - src/wallet/gtest/test_wallet.cpp
Clean up wallet unit tests: replace .value() with .get() for clarity.
[VerusCoin.git] / src / wallet / gtest / test_wallet.cpp
1 #include <gmock/gmock.h>
2 #include <gtest/gtest.h>
3 #include <sodium.h>
4
5 #include "base58.h"
6 #include "chainparams.h"
7 #include "key_io.h"
8 #include "main.h"
9 #include "primitives/block.h"
10 #include "random.h"
11 #include "transaction_builder.h"
12 #include "utiltest.h"
13 #include "wallet/wallet.h"
14 #include "zcash/JoinSplit.hpp"
15 #include "zcash/Note.hpp"
16 #include "zcash/NoteEncryption.hpp"
17
18 #include <boost/filesystem.hpp>
19
20 using ::testing::Return;
21
22 extern ZCJoinSplit* params;
23
24 ACTION(ThrowLogicError) {
25     throw std::logic_error("Boom");
26 }
27
28 static const std::string tSecretRegtest = "cND2ZvtabDbJ1gucx9GWH6XT9kgTAqfb6cotPt5Q5CyxVDhid2EN";
29
30 class MockWalletDB {
31 public:
32     MOCK_METHOD0(TxnBegin, bool());
33     MOCK_METHOD0(TxnCommit, bool());
34     MOCK_METHOD0(TxnAbort, bool());
35
36     MOCK_METHOD2(WriteTx, bool(uint256 hash, const CWalletTx& wtx));
37     MOCK_METHOD1(WriteWitnessCacheSize, bool(int64_t nWitnessCacheSize));
38     MOCK_METHOD1(WriteBestBlock, bool(const CBlockLocator& loc));
39 };
40
41 template void CWallet::SetBestChainINTERNAL<MockWalletDB>(
42         MockWalletDB& walletdb, const CBlockLocator& loc);
43
44 class TestWallet : public CWallet {
45 public:
46     TestWallet() : CWallet() { }
47
48     bool EncryptKeys(CKeyingMaterial& vMasterKeyIn) {
49         return CCryptoKeyStore::EncryptKeys(vMasterKeyIn);
50     }
51
52     bool Unlock(const CKeyingMaterial& vMasterKeyIn) {
53         return CCryptoKeyStore::Unlock(vMasterKeyIn);
54     }
55
56     void IncrementNoteWitnesses(const CBlockIndex* pindex,
57                                 const CBlock* pblock,
58                                 SproutMerkleTree& sproutTree,
59                                 SaplingMerkleTree& saplingTree) {
60         CWallet::IncrementNoteWitnesses(pindex, pblock, sproutTree, saplingTree);
61     }
62     void DecrementNoteWitnesses(const CBlockIndex* pindex) {
63         CWallet::DecrementNoteWitnesses(pindex);
64     }
65     void SetBestChain(MockWalletDB& walletdb, const CBlockLocator& loc) {
66         CWallet::SetBestChainINTERNAL(walletdb, loc);
67     }
68     bool UpdatedNoteData(const CWalletTx& wtxIn, CWalletTx& wtx) {
69         return CWallet::UpdatedNoteData(wtxIn, wtx);
70     }
71     void MarkAffectedTransactionsDirty(const CTransaction& tx) {
72         CWallet::MarkAffectedTransactionsDirty(tx);
73     }
74 };
75
76 CWalletTx GetValidReceive(const libzcash::SproutSpendingKey& sk, CAmount value, bool randomInputs, int32_t version = 2) {
77     return GetValidReceive(*params, sk, value, randomInputs, version);
78 }
79
80 libzcash::SproutNote GetNote(const libzcash::SproutSpendingKey& sk,
81                        const CTransaction& tx, size_t js, size_t n) {
82     return GetNote(*params, sk, tx, js, n);
83 }
84
85 CWalletTx GetValidSpend(const libzcash::SproutSpendingKey& sk,
86                         const libzcash::SproutNote& note, CAmount value) {
87     return GetValidSpend(*params, sk, note, value);
88 }
89
90 std::vector<SaplingOutPoint> SetSaplingNoteData(CWalletTx& wtx) {
91     mapSaplingNoteData_t saplingNoteData;
92     SaplingOutPoint saplingOutPoint = {wtx.GetHash(), 0};
93     SaplingNoteData saplingNd;
94     saplingNoteData[saplingOutPoint] = saplingNd;
95     wtx.SetSaplingNoteData(saplingNoteData);
96     std::vector<SaplingOutPoint> saplingNotes {saplingOutPoint};
97     return saplingNotes;
98 }
99
100 std::pair<JSOutPoint, SaplingOutPoint> CreateValidBlock(TestWallet& wallet,
101                             const libzcash::SproutSpendingKey& sk,
102                             const CBlockIndex& index,
103                             CBlock& block,
104                             SproutMerkleTree& sproutTree,
105                             SaplingMerkleTree& saplingTree) {
106     auto wtx = GetValidReceive(sk, 50, true, 4);
107     auto note = GetNote(sk, wtx, 0, 1);
108     auto nullifier = note.nullifier(sk);
109
110     mapSproutNoteData_t noteData;
111     JSOutPoint jsoutpt {wtx.GetHash(), 0, 1};
112     SproutNoteData nd {sk.address(), nullifier};
113     noteData[jsoutpt] = nd;
114     wtx.SetSproutNoteData(noteData);
115     auto saplingNotes = SetSaplingNoteData(wtx);
116     wallet.AddToWallet(wtx, true, NULL);
117
118     block.vtx.push_back(wtx);
119     wallet.IncrementNoteWitnesses(&index, &block, sproutTree, saplingTree);
120
121     return std::make_pair(jsoutpt, saplingNotes[0]);
122 }
123
124 std::pair<uint256, uint256> GetWitnessesAndAnchors(TestWallet& wallet,
125                                 std::vector<JSOutPoint>& sproutNotes,
126                                 std::vector<SaplingOutPoint>& saplingNotes,
127                                 std::vector<boost::optional<SproutWitness>>& sproutWitnesses,
128                                 std::vector<boost::optional<SaplingWitness>>& saplingWitnesses) {
129     sproutWitnesses.clear();
130     saplingWitnesses.clear();
131     uint256 sproutAnchor;
132     uint256 saplingAnchor;
133     wallet.GetSproutNoteWitnesses(sproutNotes, sproutWitnesses, sproutAnchor);
134     wallet.GetSaplingNoteWitnesses(saplingNotes, saplingWitnesses, saplingAnchor);
135     return std::make_pair(sproutAnchor, saplingAnchor);
136 }
137
138 TEST(WalletTests, SetupDatadirLocationRunAsFirstTest) {
139     // Get temporary and unique path for file.
140     boost::filesystem::path pathTemp = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path();
141     boost::filesystem::create_directories(pathTemp);
142     mapArgs["-datadir"] = pathTemp.string();
143 }
144
145 TEST(WalletTests, SproutNoteDataSerialisation) {
146     auto sk = libzcash::SproutSpendingKey::random();
147     auto wtx = GetValidReceive(sk, 10, true);
148     auto note = GetNote(sk, wtx, 0, 1);
149     auto nullifier = note.nullifier(sk);
150
151     mapSproutNoteData_t noteData;
152     JSOutPoint jsoutpt {wtx.GetHash(), 0, 1};
153     SproutNoteData nd {sk.address(), nullifier};
154     SproutMerkleTree tree;
155     nd.witnesses.push_front(tree.witness());
156     noteData[jsoutpt] = nd;
157
158     CDataStream ss(SER_DISK, CLIENT_VERSION);
159     ss << noteData;
160
161     mapSproutNoteData_t noteData2;
162     ss >> noteData2;
163
164     EXPECT_EQ(noteData, noteData2);
165     EXPECT_EQ(noteData[jsoutpt].witnesses, noteData2[jsoutpt].witnesses);
166 }
167
168
169 TEST(WalletTests, FindUnspentSproutNotes) {
170     SelectParams(CBaseChainParams::TESTNET);
171     CWallet wallet;
172     auto sk = libzcash::SproutSpendingKey::random();
173     wallet.AddSproutSpendingKey(sk);
174
175     auto wtx = GetValidReceive(sk, 10, true);
176     auto note = GetNote(sk, wtx, 0, 1);
177     auto nullifier = note.nullifier(sk);
178
179     mapSproutNoteData_t noteData;
180     JSOutPoint jsoutpt {wtx.GetHash(), 0, 1};
181     SproutNoteData nd {sk.address(), nullifier};
182     noteData[jsoutpt] = nd;
183
184     wtx.SetSproutNoteData(noteData);
185     wallet.AddToWallet(wtx, true, NULL);
186     EXPECT_FALSE(wallet.IsSproutSpent(nullifier));
187
188     // We currently have an unspent and unconfirmed note in the wallet (depth of -1)
189     std::vector<CSproutNotePlaintextEntry> entries;
190     wallet.GetFilteredNotes(entries, "", 0);
191     EXPECT_EQ(0, entries.size());
192     entries.clear();
193     wallet.GetFilteredNotes(entries, "", -1);
194     EXPECT_EQ(1, entries.size());
195     entries.clear();
196
197     // Fake-mine the transaction
198     EXPECT_EQ(-1, chainActive.Height());
199     CBlock block;
200     block.vtx.push_back(wtx);
201     block.hashMerkleRoot = block.BuildMerkleTree();
202     auto blockHash = block.GetHash();
203     CBlockIndex fakeIndex {block};
204     mapBlockIndex.insert(std::make_pair(blockHash, &fakeIndex));
205     chainActive.SetTip(&fakeIndex);
206     EXPECT_TRUE(chainActive.Contains(&fakeIndex));
207     EXPECT_EQ(0, chainActive.Height());
208
209     wtx.SetMerkleBranch(block);
210     wallet.AddToWallet(wtx, true, NULL);
211     EXPECT_FALSE(wallet.IsSproutSpent(nullifier));
212
213
214     // We now have an unspent and confirmed note in the wallet (depth of 1)
215     wallet.GetFilteredNotes(entries, "", 0);
216     EXPECT_EQ(1, entries.size());
217     entries.clear();
218     wallet.GetFilteredNotes(entries, "", 1);
219     EXPECT_EQ(1, entries.size());
220     entries.clear();
221     wallet.GetFilteredNotes(entries, "", 2);
222     EXPECT_EQ(0, entries.size());
223     entries.clear();
224
225
226     // Let's spend the note.
227     auto wtx2 = GetValidSpend(sk, note, 5);
228     wallet.AddToWallet(wtx2, true, NULL);
229     EXPECT_FALSE(wallet.IsSproutSpent(nullifier));
230
231     // Fake-mine a spend transaction
232     EXPECT_EQ(0, chainActive.Height());
233     CBlock block2;
234     block2.vtx.push_back(wtx2);
235     block2.hashMerkleRoot = block2.BuildMerkleTree();
236     block2.hashPrevBlock = blockHash;
237     auto blockHash2 = block2.GetHash();
238     CBlockIndex fakeIndex2 {block2};
239     mapBlockIndex.insert(std::make_pair(blockHash2, &fakeIndex2));
240     fakeIndex2.nHeight = 1;
241     chainActive.SetTip(&fakeIndex2);
242     EXPECT_TRUE(chainActive.Contains(&fakeIndex2));
243     EXPECT_EQ(1, chainActive.Height());
244
245     wtx2.SetMerkleBranch(block2);
246     wallet.AddToWallet(wtx2, true, NULL);
247     EXPECT_TRUE(wallet.IsSproutSpent(nullifier));
248
249     // The note has been spent.  By default, GetFilteredNotes() ignores spent notes.
250     wallet.GetFilteredNotes(entries, "", 0);
251     EXPECT_EQ(0, entries.size());
252     entries.clear();
253     // Let's include spent notes to retrieve it.
254     wallet.GetFilteredNotes(entries, "", 0, false);
255     EXPECT_EQ(1, entries.size());
256     entries.clear();
257     // The spent note has two confirmations.
258     wallet.GetFilteredNotes(entries, "", 2, false);
259     EXPECT_EQ(1, entries.size());
260     entries.clear();
261     // It does not have 3 confirmations.
262     wallet.GetFilteredNotes(entries, "", 3, false);
263     EXPECT_EQ(0, entries.size());
264     entries.clear();
265
266
267     // Let's receive a new note
268     CWalletTx wtx3;
269     {
270         auto wtx = GetValidReceive(sk, 20, true);
271         auto note = GetNote(sk, wtx, 0, 1);
272         auto nullifier = note.nullifier(sk);
273
274         mapSproutNoteData_t noteData;
275         JSOutPoint jsoutpt {wtx.GetHash(), 0, 1};
276         SproutNoteData nd {sk.address(), nullifier};
277         noteData[jsoutpt] = nd;
278
279         wtx.SetSproutNoteData(noteData);
280         wallet.AddToWallet(wtx, true, NULL);
281         EXPECT_FALSE(wallet.IsSproutSpent(nullifier));
282
283         wtx3 = wtx;
284     }
285
286     // Fake-mine the new transaction
287     EXPECT_EQ(1, chainActive.Height());
288     CBlock block3;
289     block3.vtx.push_back(wtx3);
290     block3.hashMerkleRoot = block3.BuildMerkleTree();
291     block3.hashPrevBlock = blockHash2;
292     auto blockHash3 = block3.GetHash();
293     CBlockIndex fakeIndex3 {block3};
294     mapBlockIndex.insert(std::make_pair(blockHash3, &fakeIndex3));
295     fakeIndex3.nHeight = 2;
296     chainActive.SetTip(&fakeIndex3);
297     EXPECT_TRUE(chainActive.Contains(&fakeIndex3));
298     EXPECT_EQ(2, chainActive.Height());
299
300     wtx3.SetMerkleBranch(block3);
301     wallet.AddToWallet(wtx3, true, NULL);
302
303     // We now have an unspent note which has one confirmation, in addition to our spent note.
304     wallet.GetFilteredNotes(entries, "", 1);
305     EXPECT_EQ(1, entries.size());
306     entries.clear();
307     // Let's return the spent note too.
308     wallet.GetFilteredNotes(entries, "", 1, false);
309     EXPECT_EQ(2, entries.size());
310     entries.clear();
311     // Increasing number of confirmations will exclude our new unspent note.
312     wallet.GetFilteredNotes(entries, "", 2, false);
313     EXPECT_EQ(1, entries.size());
314     entries.clear();    
315     // If we also ignore spent notes at this depth, we won't find any notes.
316     wallet.GetFilteredNotes(entries, "", 2, true);
317     EXPECT_EQ(0, entries.size());
318     entries.clear(); 
319
320     // Tear down
321     chainActive.SetTip(NULL);
322     mapBlockIndex.erase(blockHash);
323     mapBlockIndex.erase(blockHash2);
324     mapBlockIndex.erase(blockHash3);
325 }
326
327
328 TEST(WalletTests, SetSproutNoteAddrsInCWalletTx) {
329     auto sk = libzcash::SproutSpendingKey::random();
330     auto wtx = GetValidReceive(sk, 10, true);
331     auto note = GetNote(sk, wtx, 0, 1);
332     auto nullifier = note.nullifier(sk);
333     EXPECT_EQ(0, wtx.mapSproutNoteData.size());
334
335     mapSproutNoteData_t noteData;
336     JSOutPoint jsoutpt {wtx.GetHash(), 0, 1};
337     SproutNoteData nd {sk.address(), nullifier};
338     noteData[jsoutpt] = nd;
339
340     wtx.SetSproutNoteData(noteData);
341     EXPECT_EQ(noteData, wtx.mapSproutNoteData);
342 }
343
344 TEST(WalletTests, SetSaplingNoteAddrsInCWalletTx) {
345     SelectParams(CBaseChainParams::REGTEST);
346     UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
347     UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
348     auto consensusParams = Params().GetConsensus();
349
350     TestWallet wallet;
351
352     auto sk = libzcash::SaplingSpendingKey::random();
353     auto expsk = sk.expanded_spending_key();
354     auto fvk = sk.full_viewing_key();
355     auto pk = sk.default_address();
356     auto ivk = fvk.in_viewing_key();
357
358     libzcash::SaplingNote note(pk, 50000);
359     auto cm = note.cm().get();
360     SaplingMerkleTree tree;
361     tree.append(cm);
362     auto anchor = tree.root();
363     auto witness = tree.witness();
364
365     auto nf = note.nullifier(fvk, witness.position());
366     ASSERT_TRUE(nf);
367     uint256 nullifier = nf.get();
368
369     auto builder = TransactionBuilder(consensusParams, 1);
370     ASSERT_TRUE(builder.AddSaplingSpend(expsk, note, anchor, witness));
371     builder.AddSaplingOutput(fvk, pk, 50000, {});
372     builder.SetFee(0);
373     auto maybe_tx = builder.Build();
374     ASSERT_EQ(static_cast<bool>(maybe_tx), true);
375     auto tx = maybe_tx.get();
376
377     CWalletTx wtx {&wallet, tx};
378
379     EXPECT_EQ(0, wtx.mapSaplingNoteData.size());
380     mapSaplingNoteData_t noteData;
381
382     SaplingOutPoint op {wtx.GetHash(), 0};
383     SaplingNoteData nd;
384     nd.nullifier = nullifier;
385     nd.ivk = ivk;
386     nd.witnesses.push_front(witness);
387     nd.witnessHeight = 123;
388     noteData.insert(std::make_pair(op, nd));
389
390     wtx.SetSaplingNoteData(noteData);
391     EXPECT_EQ(noteData, wtx.mapSaplingNoteData);
392
393     // Test individual fields in case equality operator is defined/changed.
394     EXPECT_EQ(ivk, wtx.mapSaplingNoteData[op].ivk);
395     EXPECT_EQ(nullifier, wtx.mapSaplingNoteData[op].nullifier);
396     EXPECT_EQ(nd.witnessHeight, wtx.mapSaplingNoteData[op].witnessHeight);
397     EXPECT_TRUE(witness == wtx.mapSaplingNoteData[op].witnesses.front());
398
399     // Revert to default
400     UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
401     UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
402 }
403
404 TEST(WalletTests, SetSproutInvalidNoteAddrsInCWalletTx) {
405     CWalletTx wtx;
406     EXPECT_EQ(0, wtx.mapSproutNoteData.size());
407
408     mapSproutNoteData_t noteData;
409     auto sk = libzcash::SproutSpendingKey::random();
410     JSOutPoint jsoutpt {wtx.GetHash(), 0, 1};
411     SproutNoteData nd {sk.address(), uint256()};
412     noteData[jsoutpt] = nd;
413
414     EXPECT_THROW(wtx.SetSproutNoteData(noteData), std::logic_error);
415 }
416
417 // The following test is the same as SetInvalidSaplingNoteDataInCWalletTx
418 // TEST(WalletTests, SetSaplingInvalidNoteAddrsInCWalletTx)
419
420 // Cannot add note data for an index which does not exist in tx.vShieldedOutput
421 TEST(WalletTests, SetInvalidSaplingNoteDataInCWalletTx) {
422     CWalletTx wtx;
423     EXPECT_EQ(0, wtx.mapSaplingNoteData.size());
424
425     mapSaplingNoteData_t noteData;
426     SaplingOutPoint op {uint256(), 1};
427     SaplingNoteData nd;
428     noteData.insert(std::make_pair(op, nd));
429
430     EXPECT_THROW(wtx.SetSaplingNoteData(noteData), std::logic_error);
431 }
432
433 TEST(WalletTests, GetSproutNoteNullifier) {
434     CWallet wallet;
435
436     auto sk = libzcash::SproutSpendingKey::random();
437     auto address = sk.address();
438     auto dec = ZCNoteDecryption(sk.receiving_key());
439
440     auto wtx = GetValidReceive(sk, 10, true);
441     auto note = GetNote(sk, wtx, 0, 1);
442     auto nullifier = note.nullifier(sk);
443
444     auto hSig = wtx.vjoinsplit[0].h_sig(
445         *params, wtx.joinSplitPubKey);
446
447     auto ret = wallet.GetSproutNoteNullifier(
448         wtx.vjoinsplit[0],
449         address,
450         dec,
451         hSig, 1);
452     EXPECT_NE(nullifier, ret);
453
454     wallet.AddSproutSpendingKey(sk);
455
456     ret = wallet.GetSproutNoteNullifier(
457         wtx.vjoinsplit[0],
458         address,
459         dec,
460         hSig, 1);
461     EXPECT_EQ(nullifier, ret);
462 }
463
464 TEST(WalletTests, FindMySaplingNotes) {
465     SelectParams(CBaseChainParams::REGTEST);
466     UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
467     UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
468     auto consensusParams = Params().GetConsensus();
469
470     TestWallet wallet;
471
472     // Generate dummy Sapling address
473     auto sk = libzcash::SaplingSpendingKey::random();
474     auto expsk = sk.expanded_spending_key();
475     auto fvk = sk.full_viewing_key();
476     auto pk = sk.default_address();
477
478     // Generate dummy Sapling note
479     libzcash::SaplingNote note(pk, 50000);
480     auto cm = note.cm().get();
481     SaplingMerkleTree tree;
482     tree.append(cm);
483     auto anchor = tree.root();
484     auto witness = tree.witness();
485
486     // Generate transaction
487     auto builder = TransactionBuilder(consensusParams, 1);
488     ASSERT_TRUE(builder.AddSaplingSpend(expsk, note, anchor, witness));
489     builder.AddSaplingOutput(fvk, pk, 25000, {});
490     auto maybe_tx = builder.Build();
491     ASSERT_EQ(static_cast<bool>(maybe_tx), true);
492     auto tx = maybe_tx.get();
493
494     // No Sapling notes can be found in tx which belong to the wallet
495     CWalletTx wtx {&wallet, tx};
496     ASSERT_FALSE(wallet.HaveSaplingSpendingKey(fvk));
497     auto noteMap = wallet.FindMySaplingNotes(wtx);
498     EXPECT_EQ(0, noteMap.size());
499
500     // Add spending key to wallet, so Sapling notes can be found
501     ASSERT_TRUE(wallet.AddSaplingZKey(sk));
502     ASSERT_TRUE(wallet.HaveSaplingSpendingKey(fvk));
503     noteMap = wallet.FindMySaplingNotes(wtx);
504     EXPECT_EQ(2, noteMap.size());
505
506     // Revert to default
507     UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
508     UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
509 }
510
511 TEST(WalletTests, FindMySproutNotes) {
512     CWallet wallet;
513
514     auto sk = libzcash::SproutSpendingKey::random();
515     auto sk2 = libzcash::SproutSpendingKey::random();
516     wallet.AddSproutSpendingKey(sk2);
517
518     auto wtx = GetValidReceive(sk, 10, true);
519     auto note = GetNote(sk, wtx, 0, 1);
520     auto nullifier = note.nullifier(sk);
521
522     auto noteMap = wallet.FindMySproutNotes(wtx);
523     EXPECT_EQ(0, noteMap.size());
524
525     wallet.AddSproutSpendingKey(sk);
526
527     noteMap = wallet.FindMySproutNotes(wtx);
528     EXPECT_EQ(2, noteMap.size());
529
530     JSOutPoint jsoutpt {wtx.GetHash(), 0, 1};
531     SproutNoteData nd {sk.address(), nullifier};
532     EXPECT_EQ(1, noteMap.count(jsoutpt));
533     EXPECT_EQ(nd, noteMap[jsoutpt]);
534 }
535
536 TEST(WalletTests, FindMySproutNotesInEncryptedWallet) {
537     TestWallet wallet;
538     uint256 r {GetRandHash()};
539     CKeyingMaterial vMasterKey (r.begin(), r.end());
540
541     auto sk = libzcash::SproutSpendingKey::random();
542     wallet.AddSproutSpendingKey(sk);
543
544     ASSERT_TRUE(wallet.EncryptKeys(vMasterKey));
545
546     auto wtx = GetValidReceive(sk, 10, true);
547     auto note = GetNote(sk, wtx, 0, 1);
548     auto nullifier = note.nullifier(sk);
549
550     auto noteMap = wallet.FindMySproutNotes(wtx);
551     EXPECT_EQ(2, noteMap.size());
552
553     JSOutPoint jsoutpt {wtx.GetHash(), 0, 1};
554     SproutNoteData nd {sk.address(), nullifier};
555     EXPECT_EQ(1, noteMap.count(jsoutpt));
556     EXPECT_NE(nd, noteMap[jsoutpt]);
557
558     ASSERT_TRUE(wallet.Unlock(vMasterKey));
559
560     noteMap = wallet.FindMySproutNotes(wtx);
561     EXPECT_EQ(2, noteMap.size());
562     EXPECT_EQ(1, noteMap.count(jsoutpt));
563     EXPECT_EQ(nd, noteMap[jsoutpt]);
564 }
565
566 TEST(WalletTests, GetConflictedSproutNotes) {
567     CWallet wallet;
568
569     auto sk = libzcash::SproutSpendingKey::random();
570     wallet.AddSproutSpendingKey(sk);
571
572     auto wtx = GetValidReceive(sk, 10, true);
573     auto note = GetNote(sk, wtx, 0, 1);
574     auto nullifier = note.nullifier(sk);
575
576     auto wtx2 = GetValidSpend(sk, note, 5);
577     auto wtx3 = GetValidSpend(sk, note, 10);
578     auto hash2 = wtx2.GetHash();
579     auto hash3 = wtx3.GetHash();
580
581     // No conflicts for no spends
582     EXPECT_EQ(0, wallet.GetConflicts(hash2).size());
583     wallet.AddToWallet(wtx, true, NULL);
584     EXPECT_EQ(0, wallet.GetConflicts(hash2).size());
585
586     // No conflicts for one spend
587     wallet.AddToWallet(wtx2, true, NULL);
588     EXPECT_EQ(0, wallet.GetConflicts(hash2).size());
589
590     // Conflicts for two spends
591     wallet.AddToWallet(wtx3, true, NULL);
592     auto c3 = wallet.GetConflicts(hash2);
593     EXPECT_EQ(2, c3.size());
594     EXPECT_EQ(std::set<uint256>({hash2, hash3}), c3);
595 }
596
597 // Generate note A and spend to create note B, from which we spend to create two conflicting transactions
598 TEST(WalletTests, GetConflictedSaplingNotes) {
599     SelectParams(CBaseChainParams::REGTEST);
600     UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
601     UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
602     auto consensusParams = Params().GetConsensus();
603
604     TestWallet wallet;
605
606     // Generate Sapling address
607     auto sk = libzcash::SaplingSpendingKey::random();
608     auto expsk = sk.expanded_spending_key();
609     auto fvk = sk.full_viewing_key();
610     auto ivk = fvk.in_viewing_key();
611     auto pk = sk.default_address();
612
613     ASSERT_TRUE(wallet.AddSaplingZKey(sk));
614     ASSERT_TRUE(wallet.HaveSaplingSpendingKey(fvk));
615
616     // Generate note A
617     libzcash::SaplingNote note(pk, 50000);
618     auto cm = note.cm().get();
619     SaplingMerkleTree saplingTree;
620     saplingTree.append(cm);
621     auto anchor = saplingTree.root();
622     auto witness = saplingTree.witness();
623
624     // Generate tx to create output note B
625     auto builder = TransactionBuilder(consensusParams, 1);
626     ASSERT_TRUE(builder.AddSaplingSpend(expsk, note, anchor, witness));
627     builder.AddSaplingOutput(fvk, pk, 35000, {});
628     auto maybe_tx = builder.Build();
629     ASSERT_EQ(static_cast<bool>(maybe_tx), true);
630     auto tx = maybe_tx.get();
631     CWalletTx wtx {&wallet, tx};
632
633     // Fake-mine the transaction
634     EXPECT_EQ(-1, chainActive.Height());
635     SproutMerkleTree sproutTree;
636     CBlock block;
637     block.vtx.push_back(wtx);
638     block.hashMerkleRoot = block.BuildMerkleTree();
639     auto blockHash = block.GetHash();
640     CBlockIndex fakeIndex {block};
641     mapBlockIndex.insert(std::make_pair(blockHash, &fakeIndex));
642     chainActive.SetTip(&fakeIndex);
643     EXPECT_TRUE(chainActive.Contains(&fakeIndex));
644     EXPECT_EQ(0, chainActive.Height());
645
646     // Simulate SyncTransaction which calls AddToWalletIfInvolvingMe
647     auto saplingNoteData = wallet.FindMySaplingNotes(wtx);
648     ASSERT_TRUE(saplingNoteData.size() > 0);
649     wtx.SetSaplingNoteData(saplingNoteData);
650     wtx.SetMerkleBranch(block);
651     wallet.AddToWallet(wtx, true, NULL);
652
653     // Simulate receiving new block and ChainTip signal
654     wallet.IncrementNoteWitnesses(&fakeIndex, &block, sproutTree, saplingTree);
655     wallet.UpdateSaplingNullifierNoteMapForBlock(&block);
656
657     // Retrieve the updated wtx from wallet
658     uint256 hash = wtx.GetHash();
659     wtx = wallet.mapWallet[hash];
660
661     // Decrypt output note B
662     auto maybe_pt = libzcash::SaplingNotePlaintext::decrypt(
663             wtx.vShieldedOutput[0].encCiphertext,
664             ivk,
665             wtx.vShieldedOutput[0].ephemeralKey,
666             wtx.vShieldedOutput[0].cm);
667     ASSERT_EQ(static_cast<bool>(maybe_pt), true);
668     auto maybe_note = maybe_pt.get().note(ivk);
669     ASSERT_EQ(static_cast<bool>(maybe_note), true);
670     auto note2 = maybe_note.get();
671
672     SaplingOutPoint sop0(wtx.GetHash(), 0);
673     auto spend_note_witness =  wtx.mapSaplingNoteData[sop0].witnesses.front();
674     auto maybe_nf = note2.nullifier(fvk, spend_note_witness.position());
675     ASSERT_EQ(static_cast<bool>(maybe_nf), true);
676     auto nullifier2 = maybe_nf.get();
677
678     anchor = saplingTree.root();
679
680     // Create transaction to spend note B
681     auto builder2 = TransactionBuilder(consensusParams, 2);
682     ASSERT_TRUE(builder2.AddSaplingSpend(expsk, note2, anchor, spend_note_witness));
683     builder2.AddSaplingOutput(fvk, pk, 20000, {});
684     auto maybe_tx2 = builder2.Build();
685     ASSERT_EQ(static_cast<bool>(maybe_tx2), true);
686     auto tx2 = maybe_tx2.get();
687
688     // Create conflicting transaction which also spends note B
689     auto builder3 = TransactionBuilder(consensusParams, 2);
690     ASSERT_TRUE(builder3.AddSaplingSpend(expsk, note2, anchor, spend_note_witness));
691     builder3.AddSaplingOutput(fvk, pk, 19999, {});
692     auto maybe_tx3 = builder3.Build();
693     ASSERT_EQ(static_cast<bool>(maybe_tx3), true);
694     auto tx3 = maybe_tx3.get();
695
696     CWalletTx wtx2 {&wallet, tx2};
697     CWalletTx wtx3 {&wallet, tx3};
698
699     auto hash2 = wtx2.GetHash();
700     auto hash3 = wtx3.GetHash();
701
702     // No conflicts for no spends (wtx is currently the only transaction in the wallet)
703     EXPECT_EQ(0, wallet.GetConflicts(hash2).size());
704     EXPECT_EQ(0, wallet.GetConflicts(hash3).size());
705
706     // No conflicts for one spend
707     wallet.AddToWallet(wtx2, true, NULL);
708     EXPECT_EQ(0, wallet.GetConflicts(hash2).size());
709
710     // Conflicts for two spends
711     wallet.AddToWallet(wtx3, true, NULL);
712     auto c3 = wallet.GetConflicts(hash2);
713     EXPECT_EQ(2, c3.size());
714     EXPECT_EQ(std::set<uint256>({hash2, hash3}), c3);
715
716     // Tear down
717     chainActive.SetTip(NULL);
718     mapBlockIndex.erase(blockHash);
719
720     // Revert to default
721     UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
722     UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
723 }
724
725 TEST(WalletTests, SproutNullifierIsSpent) {
726     CWallet wallet;
727
728     auto sk = libzcash::SproutSpendingKey::random();
729     wallet.AddSproutSpendingKey(sk);
730
731     auto wtx = GetValidReceive(sk, 10, true);
732     auto note = GetNote(sk, wtx, 0, 1);
733     auto nullifier = note.nullifier(sk);
734
735     EXPECT_FALSE(wallet.IsSproutSpent(nullifier));
736
737     wallet.AddToWallet(wtx, true, NULL);
738     EXPECT_FALSE(wallet.IsSproutSpent(nullifier));
739
740     auto wtx2 = GetValidSpend(sk, note, 5);
741     wallet.AddToWallet(wtx2, true, NULL);
742     EXPECT_FALSE(wallet.IsSproutSpent(nullifier));
743
744     // Fake-mine the transaction
745     EXPECT_EQ(-1, chainActive.Height());
746     CBlock block;
747     block.vtx.push_back(wtx2);
748     block.hashMerkleRoot = block.BuildMerkleTree();
749     auto blockHash = block.GetHash();
750     CBlockIndex fakeIndex {block};
751     mapBlockIndex.insert(std::make_pair(blockHash, &fakeIndex));
752     chainActive.SetTip(&fakeIndex);
753     EXPECT_TRUE(chainActive.Contains(&fakeIndex));
754     EXPECT_EQ(0, chainActive.Height());
755
756     wtx2.SetMerkleBranch(block);
757     wallet.AddToWallet(wtx2, true, NULL);
758     EXPECT_TRUE(wallet.IsSproutSpent(nullifier));
759
760     // Tear down
761     chainActive.SetTip(NULL);
762     mapBlockIndex.erase(blockHash);
763 }
764
765 TEST(WalletTests, SaplingNullifierIsSpent) {
766     SelectParams(CBaseChainParams::REGTEST);
767     UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
768     UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
769     auto consensusParams = Params().GetConsensus();
770
771     TestWallet wallet;
772
773     // Generate dummy Sapling address
774     auto sk = libzcash::SaplingSpendingKey::random();
775     auto expsk = sk.expanded_spending_key();
776     auto fvk = sk.full_viewing_key();
777     auto pk = sk.default_address();
778
779     // Generate dummy Sapling note
780     libzcash::SaplingNote note(pk, 50000);
781     auto cm = note.cm().get();
782     SaplingMerkleTree tree;
783     tree.append(cm);
784     auto anchor = tree.root();
785     auto witness = tree.witness();
786
787     // Generate transaction
788     auto builder = TransactionBuilder(consensusParams, 1);
789     ASSERT_TRUE(builder.AddSaplingSpend(expsk, note, anchor, witness));
790     builder.AddSaplingOutput(fvk, pk, 25000, {});
791     auto maybe_tx = builder.Build();
792     ASSERT_EQ(static_cast<bool>(maybe_tx), true);
793     auto tx = maybe_tx.get();
794
795     CWalletTx wtx {&wallet, tx};
796     ASSERT_TRUE(wallet.AddSaplingZKey(sk));
797     ASSERT_TRUE(wallet.HaveSaplingSpendingKey(fvk));
798
799     // Manually compute the nullifier based on the known position
800     auto nf = note.nullifier(fvk, witness.position());
801     ASSERT_TRUE(nf);
802     uint256 nullifier = nf.get();
803
804     // Verify note has not been spent
805     EXPECT_FALSE(wallet.IsSaplingSpent(nullifier));
806
807     // Fake-mine the transaction
808     EXPECT_EQ(-1, chainActive.Height());
809     CBlock block;
810     block.vtx.push_back(wtx);
811     block.hashMerkleRoot = block.BuildMerkleTree();
812     auto blockHash = block.GetHash();
813     CBlockIndex fakeIndex {block};
814     mapBlockIndex.insert(std::make_pair(blockHash, &fakeIndex));
815     chainActive.SetTip(&fakeIndex);
816     EXPECT_TRUE(chainActive.Contains(&fakeIndex));
817     EXPECT_EQ(0, chainActive.Height());
818
819     wtx.SetMerkleBranch(block);
820     wallet.AddToWallet(wtx, true, NULL);
821
822     // Verify note has been spent
823     EXPECT_TRUE(wallet.IsSaplingSpent(nullifier));
824
825     // Tear down
826     chainActive.SetTip(NULL);
827     mapBlockIndex.erase(blockHash);
828
829     // Revert to default
830     UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
831     UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
832 }
833
834 TEST(WalletTests, NavigateFromSproutNullifierToNote) {
835     CWallet wallet;
836
837     auto sk = libzcash::SproutSpendingKey::random();
838     wallet.AddSproutSpendingKey(sk);
839
840     auto wtx = GetValidReceive(sk, 10, true);
841     auto note = GetNote(sk, wtx, 0, 1);
842     auto nullifier = note.nullifier(sk);
843
844     mapSproutNoteData_t noteData;
845     JSOutPoint jsoutpt {wtx.GetHash(), 0, 1};
846     SproutNoteData nd {sk.address(), nullifier};
847     noteData[jsoutpt] = nd;
848
849     wtx.SetSproutNoteData(noteData);
850
851     EXPECT_EQ(0, wallet.mapSproutNullifiersToNotes.count(nullifier));
852
853     wallet.AddToWallet(wtx, true, NULL);
854     EXPECT_EQ(1, wallet.mapSproutNullifiersToNotes.count(nullifier));
855     EXPECT_EQ(wtx.GetHash(), wallet.mapSproutNullifiersToNotes[nullifier].hash);
856     EXPECT_EQ(0, wallet.mapSproutNullifiersToNotes[nullifier].js);
857     EXPECT_EQ(1, wallet.mapSproutNullifiersToNotes[nullifier].n);
858 }
859
860 TEST(WalletTests, NavigateFromSaplingNullifierToNote) {
861     SelectParams(CBaseChainParams::REGTEST);
862     UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
863     UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
864     auto consensusParams = Params().GetConsensus();
865
866     TestWallet wallet;
867
868     // Generate dummy Sapling address
869     auto sk = libzcash::SaplingSpendingKey::random();
870     auto expsk = sk.expanded_spending_key();
871     auto fvk = sk.full_viewing_key();
872     auto pk = sk.default_address();
873
874     // Generate dummy Sapling note
875     libzcash::SaplingNote note(pk, 50000);
876     auto cm = note.cm().get();
877     SaplingMerkleTree saplingTree;
878     saplingTree.append(cm);
879     auto anchor = saplingTree.root();
880     auto witness = saplingTree.witness();
881
882     // Generate transaction
883     auto builder = TransactionBuilder(consensusParams, 1);
884     ASSERT_TRUE(builder.AddSaplingSpend(expsk, note, anchor, witness));
885     builder.AddSaplingOutput(fvk, pk, 25000, {});
886     auto maybe_tx = builder.Build();
887     ASSERT_EQ(static_cast<bool>(maybe_tx), true);
888     auto tx = maybe_tx.get();
889
890     CWalletTx wtx {&wallet, tx};
891     ASSERT_TRUE(wallet.AddSaplingZKey(sk));
892     ASSERT_TRUE(wallet.HaveSaplingSpendingKey(fvk));
893
894     // Manually compute the nullifier based on the expected position
895     auto nf = note.nullifier(fvk, witness.position());
896     ASSERT_TRUE(nf);
897     uint256 nullifier = nf.get();
898
899     // Verify dummy note is unspent
900     EXPECT_FALSE(wallet.IsSaplingSpent(nullifier));
901
902     // Fake-mine the transaction
903     EXPECT_EQ(-1, chainActive.Height());
904     SproutMerkleTree sproutTree;
905     CBlock block;
906     block.vtx.push_back(wtx);
907     block.hashMerkleRoot = block.BuildMerkleTree();
908     auto blockHash = block.GetHash();
909     CBlockIndex fakeIndex {block};
910     mapBlockIndex.insert(std::make_pair(blockHash, &fakeIndex));
911     chainActive.SetTip(&fakeIndex);
912     EXPECT_TRUE(chainActive.Contains(&fakeIndex));
913     EXPECT_EQ(0, chainActive.Height());
914
915     // Simulate SyncTransaction which calls AddToWalletIfInvolvingMe
916     wtx.SetMerkleBranch(block);
917     auto saplingNoteData = wallet.FindMySaplingNotes(wtx);
918     ASSERT_TRUE(saplingNoteData.size() > 0);
919     wtx.SetSaplingNoteData(saplingNoteData);
920     wallet.AddToWallet(wtx, true, NULL);
921
922     // Verify dummy note is now spent, as AddToWallet invokes AddToSpends()
923     EXPECT_TRUE(wallet.IsSaplingSpent(nullifier));
924
925     // Test invariant: no witnesses means no nullifier.
926     EXPECT_EQ(0, wallet.mapSaplingNullifiersToNotes.size());
927     for (mapSaplingNoteData_t::value_type &item : wtx.mapSaplingNoteData) {
928         SaplingNoteData nd = item.second;
929         ASSERT_TRUE(nd.witnesses.empty());
930         ASSERT_FALSE(nd.nullifier);
931     }
932
933     // Simulate receiving new block and ChainTip signal
934     wallet.IncrementNoteWitnesses(&fakeIndex, &block, sproutTree, saplingTree);
935     wallet.UpdateSaplingNullifierNoteMapForBlock(&block);
936
937     // Retrieve the updated wtx from wallet
938     uint256 hash = wtx.GetHash();
939     wtx = wallet.mapWallet[hash];
940
941     // Verify Sapling nullifiers map to SaplingOutPoints
942     EXPECT_EQ(2, wallet.mapSaplingNullifiersToNotes.size());
943     for (mapSaplingNoteData_t::value_type &item : wtx.mapSaplingNoteData) {
944         SaplingOutPoint op = item.first;
945         SaplingNoteData nd = item.second;
946         EXPECT_EQ(hash, op.hash);
947         EXPECT_EQ(1, nd.witnesses.size());
948         ASSERT_TRUE(nd.nullifier);
949         auto nf = nd.nullifier.get();
950         EXPECT_EQ(1, wallet.mapSaplingNullifiersToNotes.count(nf));
951         EXPECT_EQ(op.hash, wallet.mapSaplingNullifiersToNotes[nf].hash);
952         EXPECT_EQ(op.n, wallet.mapSaplingNullifiersToNotes[nf].n);
953     }
954
955     // Tear down
956     chainActive.SetTip(NULL);
957     mapBlockIndex.erase(blockHash);
958
959     // Revert to default
960     UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
961     UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
962 }
963
964 TEST(WalletTests, SpentSproutNoteIsFromMe) {
965     CWallet wallet;
966
967     auto sk = libzcash::SproutSpendingKey::random();
968     wallet.AddSproutSpendingKey(sk);
969
970     auto wtx = GetValidReceive(sk, 10, true);
971     auto note = GetNote(sk, wtx, 0, 1);
972     auto nullifier = note.nullifier(sk);
973     auto wtx2 = GetValidSpend(sk, note, 5);
974
975     EXPECT_FALSE(wallet.IsFromMe(wtx));
976     EXPECT_FALSE(wallet.IsFromMe(wtx2));
977
978     mapSproutNoteData_t noteData;
979     JSOutPoint jsoutpt {wtx.GetHash(), 0, 1};
980     SproutNoteData nd {sk.address(), nullifier};
981     noteData[jsoutpt] = nd;
982
983     wtx.SetSproutNoteData(noteData);
984     EXPECT_FALSE(wallet.IsFromMe(wtx));
985     EXPECT_FALSE(wallet.IsFromMe(wtx2));
986
987     wallet.AddToWallet(wtx, true, NULL);
988     EXPECT_FALSE(wallet.IsFromMe(wtx));
989     EXPECT_TRUE(wallet.IsFromMe(wtx2));
990 }
991
992 // Create note A, spend A to create note B, spend and verify note B is from me.
993 TEST(WalletTests, SpentSaplingNoteIsFromMe) {
994     SelectParams(CBaseChainParams::REGTEST);
995     UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
996     UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
997     auto consensusParams = Params().GetConsensus();
998
999     TestWallet wallet;
1000
1001     // Generate Sapling address
1002     auto sk = libzcash::SaplingSpendingKey::random();
1003     auto expsk = sk.expanded_spending_key();
1004     auto fvk = sk.full_viewing_key();
1005     auto ivk = fvk.in_viewing_key();
1006     auto pk = sk.default_address();
1007
1008     // Generate Sapling note A
1009     libzcash::SaplingNote note(pk, 50000);
1010     auto cm = note.cm().get();
1011     SaplingMerkleTree saplingTree;
1012     saplingTree.append(cm);
1013     auto anchor = saplingTree.root();
1014     auto witness = saplingTree.witness();
1015
1016     // Generate transaction, which sends funds to note B
1017     auto builder = TransactionBuilder(consensusParams, 1);
1018     ASSERT_TRUE(builder.AddSaplingSpend(expsk, note, anchor, witness));
1019     builder.AddSaplingOutput(fvk, pk, 25000, {});
1020     auto maybe_tx = builder.Build();
1021     ASSERT_EQ(static_cast<bool>(maybe_tx), true);
1022     auto tx = maybe_tx.get();
1023
1024     CWalletTx wtx {&wallet, tx};
1025     ASSERT_TRUE(wallet.AddSaplingZKey(sk));
1026     ASSERT_TRUE(wallet.HaveSaplingSpendingKey(fvk));
1027
1028     // Fake-mine the transaction
1029     EXPECT_EQ(-1, chainActive.Height());
1030     SproutMerkleTree sproutTree;
1031     CBlock block;
1032     block.vtx.push_back(wtx);
1033     block.hashMerkleRoot = block.BuildMerkleTree();
1034     auto blockHash = block.GetHash();
1035     CBlockIndex fakeIndex {block};
1036     mapBlockIndex.insert(std::make_pair(blockHash, &fakeIndex));
1037     chainActive.SetTip(&fakeIndex);
1038     EXPECT_TRUE(chainActive.Contains(&fakeIndex));
1039     EXPECT_EQ(0, chainActive.Height());
1040
1041     auto saplingNoteData = wallet.FindMySaplingNotes(wtx);
1042     ASSERT_TRUE(saplingNoteData.size() > 0);
1043     wtx.SetSaplingNoteData(saplingNoteData);
1044     wtx.SetMerkleBranch(block);
1045     wallet.AddToWallet(wtx, true, NULL);
1046
1047     // Simulate receiving new block and ChainTip signal.
1048     // This triggers calculation of nullifiers for notes belonging to this wallet
1049     // in the output descriptions of wtx.
1050     wallet.IncrementNoteWitnesses(&fakeIndex, &block, sproutTree, saplingTree);
1051     wallet.UpdateSaplingNullifierNoteMapForBlock(&block);
1052
1053     // Retrieve the updated wtx from wallet
1054     wtx = wallet.mapWallet[wtx.GetHash()];
1055
1056     // The test wallet never received the fake note which is being spent, so there
1057     // is no mapping from nullifier to notedata stored in mapSaplingNullifiersToNotes.
1058     // Therefore the wallet does not know the tx belongs to the wallet.
1059     EXPECT_FALSE(wallet.IsFromMe(wtx));
1060
1061     // Manually compute the nullifier and check map entry does not exist
1062     auto nf = note.nullifier(fvk, witness.position());
1063     ASSERT_TRUE(nf);
1064     ASSERT_FALSE(wallet.mapSaplingNullifiersToNotes.count(nf.get()));
1065
1066     // Decrypt note B
1067     auto maybe_pt = libzcash::SaplingNotePlaintext::decrypt(
1068         wtx.vShieldedOutput[0].encCiphertext,
1069         ivk,
1070         wtx.vShieldedOutput[0].ephemeralKey,
1071         wtx.vShieldedOutput[0].cm);
1072     ASSERT_EQ(static_cast<bool>(maybe_pt), true);
1073     auto maybe_note = maybe_pt.get().note(ivk);
1074     ASSERT_EQ(static_cast<bool>(maybe_note), true);
1075     auto note2 = maybe_note.get();
1076
1077     // Get witness to retrieve position of note B we want to spend
1078     SaplingOutPoint sop0(wtx.GetHash(), 0);
1079     auto spend_note_witness =  wtx.mapSaplingNoteData[sop0].witnesses.front();
1080     auto maybe_nf = note2.nullifier(fvk, spend_note_witness.position());
1081     ASSERT_EQ(static_cast<bool>(maybe_nf), true);
1082     auto nullifier2 = maybe_nf.get();
1083
1084     // NOTE: Not updating the anchor results in a core dump.  Shouldn't builder just return error?
1085     // *** Error in `./zcash-gtest': double free or corruption (out): 0x00007ffd8755d990 ***
1086     anchor = saplingTree.root();
1087
1088     // Create transaction to spend note B
1089     auto builder2 = TransactionBuilder(consensusParams, 2);
1090     ASSERT_TRUE(builder2.AddSaplingSpend(expsk, note2, anchor, spend_note_witness));
1091     builder2.AddSaplingOutput(fvk, pk, 12500, {});
1092     auto maybe_tx2 = builder2.Build();
1093     ASSERT_EQ(static_cast<bool>(maybe_tx2), true);
1094     auto tx2 = maybe_tx2.get();
1095     EXPECT_EQ(tx2.vin.size(), 0);
1096     EXPECT_EQ(tx2.vout.size(), 0);
1097     EXPECT_EQ(tx2.vjoinsplit.size(), 0);
1098     EXPECT_EQ(tx2.vShieldedSpend.size(), 1);
1099     EXPECT_EQ(tx2.vShieldedOutput.size(), 2);
1100     EXPECT_EQ(tx2.valueBalance, 10000);
1101
1102     CWalletTx wtx2 {&wallet, tx2};
1103
1104     // Fake-mine this tx into the next block
1105     EXPECT_EQ(0, chainActive.Height());
1106     CBlock block2;
1107     block2.vtx.push_back(wtx2);
1108     block2.hashMerkleRoot = block2.BuildMerkleTree();
1109     block2.hashPrevBlock = blockHash;
1110     auto blockHash2 = block2.GetHash();
1111     CBlockIndex fakeIndex2 {block2};
1112     mapBlockIndex.insert(std::make_pair(blockHash2, &fakeIndex2));
1113     fakeIndex2.nHeight = 1;
1114     chainActive.SetTip(&fakeIndex2);
1115     EXPECT_TRUE(chainActive.Contains(&fakeIndex2));
1116     EXPECT_EQ(1, chainActive.Height());
1117
1118     auto saplingNoteData2 = wallet.FindMySaplingNotes(wtx2);
1119     ASSERT_TRUE(saplingNoteData2.size() > 0);
1120     wtx2.SetSaplingNoteData(saplingNoteData2);
1121     wtx2.SetMerkleBranch(block2);
1122     wallet.AddToWallet(wtx2, true, NULL);
1123
1124     // Verify note B is spent. AddToWallet invokes AddToSpends which updates mapTxSaplingNullifiers
1125     EXPECT_TRUE(wallet.IsSaplingSpent(nullifier2));
1126
1127     // Verify note B belongs to wallet.
1128     EXPECT_TRUE(wallet.IsFromMe(wtx2));
1129     ASSERT_TRUE(wallet.mapSaplingNullifiersToNotes.count(nullifier2));
1130
1131     // Tear down
1132     chainActive.SetTip(NULL);
1133     mapBlockIndex.erase(blockHash);
1134     mapBlockIndex.erase(blockHash2);
1135
1136     // Revert to default
1137     UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
1138     UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
1139 }
1140
1141 TEST(WalletTests, CachedWitnessesEmptyChain) {
1142     TestWallet wallet;
1143
1144     auto sk = libzcash::SproutSpendingKey::random();
1145     wallet.AddSproutSpendingKey(sk);
1146
1147     auto wtx = GetValidReceive(sk, 10, true, 4);
1148     auto note = GetNote(sk, wtx, 0, 0);
1149     auto note2 = GetNote(sk, wtx, 0, 1);
1150     auto nullifier = note.nullifier(sk);
1151     auto nullifier2 = note2.nullifier(sk);
1152
1153     mapSproutNoteData_t sproutNoteData;
1154     JSOutPoint jsoutpt {wtx.GetHash(), 0, 0};
1155     JSOutPoint jsoutpt2 {wtx.GetHash(), 0, 1};
1156     SproutNoteData nd {sk.address(), nullifier};
1157     SproutNoteData nd2 {sk.address(), nullifier2};
1158     sproutNoteData[jsoutpt] = nd;
1159     sproutNoteData[jsoutpt2] = nd2;
1160     wtx.SetSproutNoteData(sproutNoteData);
1161
1162     std::vector<JSOutPoint> sproutNotes {jsoutpt, jsoutpt2};
1163     std::vector<SaplingOutPoint> saplingNotes = SetSaplingNoteData(wtx);
1164
1165     std::vector<boost::optional<SproutWitness>> sproutWitnesses;
1166     std::vector<boost::optional<SaplingWitness>> saplingWitnesses;
1167
1168     ::GetWitnessesAndAnchors(wallet, sproutNotes, saplingNotes, sproutWitnesses, saplingWitnesses);
1169
1170     EXPECT_FALSE((bool) sproutWitnesses[0]);
1171     EXPECT_FALSE((bool) sproutWitnesses[1]);
1172     EXPECT_FALSE((bool) saplingWitnesses[0]);
1173
1174     wallet.AddToWallet(wtx, true, NULL);
1175
1176     ::GetWitnessesAndAnchors(wallet, sproutNotes, saplingNotes, sproutWitnesses, saplingWitnesses);
1177
1178     EXPECT_FALSE((bool) sproutWitnesses[0]);
1179     EXPECT_FALSE((bool) sproutWitnesses[1]);
1180     EXPECT_FALSE((bool) saplingWitnesses[0]);
1181
1182     CBlock block;
1183     block.vtx.push_back(wtx);
1184     CBlockIndex index(block);
1185     SproutMerkleTree sproutTree;
1186     SaplingMerkleTree saplingTree;
1187     wallet.IncrementNoteWitnesses(&index, &block, sproutTree, saplingTree);
1188
1189     ::GetWitnessesAndAnchors(wallet, sproutNotes, saplingNotes, sproutWitnesses, saplingWitnesses);
1190
1191     EXPECT_TRUE((bool) sproutWitnesses[0]);
1192     EXPECT_TRUE((bool) sproutWitnesses[1]);
1193     EXPECT_TRUE((bool) saplingWitnesses[0]);
1194
1195     // Until #1302 is implemented, this should triggger an assertion
1196     EXPECT_DEATH(wallet.DecrementNoteWitnesses(&index),
1197                  ".*nWitnessCacheSize > 0.*");
1198 }
1199
1200 TEST(WalletTests, CachedWitnessesChainTip) {
1201     TestWallet wallet;
1202     std::pair<uint256, uint256> anchors1;
1203     CBlock block1;
1204     SproutMerkleTree sproutTree;
1205     SaplingMerkleTree saplingTree;
1206
1207     auto sk = libzcash::SproutSpendingKey::random();
1208     wallet.AddSproutSpendingKey(sk);
1209
1210     {
1211         // First block (case tested in _empty_chain)
1212         CBlockIndex index1(block1);
1213         index1.nHeight = 1;
1214         auto outpts = CreateValidBlock(wallet, sk, index1, block1, sproutTree, saplingTree);
1215
1216         // Called to fetch anchor
1217         std::vector<JSOutPoint> sproutNotes {outpts.first};
1218         std::vector<SaplingOutPoint> saplingNotes {outpts.second};
1219         std::vector<boost::optional<SproutWitness>> sproutWitnesses;
1220         std::vector<boost::optional<SaplingWitness>> saplingWitnesses;
1221
1222         anchors1 = GetWitnessesAndAnchors(wallet, sproutNotes, saplingNotes, sproutWitnesses, saplingWitnesses);
1223         EXPECT_NE(anchors1.first, anchors1.second);
1224     }
1225
1226     {
1227         // Second transaction
1228         auto wtx = GetValidReceive(sk, 50, true, 4);
1229         auto note = GetNote(sk, wtx, 0, 1);
1230         auto nullifier = note.nullifier(sk);
1231
1232         mapSproutNoteData_t sproutNoteData;
1233         JSOutPoint jsoutpt {wtx.GetHash(), 0, 1};
1234         SproutNoteData nd {sk.address(), nullifier};
1235         sproutNoteData[jsoutpt] = nd;
1236         wtx.SetSproutNoteData(sproutNoteData);
1237         std::vector<SaplingOutPoint> saplingNotes = SetSaplingNoteData(wtx);
1238         wallet.AddToWallet(wtx, true, NULL);
1239
1240         std::vector<JSOutPoint> sproutNotes {jsoutpt};
1241         std::vector<boost::optional<SproutWitness>> sproutWitnesses;
1242         std::vector<boost::optional<SaplingWitness>> saplingWitnesses;
1243
1244         GetWitnessesAndAnchors(wallet, sproutNotes, saplingNotes, sproutWitnesses, saplingWitnesses);
1245
1246         EXPECT_FALSE((bool) sproutWitnesses[0]);
1247         EXPECT_FALSE((bool) saplingWitnesses[0]);
1248
1249         // Second block
1250         CBlock block2;
1251         block2.hashPrevBlock = block1.GetHash();
1252         block2.vtx.push_back(wtx);
1253         CBlockIndex index2(block2);
1254         index2.nHeight = 2;
1255         SproutMerkleTree sproutTree2 {sproutTree};
1256         SaplingMerkleTree saplingTree2 {saplingTree};
1257         wallet.IncrementNoteWitnesses(&index2, &block2, sproutTree2, saplingTree2);
1258
1259         auto anchors2 = GetWitnessesAndAnchors(wallet, sproutNotes, saplingNotes, sproutWitnesses, saplingWitnesses);
1260         EXPECT_NE(anchors2.first, anchors2.second);
1261
1262         EXPECT_TRUE((bool) sproutWitnesses[0]);
1263         EXPECT_TRUE((bool) saplingWitnesses[0]);
1264         EXPECT_NE(anchors1.first, anchors2.first);
1265         EXPECT_NE(anchors1.second, anchors2.second);
1266
1267         // Decrementing should give us the previous anchor
1268         wallet.DecrementNoteWitnesses(&index2);
1269         auto anchors3 = GetWitnessesAndAnchors(wallet, sproutNotes, saplingNotes, sproutWitnesses, saplingWitnesses);
1270
1271         EXPECT_FALSE((bool) sproutWitnesses[0]);
1272         EXPECT_FALSE((bool) saplingWitnesses[0]);
1273         // Should not equal first anchor because none of these notes had witnesses
1274         EXPECT_NE(anchors1.first, anchors3.first);
1275         EXPECT_NE(anchors1.second, anchors3.second);
1276
1277         // Re-incrementing with the same block should give the same result
1278         wallet.IncrementNoteWitnesses(&index2, &block2, sproutTree, saplingTree);
1279         auto anchors4 = GetWitnessesAndAnchors(wallet, sproutNotes, saplingNotes, sproutWitnesses, saplingWitnesses);
1280         EXPECT_NE(anchors4.first, anchors4.second);
1281
1282         EXPECT_TRUE((bool) sproutWitnesses[0]);
1283         EXPECT_TRUE((bool) saplingWitnesses[0]);
1284         EXPECT_EQ(anchors2.first, anchors4.first);
1285         EXPECT_EQ(anchors2.second, anchors4.second);
1286
1287         // Incrementing with the same block again should not change the cache
1288         wallet.IncrementNoteWitnesses(&index2, &block2, sproutTree, saplingTree);
1289         std::vector<boost::optional<SproutWitness>> sproutWitnesses5;
1290         std::vector<boost::optional<SaplingWitness>> saplingWitnesses5;
1291
1292         auto anchors5 = GetWitnessesAndAnchors(wallet, sproutNotes, saplingNotes, sproutWitnesses5, saplingWitnesses5);
1293         EXPECT_NE(anchors5.first, anchors5.second);
1294
1295         EXPECT_EQ(sproutWitnesses, sproutWitnesses5);
1296         EXPECT_EQ(saplingWitnesses, saplingWitnesses5);
1297         EXPECT_EQ(anchors4.first, anchors5.first);
1298         EXPECT_EQ(anchors4.second, anchors5.second);
1299     }
1300 }
1301
1302 TEST(WalletTests, CachedWitnessesDecrementFirst) {
1303     TestWallet wallet;
1304     SproutMerkleTree sproutTree;
1305     SaplingMerkleTree saplingTree;
1306
1307     auto sk = libzcash::SproutSpendingKey::random();
1308     wallet.AddSproutSpendingKey(sk);
1309
1310     {
1311         // First block (case tested in _empty_chain)
1312         CBlock block1;
1313         CBlockIndex index1(block1);
1314         index1.nHeight = 1;
1315         CreateValidBlock(wallet, sk, index1, block1, sproutTree, saplingTree);
1316     }
1317
1318     std::pair<uint256, uint256> anchors2;
1319     CBlock block2;
1320     CBlockIndex index2(block2);
1321
1322     {
1323         // Second block (case tested in _chain_tip)
1324         index2.nHeight = 2;
1325         auto outpts = CreateValidBlock(wallet, sk, index2, block2, sproutTree, saplingTree);
1326
1327         // Called to fetch anchor
1328         std::vector<JSOutPoint> sproutNotes {outpts.first};
1329         std::vector<SaplingOutPoint> saplingNotes {outpts.second};
1330         std::vector<boost::optional<SproutWitness>> sproutWitnesses;
1331         std::vector<boost::optional<SaplingWitness>> saplingWitnesses;
1332         anchors2 = GetWitnessesAndAnchors(wallet, sproutNotes, saplingNotes, sproutWitnesses, saplingWitnesses);
1333     }
1334
1335 {
1336         // Third transaction - never mined
1337         auto wtx = GetValidReceive(sk, 20, true, 4);
1338         auto note = GetNote(sk, wtx, 0, 1);
1339         auto nullifier = note.nullifier(sk);
1340
1341         mapSproutNoteData_t noteData;
1342         JSOutPoint jsoutpt {wtx.GetHash(), 0, 1};
1343         SproutNoteData nd {sk.address(), nullifier};
1344         noteData[jsoutpt] = nd;
1345         wtx.SetSproutNoteData(noteData);
1346         std::vector<SaplingOutPoint> saplingNotes = SetSaplingNoteData(wtx);
1347         wallet.AddToWallet(wtx, true, NULL);
1348
1349         std::vector<JSOutPoint> sproutNotes {jsoutpt};
1350         std::vector<boost::optional<SproutWitness>> sproutWitnesses;
1351         std::vector<boost::optional<SaplingWitness>> saplingWitnesses;
1352
1353         auto anchors3 = GetWitnessesAndAnchors(wallet, sproutNotes, saplingNotes, sproutWitnesses, saplingWitnesses);
1354
1355         EXPECT_FALSE((bool) sproutWitnesses[0]);
1356         EXPECT_FALSE((bool) saplingWitnesses[0]);
1357
1358         // Decrementing (before the transaction has ever seen an increment)
1359         // should give us the previous anchor
1360         wallet.DecrementNoteWitnesses(&index2);
1361
1362         auto anchors4 = GetWitnessesAndAnchors(wallet, sproutNotes, saplingNotes, sproutWitnesses, saplingWitnesses);
1363
1364         EXPECT_FALSE((bool) sproutWitnesses[0]);
1365         EXPECT_FALSE((bool) saplingWitnesses[0]);
1366         // Should not equal second anchor because none of these notes had witnesses
1367         EXPECT_NE(anchors2.first, anchors4.first);
1368         EXPECT_NE(anchors2.second, anchors4.second);
1369
1370         // Re-incrementing with the same block should give the same result
1371         wallet.IncrementNoteWitnesses(&index2, &block2, sproutTree, saplingTree);
1372
1373         auto anchors5 = GetWitnessesAndAnchors(wallet, sproutNotes, saplingNotes, sproutWitnesses, saplingWitnesses);
1374
1375         EXPECT_FALSE((bool) sproutWitnesses[0]);
1376         EXPECT_FALSE((bool) saplingWitnesses[0]);
1377         EXPECT_EQ(anchors3.first, anchors5.first);
1378         EXPECT_EQ(anchors3.second, anchors5.second);
1379     }
1380 }
1381
1382 TEST(WalletTests, CachedWitnessesCleanIndex) {
1383     TestWallet wallet;
1384     std::vector<CBlock> blocks;
1385     std::vector<CBlockIndex> indices;
1386     std::vector<JSOutPoint> sproutNotes;
1387     std::vector<SaplingOutPoint> saplingNotes;
1388     std::vector<uint256> sproutAnchors;
1389     std::vector<uint256> saplingAnchors;
1390     SproutMerkleTree sproutTree;
1391     SproutMerkleTree sproutRiTree = sproutTree;
1392     SaplingMerkleTree saplingTree;
1393     SaplingMerkleTree saplingRiTree = saplingTree;
1394     std::vector<boost::optional<SproutWitness>> sproutWitnesses;
1395     std::vector<boost::optional<SaplingWitness>> saplingWitnesses;
1396
1397     auto sk = libzcash::SproutSpendingKey::random();
1398     wallet.AddSproutSpendingKey(sk);
1399
1400     // Generate a chain
1401     size_t numBlocks = WITNESS_CACHE_SIZE + 10;
1402     blocks.resize(numBlocks);
1403     indices.resize(numBlocks);
1404     for (size_t i = 0; i < numBlocks; i++) {
1405         indices[i].nHeight = i;
1406         auto oldSproutRoot = sproutTree.root();
1407         auto oldSaplingRoot = saplingTree.root();
1408         auto outpts = CreateValidBlock(wallet, sk, indices[i], blocks[i], sproutTree, saplingTree);
1409         EXPECT_NE(oldSproutRoot, sproutTree.root());
1410         EXPECT_NE(oldSaplingRoot, saplingTree.root());
1411         sproutNotes.push_back(outpts.first);
1412         saplingNotes.push_back(outpts.second);
1413
1414         auto anchors = GetWitnessesAndAnchors(wallet, sproutNotes, saplingNotes, sproutWitnesses, saplingWitnesses);
1415         for (size_t j = 0; j <= i; j++) {
1416             EXPECT_TRUE((bool) sproutWitnesses[j]);
1417             EXPECT_TRUE((bool) saplingWitnesses[j]);
1418         }
1419         sproutAnchors.push_back(anchors.first);
1420         saplingAnchors.push_back(anchors.second);
1421     }
1422
1423     // Now pretend we are reindexing: the chain is cleared, and each block is
1424     // used to increment witnesses again.
1425     for (size_t i = 0; i < numBlocks; i++) {
1426         SproutMerkleTree sproutRiPrevTree {sproutRiTree};
1427         SaplingMerkleTree saplingRiPrevTree {saplingRiTree};
1428         wallet.IncrementNoteWitnesses(&(indices[i]), &(blocks[i]), sproutRiTree, saplingRiTree);
1429
1430         auto anchors = GetWitnessesAndAnchors(wallet, sproutNotes, saplingNotes, sproutWitnesses, saplingWitnesses);
1431         for (size_t j = 0; j < numBlocks; j++) {
1432             EXPECT_TRUE((bool) sproutWitnesses[j]);
1433             EXPECT_TRUE((bool) saplingWitnesses[j]);
1434         }
1435         // Should equal final anchor because witness cache unaffected
1436         EXPECT_EQ(sproutAnchors.back(), anchors.first);
1437         EXPECT_EQ(saplingAnchors.back(), anchors.second);
1438
1439         if ((i == 5) || (i == 50)) {
1440             // Pretend a reorg happened that was recorded in the block files
1441             {
1442                 wallet.DecrementNoteWitnesses(&(indices[i]));
1443
1444                 auto anchors = GetWitnessesAndAnchors(wallet, sproutNotes, saplingNotes, sproutWitnesses, saplingWitnesses);
1445                 for (size_t j = 0; j < numBlocks; j++) {
1446                     EXPECT_TRUE((bool) sproutWitnesses[j]);
1447                     EXPECT_TRUE((bool) saplingWitnesses[j]);
1448                 }
1449                 // Should equal final anchor because witness cache unaffected
1450                 EXPECT_EQ(sproutAnchors.back(), anchors.first);
1451                 EXPECT_EQ(saplingAnchors.back(), anchors.second);
1452             }
1453
1454             {
1455                 wallet.IncrementNoteWitnesses(&(indices[i]), &(blocks[i]), sproutRiPrevTree, saplingRiPrevTree);
1456                 auto anchors = GetWitnessesAndAnchors(wallet, sproutNotes, saplingNotes, sproutWitnesses, saplingWitnesses);
1457                 for (size_t j = 0; j < numBlocks; j++) {
1458                     EXPECT_TRUE((bool) sproutWitnesses[j]);
1459                     EXPECT_TRUE((bool) saplingWitnesses[j]);
1460                 }
1461                 // Should equal final anchor because witness cache unaffected
1462                 EXPECT_EQ(sproutAnchors.back(), anchors.first);
1463                 EXPECT_EQ(saplingAnchors.back(), anchors.second);
1464             }
1465         }
1466     }
1467 }
1468
1469 TEST(WalletTests, ClearNoteWitnessCache) {
1470     TestWallet wallet;
1471
1472     auto sk = libzcash::SproutSpendingKey::random();
1473     wallet.AddSproutSpendingKey(sk);
1474
1475     auto wtx = GetValidReceive(sk, 10, true, 4);
1476     auto hash = wtx.GetHash();
1477     auto note = GetNote(sk, wtx, 0, 0);
1478     auto nullifier = note.nullifier(sk);
1479
1480     mapSproutNoteData_t noteData;
1481     JSOutPoint jsoutpt {wtx.GetHash(), 0, 0};
1482     JSOutPoint jsoutpt2 {wtx.GetHash(), 0, 1};
1483     SproutNoteData nd {sk.address(), nullifier};
1484     noteData[jsoutpt] = nd;
1485     wtx.SetSproutNoteData(noteData);
1486     auto saplingNotes = SetSaplingNoteData(wtx);
1487
1488     // Pretend we mined the tx by adding a fake witness
1489     SproutMerkleTree sproutTree;
1490     wtx.mapSproutNoteData[jsoutpt].witnesses.push_front(sproutTree.witness());
1491     wtx.mapSproutNoteData[jsoutpt].witnessHeight = 1;
1492     wallet.nWitnessCacheSize = 1;
1493
1494     SaplingMerkleTree saplingTree;
1495     wtx.mapSaplingNoteData[saplingNotes[0]].witnesses.push_front(saplingTree.witness());
1496     wtx.mapSaplingNoteData[saplingNotes[0]].witnessHeight = 1;
1497     wallet.nWitnessCacheSize = 2;
1498
1499     wallet.AddToWallet(wtx, true, NULL);
1500
1501     std::vector<JSOutPoint> sproutNotes {jsoutpt, jsoutpt2};
1502     std::vector<boost::optional<SproutWitness>> sproutWitnesses;
1503     std::vector<boost::optional<SaplingWitness>> saplingWitnesses;
1504
1505     // Before clearing, we should have a witness for one note
1506     GetWitnessesAndAnchors(wallet, sproutNotes, saplingNotes, sproutWitnesses, saplingWitnesses);
1507     EXPECT_TRUE((bool) sproutWitnesses[0]);
1508     EXPECT_FALSE((bool) sproutWitnesses[1]);
1509     EXPECT_TRUE((bool) saplingWitnesses[0]);
1510     EXPECT_FALSE((bool) saplingWitnesses[1]);
1511     EXPECT_EQ(1, wallet.mapWallet[hash].mapSproutNoteData[jsoutpt].witnessHeight);
1512     EXPECT_EQ(1, wallet.mapWallet[hash].mapSaplingNoteData[saplingNotes[0]].witnessHeight);
1513     EXPECT_EQ(2, wallet.nWitnessCacheSize);
1514
1515     // After clearing, we should not have a witness for either note
1516     wallet.ClearNoteWitnessCache();
1517     auto anchors2 = GetWitnessesAndAnchors(wallet, sproutNotes, saplingNotes, sproutWitnesses, saplingWitnesses);
1518     EXPECT_FALSE((bool) sproutWitnesses[0]);
1519     EXPECT_FALSE((bool) sproutWitnesses[1]);
1520     EXPECT_FALSE((bool) saplingWitnesses[0]);
1521     EXPECT_FALSE((bool) saplingWitnesses[1]);
1522     EXPECT_EQ(-1, wallet.mapWallet[hash].mapSproutNoteData[jsoutpt].witnessHeight);
1523     EXPECT_EQ(-1, wallet.mapWallet[hash].mapSaplingNoteData[saplingNotes[0]].witnessHeight);
1524     EXPECT_EQ(0, wallet.nWitnessCacheSize);
1525 }
1526
1527 TEST(WalletTests, WriteWitnessCache) {
1528     TestWallet wallet;
1529     MockWalletDB walletdb;
1530     CBlockLocator loc;
1531
1532     auto sk = libzcash::SproutSpendingKey::random();
1533     wallet.AddSproutSpendingKey(sk);
1534
1535     auto wtx = GetValidReceive(sk, 10, true);
1536     wallet.AddToWallet(wtx, true, NULL);
1537
1538     // TxnBegin fails
1539     EXPECT_CALL(walletdb, TxnBegin())
1540         .WillOnce(Return(false));
1541     wallet.SetBestChain(walletdb, loc);
1542     EXPECT_CALL(walletdb, TxnBegin())
1543         .WillRepeatedly(Return(true));
1544
1545     // WriteTx fails
1546     EXPECT_CALL(walletdb, WriteTx(wtx.GetHash(), wtx))
1547         .WillOnce(Return(false));
1548     EXPECT_CALL(walletdb, TxnAbort())
1549         .Times(1);
1550     wallet.SetBestChain(walletdb, loc);
1551
1552     // WriteTx throws
1553     EXPECT_CALL(walletdb, WriteTx(wtx.GetHash(), wtx))
1554         .WillOnce(ThrowLogicError());
1555     EXPECT_CALL(walletdb, TxnAbort())
1556         .Times(1);
1557     wallet.SetBestChain(walletdb, loc);
1558     EXPECT_CALL(walletdb, WriteTx(wtx.GetHash(), wtx))
1559         .WillRepeatedly(Return(true));
1560
1561     // WriteWitnessCacheSize fails
1562     EXPECT_CALL(walletdb, WriteWitnessCacheSize(0))
1563         .WillOnce(Return(false));
1564     EXPECT_CALL(walletdb, TxnAbort())
1565         .Times(1);
1566     wallet.SetBestChain(walletdb, loc);
1567
1568     // WriteWitnessCacheSize throws
1569     EXPECT_CALL(walletdb, WriteWitnessCacheSize(0))
1570         .WillOnce(ThrowLogicError());
1571     EXPECT_CALL(walletdb, TxnAbort())
1572         .Times(1);
1573     wallet.SetBestChain(walletdb, loc);
1574     EXPECT_CALL(walletdb, WriteWitnessCacheSize(0))
1575         .WillRepeatedly(Return(true));
1576
1577     // WriteBestBlock fails
1578     EXPECT_CALL(walletdb, WriteBestBlock(loc))
1579         .WillOnce(Return(false));
1580     EXPECT_CALL(walletdb, TxnAbort())
1581         .Times(1);
1582     wallet.SetBestChain(walletdb, loc);
1583
1584     // WriteBestBlock throws
1585     EXPECT_CALL(walletdb, WriteBestBlock(loc))
1586         .WillOnce(ThrowLogicError());
1587     EXPECT_CALL(walletdb, TxnAbort())
1588         .Times(1);
1589     wallet.SetBestChain(walletdb, loc);
1590     EXPECT_CALL(walletdb, WriteBestBlock(loc))
1591         .WillRepeatedly(Return(true));
1592
1593     // TxCommit fails
1594     EXPECT_CALL(walletdb, TxnCommit())
1595         .WillOnce(Return(false));
1596     wallet.SetBestChain(walletdb, loc);
1597     EXPECT_CALL(walletdb, TxnCommit())
1598         .WillRepeatedly(Return(true));
1599
1600     // Everything succeeds
1601     wallet.SetBestChain(walletdb, loc);
1602 }
1603
1604 TEST(WalletTests, UpdateSproutNullifierNoteMap) {
1605     TestWallet wallet;
1606     uint256 r {GetRandHash()};
1607     CKeyingMaterial vMasterKey (r.begin(), r.end());
1608
1609     auto sk = libzcash::SproutSpendingKey::random();
1610     wallet.AddSproutSpendingKey(sk);
1611
1612     ASSERT_TRUE(wallet.EncryptKeys(vMasterKey));
1613
1614     auto wtx = GetValidReceive(sk, 10, true);
1615     auto note = GetNote(sk, wtx, 0, 1);
1616     auto nullifier = note.nullifier(sk);
1617
1618     // Pretend that we called FindMySproutNotes while the wallet was locked
1619     mapSproutNoteData_t noteData;
1620     JSOutPoint jsoutpt {wtx.GetHash(), 0, 1};
1621     SproutNoteData nd {sk.address()};
1622     noteData[jsoutpt] = nd;
1623     wtx.SetSproutNoteData(noteData);
1624
1625     wallet.AddToWallet(wtx, true, NULL);
1626     EXPECT_EQ(0, wallet.mapSproutNullifiersToNotes.count(nullifier));
1627
1628     EXPECT_FALSE(wallet.UpdateNullifierNoteMap());
1629
1630     ASSERT_TRUE(wallet.Unlock(vMasterKey));
1631
1632     EXPECT_TRUE(wallet.UpdateNullifierNoteMap());
1633     EXPECT_EQ(1, wallet.mapSproutNullifiersToNotes.count(nullifier));
1634     EXPECT_EQ(wtx.GetHash(), wallet.mapSproutNullifiersToNotes[nullifier].hash);
1635     EXPECT_EQ(0, wallet.mapSproutNullifiersToNotes[nullifier].js);
1636     EXPECT_EQ(1, wallet.mapSproutNullifiersToNotes[nullifier].n);
1637 }
1638
1639 TEST(WalletTests, UpdatedSproutNoteData) {
1640     TestWallet wallet;
1641
1642     auto sk = libzcash::SproutSpendingKey::random();
1643     wallet.AddSproutSpendingKey(sk);
1644
1645     auto wtx = GetValidReceive(sk, 10, true);
1646     auto note = GetNote(sk, wtx, 0, 0);
1647     auto note2 = GetNote(sk, wtx, 0, 1);
1648     auto nullifier = note.nullifier(sk);
1649     auto nullifier2 = note2.nullifier(sk);
1650     auto wtx2 = wtx;
1651
1652     // First pretend we added the tx to the wallet and
1653     // we don't have the key for the second note
1654     mapSproutNoteData_t noteData;
1655     JSOutPoint jsoutpt {wtx.GetHash(), 0, 0};
1656     SproutNoteData nd {sk.address(), nullifier};
1657     noteData[jsoutpt] = nd;
1658     wtx.SetSproutNoteData(noteData);
1659
1660     // Pretend we mined the tx by adding a fake witness
1661     SproutMerkleTree tree;
1662     wtx.mapSproutNoteData[jsoutpt].witnesses.push_front(tree.witness());
1663     wtx.mapSproutNoteData[jsoutpt].witnessHeight = 100;
1664
1665     // Now pretend we added the key for the second note, and
1666     // the tx was "added" to the wallet again to update it.
1667     // This happens via the 'z_importkey' RPC method.
1668     JSOutPoint jsoutpt2 {wtx2.GetHash(), 0, 1};
1669     SproutNoteData nd2 {sk.address(), nullifier2};
1670     noteData[jsoutpt2] = nd2;
1671     wtx2.SetSproutNoteData(noteData);
1672
1673     // The txs should initially be different
1674     EXPECT_NE(wtx.mapSproutNoteData, wtx2.mapSproutNoteData);
1675     EXPECT_EQ(1, wtx.mapSproutNoteData[jsoutpt].witnesses.size());
1676     EXPECT_EQ(100, wtx.mapSproutNoteData[jsoutpt].witnessHeight);
1677
1678     // After updating, they should be the same
1679     EXPECT_TRUE(wallet.UpdatedNoteData(wtx2, wtx));
1680     EXPECT_EQ(wtx.mapSproutNoteData, wtx2.mapSproutNoteData);
1681     EXPECT_EQ(1, wtx.mapSproutNoteData[jsoutpt].witnesses.size());
1682     EXPECT_EQ(100, wtx.mapSproutNoteData[jsoutpt].witnessHeight);
1683     // TODO: The new note should get witnessed (but maybe not here) (#1350)
1684 }
1685
1686 TEST(WalletTests, UpdatedSaplingNoteData) {
1687     SelectParams(CBaseChainParams::REGTEST);
1688     UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
1689     UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
1690     auto consensusParams = Params().GetConsensus();
1691
1692     TestWallet wallet;
1693
1694     // Generate dummy Sapling address
1695     auto sk = libzcash::SaplingSpendingKey::random();
1696     auto expsk = sk.expanded_spending_key();
1697     auto fvk = sk.full_viewing_key();
1698     auto pk = sk.default_address();
1699
1700     // Generate dummy recipient Sapling address
1701     auto sk2 = libzcash::SaplingSpendingKey::random();
1702     auto fvk2 = sk2.full_viewing_key();
1703     auto pk2 = sk2.default_address();
1704
1705     // Generate dummy Sapling note
1706     libzcash::SaplingNote note(pk, 50000);
1707     auto cm = note.cm().get();
1708     SaplingMerkleTree saplingTree;
1709     saplingTree.append(cm);
1710     auto anchor = saplingTree.root();
1711     auto witness = saplingTree.witness();
1712
1713     // Generate transaction
1714     auto builder = TransactionBuilder(consensusParams, 1);
1715     ASSERT_TRUE(builder.AddSaplingSpend(expsk, note, anchor, witness));
1716     builder.AddSaplingOutput(fvk, pk2, 25000, {});
1717     auto maybe_tx = builder.Build();
1718     ASSERT_EQ(static_cast<bool>(maybe_tx), true);
1719     auto tx = maybe_tx.get();
1720
1721     // Wallet contains fvk1 but not fvk2
1722     CWalletTx wtx {&wallet, tx};
1723     ASSERT_TRUE(wallet.AddSaplingZKey(sk));
1724     ASSERT_TRUE(wallet.HaveSaplingSpendingKey(fvk));
1725     ASSERT_FALSE(wallet.HaveSaplingSpendingKey(fvk2));
1726
1727     // Fake-mine the transaction
1728     EXPECT_EQ(-1, chainActive.Height());
1729     SproutMerkleTree sproutTree;
1730     CBlock block;
1731     block.vtx.push_back(wtx);
1732     block.hashMerkleRoot = block.BuildMerkleTree();
1733     auto blockHash = block.GetHash();
1734     CBlockIndex fakeIndex {block};
1735     mapBlockIndex.insert(std::make_pair(blockHash, &fakeIndex));
1736     chainActive.SetTip(&fakeIndex);
1737     EXPECT_TRUE(chainActive.Contains(&fakeIndex));
1738     EXPECT_EQ(0, chainActive.Height());
1739
1740     // Simulate SyncTransaction which calls AddToWalletIfInvolvingMe
1741     auto saplingNoteData = wallet.FindMySaplingNotes(wtx);
1742     ASSERT_TRUE(saplingNoteData.size() == 1); // wallet only has key for change output
1743     wtx.SetSaplingNoteData(saplingNoteData);
1744     wtx.SetMerkleBranch(block);
1745     wallet.AddToWallet(wtx, true, NULL);
1746
1747     // Simulate receiving new block and ChainTip signal
1748     wallet.IncrementNoteWitnesses(&fakeIndex, &block, sproutTree, saplingTree);
1749     wallet.UpdateSaplingNullifierNoteMapForBlock(&block);
1750
1751     // Retrieve the updated wtx from wallet
1752     uint256 hash = wtx.GetHash();
1753     wtx = wallet.mapWallet[hash];
1754
1755     // Now lets add key fvk2 so wallet can find the payment note sent to pk2
1756     ASSERT_TRUE(wallet.AddSaplingZKey(sk2));
1757     ASSERT_TRUE(wallet.HaveSaplingSpendingKey(fvk2));
1758     CWalletTx wtx2 = wtx;
1759     auto saplingNoteData2 = wallet.FindMySaplingNotes(wtx2);
1760     ASSERT_TRUE(saplingNoteData2.size() == 2);
1761     wtx2.SetSaplingNoteData(saplingNoteData2);
1762
1763     // The payment note has not been witnessed yet, so let's fake the witness.
1764     SaplingOutPoint sop0(wtx2.GetHash(), 0);
1765     SaplingOutPoint sop1(wtx2.GetHash(), 1);
1766     wtx2.mapSaplingNoteData[sop0].witnesses.push_front(saplingTree.witness());
1767     wtx2.mapSaplingNoteData[sop0].witnessHeight = 0;
1768
1769     // The txs are different as wtx is aware of just the change output,
1770     // whereas wtx2 is aware of both payment and change outputs.
1771     EXPECT_NE(wtx.mapSaplingNoteData, wtx2.mapSaplingNoteData);
1772     EXPECT_EQ(1, wtx.mapSaplingNoteData.size());
1773     EXPECT_EQ(1, wtx.mapSaplingNoteData[sop1].witnesses.size());    // wtx has witness for change
1774
1775     EXPECT_EQ(2, wtx2.mapSaplingNoteData.size());
1776     EXPECT_EQ(1, wtx2.mapSaplingNoteData[sop0].witnesses.size());    // wtx2 has fake witness for payment output
1777     EXPECT_EQ(0, wtx2.mapSaplingNoteData[sop1].witnesses.size());    // wtx2 never had incrementnotewitness called
1778
1779     // After updating, they should be the same
1780     EXPECT_TRUE(wallet.UpdatedNoteData(wtx2, wtx));
1781
1782     // We can't do this:
1783     // EXPECT_EQ(wtx.mapSaplingNoteData, wtx2.mapSaplingNoteData);
1784     // because nullifiers (if part of == comparator) have not all been computed
1785     // Also note that mapwallet[hash] is not updated with the updated wtx.
1786    // wtx = wallet.mapWallet[hash];
1787
1788     EXPECT_EQ(2, wtx.mapSaplingNoteData.size());
1789     EXPECT_EQ(2, wtx2.mapSaplingNoteData.size());
1790     // wtx copied over the fake witness from wtx2 for the payment output
1791     EXPECT_EQ(wtx.mapSaplingNoteData[sop0].witnesses.front(), wtx2.mapSaplingNoteData[sop0].witnesses.front());
1792     // wtx2 never had its change output witnessed even though it has been in wtx
1793     EXPECT_EQ(0, wtx2.mapSaplingNoteData[sop1].witnesses.size());
1794     EXPECT_EQ(wtx.mapSaplingNoteData[sop1].witnesses.front(), saplingTree.witness());
1795
1796     // Tear down
1797     chainActive.SetTip(NULL);
1798     mapBlockIndex.erase(blockHash);
1799
1800     // Revert to default
1801     UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
1802     UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
1803 }
1804
1805 TEST(WalletTests, MarkAffectedSproutTransactionsDirty) {
1806     TestWallet wallet;
1807
1808     auto sk = libzcash::SproutSpendingKey::random();
1809     wallet.AddSproutSpendingKey(sk);
1810
1811     auto wtx = GetValidReceive(sk, 10, true);
1812     auto hash = wtx.GetHash();
1813     auto note = GetNote(sk, wtx, 0, 1);
1814     auto nullifier = note.nullifier(sk);
1815     auto wtx2 = GetValidSpend(sk, note, 5);
1816
1817     mapSproutNoteData_t noteData;
1818     JSOutPoint jsoutpt {hash, 0, 1};
1819     SproutNoteData nd {sk.address(), nullifier};
1820     noteData[jsoutpt] = nd;
1821
1822     wtx.SetSproutNoteData(noteData);
1823     wallet.AddToWallet(wtx, true, NULL);
1824     wallet.MarkAffectedTransactionsDirty(wtx);
1825
1826     // After getting a cached value, the first tx should be clean
1827     wallet.mapWallet[hash].GetDebit(ISMINE_ALL);
1828     EXPECT_TRUE(wallet.mapWallet[hash].fDebitCached);
1829
1830     // After adding the note spend, the first tx should be dirty
1831     wallet.AddToWallet(wtx2, true, NULL);
1832     wallet.MarkAffectedTransactionsDirty(wtx2);
1833     EXPECT_FALSE(wallet.mapWallet[hash].fDebitCached);
1834 }
1835
1836 TEST(WalletTests, MarkAffectedSaplingTransactionsDirty) {
1837     SelectParams(CBaseChainParams::REGTEST);
1838     UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
1839     UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
1840     auto consensusParams = Params().GetConsensus();
1841
1842     TestWallet wallet;
1843
1844     // Generate Sapling address
1845     auto sk = libzcash::SaplingSpendingKey::random();
1846     auto expsk = sk.expanded_spending_key();
1847     auto fvk = sk.full_viewing_key();
1848     auto ivk = fvk.in_viewing_key();
1849     auto pk = sk.default_address();
1850
1851     ASSERT_TRUE(wallet.AddSaplingZKey(sk));
1852     ASSERT_TRUE(wallet.HaveSaplingSpendingKey(fvk));
1853
1854     // Set up transparent address
1855     CBasicKeyStore keystore;
1856     CKey tsk = DecodeSecret(tSecretRegtest);
1857     keystore.AddKey(tsk);
1858     auto scriptPubKey = GetScriptForDestination(tsk.GetPubKey().GetID());
1859
1860     // Generate shielding tx from transparent to Sapling
1861     // 0.0005 t-ZEC in, 0.0004 z-ZEC out, 0.0001 t-ZEC fee
1862     auto builder = TransactionBuilder(consensusParams, 1, &keystore);
1863     builder.AddTransparentInput(COutPoint(), scriptPubKey, 50000);
1864     builder.AddSaplingOutput(fvk, pk, 40000, {});
1865     auto maybe_tx = builder.Build();
1866     ASSERT_EQ(static_cast<bool>(maybe_tx), true);
1867     auto tx1 = maybe_tx.get();
1868
1869     EXPECT_EQ(tx1.vin.size(), 1);
1870     EXPECT_EQ(tx1.vout.size(), 0);
1871     EXPECT_EQ(tx1.vjoinsplit.size(), 0);
1872     EXPECT_EQ(tx1.vShieldedSpend.size(), 0);
1873     EXPECT_EQ(tx1.vShieldedOutput.size(), 1);
1874     EXPECT_EQ(tx1.valueBalance, -40000);
1875
1876     CWalletTx wtx {&wallet, tx1};
1877
1878     // Fake-mine the transaction
1879     EXPECT_EQ(-1, chainActive.Height());
1880     SaplingMerkleTree saplingTree;
1881     SproutMerkleTree sproutTree;
1882     CBlock block;
1883     block.vtx.push_back(wtx);
1884     block.hashMerkleRoot = block.BuildMerkleTree();
1885     auto blockHash = block.GetHash();
1886     CBlockIndex fakeIndex {block};
1887     mapBlockIndex.insert(std::make_pair(blockHash, &fakeIndex));
1888     chainActive.SetTip(&fakeIndex);
1889     EXPECT_TRUE(chainActive.Contains(&fakeIndex));
1890     EXPECT_EQ(0, chainActive.Height());
1891
1892     // Simulate SyncTransaction which calls AddToWalletIfInvolvingMe
1893     auto saplingNoteData = wallet.FindMySaplingNotes(wtx);
1894     ASSERT_TRUE(saplingNoteData.size() > 0);
1895     wtx.SetSaplingNoteData(saplingNoteData);
1896     wtx.SetMerkleBranch(block);
1897     wallet.AddToWallet(wtx, true, NULL);
1898
1899     // Simulate receiving new block and ChainTip signal
1900     wallet.IncrementNoteWitnesses(&fakeIndex, &block, sproutTree, saplingTree);
1901     wallet.UpdateSaplingNullifierNoteMapForBlock(&block);
1902
1903     // Retrieve the updated wtx from wallet
1904     uint256 hash = wtx.GetHash();
1905     wtx = wallet.mapWallet[hash];
1906
1907     // Prepare to spend the note that was just created
1908     auto maybe_pt = libzcash::SaplingNotePlaintext::decrypt(
1909             tx1.vShieldedOutput[0].encCiphertext, ivk, tx1.vShieldedOutput[0].ephemeralKey, tx1.vShieldedOutput[0].cm);
1910     ASSERT_EQ(static_cast<bool>(maybe_pt), true);
1911     auto maybe_note = maybe_pt.get().note(ivk);
1912     ASSERT_EQ(static_cast<bool>(maybe_note), true);
1913     auto note = maybe_note.get();
1914     auto anchor = saplingTree.root();
1915     auto witness = saplingTree.witness();
1916
1917     // Create a Sapling-only transaction
1918     // 0.0004 z-ZEC in, 0.00025 z-ZEC out, 0.0001 t-ZEC fee, 0.00005 z-ZEC change
1919     auto builder2 = TransactionBuilder(consensusParams, 2);
1920     ASSERT_TRUE(builder2.AddSaplingSpend(expsk, note, anchor, witness));
1921     builder2.AddSaplingOutput(fvk, pk, 25000, {});
1922     auto maybe_tx2 = builder2.Build();
1923     ASSERT_EQ(static_cast<bool>(maybe_tx2), true);
1924     auto tx2 = maybe_tx2.get();
1925
1926     EXPECT_EQ(tx2.vin.size(), 0);
1927     EXPECT_EQ(tx2.vout.size(), 0);
1928     EXPECT_EQ(tx2.vjoinsplit.size(), 0);
1929     EXPECT_EQ(tx2.vShieldedSpend.size(), 1);
1930     EXPECT_EQ(tx2.vShieldedOutput.size(), 2);
1931     EXPECT_EQ(tx2.valueBalance, 10000);
1932
1933     CWalletTx wtx2 {&wallet, tx2};
1934     auto hash2 = wtx2.GetHash();
1935
1936     wallet.MarkAffectedTransactionsDirty(wtx);
1937
1938     // After getting a cached value, the first tx should be clean
1939     wallet.mapWallet[hash].GetDebit(ISMINE_ALL);
1940     EXPECT_TRUE(wallet.mapWallet[hash].fDebitCached);
1941
1942     // After adding the note spend, the first tx should be dirty
1943     wallet.AddToWallet(wtx2, true, NULL);
1944     wallet.MarkAffectedTransactionsDirty(wtx2);
1945     EXPECT_FALSE(wallet.mapWallet[hash].fDebitCached);
1946
1947     // Tear down
1948     chainActive.SetTip(NULL);
1949     mapBlockIndex.erase(blockHash);
1950
1951     // Revert to default
1952     UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
1953     UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
1954 }
1955
1956 TEST(WalletTests, SproutNoteLocking) {
1957     TestWallet wallet;
1958
1959     auto sk = libzcash::SproutSpendingKey::random();
1960     wallet.AddSproutSpendingKey(sk);
1961
1962     auto wtx = GetValidReceive(sk, 10, true);
1963     auto wtx2 = GetValidReceive(sk, 10, true);
1964
1965     JSOutPoint jsoutpt {wtx.GetHash(), 0, 0};
1966     JSOutPoint jsoutpt2 {wtx2.GetHash(),0, 0};
1967
1968     // Test selective locking
1969     wallet.LockNote(jsoutpt);
1970     EXPECT_TRUE(wallet.IsLockedNote(jsoutpt));
1971     EXPECT_FALSE(wallet.IsLockedNote(jsoutpt2));
1972
1973     // Test selective unlocking
1974     wallet.UnlockNote(jsoutpt);
1975     EXPECT_FALSE(wallet.IsLockedNote(jsoutpt));
1976
1977     // Test multiple locking
1978     wallet.LockNote(jsoutpt);
1979     wallet.LockNote(jsoutpt2);
1980     EXPECT_TRUE(wallet.IsLockedNote(jsoutpt));
1981     EXPECT_TRUE(wallet.IsLockedNote(jsoutpt2));
1982
1983     // Test unlock all
1984     wallet.UnlockAllNotes();
1985     EXPECT_FALSE(wallet.IsLockedNote(jsoutpt));
1986     EXPECT_FALSE(wallet.IsLockedNote(jsoutpt2));
1987 }
This page took 0.135896 seconds and 4 git commands to generate.