Merge pull request #5526 from str4d/wallet-unified-addrs-in-rpcs

Handle wallet Unified Addresses in RPCs
This commit is contained in:
Kris Nuttycombe 2022-02-09 21:11:41 -07:00 committed by GitHub
commit 2aad87e147
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 63 additions and 20 deletions

View File

@ -46,6 +46,7 @@ class WalletListNotes(BitcoinTestFramework):
assert_equal(1, len(unspent_cb))
assert_equal(False, unspent_cb[0]['change'])
assert_equal(txid_1, unspent_cb[0]['txid'])
assert_equal('sprout', unspent_cb[0]['type'])
assert_equal(True, unspent_cb[0]['spendable'])
assert_equal(sproutzaddr, unspent_cb[0]['address'])
assert_equal(receive_amount_1, unspent_cb[0]['amount'])
@ -78,12 +79,14 @@ class WalletListNotes(BitcoinTestFramework):
unspent_tx = sorted(unspent_tx, key=lambda k: k['amount'])
assert_equal(False, unspent_tx[0]['change'])
assert_equal(txid_2, unspent_tx[0]['txid'])
assert_equal('sapling', unspent_tx[0]['type'])
assert_equal(True, unspent_tx[0]['spendable'])
assert_equal(saplingzaddr, unspent_tx[0]['address'])
assert_equal(receive_amount_2, unspent_tx[0]['amount'])
assert_equal(True, unspent_tx[1]['change'])
assert_equal(txid_2, unspent_tx[1]['txid'])
assert_equal('sprout', unspent_tx[1]['type'])
assert_equal(True, unspent_tx[1]['spendable'])
assert_equal(sproutzaddr, unspent_tx[1]['address'])
assert_equal(change_amount_2, unspent_tx[1]['amount'])
@ -115,18 +118,21 @@ class WalletListNotes(BitcoinTestFramework):
assert_equal(False, unspent_tx[0]['change'])
assert_equal(txid_2, unspent_tx[0]['txid'])
assert_equal('sapling', unspent_tx[0]['type'])
assert_equal(True, unspent_tx[0]['spendable'])
assert_equal(saplingzaddr, unspent_tx[0]['address'])
assert_equal(receive_amount_2, unspent_tx[0]['amount'])
assert_equal(False, unspent_tx[1]['change'])
assert_equal(txid_3, unspent_tx[1]['txid'])
assert_equal('sapling', unspent_tx[1]['type'])
assert_equal(True, unspent_tx[1]['spendable'])
assert_equal(saplingzaddr2, unspent_tx[1]['address'])
assert_equal(receive_amount_3, unspent_tx[1]['amount'])
assert_equal(True, unspent_tx[2]['change'])
assert_equal(txid_3, unspent_tx[2]['txid'])
assert_equal('sprout', unspent_tx[2]['type'])
assert_equal(True, unspent_tx[2]['spendable'])
assert_equal(sproutzaddr, unspent_tx[2]['address'])
assert_equal(change_amount_3, unspent_tx[2]['amount'])

View File

@ -26,6 +26,15 @@ class WalletShieldCoinbaseUANU5(WalletShieldCoinbaseTest):
assert_equal(balances['pools']['sapling']['valueZat'], expected * COIN)
# assert_equal(balances['pools']['orchard']['valueZat'], expected * COIN)
# While we're at it, check that z_listunspent only shows outputs with
# the Unified Address (not the Orchard receiver), and of the expected
# type.
unspent = node.z_listunspent(1, 999999, False, [self.addr])
assert_equal(
[{'type': 'sapling', 'address': self.addr} for _ in unspent],
[{'type': x['type'], 'address': x['address']} for x in unspent],
)
if __name__ == '__main__':
print("Test shielding to a unified address with NU5 activated")

View File

@ -24,6 +24,15 @@ class WalletShieldCoinbaseUASapling(WalletShieldCoinbaseTest):
assert_equal(balances['pools']['sapling']['valueZat'], expected * COIN)
assert('orchard' not in balances['pools'])
# While we're at it, check that z_listunspent only shows outputs with
# the Unified Address (not the Sapling receiver), and of the expected
# type.
unspent = node.z_listunspent(1, 999999, False, [self.addr])
assert_equal(
[{'type': 'sapling', 'address': self.addr} for _ in unspent],
[{'type': x['type'], 'address': x['address']} for x in unspent],
)
if __name__ == '__main__':
print("Test shielding to a unified address with sapling activated (but not NU5)")

View File

@ -129,6 +129,7 @@ class WalletShieldingCoinbaseTest (BitcoinTestFramework):
assert(len(results) == 0)
results = self.nodes[0].z_listunspent(0) # set minconf to zero
assert(len(results) == 1)
assert_equal(results[0]["type"], "sapling")
assert_equal(results[0]["address"], myzaddr)
assert_equal(results[0]["amount"], shieldvalue)
assert_equal(results[0]["confirmations"], 0)
@ -140,6 +141,7 @@ class WalletShieldingCoinbaseTest (BitcoinTestFramework):
# Verify that z_listunspent returns one note which has been confirmed
results = self.nodes[0].z_listunspent()
assert(len(results) == 1)
assert_equal(results[0]["type"], "sapling")
assert_equal(results[0]["address"], myzaddr)
assert_equal(results[0]["amount"], shieldvalue)
assert_equal(results[0]["confirmations"], 1)
@ -148,6 +150,7 @@ class WalletShieldingCoinbaseTest (BitcoinTestFramework):
# Verify that z_listunspent returns note for watchonly address on node 3.
results = self.nodes[3].z_listunspent(1, 999, True)
assert(len(results) == 1)
assert_equal(results[0]["type"], "sapling")
assert_equal(results[0]["address"], myzaddr)
assert_equal(results[0]["amount"], shieldvalue)
assert_equal(results[0]["confirmations"], 1)

View File

@ -2256,21 +2256,22 @@ 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} (Sprout)\n"
"{txid, outindex, confirmations, address, amount, memo} (Sapling)\n"
"{txid, type, jsindex, jsoutindex, confirmations, address, amount, memo} (Sprout)\n"
"{txid, type, 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 (both Sprout and Sapling) to filter on. Duplicate addresses not allowed.\n"
"4. \"addresses\" (string) A json array of shielded addresses to filter on. Duplicate addresses not allowed.\n"
" [\n"
" \"address\" (string) zaddr\n"
" \"address\" (string) Sprout, Sapling, or Unified address\n"
" ,...\n"
" ]\n"
"\nResult (output indices for only one pool will be present):\n"
"[ (array of json object)\n"
" {\n"
" \"txid\" : \"txid\", (string) the transaction id \n"
" \"type\" : \"sprout|sapling|orchard\", (string) The shielded pool\n"
" \"jsindex\" (sprout) : n, (numeric) the joinsplit index\n"
" \"jsoutindex\" (sprout) : n, (numeric) the output index of the joinsplit\n"
" \"outindex\" (sapling) : n, (numeric) the output index\n"
@ -2373,6 +2374,7 @@ UniValue z_listunspent(const UniValue& params, bool fHelp)
for (auto & entry : sproutEntries) {
UniValue obj(UniValue::VOBJ);
obj.pushKV("txid", entry.jsop.hash.ToString());
obj.pushKV("type", ADDR_TYPE_SPROUT);
obj.pushKV("jsindex", (int)entry.jsop.js );
obj.pushKV("jsoutindex", (int)entry.jsop.n);
obj.pushKV("confirmations", entry.confirmations);
@ -2391,12 +2393,19 @@ UniValue z_listunspent(const UniValue& params, bool fHelp)
for (auto & entry : saplingEntries) {
UniValue obj(UniValue::VOBJ);
obj.pushKV("txid", entry.op.hash.ToString());
obj.pushKV("type", ADDR_TYPE_SAPLING);
obj.pushKV("outindex", (int)entry.op.n);
obj.pushKV("confirmations", entry.confirmations);
bool hasSaplingSpendingKey = pwalletMain->HaveSaplingSpendingKeyForAddress(entry.address);
obj.pushKV("spendable", hasSaplingSpendingKey);
// TODO: If we found this entry via a UA, show that instead.
obj.pushKV("address", keyIO.EncodePaymentAddress(entry.address));
obj.pushKV("address", keyIO.EncodePaymentAddress([&]() {
auto ua = pwalletMain->FindUnifiedAddressByReceiver(entry.address);
if (ua.has_value()) {
return libzcash::PaymentAddress{ua.value()};
} else {
return libzcash::PaymentAddress{entry.address};
}
}()));
obj.pushKV("amount", ValueFromAmount(CAmount(entry.note.value()))); // note.value() is equivalent to plaintext.value()
obj.pushKV("memo", HexStr(entry.memo));
if (hasSaplingSpendingKey) {
@ -3235,6 +3244,7 @@ UniValue z_listaddresses(const UniValue& params, bool fHelp)
"z_listaddresses ( includeWatchonly )\n"
"\nDEPRECATED\n"
"\nReturns the list of shielded addresses belonging to the wallet.\n"
"\nThis never returns Unified Addresses; see 'listaddresses' for them.\n"
"\nArguments:\n"
"1. includeWatchonly (bool, optional, default=false) Also include watchonly addresses (see 'z_importviewingkey')\n"
"\nResult:\n"
@ -3269,6 +3279,10 @@ UniValue z_listaddresses(const UniValue& params, bool fHelp)
std::set<libzcash::SaplingPaymentAddress> addresses;
pwalletMain->GetSaplingPaymentAddresses(addresses);
for (auto addr : addresses) {
// Don't show Sapling receivers that are part of an account in the wallet.
if (pwalletMain->FindUnifiedAddressByReceiver(addr).has_value()) {
continue;
}
if (fIncludeWatchonly || pwalletMain->HaveSaplingSpendingKeyForAddress(addr)) {
ret.push_back(keyIO.EncodePaymentAddress(addr));
}
@ -4066,13 +4080,14 @@ UniValue z_viewtransaction(const UniValue& params, bool fHelp)
// If the note belongs to a Sapling address that is part of an account in the
// wallet, show the corresponding Unified Address.
std::string address;
const auto ua = pwalletMain->FindUnifiedAddressByReceiver(pa);
if (ua.has_value()) {
address = keyIO.EncodePaymentAddress(ua.value());
} else {
address = keyIO.EncodePaymentAddress(pa);
}
std::string address = keyIO.EncodePaymentAddress([&]() {
auto ua = pwalletMain->FindUnifiedAddressByReceiver(pa);
if (ua.has_value()) {
return libzcash::PaymentAddress{ua.value()};
} else {
return libzcash::PaymentAddress{pa};
}
}());
UniValue entry(UniValue::VOBJ);
entry.pushKV("type", ADDR_TYPE_SAPLING);
@ -4119,13 +4134,14 @@ UniValue z_viewtransaction(const UniValue& params, bool fHelp)
// If the note belongs to a Sapling address that is part of an account in the
// wallet, show the corresponding Unified Address.
std::string address;
const auto ua = pwalletMain->FindUnifiedAddressByReceiver(pa);
if (ua.has_value()) {
address = keyIO.EncodePaymentAddress(ua.value());
} else {
address = keyIO.EncodePaymentAddress(pa);
}
std::string address = keyIO.EncodePaymentAddress([&]() {
auto ua = pwalletMain->FindUnifiedAddressByReceiver(pa);
if (ua.has_value()) {
return libzcash::PaymentAddress{ua.value()};
} else {
return libzcash::PaymentAddress{pa};
}
}());
UniValue entry(UniValue::VOBJ);
entry.pushKV("type", ADDR_TYPE_SAPLING);