From f86ee1c25237f2498ebfcc1a7264eae5fbfa2ff5 Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Tue, 17 Jul 2018 11:56:01 -0600 Subject: [PATCH] Pass sapling merkle tree when incrementing witnesses --- src/main.cpp | 16 +++++---- src/validationinterface.cpp | 4 +-- src/validationinterface.h | 4 +-- src/wallet/gtest/test_wallet.cpp | 57 ++++++++++++++++++-------------- src/wallet/wallet.cpp | 26 ++++++++++----- src/wallet/wallet.h | 5 +-- src/zcbenchmarks.cpp | 7 ++-- 7 files changed, 71 insertions(+), 48 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 1f1893654..182eff232 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2824,15 +2824,17 @@ bool static DisconnectTip(CValidationState &state, bool fBare = false) { // Update chainActive and related variables. UpdateTip(pindexDelete->pprev); // Get the current commitment tree - ZCIncrementalMerkleTree newTree; - assert(pcoinsTip->GetSproutAnchorAt(pcoinsTip->GetBestAnchor(SPROUT), newTree)); + ZCIncrementalMerkleTree newSproutTree; + ZCSaplingIncrementalMerkleTree newSaplingTree; + assert(pcoinsTip->GetSproutAnchorAt(pcoinsTip->GetBestAnchor(SPROUT), newSproutTree)); + assert(pcoinsTip->GetSaplingAnchorAt(pcoinsTip->GetBestAnchor(SAPLING), newSaplingTree)); // Let wallets know transactions went from 1-confirmed to // 0-confirmed or conflicted: BOOST_FOREACH(const CTransaction &tx, block.vtx) { SyncWithWallets(tx, NULL); } // Update cached incremental witnesses - GetMainSignals().ChainTip(pindexDelete, &block, newTree, false); + GetMainSignals().ChainTip(pindexDelete, &block, newSproutTree, newSaplingTree, false); return true; } @@ -2858,8 +2860,10 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock * pblock = █ } // Get the current commitment tree - ZCIncrementalMerkleTree oldTree; - assert(pcoinsTip->GetSproutAnchorAt(pcoinsTip->GetBestAnchor(SPROUT), oldTree)); + ZCIncrementalMerkleTree oldSproutTree; + ZCSaplingIncrementalMerkleTree oldSaplingTree; + assert(pcoinsTip->GetSproutAnchorAt(pcoinsTip->GetBestAnchor(SPROUT), oldSproutTree)); + assert(pcoinsTip->GetSaplingAnchorAt(pcoinsTip->GetBestAnchor(SAPLING), oldSaplingTree)); // Apply the block atomically to the chain state. int64_t nTime2 = GetTimeMicros(); nTimeReadFromDisk += nTime2 - nTime1; int64_t nTime3; @@ -2904,7 +2908,7 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock * SyncWithWallets(tx, pblock); } // Update cached incremental witnesses - GetMainSignals().ChainTip(pindexNew, pblock, oldTree, true); + GetMainSignals().ChainTip(pindexNew, pblock, oldSproutTree, oldSaplingTree, true); EnforceNodeDeprecation(pindexNew->nHeight); diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp index cd3e30f3d..ae1e322c2 100644 --- a/src/validationinterface.cpp +++ b/src/validationinterface.cpp @@ -17,7 +17,7 @@ void RegisterValidationInterface(CValidationInterface* pwalletIn) { g_signals.SyncTransaction.connect(boost::bind(&CValidationInterface::SyncTransaction, pwalletIn, _1, _2)); g_signals.EraseTransaction.connect(boost::bind(&CValidationInterface::EraseFromWallet, pwalletIn, _1)); g_signals.UpdatedTransaction.connect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1)); - g_signals.ChainTip.connect(boost::bind(&CValidationInterface::ChainTip, pwalletIn, _1, _2, _3, _4)); + g_signals.ChainTip.connect(boost::bind(&CValidationInterface::ChainTip, pwalletIn, _1, _2, _3, _4, _5)); g_signals.SetBestChain.connect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1)); g_signals.Inventory.connect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1)); g_signals.Broadcast.connect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1)); @@ -28,7 +28,7 @@ void UnregisterValidationInterface(CValidationInterface* pwalletIn) { g_signals.BlockChecked.disconnect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2)); g_signals.Broadcast.disconnect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1)); g_signals.Inventory.disconnect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1)); - g_signals.ChainTip.disconnect(boost::bind(&CValidationInterface::ChainTip, pwalletIn, _1, _2, _3, _4)); + g_signals.ChainTip.disconnect(boost::bind(&CValidationInterface::ChainTip, pwalletIn, _1, _2, _3, _4, _5)); g_signals.SetBestChain.disconnect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1)); g_signals.UpdatedTransaction.disconnect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1)); g_signals.EraseTransaction.disconnect(boost::bind(&CValidationInterface::EraseFromWallet, pwalletIn, _1)); diff --git a/src/validationinterface.h b/src/validationinterface.h index 1855dacd7..60e90d012 100644 --- a/src/validationinterface.h +++ b/src/validationinterface.h @@ -34,7 +34,7 @@ protected: virtual void UpdatedBlockTip(const CBlockIndex *pindex) {} virtual void SyncTransaction(const CTransaction &tx, const CBlock *pblock) {} virtual void EraseFromWallet(const uint256 &hash) {} - virtual void ChainTip(const CBlockIndex *pindex, const CBlock *pblock, ZCIncrementalMerkleTree tree, bool added) {} + virtual void ChainTip(const CBlockIndex *pindex, const CBlock *pblock, ZCIncrementalMerkleTree sproutTree, ZCSaplingIncrementalMerkleTree saplingTree, bool added) {} virtual void SetBestChain(const CBlockLocator &locator) {} virtual void UpdatedTransaction(const uint256 &hash) {} virtual void Inventory(const uint256 &hash) {} @@ -55,7 +55,7 @@ struct CMainSignals { /** Notifies listeners of an updated transaction without new data (for now: a coinbase potentially becoming visible). */ boost::signals2::signal UpdatedTransaction; /** Notifies listeners of a change to the tip of the active block chain. */ - boost::signals2::signal ChainTip; + boost::signals2::signal ChainTip; /** Notifies listeners of a new active block chain. */ boost::signals2::signal SetBestChain; /** Notifies listeners about an inventory item being seen on the network. */ diff --git a/src/wallet/gtest/test_wallet.cpp b/src/wallet/gtest/test_wallet.cpp index ea5d6bf1d..85f47b790 100644 --- a/src/wallet/gtest/test_wallet.cpp +++ b/src/wallet/gtest/test_wallet.cpp @@ -51,8 +51,9 @@ public: void IncrementNoteWitnesses(const CBlockIndex* pindex, const CBlock* pblock, - ZCIncrementalMerkleTree& tree) { - CWallet::IncrementNoteWitnesses(pindex, pblock, tree); + ZCIncrementalMerkleTree& sproutTree, + ZCSaplingIncrementalMerkleTree& saplingTree) { + CWallet::IncrementNoteWitnesses(pindex, pblock, sproutTree, saplingTree); } void DecrementNoteWitnesses(const CBlockIndex* pindex) { CWallet::DecrementNoteWitnesses(pindex); @@ -86,7 +87,8 @@ JSOutPoint CreateValidBlock(TestWallet& wallet, const libzcash::SproutSpendingKey& sk, const CBlockIndex& index, CBlock& block, - ZCIncrementalMerkleTree& tree) { + ZCIncrementalMerkleTree& sproutTree, + ZCSaplingIncrementalMerkleTree& saplingTree) { auto wtx = GetValidReceive(sk, 50, true); auto note = GetNote(sk, wtx, 0, 1); auto nullifier = note.nullifier(sk); @@ -99,7 +101,7 @@ JSOutPoint CreateValidBlock(TestWallet& wallet, wallet.AddToWallet(wtx, true, NULL); block.vtx.push_back(wtx); - wallet.IncrementNoteWitnesses(&index, &block, tree); + wallet.IncrementNoteWitnesses(&index, &block, sproutTree, saplingTree); return jsoutpt; } @@ -572,8 +574,9 @@ TEST(wallet_tests, cached_witnesses_empty_chain) { CBlock block; block.vtx.push_back(wtx); CBlockIndex index(block); - ZCIncrementalMerkleTree tree; - wallet.IncrementNoteWitnesses(&index, &block, tree); + ZCIncrementalMerkleTree sproutTree; + ZCSaplingIncrementalMerkleTree saplingTree; + wallet.IncrementNoteWitnesses(&index, &block, sproutTree, saplingTree); witnesses.clear(); wallet.GetNoteWitnesses(notes, witnesses, anchor); EXPECT_TRUE((bool) witnesses[0]); @@ -588,7 +591,8 @@ TEST(wallet_tests, cached_witnesses_chain_tip) { TestWallet wallet; uint256 anchor1; CBlock block1; - ZCIncrementalMerkleTree tree; + ZCIncrementalMerkleTree sproutTree; + ZCSaplingIncrementalMerkleTree saplingTree; auto sk = libzcash::SproutSpendingKey::random(); wallet.AddSpendingKey(sk); @@ -597,7 +601,7 @@ TEST(wallet_tests, cached_witnesses_chain_tip) { // First block (case tested in _empty_chain) CBlockIndex index1(block1); index1.nHeight = 1; - auto jsoutpt = CreateValidBlock(wallet, sk, index1, block1, tree); + auto jsoutpt = CreateValidBlock(wallet, sk, index1, block1, sproutTree, saplingTree); // Called to fetch anchor std::vector notes {jsoutpt}; @@ -631,8 +635,9 @@ TEST(wallet_tests, cached_witnesses_chain_tip) { block2.vtx.push_back(wtx); CBlockIndex index2(block2); index2.nHeight = 2; - ZCIncrementalMerkleTree tree2 {tree}; - wallet.IncrementNoteWitnesses(&index2, &block2, tree2); + ZCIncrementalMerkleTree sproutTree2 {sproutTree}; + ZCSaplingIncrementalMerkleTree saplingTree2 {saplingTree}; + wallet.IncrementNoteWitnesses(&index2, &block2, sproutTree2, saplingTree2); witnesses.clear(); wallet.GetNoteWitnesses(notes, witnesses, anchor2); EXPECT_TRUE((bool) witnesses[0]); @@ -649,7 +654,7 @@ TEST(wallet_tests, cached_witnesses_chain_tip) { // Re-incrementing with the same block should give the same result uint256 anchor4; - wallet.IncrementNoteWitnesses(&index2, &block2, tree); + wallet.IncrementNoteWitnesses(&index2, &block2, sproutTree, saplingTree); witnesses.clear(); wallet.GetNoteWitnesses(notes, witnesses, anchor4); EXPECT_TRUE((bool) witnesses[0]); @@ -657,7 +662,7 @@ TEST(wallet_tests, cached_witnesses_chain_tip) { // Incrementing with the same block again should not change the cache uint256 anchor5; - wallet.IncrementNoteWitnesses(&index2, &block2, tree); + wallet.IncrementNoteWitnesses(&index2, &block2, sproutTree, saplingTree); std::vector> witnesses5; wallet.GetNoteWitnesses(notes, witnesses5, anchor5); EXPECT_EQ(witnesses, witnesses5); @@ -670,7 +675,8 @@ TEST(wallet_tests, CachedWitnessesDecrementFirst) { uint256 anchor2; CBlock block2; CBlockIndex index2(block2); - ZCIncrementalMerkleTree tree; + ZCIncrementalMerkleTree sproutTree; + ZCSaplingIncrementalMerkleTree saplingTree; auto sk = libzcash::SproutSpendingKey::random(); wallet.AddSpendingKey(sk); @@ -680,13 +686,13 @@ TEST(wallet_tests, CachedWitnessesDecrementFirst) { CBlock block1; CBlockIndex index1(block1); index1.nHeight = 1; - CreateValidBlock(wallet, sk, index1, block1, tree); + CreateValidBlock(wallet, sk, index1, block1, sproutTree, saplingTree); } { // Second block (case tested in _chain_tip) index2.nHeight = 2; - auto jsoutpt = CreateValidBlock(wallet, sk, index2, block2, tree); + auto jsoutpt = CreateValidBlock(wallet, sk, index2, block2, sproutTree, saplingTree); // Called to fetch anchor std::vector notes {jsoutpt}; @@ -726,7 +732,7 @@ TEST(wallet_tests, CachedWitnessesDecrementFirst) { // Re-incrementing with the same block should give the same result uint256 anchor5; - wallet.IncrementNoteWitnesses(&index2, &block2, tree); + wallet.IncrementNoteWitnesses(&index2, &block2, sproutTree, saplingTree); witnesses.clear(); wallet.GetNoteWitnesses(notes, witnesses, anchor5); EXPECT_FALSE((bool) witnesses[0]); @@ -740,8 +746,10 @@ TEST(wallet_tests, CachedWitnessesCleanIndex) { std::vector indices; std::vector notes; std::vector anchors; - ZCIncrementalMerkleTree tree; - ZCIncrementalMerkleTree riTree = tree; + ZCIncrementalMerkleTree sproutTree; + ZCIncrementalMerkleTree sproutRiTree = sproutTree; + ZCSaplingIncrementalMerkleTree saplingTree; + ZCSaplingIncrementalMerkleTree saplingRiTree = saplingTree; std::vector> witnesses; auto sk = libzcash::SproutSpendingKey::random(); @@ -753,9 +761,9 @@ TEST(wallet_tests, CachedWitnessesCleanIndex) { indices.resize(numBlocks); for (size_t i = 0; i < numBlocks; i++) { indices[i].nHeight = i; - auto old = tree.root(); - auto jsoutpt = CreateValidBlock(wallet, sk, indices[i], blocks[i], tree); - EXPECT_NE(old, tree.root()); + auto old = sproutTree.root(); + auto jsoutpt = CreateValidBlock(wallet, sk, indices[i], blocks[i], sproutTree, saplingTree); + EXPECT_NE(old, sproutTree.root()); notes.push_back(jsoutpt); witnesses.clear(); @@ -770,8 +778,9 @@ TEST(wallet_tests, CachedWitnessesCleanIndex) { // Now pretend we are reindexing: the chain is cleared, and each block is // used to increment witnesses again. for (size_t i = 0; i < numBlocks; i++) { - ZCIncrementalMerkleTree riPrevTree {riTree}; - wallet.IncrementNoteWitnesses(&(indices[i]), &(blocks[i]), riTree); + ZCIncrementalMerkleTree sproutRiPrevTree {sproutRiTree}; + ZCSaplingIncrementalMerkleTree saplingRiPrevTree {saplingRiTree}; + wallet.IncrementNoteWitnesses(&(indices[i]), &(blocks[i]), sproutRiTree, saplingRiTree); witnesses.clear(); uint256 anchor; wallet.GetNoteWitnesses(notes, witnesses, anchor); @@ -796,7 +805,7 @@ TEST(wallet_tests, CachedWitnessesCleanIndex) { } { - wallet.IncrementNoteWitnesses(&(indices[i]), &(blocks[i]), riPrevTree); + wallet.IncrementNoteWitnesses(&(indices[i]), &(blocks[i]), sproutRiPrevTree, saplingRiPrevTree); witnesses.clear(); uint256 anchor; wallet.GetNoteWitnesses(notes, witnesses, anchor); diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 3f08002d9..f26c8bba7 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -449,11 +449,14 @@ bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, return false; } -void CWallet::ChainTip(const CBlockIndex *pindex, const CBlock *pblock, - ZCIncrementalMerkleTree tree, bool added) +void CWallet::ChainTip(const CBlockIndex *pindex, + const CBlock *pblock, + ZCIncrementalMerkleTree sproutTree, + ZCSaplingIncrementalMerkleTree saplingTree, + bool added) { if (added) { - IncrementNoteWitnesses(pindex, pblock, tree); + IncrementNoteWitnesses(pindex, pblock, sproutTree, saplingTree); } else { DecrementNoteWitnesses(pindex); } @@ -844,7 +847,8 @@ void UpdateWitnessHeights(NoteDataMap& noteDataMap, int indexHeight, int64_t nWi void CWallet::IncrementNoteWitnesses(const CBlockIndex* pindex, const CBlock* pblockIn, - ZCIncrementalMerkleTree& tree) + ZCIncrementalMerkleTree& sproutTree, + ZCSaplingIncrementalMerkleTree& saplingTree) { LOCK(cs_wallet); for (std::pair& wtxItem : mapWallet) { @@ -869,7 +873,7 @@ void CWallet::IncrementNoteWitnesses(const CBlockIndex* pindex, const JSDescription& jsdesc = tx.vjoinsplit[i]; for (uint8_t j = 0; j < jsdesc.commitments.size(); j++) { const uint256& note_commitment = jsdesc.commitments[j]; - tree.append(note_commitment); + sproutTree.append(note_commitment); // Increment existing witnesses for (std::pair& wtxItem : mapWallet) { @@ -879,7 +883,7 @@ void CWallet::IncrementNoteWitnesses(const CBlockIndex* pindex, // If this is our note, witness it if (txIsOurs) { JSOutPoint jsoutpt {hash, i, j}; - ::WitnessNoteIfMine(mapWallet[hash].mapSproutNoteData, pindex->nHeight, nWitnessCacheSize, jsoutpt, tree.witness()); + ::WitnessNoteIfMine(mapWallet[hash].mapSproutNoteData, pindex->nHeight, nWitnessCacheSize, jsoutpt, sproutTree.witness()); } } } @@ -1919,12 +1923,16 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate) ret++; } - ZCIncrementalMerkleTree tree; + ZCIncrementalMerkleTree sproutTree; + ZCSaplingIncrementalMerkleTree saplingTree; // This should never fail: we should always be able to get the tree // state on the path to the tip of our chain - assert(pcoinsTip->GetSproutAnchorAt(pindex->hashSproutAnchor, tree)); + assert(pcoinsTip->GetSproutAnchorAt(pindex->hashSproutAnchor, sproutTree)); + if (pindex->pprev) { + assert(pcoinsTip->GetSaplingAnchorAt(pindex->pprev->hashFinalSaplingRoot, saplingTree)); + } // Increment note witness caches - IncrementNoteWitnesses(pindex, &block, tree); + IncrementNoteWitnesses(pindex, &block, sproutTree, saplingTree); pindex = chainActive.Next(pindex); if (GetTime() >= nNow + 60) { diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 4e93765e1..87f49b4e7 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -730,7 +730,8 @@ protected: */ void IncrementNoteWitnesses(const CBlockIndex* pindex, const CBlock* pblock, - ZCIncrementalMerkleTree& tree); + ZCIncrementalMerkleTree& sproutTree, + ZCSaplingIncrementalMerkleTree& saplingTree); /** * pindex is the old tip being disconnected. */ @@ -1084,7 +1085,7 @@ public: CAmount GetDebit(const CTransaction& tx, const isminefilter& filter) const; CAmount GetCredit(const CTransaction& tx, const isminefilter& filter) const; CAmount GetChange(const CTransaction& tx) const; - void ChainTip(const CBlockIndex *pindex, const CBlock *pblock, ZCIncrementalMerkleTree tree, bool added); + void ChainTip(const CBlockIndex *pindex, const CBlock *pblock, ZCIncrementalMerkleTree sproutTree, ZCSaplingIncrementalMerkleTree saplingTree, bool added); /** Saves witness caches and best block locator to disk. */ void SetBestChain(const CBlockLocator& loc); std::set> GetNullifiersForAddresses(const std::set & addresses); diff --git a/src/zcbenchmarks.cpp b/src/zcbenchmarks.cpp index 89fb92c1e..aa6fac763 100644 --- a/src/zcbenchmarks.cpp +++ b/src/zcbenchmarks.cpp @@ -298,7 +298,8 @@ double benchmark_try_decrypt_notes(size_t nAddrs) double benchmark_increment_note_witnesses(size_t nTxs) { CWallet wallet; - ZCIncrementalMerkleTree tree; + ZCIncrementalMerkleTree sproutTree; + ZCSaplingIncrementalMerkleTree saplingTree; auto sk = libzcash::SproutSpendingKey::random(); wallet.AddSpendingKey(sk); @@ -323,7 +324,7 @@ double benchmark_increment_note_witnesses(size_t nTxs) index1.nHeight = 1; // Increment to get transactions witnessed - wallet.ChainTip(&index1, &block1, tree, true); + wallet.ChainTip(&index1, &block1, sproutTree, saplingTree, true); // Second block CBlock block2; @@ -347,7 +348,7 @@ double benchmark_increment_note_witnesses(size_t nTxs) struct timeval tv_start; timer_start(tv_start); - wallet.ChainTip(&index2, &block2, tree, true); + wallet.ChainTip(&index2, &block2, sproutTree, saplingTree, true); return timer_stop(tv_start); }