From 9396b85db85d64192fc87b6441716a05dc96bc9e Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Tue, 9 Oct 2018 09:48:32 -0600 Subject: [PATCH 1/4] Remove unspent note entry structs --- src/wallet/rpcwallet.cpp | 12 ++++++------ src/wallet/wallet.cpp | 12 ++++++------ src/wallet/wallet.h | 27 ++++++--------------------- 3 files changed, 18 insertions(+), 33 deletions(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index b85ab8f89..9796f8d19 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2566,17 +2566,17 @@ UniValue z_listunspent(const UniValue& params, bool fHelp) UniValue results(UniValue::VARR); if (zaddrs.size() > 0) { - std::vector sproutEntries; - std::vector saplingEntries; + std::vector sproutEntries; + std::vector saplingEntries; pwalletMain->GetUnspentFilteredNotes(sproutEntries, saplingEntries, zaddrs, nMinDepth, nMaxDepth, !fIncludeWatchonly); std::set> nullifierSet = pwalletMain->GetNullifiersForAddresses(zaddrs); - for (CUnspentSproutNotePlaintextEntry & entry : sproutEntries) { + for (auto & entry : sproutEntries) { UniValue obj(UniValue::VOBJ); obj.push_back(Pair("txid", entry.jsop.hash.ToString())); obj.push_back(Pair("jsindex", (int)entry.jsop.js )); obj.push_back(Pair("jsoutindex", (int)entry.jsop.n)); - obj.push_back(Pair("confirmations", entry.nHeight)); + obj.push_back(Pair("confirmations", entry.confirmations)); bool hasSproutSpendingKey = pwalletMain->HaveSproutSpendingKey(boost::get(entry.address)); obj.push_back(Pair("spendable", hasSproutSpendingKey)); obj.push_back(Pair("address", EncodePaymentAddress(entry.address))); @@ -2589,11 +2589,11 @@ UniValue z_listunspent(const UniValue& params, bool fHelp) results.push_back(obj); } - for (UnspentSaplingNoteEntry & entry : saplingEntries) { + for (auto & entry : saplingEntries) { UniValue obj(UniValue::VOBJ); obj.push_back(Pair("txid", entry.op.hash.ToString())); obj.push_back(Pair("outindex", (int)entry.op.n)); - obj.push_back(Pair("confirmations", entry.nHeight)); + obj.push_back(Pair("confirmations", entry.confirmations)); libzcash::SaplingIncomingViewingKey ivk; libzcash::SaplingFullViewingKey fvk; pwalletMain->GetSaplingIncomingViewingKey(boost::get(entry.address), ivk); diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 3690ed166..6a29242fa 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -4440,7 +4440,7 @@ void CWallet::GetFilteredNotes( hSig, (unsigned char) j); - sproutEntries.push_back(CSproutNotePlaintextEntry{jsop, pa, plaintext}); + sproutEntries.push_back(CSproutNotePlaintextEntry{jsop, pa, plaintext, wtx.GetDepthInMainChain()}); } catch (const note_decryption_failed &err) { // Couldn't decrypt with this spending key @@ -4495,7 +4495,7 @@ void CWallet::GetFilteredNotes( auto note = notePt.note(nd.ivk).get(); saplingEntries.push_back(SaplingNoteEntry { - op, pa, note, notePt.memo() }); + op, pa, note, notePt.memo(), wtx.GetDepthInMainChain() }); } } } @@ -4503,8 +4503,8 @@ void CWallet::GetFilteredNotes( /* Find unspent notes filtered by payment address, min depth and max depth */ void CWallet::GetUnspentFilteredNotes( - std::vector& sproutEntries, - std::vector& saplingEntries, + std::vector& sproutEntries, + std::vector& saplingEntries, std::set& filterAddresses, int minDepth, int maxDepth, @@ -4560,7 +4560,7 @@ void CWallet::GetUnspentFilteredNotes( hSig, (unsigned char) j); - sproutEntries.push_back(CUnspentSproutNotePlaintextEntry{jsop, pa, plaintext, wtx.GetDepthInMainChain()}); + sproutEntries.push_back(CSproutNotePlaintextEntry{jsop, pa, plaintext, wtx.GetDepthInMainChain()}); } catch (const note_decryption_failed &err) { // Couldn't decrypt with this spending key @@ -4609,7 +4609,7 @@ void CWallet::GetUnspentFilteredNotes( } auto note = notePt.note(nd.ivk).get(); - saplingEntries.push_back(UnspentSaplingNoteEntry { + saplingEntries.push_back(SaplingNoteEntry { op, pa, note, notePt.memo(), wtx.GetDepthInMainChain() }); } } diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index e7d30f467..45918a26c 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -309,38 +309,23 @@ public: typedef std::map mapSproutNoteData_t; typedef std::map mapSaplingNoteData_t; -/** Decrypted note and its location in a transaction. */ +/** Decrypted note, its location in a transaction, and number of confirmations. */ struct CSproutNotePlaintextEntry { JSOutPoint jsop; libzcash::SproutPaymentAddress address; libzcash::SproutNotePlaintext plaintext; + int confirmations; }; -/** Decrypted note, location in a transaction, and confirmation height. */ -struct CUnspentSproutNotePlaintextEntry { - JSOutPoint jsop; - libzcash::SproutPaymentAddress address; - libzcash::SproutNotePlaintext plaintext; - int nHeight; -}; - -/** Sapling note and its location in a transaction. */ +/** Sapling note, its location in a transaction, and number of confirmations. */ struct SaplingNoteEntry { SaplingOutPoint op; libzcash::SaplingPaymentAddress address; libzcash::SaplingNote note; std::array memo; -}; - -/** Sapling note, location in a transaction, and confirmation height. */ -struct UnspentSaplingNoteEntry { - SaplingOutPoint op; - libzcash::SaplingPaymentAddress address; - libzcash::SaplingNote note; - std::array memo; - int nHeight; + int confirmations; }; /** A transaction with a merkle branch linking it to the block chain. */ @@ -1305,8 +1290,8 @@ public: bool ignoreUnspendable=true); /* Find unspent notes filtered by payment address, min depth and max depth */ - void GetUnspentFilteredNotes(std::vector& sproutEntries, - std::vector& saplingEntries, + void GetUnspentFilteredNotes(std::vector& sproutEntries, + std::vector& saplingEntries, std::set& filterAddresses, int minDepth=1, int maxDepth=INT_MAX, From ef27d7e4b3e30651c497aa63b529ebebaf1e5c29 Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Tue, 9 Oct 2018 12:19:56 -0600 Subject: [PATCH 2/4] Add functionality from GetUnspentFilteredNotes to GetFilteredNotes --- src/wallet/wallet.cpp | 18 ++++++++++-------- src/wallet/wallet.h | 6 ++++-- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 6a29242fa..e600999b6 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -4362,7 +4362,7 @@ void CWallet::GetFilteredNotes( std::string address, int minDepth, bool ignoreSpent, - bool ignoreUnspendable) + bool requireSpendingKey) { std::set filterAddresses; @@ -4370,7 +4370,7 @@ void CWallet::GetFilteredNotes( filterAddresses.insert(DecodePaymentAddress(address)); } - GetFilteredNotes(sproutEntries, saplingEntries, filterAddresses, minDepth, ignoreSpent, ignoreUnspendable); + GetFilteredNotes(sproutEntries, saplingEntries, filterAddresses, minDepth, INT_MAX, ignoreSpent, requireSpendingKey); } /** @@ -4382,8 +4382,10 @@ void CWallet::GetFilteredNotes( std::vector& saplingEntries, std::set& filterAddresses, int minDepth, + int maxDepth, bool ignoreSpent, - bool ignoreUnspendable) + bool requireSpendingKey, + bool ignoreLocked) { LOCK2(cs_main, cs_wallet); @@ -4391,7 +4393,7 @@ void CWallet::GetFilteredNotes( CWalletTx wtx = p.second; // Filter the transactions before checking for notes - if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < minDepth) { + if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < minDepth || wtx.GetDepthInMainChain() > maxDepth) { continue; } @@ -4411,12 +4413,12 @@ void CWallet::GetFilteredNotes( } // skip notes which cannot be spent - if (ignoreUnspendable && !HaveSproutSpendingKey(pa)) { + if (requireSpendingKey && !HaveSproutSpendingKey(pa)) { continue; } // skip locked notes - if (IsLockedNote(jsop)) { + if (ignoreLocked && IsLockedNote(jsop)) { continue; } @@ -4477,7 +4479,7 @@ void CWallet::GetFilteredNotes( } // skip notes which cannot be spent - if (ignoreUnspendable) { + if (requireSpendingKey) { libzcash::SaplingIncomingViewingKey ivk; libzcash::SaplingFullViewingKey fvk; if (!(GetSaplingIncomingViewingKey(pa, ivk) && @@ -4489,7 +4491,7 @@ void CWallet::GetFilteredNotes( // skip locked notes // TODO: Add locking for Sapling notes - // if (IsLockedNote(jsop)) { + // if (ignoreLocked && IsLockedNote(op)) { // continue; // } diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 45918a26c..7806ae686 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -1279,15 +1279,17 @@ public: std::string address, int minDepth=1, bool ignoreSpent=true, - bool ignoreUnspendable=true); + bool requireSpendingKey=true); /* Find notes filtered by payment addresses, min depth, ability to spend */ void GetFilteredNotes(std::vector& sproutEntries, std::vector& saplingEntries, std::set& filterAddresses, int minDepth=1, + int maxDepth=INT_MAX, bool ignoreSpent=true, - bool ignoreUnspendable=true); + bool requireSpendingKey=true, + bool ignoreLocked=true); /* Find unspent notes filtered by payment address, min depth and max depth */ void GetUnspentFilteredNotes(std::vector& sproutEntries, From e92414f91e63edc5811c47bbda9645012b9b74b3 Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Tue, 9 Oct 2018 12:44:45 -0600 Subject: [PATCH 3/4] Remove GetUnspentFilteredNotes --- src/wallet/rpcwallet.cpp | 2 +- src/wallet/wallet.cpp | 114 --------------------------------------- src/wallet/wallet.h | 8 --- 3 files changed, 1 insertion(+), 123 deletions(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 9796f8d19..fd128598a 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2568,7 +2568,7 @@ UniValue z_listunspent(const UniValue& params, bool fHelp) if (zaddrs.size() > 0) { std::vector sproutEntries; std::vector saplingEntries; - pwalletMain->GetUnspentFilteredNotes(sproutEntries, saplingEntries, zaddrs, nMinDepth, nMaxDepth, !fIncludeWatchonly); + pwalletMain->GetFilteredNotes(sproutEntries, saplingEntries, zaddrs, nMinDepth, nMaxDepth, true, !fIncludeWatchonly, false); std::set> nullifierSet = pwalletMain->GetNullifiersForAddresses(zaddrs); for (auto & entry : sproutEntries) { diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index e600999b6..76a44afc0 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -4503,120 +4503,6 @@ void CWallet::GetFilteredNotes( } -/* Find unspent notes filtered by payment address, min depth and max depth */ -void CWallet::GetUnspentFilteredNotes( - std::vector& sproutEntries, - std::vector& saplingEntries, - std::set& filterAddresses, - int minDepth, - int maxDepth, - bool requireSpendingKey) -{ - LOCK2(cs_main, cs_wallet); - - for (auto & p : mapWallet) { - CWalletTx wtx = p.second; - - // Filter the transactions before checking for notes - if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < minDepth || wtx.GetDepthInMainChain() > maxDepth) { - continue; - } - - for (auto & pair : wtx.mapSproutNoteData) { - JSOutPoint jsop = pair.first; - SproutNoteData nd = pair.second; - SproutPaymentAddress pa = nd.address; - - // skip notes which belong to a different payment address in the wallet - if (!(filterAddresses.empty() || filterAddresses.count(pa))) { - continue; - } - - // skip note which has been spent - if (nd.nullifier && IsSproutSpent(*nd.nullifier)) { - continue; - } - - // skip notes where the spending key is not available - if (requireSpendingKey && !HaveSproutSpendingKey(pa)) { - continue; - } - - int i = jsop.js; // Index into CTransaction.vjoinsplit - int j = jsop.n; // Index into JSDescription.ciphertexts - - // Get cached decryptor - ZCNoteDecryption decryptor; - if (!GetNoteDecryptor(pa, decryptor)) { - // Note decryptors are created when the wallet is loaded, so it should always exist - throw std::runtime_error(strprintf("Could not find note decryptor for payment address %s", EncodePaymentAddress(pa))); - } - - // determine amount of funds in the note - auto hSig = wtx.vjoinsplit[i].h_sig(*pzcashParams, wtx.joinSplitPubKey); - try { - SproutNotePlaintext plaintext = SproutNotePlaintext::decrypt( - decryptor, - wtx.vjoinsplit[i].ciphertexts[j], - wtx.vjoinsplit[i].ephemeralKey, - hSig, - (unsigned char) j); - - sproutEntries.push_back(CSproutNotePlaintextEntry{jsop, pa, plaintext, wtx.GetDepthInMainChain()}); - - } catch (const note_decryption_failed &err) { - // Couldn't decrypt with this spending key - throw std::runtime_error(strprintf("Could not decrypt note for payment address %s", EncodePaymentAddress(pa))); - } catch (const std::exception &exc) { - // Unexpected failure - throw std::runtime_error(strprintf("Error while decrypting note for payment address %s: %s", EncodePaymentAddress(pa), exc.what())); - } - } - - for (auto & pair : wtx.mapSaplingNoteData) { - SaplingOutPoint op = pair.first; - SaplingNoteData nd = pair.second; - - auto maybe_pt = SaplingNotePlaintext::decrypt( - wtx.vShieldedOutput[op.n].encCiphertext, - nd.ivk, - wtx.vShieldedOutput[op.n].ephemeralKey, - wtx.vShieldedOutput[op.n].cm); - assert(static_cast(maybe_pt)); - auto notePt = maybe_pt.get(); - - auto maybe_pa = nd.ivk.address(notePt.d); - assert(static_cast(maybe_pa)); - auto pa = maybe_pa.get(); - - // skip notes which belong to a different payment address in the wallet - if (!(filterAddresses.empty() || filterAddresses.count(pa))) { - continue; - } - - // skip note which has been spent - if (nd.nullifier && IsSaplingSpent(*nd.nullifier)) { - continue; - } - - // skip notes where the spending key is not available - if (requireSpendingKey) { - libzcash::SaplingIncomingViewingKey ivk; - libzcash::SaplingFullViewingKey fvk; - if (!(GetSaplingIncomingViewingKey(pa, ivk) && - GetSaplingFullViewingKey(ivk, fvk) && - HaveSaplingSpendingKey(fvk))) { - continue; - } - } - - auto note = notePt.note(nd.ivk).get(); - saplingEntries.push_back(SaplingNoteEntry { - op, pa, note, notePt.memo(), wtx.GetDepthInMainChain() }); - } - } -} - // // Shielded key and address generalizations // diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 7806ae686..f492657f7 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -1290,14 +1290,6 @@ public: bool ignoreSpent=true, bool requireSpendingKey=true, bool ignoreLocked=true); - - /* Find unspent notes filtered by payment address, min depth and max depth */ - void GetUnspentFilteredNotes(std::vector& sproutEntries, - std::vector& saplingEntries, - std::set& filterAddresses, - int minDepth=1, - int maxDepth=INT_MAX, - bool requireSpendingKey=true); }; /** A key allocated from the key pool. */ From 095eee4f4db1f9dfc4ca8f8280286c7b853f0894 Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Mon, 22 Oct 2018 10:01:17 -0600 Subject: [PATCH 4/4] Wrap long line and update comments --- src/wallet/wallet.cpp | 8 ++++++-- src/wallet/wallet.h | 3 ++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 76a44afc0..b3c419b87 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -4374,7 +4374,8 @@ void CWallet::GetFilteredNotes( } /** - * Find notes in the wallet filtered by payment addresses, min depth and ability to spend. + * Find notes in the wallet filtered by payment addresses, min depth, max depth, + * if the note is spent, if a spending key is required, and if the notes are locked. * These notes are decrypted and added to the output parameter vector, outEntries. */ void CWallet::GetFilteredNotes( @@ -4393,7 +4394,10 @@ void CWallet::GetFilteredNotes( CWalletTx wtx = p.second; // Filter the transactions before checking for notes - if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < minDepth || wtx.GetDepthInMainChain() > maxDepth) { + if (!CheckFinalTx(wtx) || + wtx.GetBlocksToMaturity() > 0 || + wtx.GetDepthInMainChain() < minDepth || + wtx.GetDepthInMainChain() > maxDepth) { continue; } diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index f492657f7..2d65a8779 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -1281,7 +1281,8 @@ public: bool ignoreSpent=true, bool requireSpendingKey=true); - /* Find notes filtered by payment addresses, min depth, ability to spend */ + /* Find notes filtered by payment addresses, min depth, max depth, if they are spent, + if a spending key is required, and if they are locked */ void GetFilteredNotes(std::vector& sproutEntries, std::vector& saplingEntries, std::set& filterAddresses,