From a5ac2e25a040479df4bc43a75aec96b472bb2858 Mon Sep 17 00:00:00 2001 From: Simon Date: Wed, 7 Sep 2016 11:52:32 -0700 Subject: [PATCH] Add GetUnspentNotes to wallet. --- src/wallet/wallet.cpp | 69 +++++++++++++++++++++++++++++++++++++++++++ src/wallet/wallet.h | 13 ++++++++ 2 files changed, 82 insertions(+) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 52812e50d..9e8e69d36 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -3187,3 +3187,72 @@ bool CMerkleTx::AcceptToMemoryPool(bool fLimitFree, bool fRejectAbsurdFee) return ::AcceptToMemoryPool(mempool, state, *this, fLimitFree, NULL, fRejectAbsurdFee); } +bool CWallet::GetUnspentNotes(std::vector & outEntries, std::string address, size_t minDepth = 1) +{ + bool fFilterAddress = false; + libzcash::PaymentAddress filterPaymentAddress; + if (address.length() > 0) { + filterPaymentAddress = CZCPaymentAddress(address).Get(); + fFilterAddress = true; + } + + 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) { + continue; + } + + mapNoteData_t mapNoteData = FindMyNotes(wtx); + + if (mapNoteData.size() == 0) { + continue; + } + + for (auto & pair : mapNoteData) { + JSOutPoint jsop = pair.first; + CNoteData nd = pair.second; + PaymentAddress pa = nd.address; + + // skip notes which belong to a different payment address in the wallet + if (fFilterAddress && !(pa == filterPaymentAddress)) { + continue; + } + + // skip note which has been spent + if (IsSpent(nd.nullifier)) { + 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", CZCPaymentAddress(pa).ToString())); + } + + // determine amount of funds in the note + auto hSig = wtx.vjoinsplit[i].h_sig(*pzcashParams, wtx.joinSplitPubKey); + try { + NotePlaintext plaintext = NotePlaintext::decrypt( + decryptor, + wtx.vjoinsplit[i].ciphertexts[j], + wtx.vjoinsplit[i].ephemeralKey, + hSig, + (unsigned char) j); + + outEntries.push_back(CNotePlaintextEntry{jsop, plaintext}); + + } catch (const std::exception &) { + // Couldn't decrypt with this spending key + throw std::runtime_error(strprintf("Could not decrypt note for payment address %s", CZCPaymentAddress(pa).ToString())); + } + } + } +} diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index bd65287dd..d5f239d39 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -241,6 +241,15 @@ public: typedef std::map mapNoteData_t; + +struct CNotePlaintextEntry +{ + JSOutPoint jsop; + libzcash::NotePlaintext plaintext; +}; + + + /** A transaction with a merkle branch linking it to the block chain. */ class CMerkleTx : public CTransaction { @@ -894,6 +903,10 @@ public: bool GetBroadcastTransactions() const { return fBroadcastTransactions; } /** Set whether this wallet broadcasts transactions. */ void SetBroadcastTransactions(bool broadcast) { fBroadcastTransactions = broadcast; } + + /* Find unspent notes, filter by payment address, min depth */ + bool GetUnspentNotes(std::vector & outEntries, std::string address, size_t minDepth); + }; /** A key allocated from the key pool. */