Auto merge of #3436 - str4d:3214-z_getbalance, r=str4d

Add Sapling support to z_getbalance and z_gettotalbalance

Also includes preparatory changes for various other RPCs that depend on `GetFilteredNotes` etc.

Closes #3214.
This commit is contained in:
Homu 2018-08-24 21:01:53 -07:00
commit c53884d20a
5 changed files with 256 additions and 84 deletions

View File

@ -888,13 +888,14 @@ bool AsyncRPCOperation_sendmany::find_utxos(bool fAcceptCoinbase=false) {
bool AsyncRPCOperation_sendmany::find_unspent_notes() {
std::vector<CSproutNotePlaintextEntry> entries;
std::vector<CSproutNotePlaintextEntry> sproutEntries;
std::vector<SaplingNoteEntry> saplingEntries;
{
LOCK2(cs_main, pwalletMain->cs_wallet);
pwalletMain->GetFilteredNotes(entries, fromaddress_, mindepth_);
pwalletMain->GetFilteredNotes(sproutEntries, saplingEntries, fromaddress_, mindepth_);
}
for (CSproutNotePlaintextEntry & entry : entries) {
for (CSproutNotePlaintextEntry & entry : sproutEntries) {
z_inputs_.push_back(SendManyInputJSOP(entry.jsop, entry.plaintext.note(boost::get<libzcash::SproutPaymentAddress>(frompaymentaddress_)), CAmount(entry.plaintext.value())));
std::string data(entry.plaintext.memo().begin(), entry.plaintext.memo().end());
LogPrint("zrpcunsafe", "%s: found unspent note (txid=%s, vjoinsplit=%d, ciphertext=%d, amount=%s, memo=%s)\n",
@ -906,6 +907,7 @@ bool AsyncRPCOperation_sendmany::find_unspent_notes() {
HexStr(data).substr(0, 10)
);
}
// TODO: Do something with Sapling notes
if (z_inputs_.size() == 0) {
return false;

View File

@ -186,13 +186,16 @@ TEST(WalletTests, FindUnspentSproutNotes) {
EXPECT_FALSE(wallet.IsSproutSpent(nullifier));
// We currently have an unspent and unconfirmed note in the wallet (depth of -1)
std::vector<CSproutNotePlaintextEntry> entries;
wallet.GetFilteredNotes(entries, "", 0);
EXPECT_EQ(0, entries.size());
entries.clear();
wallet.GetFilteredNotes(entries, "", -1);
EXPECT_EQ(1, entries.size());
entries.clear();
std::vector<CSproutNotePlaintextEntry> sproutEntries;
std::vector<SaplingNoteEntry> saplingEntries;
wallet.GetFilteredNotes(sproutEntries, saplingEntries, "", 0);
EXPECT_EQ(0, sproutEntries.size());
sproutEntries.clear();
saplingEntries.clear();
wallet.GetFilteredNotes(sproutEntries, saplingEntries, "", -1);
EXPECT_EQ(1, sproutEntries.size());
sproutEntries.clear();
saplingEntries.clear();
// Fake-mine the transaction
EXPECT_EQ(-1, chainActive.Height());
@ -212,15 +215,18 @@ TEST(WalletTests, FindUnspentSproutNotes) {
// We now have an unspent and confirmed note in the wallet (depth of 1)
wallet.GetFilteredNotes(entries, "", 0);
EXPECT_EQ(1, entries.size());
entries.clear();
wallet.GetFilteredNotes(entries, "", 1);
EXPECT_EQ(1, entries.size());
entries.clear();
wallet.GetFilteredNotes(entries, "", 2);
EXPECT_EQ(0, entries.size());
entries.clear();
wallet.GetFilteredNotes(sproutEntries, saplingEntries, "", 0);
EXPECT_EQ(1, sproutEntries.size());
sproutEntries.clear();
saplingEntries.clear();
wallet.GetFilteredNotes(sproutEntries, saplingEntries, "", 1);
EXPECT_EQ(1, sproutEntries.size());
sproutEntries.clear();
saplingEntries.clear();
wallet.GetFilteredNotes(sproutEntries, saplingEntries, "", 2);
EXPECT_EQ(0, sproutEntries.size());
sproutEntries.clear();
saplingEntries.clear();
// Let's spend the note.
@ -247,21 +253,25 @@ TEST(WalletTests, FindUnspentSproutNotes) {
EXPECT_TRUE(wallet.IsSproutSpent(nullifier));
// The note has been spent. By default, GetFilteredNotes() ignores spent notes.
wallet.GetFilteredNotes(entries, "", 0);
EXPECT_EQ(0, entries.size());
entries.clear();
wallet.GetFilteredNotes(sproutEntries, saplingEntries, "", 0);
EXPECT_EQ(0, sproutEntries.size());
sproutEntries.clear();
saplingEntries.clear();
// Let's include spent notes to retrieve it.
wallet.GetFilteredNotes(entries, "", 0, false);
EXPECT_EQ(1, entries.size());
entries.clear();
wallet.GetFilteredNotes(sproutEntries, saplingEntries, "", 0, false);
EXPECT_EQ(1, sproutEntries.size());
sproutEntries.clear();
saplingEntries.clear();
// The spent note has two confirmations.
wallet.GetFilteredNotes(entries, "", 2, false);
EXPECT_EQ(1, entries.size());
entries.clear();
wallet.GetFilteredNotes(sproutEntries, saplingEntries, "", 2, false);
EXPECT_EQ(1, sproutEntries.size());
sproutEntries.clear();
saplingEntries.clear();
// It does not have 3 confirmations.
wallet.GetFilteredNotes(entries, "", 3, false);
EXPECT_EQ(0, entries.size());
entries.clear();
wallet.GetFilteredNotes(sproutEntries, saplingEntries, "", 3, false);
EXPECT_EQ(0, sproutEntries.size());
sproutEntries.clear();
saplingEntries.clear();
// Let's receive a new note
@ -301,21 +311,25 @@ TEST(WalletTests, FindUnspentSproutNotes) {
wallet.AddToWallet(wtx3, true, NULL);
// We now have an unspent note which has one confirmation, in addition to our spent note.
wallet.GetFilteredNotes(entries, "", 1);
EXPECT_EQ(1, entries.size());
entries.clear();
wallet.GetFilteredNotes(sproutEntries, saplingEntries, "", 1);
EXPECT_EQ(1, sproutEntries.size());
sproutEntries.clear();
saplingEntries.clear();
// Let's return the spent note too.
wallet.GetFilteredNotes(entries, "", 1, false);
EXPECT_EQ(2, entries.size());
entries.clear();
wallet.GetFilteredNotes(sproutEntries, saplingEntries, "", 1, false);
EXPECT_EQ(2, sproutEntries.size());
sproutEntries.clear();
saplingEntries.clear();
// Increasing number of confirmations will exclude our new unspent note.
wallet.GetFilteredNotes(entries, "", 2, false);
EXPECT_EQ(1, entries.size());
entries.clear();
wallet.GetFilteredNotes(sproutEntries, saplingEntries, "", 2, false);
EXPECT_EQ(1, sproutEntries.size());
sproutEntries.clear();
saplingEntries.clear();
// If we also ignore spent notes at this depth, we won't find any notes.
wallet.GetFilteredNotes(entries, "", 2, true);
EXPECT_EQ(0, entries.size());
entries.clear();
wallet.GetFilteredNotes(sproutEntries, saplingEntries, "", 2, true);
EXPECT_EQ(0, sproutEntries.size());
sproutEntries.clear();
saplingEntries.clear();
// Tear down
chainActive.SetTip(NULL);

View File

@ -2556,10 +2556,11 @@ UniValue z_listunspent(const UniValue& params, bool fHelp)
UniValue results(UniValue::VARR);
if (zaddrs.size() > 0) {
std::vector<CUnspentSproutNotePlaintextEntry> entries;
pwalletMain->GetUnspentFilteredNotes(entries, zaddrs, nMinDepth, nMaxDepth, !fIncludeWatchonly);
std::vector<CUnspentSproutNotePlaintextEntry> sproutEntries;
std::vector<UnspentSaplingNoteEntry> saplingEntries;
pwalletMain->GetUnspentFilteredNotes(sproutEntries, saplingEntries, zaddrs, nMinDepth, nMaxDepth, !fIncludeWatchonly);
std::set<std::pair<PaymentAddress, uint256>> nullifierSet = pwalletMain->GetNullifiersForAddresses(zaddrs);
for (CUnspentSproutNotePlaintextEntry & entry : entries) {
for (CUnspentSproutNotePlaintextEntry & entry : sproutEntries) {
UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("txid", entry.jsop.hash.ToString()));
obj.push_back(Pair("jsindex", (int)entry.jsop.js ));
@ -2576,6 +2577,7 @@ UniValue z_listunspent(const UniValue& params, bool fHelp)
}
results.push_back(obj);
}
// TODO: Sapling
}
return results;
@ -3248,12 +3250,16 @@ CAmount getBalanceTaddr(std::string transparentAddress, int minDepth=1, bool ign
CAmount getBalanceZaddr(std::string address, int minDepth = 1, bool ignoreUnspendable=true) {
CAmount balance = 0;
std::vector<CSproutNotePlaintextEntry> entries;
std::vector<CSproutNotePlaintextEntry> sproutEntries;
std::vector<SaplingNoteEntry> saplingEntries;
LOCK2(cs_main, pwalletMain->cs_wallet);
pwalletMain->GetFilteredNotes(entries, address, minDepth, true, ignoreUnspendable);
for (auto & entry : entries) {
pwalletMain->GetFilteredNotes(sproutEntries, saplingEntries, address, minDepth, true, ignoreUnspendable);
for (auto & entry : sproutEntries) {
balance += CAmount(entry.plaintext.value());
}
for (auto & entry : saplingEntries) {
balance += CAmount(entry.note.value());
}
return balance;
}
@ -3309,10 +3315,11 @@ UniValue z_listreceivedbyaddress(const UniValue& params, bool fHelp)
}
UniValue result(UniValue::VARR);
std::vector<CSproutNotePlaintextEntry> entries;
pwalletMain->GetFilteredNotes(entries, fromaddress, nMinDepth, false, false);
std::vector<CSproutNotePlaintextEntry> sproutEntries;
std::vector<SaplingNoteEntry> saplingEntries;
pwalletMain->GetFilteredNotes(sproutEntries, saplingEntries, fromaddress, nMinDepth, false, false);
auto nullifierSet = hasSproutSpendingKey ? pwalletMain->GetNullifiersForAddresses({zaddr}) : std::set<std::pair<PaymentAddress, uint256>>();
for (CSproutNotePlaintextEntry & entry : entries) {
for (CSproutNotePlaintextEntry & entry : sproutEntries) {
UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("txid", entry.jsop.hash.ToString()));
obj.push_back(Pair("amount", ValueFromAmount(CAmount(entry.plaintext.value()))));
@ -3326,6 +3333,7 @@ UniValue z_listreceivedbyaddress(const UniValue& params, bool fHelp)
}
result.push_back(obj);
}
// TODO: Sapling
return result;
}
@ -3338,8 +3346,8 @@ UniValue z_getbalance(const UniValue& params, bool fHelp)
throw runtime_error(
"z_getbalance \"address\" ( minconf )\n"
"\nReturns the balance of a taddr or zaddr belonging to the nodes wallet.\n"
"\nCAUTION: If address is a watch-only zaddr, the returned balance may be larger than the actual balance,"
"\nbecause spends cannot be detected with incoming viewing keys.\n"
"\nCAUTION: If the wallet has only an incoming viewing key for this address, then spends cannot be"
"\ndetected, and so the returned balance may be larger than the actual balance.\n"
"\nArguments:\n"
"1. \"address\" (string) The selected address. It may be a transparent or private address.\n"
"2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
@ -3374,11 +3382,8 @@ UniValue z_getbalance(const UniValue& params, bool fHelp)
if (!IsValidPaymentAddress(res)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or zaddr.");
}
// TODO: Add Sapling support. For now, ensure we can freely convert.
assert(boost::get<libzcash::SproutPaymentAddress>(&res) != nullptr);
auto zaddr = boost::get<libzcash::SproutPaymentAddress>(res);
if (!(pwalletMain->HaveSproutSpendingKey(zaddr) || pwalletMain->HaveSproutViewingKey(zaddr))) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, zaddr spending key or viewing key not found.");
if (!boost::apply_visitor(PaymentAddressBelongsToWallet(pwalletMain), res)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, spending key or viewing key not found.");
}
}
@ -3402,15 +3407,16 @@ UniValue z_gettotalbalance(const UniValue& params, bool fHelp)
throw runtime_error(
"z_gettotalbalance ( minconf includeWatchonly )\n"
"\nReturn the total value of funds stored in the nodes wallet.\n"
"\nCAUTION: If the wallet contains watch-only zaddrs, the returned private balance may be larger than the actual balance,"
"\nbecause spends cannot be detected with incoming viewing keys.\n"
"\nCAUTION: If the wallet contains any addresses for which it only has incoming viewing keys,"
"\nthe returned private balance may be larger than the actual balance, because spends cannot"
"\nbe detected with incoming viewing keys.\n"
"\nArguments:\n"
"1. minconf (numeric, optional, default=1) Only include private and transparent transactions confirmed at least this many times.\n"
"2. includeWatchonly (bool, optional, default=false) Also include balance in watchonly addresses (see 'importaddress' and 'z_importviewingkey')\n"
"\nResult:\n"
"{\n"
" \"transparent\": xxxxx, (numeric) the total balance of transparent funds\n"
" \"private\": xxxxx, (numeric) the total balance of private funds\n"
" \"private\": xxxxx, (numeric) the total balance of private funds (in both Sprout and Sapling addresses)\n"
" \"total\": xxxxx, (numeric) the total balance of both transparent and private funds\n"
"}\n"
"\nExamples:\n"
@ -4247,11 +4253,12 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp)
if (useAny || useAnyNote || zaddrs.size() > 0) {
// Get available notes
std::vector<CSproutNotePlaintextEntry> entries;
pwalletMain->GetFilteredNotes(entries, zaddrs);
std::vector<CSproutNotePlaintextEntry> sproutEntries;
std::vector<SaplingNoteEntry> saplingEntries;
pwalletMain->GetFilteredNotes(sproutEntries, saplingEntries, zaddrs);
// Find unspent notes and update estimated size
for (CSproutNotePlaintextEntry& entry : entries) {
for (CSproutNotePlaintextEntry& entry : sproutEntries) {
noteCounter++;
CAmount nValue = entry.plaintext.value();
@ -4265,8 +4272,7 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp)
maxedOutNotesFlag = true;
} else {
estimatedTxSize += increase;
// TODO: Add Sapling support
auto zaddr = boost::get<SproutPaymentAddress>(entry.address);
auto zaddr = entry.address;
SproutSpendingKey zkey;
pwalletMain->GetSproutSpendingKey(zaddr, zkey);
noteInputs.emplace_back(entry.jsop, entry.plaintext.note(zaddr), nValue, zkey);
@ -4278,6 +4284,7 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp)
remainingNoteValue += nValue;
}
}
// TODO: Add Sapling support
}
size_t numUtxos = utxoInputs.size();

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,71 @@ 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() });
}
}
}
//
// Shielded key and address generalizations
//
bool PaymentAddressBelongsToWallet::operator()(const libzcash::SproutPaymentAddress &zaddr) const
{
return m_wallet->HaveSproutSpendingKey(zaddr) || m_wallet->HaveSproutViewingKey(zaddr);
}
bool PaymentAddressBelongsToWallet::operator()(const libzcash::SaplingPaymentAddress &zaddr) const
{
libzcash::SaplingIncomingViewingKey ivk;
// If we have a SaplingSpendingKey or SaplingExpandedSpendingKey in the
// wallet, then we will also have the corresponding SaplingFullViewingKey.
return m_wallet->GetSaplingIncomingViewingKey(zaddr, ivk) &&
m_wallet->HaveSaplingFullViewingKey(ivk);
}
bool PaymentAddressBelongsToWallet::operator()(const libzcash::InvalidEncoding& no) const
{
return false;
}

View File

@ -307,6 +307,24 @@ struct CUnspentSproutNotePlaintextEntry {
int nHeight;
};
/** Sapling note and its location in a transaction. */
struct SaplingNoteEntry
{
SaplingOutPoint op;
libzcash::SaplingPaymentAddress address;
libzcash::SaplingNote note;
std::array<unsigned char, ZC_MEMO_SIZE> memo;
};
/** Sapling note, location in a transaction, and confirmation height. */
struct UnspentSaplingNoteEntry {
SaplingOutPoint op;
libzcash::SaplingPaymentAddress address;
libzcash::SaplingNote note;
std::array<unsigned char, ZC_MEMO_SIZE> memo;
int nHeight;
};
/** A transaction with a merkle branch linking it to the block chain. */
class CMerkleTx : public CTransaction
{
@ -1206,21 +1224,24 @@ public:
void SetBroadcastTransactions(bool broadcast) { fBroadcastTransactions = broadcast; }
/* Find notes filtered by payment address, min depth, ability to spend */
void GetFilteredNotes(std::vector<CSproutNotePlaintextEntry> & outEntries,
void GetFilteredNotes(std::vector<CSproutNotePlaintextEntry>& sproutEntries,
std::vector<SaplingNoteEntry>& saplingEntries,
std::string address,
int minDepth=1,
bool ignoreSpent=true,
bool ignoreUnspendable=true);
/* Find notes filtered by payment addresses, min depth, ability to spend */
void GetFilteredNotes(std::vector<CSproutNotePlaintextEntry>& outEntries,
void GetFilteredNotes(std::vector<CSproutNotePlaintextEntry>& sproutEntries,
std::vector<SaplingNoteEntry>& saplingEntries,
std::set<libzcash::PaymentAddress>& filterAddresses,
int minDepth=1,
bool ignoreSpent=true,
bool ignoreUnspendable=true);
/* Find unspent notes filtered by payment address, min depth and max depth */
void GetUnspentFilteredNotes(std::vector<CUnspentSproutNotePlaintextEntry>& outEntries,
void GetUnspentFilteredNotes(std::vector<CUnspentSproutNotePlaintextEntry>& sproutEntries,
std::vector<UnspentSaplingNoteEntry>& saplingEntries,
std::set<libzcash::PaymentAddress>& filterAddresses,
int minDepth=1,
int maxDepth=INT_MAX,
@ -1282,4 +1303,20 @@ public:
}
};
//
// Shielded key and address generalizations
//
class PaymentAddressBelongsToWallet : public boost::static_visitor<bool>
{
private:
CWallet *m_wallet;
public:
PaymentAddressBelongsToWallet(CWallet *wallet) : m_wallet(wallet) {}
bool operator()(const libzcash::SproutPaymentAddress &zaddr) const;
bool operator()(const libzcash::SaplingPaymentAddress &zaddr) const;
bool operator()(const libzcash::InvalidEncoding& no) const;
};
#endif // BITCOIN_WALLET_WALLET_H