Pass sapling merkle tree when incrementing witnesses

This commit is contained in:
Eirik Ogilvie-Wigley 2018-07-17 11:56:01 -06:00 committed by Simon
parent 4a0bc6047e
commit f86ee1c252
7 changed files with 71 additions and 48 deletions

View File

@ -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);

View File

@ -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));

View File

@ -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<void (const uint256 &)> UpdatedTransaction;
/** Notifies listeners of a change to the tip of the active block chain. */
boost::signals2::signal<void (const CBlockIndex *, const CBlock *, ZCIncrementalMerkleTree, bool)> ChainTip;
boost::signals2::signal<void (const CBlockIndex *, const CBlock *, ZCIncrementalMerkleTree, ZCSaplingIncrementalMerkleTree, bool)> ChainTip;
/** Notifies listeners of a new active block chain. */
boost::signals2::signal<void (const CBlockLocator &)> SetBestChain;
/** Notifies listeners about an inventory item being seen on the network. */

View File

@ -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<JSOutPoint> 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<boost::optional<ZCIncrementalWitness>> 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<JSOutPoint> 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<CBlockIndex> indices;
std::vector<JSOutPoint> notes;
std::vector<uint256> anchors;
ZCIncrementalMerkleTree tree;
ZCIncrementalMerkleTree riTree = tree;
ZCIncrementalMerkleTree sproutTree;
ZCIncrementalMerkleTree sproutRiTree = sproutTree;
ZCSaplingIncrementalMerkleTree saplingTree;
ZCSaplingIncrementalMerkleTree saplingRiTree = saplingTree;
std::vector<boost::optional<ZCIncrementalWitness>> 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);

View File

@ -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<const uint256, CWalletTx>& 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<const uint256, CWalletTx>& 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) {

View File

@ -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<std::pair<libzcash::PaymentAddress, uint256>> GetNullifiersForAddresses(const std::set<libzcash::PaymentAddress> & addresses);

View File

@ -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);
}