Add account ID to z_listunspent results.

Fixes #5795
This commit is contained in:
Kris Nuttycombe 2022-04-01 09:51:05 -06:00
parent f7b11f6da1
commit 0a5dbc10d4
4 changed files with 32 additions and 8 deletions

View File

@ -7,6 +7,7 @@ from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
NU5_BRANCH_ID,
assert_equal,
assert_true,
get_coinbase_address,
nuparams,
start_nodes,
@ -188,6 +189,7 @@ class WalletListNotes(BitcoinTestFramework):
assert_equal(txid_2, unspent_tx[0]['txid'])
assert_equal('sapling', unspent_tx[0]['pool'])
assert_equal(True, unspent_tx[0]['spendable'])
assert_true('account' not in unspent_tx[0])
assert_equal(saplingzaddr, unspent_tx[0]['address'])
assert_equal(receive_amount_2, unspent_tx[0]['amount'])
@ -195,6 +197,7 @@ class WalletListNotes(BitcoinTestFramework):
assert_equal(txid_3, unspent_tx[1]['txid'])
assert_equal('sapling', unspent_tx[1]['pool'])
assert_equal(True, unspent_tx[1]['spendable'])
assert_true('account' not in unspent_tx[1])
assert_equal(saplingzaddr2, unspent_tx[1]['address'])
assert_equal(receive_amount_3, unspent_tx[1]['amount'])
@ -202,6 +205,7 @@ class WalletListNotes(BitcoinTestFramework):
assert_equal(txid_3, unspent_tx[2]['txid'])
assert_equal('sprout', unspent_tx[2]['pool'])
assert_equal(True, unspent_tx[2]['spendable'])
assert_true('account' not in unspent_tx[2])
assert_equal(sproutzaddr, unspent_tx[2]['address'])
assert_equal(change_amount_3, unspent_tx[2]['amount'])
@ -209,6 +213,7 @@ class WalletListNotes(BitcoinTestFramework):
assert_equal(txid_4, unspent_tx[3]['txid'])
assert_equal('orchard', unspent_tx[3]['pool'])
assert_equal(True, unspent_tx[3]['spendable'])
assert_equal(account0, unspent_tx[3]['account'])
assert_equal(ua0, unspent_tx[3]['address'])
assert_equal(receive_amount_4, unspent_tx[3]['amount'])

View File

@ -2432,10 +2432,6 @@ UniValue z_listunspent(const UniValue& params, bool fHelp)
"\nReturns array of unspent shielded notes with between minconf and maxconf (inclusive) confirmations.\n"
"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"
"Orchard notes are not yet returned (the documentation below shows what the results will be when this is fixed).\n"
"Results are an array of Objects, each of which has:\n"
"{txid, pool, jsindex, jsoutindex, confirmations, address, amount, memo} (Sprout)\n"
"{txid, pool, 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"
@ -2455,7 +2451,8 @@ UniValue z_listunspent(const UniValue& params, bool fHelp)
" \"outindex\" (sapling, orchard) : n, (numeric) the Sapling output or Orchard action index\n"
" \"confirmations\" : n, (numeric) the number of confirmations\n"
" \"spendable\" : true|false, (boolean) true if note can be spent by wallet, false if address is watchonly\n"
" \"address\" : \"address\", (string) the shielded address\n"
" \"account\" : n, (numeric, optional) the unified account ID, if applicable\n"
" \"address\" : \"address\", (string, optional) the shielded address, omitted if this note was sent to an internal receiver\n"
" \"amount\": xxxxx, (numeric) the amount of value in the note\n"
" \"memo\": xxxxx, (string) hexadecimal string representation of memo field\n"
" \"change\": true|false, (boolean) true if the address that received the note is also one of the sending addresses\n"
@ -2577,6 +2574,10 @@ UniValue z_listunspent(const UniValue& params, bool fHelp)
obj.pushKV("confirmations", entry.confirmations);
bool hasSaplingSpendingKey = pwalletMain->HaveSaplingSpendingKeyForAddress(entry.address);
obj.pushKV("spendable", hasSaplingSpendingKey);
auto account = pwalletMain->FindUnifiedAccountByReceiver(entry.address);
if (account.has_value()) {
obj.pushKV("account", (uint64_t) account.value());
}
auto addr = pwalletMain->GetPaymentAddressForRecipient(entry.op.hash, entry.address);
if (addr.second != RecipientType::WalletInternalAddress) {
obj.pushKV("address", keyIO.EncodePaymentAddress(addr.first));
@ -2602,12 +2603,15 @@ UniValue z_listunspent(const UniValue& params, bool fHelp)
// TODO: add a better mechanism for checking whether we have the
// spending key for an Orchard receiver.
auto ufvkMeta = pwalletMain->GetUFVKMetadataForReceiver(entry.GetAddress());
bool haveSpendingKey =
ufvkMeta.has_value() &&
pwalletMain->GetUnifiedAccountId(ufvkMeta.value().GetUFVKId()).has_value();
auto account = pwalletMain->GetUnifiedAccountId(ufvkMeta.value().GetUFVKId());
bool haveSpendingKey = ufvkMeta.has_value() && account.has_value();
bool isInternal = pwalletMain->IsInternalRecipient(entry.GetAddress());
std::optional<std::string> addrStr;
obj.pushKV("spendable", haveSpendingKey);
if (account.has_value()) {
obj.pushKV("account", (uint64_t) account.value());
}
if (!isInternal) {
auto ua = pwalletMain->FindUnifiedAddressByReceiver(entry.GetAddress());
assert(ua.has_value());

View File

@ -6884,6 +6884,15 @@ std::optional<UnifiedAddress> CWallet::FindUnifiedAddressByReceiver(const Receiv
return std::visit(UnifiedAddressForReceiver(*this), receiver);
}
std::optional<libzcash::AccountId> CWallet::FindUnifiedAccountByReceiver(const Receiver& receiver) const {
auto ufvkMeta = GetUFVKMetadataForReceiver(receiver);
if (ufvkMeta.has_value()) {
return GetUnifiedAccountId(ufvkMeta.value().GetUFVKId());
} else {
return std::nullopt;
}
}
//
// Payment address operations
//

View File

@ -1647,6 +1647,12 @@ public:
std::optional<libzcash::UnifiedAddress> FindUnifiedAddressByReceiver(
const libzcash::Receiver& receiver) const;
/**
* Finds a unified account ID for a given receiver.
*/
std::optional<libzcash::AccountId> FindUnifiedAccountByReceiver(
const libzcash::Receiver& receiver) const;
/**
* Increment the next transaction order id
* @return next transaction order id