Add Sapling support to GetFilteredNotes() and GetUnspentFilteredNotes()

This could in future be refactored to be generic over PaymentAddress and
NotePlaintext in the return type, but for now let's be explicit about which
returned notes are for Sprout vs Sapling, and handle them separately.

Co-authored-by: Sean Bowe <ewillbefull@gmail.com>
This commit is contained in:
Jack Grigg
2018-08-01 01:24:49 +01:00
parent 20f87bc226
commit 94e99acda6
5 changed files with 207 additions and 74 deletions

View File

@@ -4091,7 +4091,13 @@ bool CMerkleTx::AcceptToMemoryPool(bool fLimitFree, bool fRejectAbsurdFee)
* Find notes in the wallet filtered by payment address, min depth and ability to spend.
* These notes are decrypted and added to the output parameter vector, outEntries.
*/
void CWallet::GetFilteredNotes(std::vector<CSproutNotePlaintextEntry> & outEntries, std::string address, int minDepth, bool ignoreSpent, bool ignoreUnspendable)
void CWallet::GetFilteredNotes(
std::vector<CSproutNotePlaintextEntry>& sproutEntries,
std::vector<SaplingNoteEntry>& saplingEntries,
std::string address,
int minDepth,
bool ignoreSpent,
bool ignoreUnspendable)
{
std::set<PaymentAddress> filterAddresses;
@@ -4099,7 +4105,7 @@ void CWallet::GetFilteredNotes(std::vector<CSproutNotePlaintextEntry> & outEntri
filterAddresses.insert(DecodePaymentAddress(address));
}
GetFilteredNotes(outEntries, filterAddresses, minDepth, ignoreSpent, ignoreUnspendable);
GetFilteredNotes(sproutEntries, saplingEntries, filterAddresses, minDepth, ignoreSpent, ignoreUnspendable);
}
/**
@@ -4107,7 +4113,8 @@ void CWallet::GetFilteredNotes(std::vector<CSproutNotePlaintextEntry> & outEntri
* These notes are decrypted and added to the output parameter vector, outEntries.
*/
void CWallet::GetFilteredNotes(
std::vector<CSproutNotePlaintextEntry>& outEntries,
std::vector<CSproutNotePlaintextEntry>& sproutEntries,
std::vector<SaplingNoteEntry>& saplingEntries,
std::set<PaymentAddress>& filterAddresses,
int minDepth,
bool ignoreSpent,
@@ -4123,10 +4130,6 @@ void CWallet::GetFilteredNotes(
continue;
}
if (wtx.mapSproutNoteData.size() == 0) {
continue;
}
for (auto & pair : wtx.mapSproutNoteData) {
JSOutPoint jsop = pair.first;
SproutNoteData nd = pair.second;
@@ -4172,7 +4175,7 @@ void CWallet::GetFilteredNotes(
hSig,
(unsigned char) j);
outEntries.push_back(CSproutNotePlaintextEntry{jsop, pa, plaintext});
sproutEntries.push_back(CSproutNotePlaintextEntry{jsop, pa, plaintext});
} catch (const note_decryption_failed &err) {
// Couldn't decrypt with this spending key
@@ -4182,13 +4185,61 @@ void CWallet::GetFilteredNotes(
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<bool>(maybe_pt));
auto notePt = maybe_pt.get();
auto maybe_pa = nd.ivk.address(notePt.d);
assert(static_cast<bool>(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;
}
if (ignoreSpent && nd.nullifier && IsSaplingSpent(*nd.nullifier)) {
continue;
}
// skip notes which cannot be spent
if (ignoreUnspendable) {
libzcash::SaplingIncomingViewingKey ivk;
libzcash::SaplingFullViewingKey fvk;
if (!(GetSaplingIncomingViewingKey(pa, ivk) &&
GetSaplingFullViewingKey(ivk, fvk) &&
HaveSaplingSpendingKey(fvk))) {
continue;
}
}
// skip locked notes
// TODO: Add locking for Sapling notes
// if (IsLockedNote(jsop)) {
// continue;
// }
auto note = notePt.note(nd.ivk).get();
saplingEntries.push_back(SaplingNoteEntry {
op, pa, note, notePt.memo() });
}
}
}
/* Find unspent notes filtered by payment address, min depth and max depth */
void CWallet::GetUnspentFilteredNotes(
std::vector<CUnspentSproutNotePlaintextEntry>& outEntries,
std::vector<CUnspentSproutNotePlaintextEntry>& sproutEntries,
std::vector<UnspentSaplingNoteEntry>& saplingEntries,
std::set<PaymentAddress>& filterAddresses,
int minDepth,
int maxDepth,
@@ -4204,10 +4255,6 @@ void CWallet::GetUnspentFilteredNotes(
continue;
}
if (wtx.mapSproutNoteData.size() == 0) {
continue;
}
for (auto & pair : wtx.mapSproutNoteData) {
JSOutPoint jsop = pair.first;
SproutNoteData nd = pair.second;
@@ -4248,7 +4295,7 @@ void CWallet::GetUnspentFilteredNotes(
hSig,
(unsigned char) j);
outEntries.push_back(CUnspentSproutNotePlaintextEntry{jsop, pa, plaintext, wtx.GetDepthInMainChain()});
sproutEntries.push_back(CUnspentSproutNotePlaintextEntry{jsop, pa, plaintext, wtx.GetDepthInMainChain()});
} catch (const note_decryption_failed &err) {
// Couldn't decrypt with this spending key
@@ -4258,6 +4305,48 @@ void CWallet::GetUnspentFilteredNotes(
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<bool>(maybe_pt));
auto notePt = maybe_pt.get();
auto maybe_pa = nd.ivk.address(notePt.d);
assert(static_cast<bool>(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(UnspentSaplingNoteEntry {
op, pa, note, notePt.memo(), wtx.GetDepthInMainChain() });
}
}
}