Auto merge of #3510 - arcalinea:3378_z_listunspent, r=bitcartel

Sapling support for z_listunspent

Closes #3378.
This commit is contained in:
Homu
2018-10-04 11:39:14 -07:00
3 changed files with 207 additions and 14 deletions

View File

@@ -2458,12 +2458,13 @@ UniValue z_listunspent(const UniValue& params, bool fHelp)
"Optionally filter to only include notes sent to specified addresses.\n"
"When minconf is 0, unspent notes with zero confirmations are returned, even though they are not immediately spendable.\n"
"Results are an array of Objects, each of which has:\n"
"{txid, jsindex, jsoutindex, confirmations, address, amount, memo}\n"
"{txid, jsindex, jsoutindex, confirmations, address, amount, memo} (Sprout)\n"
"{txid, outindex, confirmations, address, amount, memo} (Sapling)\n"
"\nArguments:\n"
"1. minconf (numeric, optional, default=1) The minimum confirmations to filter\n"
"2. maxconf (numeric, optional, default=9999999) The maximum confirmations to filter\n"
"3. includeWatchonly (bool, optional, default=false) Also include watchonly addresses (see 'z_importviewingkey')\n"
"4. \"addresses\" (string) A json array of zaddrs to filter on. Duplicate addresses not allowed.\n"
"4. \"addresses\" (string) A json array of zaddrs (both Sprout and Sapling) to filter on. Duplicate addresses not allowed.\n"
" [\n"
" \"address\" (string) zaddr\n"
" ,...\n"
@@ -2473,7 +2474,8 @@ UniValue z_listunspent(const UniValue& params, bool fHelp)
" {\n"
" \"txid\" : \"txid\", (string) the transaction id \n"
" \"jsindex\" : n (numeric) the joinsplit index\n"
" \"jsoutindex\" : n (numeric) the output index of the joinsplit\n"
" \"jsoutindex\" (sprout) : n (numeric) the output index of the joinsplit\n"
" \"outindex\" (sapling) : n (numeric) the output index\n"
" \"confirmations\" : n (numeric) the number of confirmations\n"
" \"spendable\" : true|false (boolean) true if note can be spent by wallet, false if note has zero confirmations, false if address is watchonly\n"
" \"address\" : \"address\", (string) the shielded address\n"
@@ -2533,17 +2535,14 @@ UniValue z_listunspent(const UniValue& params, bool fHelp)
}
string address = o.get_str();
auto zaddr = DecodePaymentAddress(address);
if (IsValidPaymentAddress(zaddr)) {
// TODO: Add Sapling support. For now, ensure we can freely convert.
assert(boost::get<libzcash::SproutPaymentAddress>(&zaddr) != nullptr);
libzcash::SproutPaymentAddress addr = boost::get<libzcash::SproutPaymentAddress>(zaddr);
if (!fIncludeWatchonly && !pwalletMain->HaveSproutSpendingKey(addr)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, spending key for address does not belong to wallet: ") + address);
}
zaddrs.insert(addr);
} else {
if (!IsValidPaymentAddress(zaddr)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, address is not a valid zaddr: ") + address);
}
auto hasSpendingKey = boost::apply_visitor(HaveSpendingKeyForPaymentAddress(pwalletMain), zaddr);
if (!fIncludeWatchonly && !hasSpendingKey) {
throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, spending key for address does not belong to wallet: ") + address);
}
zaddrs.insert(zaddr);
if (setAddress.count(address)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ") + address);
@@ -2553,10 +2552,15 @@ UniValue z_listunspent(const UniValue& params, bool fHelp)
}
else {
// User did not provide zaddrs, so use default i.e. all addresses
// TODO: Add Sapling support
std::set<libzcash::SproutPaymentAddress> sproutzaddrs = {};
pwalletMain->GetSproutPaymentAddresses(sproutzaddrs);
// Sapling support
std::set<libzcash::SaplingPaymentAddress> saplingzaddrs = {};
pwalletMain->GetSaplingPaymentAddresses(saplingzaddrs);
zaddrs.insert(sproutzaddrs.begin(), sproutzaddrs.end());
zaddrs.insert(saplingzaddrs.begin(), saplingzaddrs.end());
}
UniValue results(UniValue::VARR);
@@ -2566,6 +2570,7 @@ UniValue z_listunspent(const UniValue& params, bool fHelp)
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 : sproutEntries) {
UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("txid", entry.jsop.hash.ToString()));
@@ -2583,7 +2588,26 @@ UniValue z_listunspent(const UniValue& params, bool fHelp)
}
results.push_back(obj);
}
// TODO: Sapling
for (UnspentSaplingNoteEntry & 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));
libzcash::SaplingIncomingViewingKey ivk;
libzcash::SaplingFullViewingKey fvk;
pwalletMain->GetSaplingIncomingViewingKey(boost::get<libzcash::SaplingPaymentAddress>(entry.address), ivk);
pwalletMain->GetSaplingFullViewingKey(ivk, fvk);
bool hasSaplingSpendingKey = pwalletMain->HaveSaplingSpendingKey(fvk);
obj.push_back(Pair("spendable", hasSaplingSpendingKey));
obj.push_back(Pair("address", EncodePaymentAddress(entry.address)));
obj.push_back(Pair("amount", ValueFromAmount(CAmount(entry.note.value())))); // note.value() is equivalent to plaintext.value()
obj.push_back(Pair("memo", HexStr(entry.memo)));
if (hasSaplingSpendingKey) {
obj.push_back(Pair("change", pwalletMain->IsNoteSaplingChange(nullifierSet, entry.address, entry.op)));
}
results.push_back(obj);
}
}
return results;