TEST(wallet_tests, cached_witnesses_empty_chain) { TestWallet wallet; auto sk = libzcash::SpendingKey::random(); wallet.AddSpendingKey(sk); auto wtx = GetValidReceive(sk, 10, true); auto note = GetNote(sk, wtx, 0, 0); auto note2 = GetNote(sk, wtx, 0, 1); auto nullifier = note.nullifier(sk); auto nullifier2 = note2.nullifier(sk); mapNoteData_t noteData; JSOutPoint jsoutpt {wtx.GetHash(), 0, 0}; JSOutPoint jsoutpt2 {wtx.GetHash(), 0, 1}; CNoteData nd {sk.address(), nullifier}; CNoteData nd2 {sk.address(), nullifier2}; noteData[jsoutpt] = nd; noteData[jsoutpt2] = nd2; wtx.SetNoteData(noteData); std::vector<JSOutPoint> notes {jsoutpt, jsoutpt2}; std::vector<boost::optional<ZCIncrementalWitness>> witnesses; uint256 anchor; wallet.GetNoteWitnesses(notes, witnesses, anchor); EXPECT_FALSE((bool) witnesses[0]); EXPECT_FALSE((bool) witnesses[1]); wallet.AddToWallet(wtx, true, NULL); witnesses.clear(); wallet.GetNoteWitnesses(notes, witnesses, anchor); EXPECT_FALSE((bool) witnesses[0]); EXPECT_FALSE((bool) witnesses[1]); CBlock block; block.vtx.push_back(wtx); CBlockIndex index(block); ZCIncrementalMerkleTree tree; wallet.IncrementNoteWitnesses(&index, &block, tree); witnesses.clear(); wallet.GetNoteWitnesses(notes, witnesses, anchor); EXPECT_TRUE((bool) witnesses[0]); EXPECT_TRUE((bool) witnesses[1]); // Until #1302 is implemented, this should triggger an assertion EXPECT_DEATH(wallet.DecrementNoteWitnesses(&index), "Assertion `nWitnessCacheSize > 0' failed."); }
TEST(wallet_tests, cached_witnesses_chain_tip) { TestWallet wallet; uint256 anchor1; CBlock block1; ZCIncrementalMerkleTree tree; auto sk = libzcash::SpendingKey::random(); wallet.AddSpendingKey(sk); { // First transaction (case tested in _empty_chain) auto wtx = GetValidReceive(sk, 10, true); auto note = GetNote(sk, wtx, 0, 1); auto nullifier = note.nullifier(sk); mapNoteData_t noteData; JSOutPoint jsoutpt {wtx.GetHash(), 0, 1}; CNoteData nd {sk.address(), nullifier}; noteData[jsoutpt] = nd; wtx.SetNoteData(noteData); wallet.AddToWallet(wtx, true, NULL); std::vector<JSOutPoint> notes {jsoutpt}; std::vector<boost::optional<ZCIncrementalWitness>> witnesses; // First block (case tested in _empty_chain) block1.vtx.push_back(wtx); wallet.IncrementNoteWitnesses(NULL, &block1, tree); // Called to fetch anchor wallet.GetNoteWitnesses(notes, witnesses, anchor1); } { // Second transaction auto wtx = GetValidReceive(sk, 50, true); auto note = GetNote(sk, wtx, 0, 1); auto nullifier = note.nullifier(sk); mapNoteData_t noteData; JSOutPoint jsoutpt {wtx.GetHash(), 0, 1}; CNoteData nd {sk.address(), nullifier}; noteData[jsoutpt] = nd; wtx.SetNoteData(noteData); wallet.AddToWallet(wtx, true, NULL); std::vector<JSOutPoint> notes {jsoutpt}; std::vector<boost::optional<ZCIncrementalWitness>> witnesses; uint256 anchor2; wallet.GetNoteWitnesses(notes, witnesses, anchor2); EXPECT_FALSE((bool) witnesses[0]); // Second block CBlock block2; block2.hashPrevBlock = block1.GetHash(); block2.vtx.push_back(wtx); ZCIncrementalMerkleTree tree2 {tree}; wallet.IncrementNoteWitnesses(NULL, &block2, tree2); witnesses.clear(); wallet.GetNoteWitnesses(notes, witnesses, anchor2); EXPECT_TRUE((bool) witnesses[0]); EXPECT_NE(anchor1, anchor2); // Decrementing should give us the previous anchor uint256 anchor3; wallet.DecrementNoteWitnesses(); witnesses.clear(); wallet.GetNoteWitnesses(notes, witnesses, anchor3); EXPECT_FALSE((bool) witnesses[0]); // Should not equal first anchor because none of these notes had witnesses EXPECT_NE(anchor1, anchor3); // Re-incrementing with the same block should give the same result uint256 anchor4; wallet.IncrementNoteWitnesses(NULL, &block2, tree); witnesses.clear(); wallet.GetNoteWitnesses(notes, witnesses, anchor4); EXPECT_TRUE((bool) witnesses[0]); EXPECT_EQ(anchor2, anchor4); } }
TEST(wallet_tests, CachedWitnessesDecrementFirst) { TestWallet wallet; uint256 anchor2; CBlock block2; CBlockIndex index2(block2); ZCIncrementalMerkleTree tree; auto sk = libzcash::SpendingKey::random(); wallet.AddSpendingKey(sk); { // First transaction (case tested in _empty_chain) auto wtx = GetValidReceive(sk, 10, true); auto note = GetNote(sk, wtx, 0, 1); auto nullifier = note.nullifier(sk); mapNoteData_t noteData; JSOutPoint jsoutpt {wtx.GetHash(), 0, 1}; CNoteData nd {sk.address(), nullifier}; noteData[jsoutpt] = nd; wtx.SetNoteData(noteData); wallet.AddToWallet(wtx, true, NULL); // First block (case tested in _empty_chain) CBlock block1; block1.vtx.push_back(wtx); CBlockIndex index1(block1); index1.nHeight = 1; wallet.IncrementNoteWitnesses(&index1, &block1, tree); } { // Second transaction (case tested in _chain_tip) auto wtx = GetValidReceive(sk, 50, true); auto note = GetNote(sk, wtx, 0, 1); auto nullifier = note.nullifier(sk); mapNoteData_t noteData; JSOutPoint jsoutpt {wtx.GetHash(), 0, 1}; CNoteData nd {sk.address(), nullifier}; noteData[jsoutpt] = nd; wtx.SetNoteData(noteData); wallet.AddToWallet(wtx, true, NULL); std::vector<JSOutPoint> notes {jsoutpt}; std::vector<boost::optional<ZCIncrementalWitness>> witnesses; // Second block (case tested in _chain_tip) block2.vtx.push_back(wtx); index2.nHeight = 2; wallet.IncrementNoteWitnesses(&index2, &block2, tree); // Called to fetch anchor wallet.GetNoteWitnesses(notes, witnesses, anchor2); } { // Third transaction - never mined auto wtx = GetValidReceive(sk, 20, true); auto note = GetNote(sk, wtx, 0, 1); auto nullifier = note.nullifier(sk); mapNoteData_t noteData; JSOutPoint jsoutpt {wtx.GetHash(), 0, 1}; CNoteData nd {sk.address(), nullifier}; noteData[jsoutpt] = nd; wtx.SetNoteData(noteData); wallet.AddToWallet(wtx, true, NULL); std::vector<JSOutPoint> notes {jsoutpt}; std::vector<boost::optional<ZCIncrementalWitness>> witnesses; uint256 anchor3; wallet.GetNoteWitnesses(notes, witnesses, anchor3); EXPECT_FALSE((bool) witnesses[0]); // Decrementing (before the transaction has ever seen an increment) // should give us the previous anchor uint256 anchor4; wallet.DecrementNoteWitnesses(&index2); witnesses.clear(); wallet.GetNoteWitnesses(notes, witnesses, anchor4); EXPECT_FALSE((bool) witnesses[0]); // Should not equal second anchor because none of these notes had witnesses EXPECT_NE(anchor2, anchor4); // Re-incrementing with the same block should give the same result uint256 anchor5; wallet.IncrementNoteWitnesses(&index2, &block2, tree); witnesses.clear(); wallet.GetNoteWitnesses(notes, witnesses, anchor5); EXPECT_FALSE((bool) witnesses[0]); EXPECT_EQ(anchor3, anchor5); } }