wallet: Show UAs instead of Sapling receivers in `z_listunspent`
We also add a `type` field to the output objects (matching the field in `z_viewtransaction`), now that the output type can't be distinguished solely from the address encoding.
This commit is contained in:
parent
0a9c27e8f2
commit
88dde127f4
|
@ -46,6 +46,7 @@ class WalletListNotes(BitcoinTestFramework):
|
||||||
assert_equal(1, len(unspent_cb))
|
assert_equal(1, len(unspent_cb))
|
||||||
assert_equal(False, unspent_cb[0]['change'])
|
assert_equal(False, unspent_cb[0]['change'])
|
||||||
assert_equal(txid_1, unspent_cb[0]['txid'])
|
assert_equal(txid_1, unspent_cb[0]['txid'])
|
||||||
|
assert_equal('sprout', unspent_cb[0]['type'])
|
||||||
assert_equal(True, unspent_cb[0]['spendable'])
|
assert_equal(True, unspent_cb[0]['spendable'])
|
||||||
assert_equal(sproutzaddr, unspent_cb[0]['address'])
|
assert_equal(sproutzaddr, unspent_cb[0]['address'])
|
||||||
assert_equal(receive_amount_1, unspent_cb[0]['amount'])
|
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'])
|
unspent_tx = sorted(unspent_tx, key=lambda k: k['amount'])
|
||||||
assert_equal(False, unspent_tx[0]['change'])
|
assert_equal(False, unspent_tx[0]['change'])
|
||||||
assert_equal(txid_2, unspent_tx[0]['txid'])
|
assert_equal(txid_2, unspent_tx[0]['txid'])
|
||||||
|
assert_equal('sapling', unspent_tx[0]['type'])
|
||||||
assert_equal(True, unspent_tx[0]['spendable'])
|
assert_equal(True, unspent_tx[0]['spendable'])
|
||||||
assert_equal(saplingzaddr, unspent_tx[0]['address'])
|
assert_equal(saplingzaddr, unspent_tx[0]['address'])
|
||||||
assert_equal(receive_amount_2, unspent_tx[0]['amount'])
|
assert_equal(receive_amount_2, unspent_tx[0]['amount'])
|
||||||
|
|
||||||
assert_equal(True, unspent_tx[1]['change'])
|
assert_equal(True, unspent_tx[1]['change'])
|
||||||
assert_equal(txid_2, unspent_tx[1]['txid'])
|
assert_equal(txid_2, unspent_tx[1]['txid'])
|
||||||
|
assert_equal('sprout', unspent_tx[1]['type'])
|
||||||
assert_equal(True, unspent_tx[1]['spendable'])
|
assert_equal(True, unspent_tx[1]['spendable'])
|
||||||
assert_equal(sproutzaddr, unspent_tx[1]['address'])
|
assert_equal(sproutzaddr, unspent_tx[1]['address'])
|
||||||
assert_equal(change_amount_2, unspent_tx[1]['amount'])
|
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(False, unspent_tx[0]['change'])
|
||||||
assert_equal(txid_2, unspent_tx[0]['txid'])
|
assert_equal(txid_2, unspent_tx[0]['txid'])
|
||||||
|
assert_equal('sapling', unspent_tx[0]['type'])
|
||||||
assert_equal(True, unspent_tx[0]['spendable'])
|
assert_equal(True, unspent_tx[0]['spendable'])
|
||||||
assert_equal(saplingzaddr, unspent_tx[0]['address'])
|
assert_equal(saplingzaddr, unspent_tx[0]['address'])
|
||||||
assert_equal(receive_amount_2, unspent_tx[0]['amount'])
|
assert_equal(receive_amount_2, unspent_tx[0]['amount'])
|
||||||
|
|
||||||
assert_equal(False, unspent_tx[1]['change'])
|
assert_equal(False, unspent_tx[1]['change'])
|
||||||
assert_equal(txid_3, unspent_tx[1]['txid'])
|
assert_equal(txid_3, unspent_tx[1]['txid'])
|
||||||
|
assert_equal('sapling', unspent_tx[1]['type'])
|
||||||
assert_equal(True, unspent_tx[1]['spendable'])
|
assert_equal(True, unspent_tx[1]['spendable'])
|
||||||
assert_equal(saplingzaddr2, unspent_tx[1]['address'])
|
assert_equal(saplingzaddr2, unspent_tx[1]['address'])
|
||||||
assert_equal(receive_amount_3, unspent_tx[1]['amount'])
|
assert_equal(receive_amount_3, unspent_tx[1]['amount'])
|
||||||
|
|
||||||
assert_equal(True, unspent_tx[2]['change'])
|
assert_equal(True, unspent_tx[2]['change'])
|
||||||
assert_equal(txid_3, unspent_tx[2]['txid'])
|
assert_equal(txid_3, unspent_tx[2]['txid'])
|
||||||
|
assert_equal('sprout', unspent_tx[2]['type'])
|
||||||
assert_equal(True, unspent_tx[2]['spendable'])
|
assert_equal(True, unspent_tx[2]['spendable'])
|
||||||
assert_equal(sproutzaddr, unspent_tx[2]['address'])
|
assert_equal(sproutzaddr, unspent_tx[2]['address'])
|
||||||
assert_equal(change_amount_3, unspent_tx[2]['amount'])
|
assert_equal(change_amount_3, unspent_tx[2]['amount'])
|
||||||
|
|
|
@ -26,6 +26,15 @@ class WalletShieldCoinbaseUANU5(WalletShieldCoinbaseTest):
|
||||||
assert_equal(balances['pools']['sapling']['valueZat'], expected * COIN)
|
assert_equal(balances['pools']['sapling']['valueZat'], expected * COIN)
|
||||||
# assert_equal(balances['pools']['orchard']['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__':
|
if __name__ == '__main__':
|
||||||
print("Test shielding to a unified address with NU5 activated")
|
print("Test shielding to a unified address with NU5 activated")
|
||||||
|
|
|
@ -24,6 +24,15 @@ class WalletShieldCoinbaseUASapling(WalletShieldCoinbaseTest):
|
||||||
assert_equal(balances['pools']['sapling']['valueZat'], expected * COIN)
|
assert_equal(balances['pools']['sapling']['valueZat'], expected * COIN)
|
||||||
assert('orchard' not in balances['pools'])
|
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__':
|
if __name__ == '__main__':
|
||||||
print("Test shielding to a unified address with sapling activated (but not NU5)")
|
print("Test shielding to a unified address with sapling activated (but not NU5)")
|
||||||
|
|
|
@ -129,6 +129,7 @@ class WalletShieldingCoinbaseTest (BitcoinTestFramework):
|
||||||
assert(len(results) == 0)
|
assert(len(results) == 0)
|
||||||
results = self.nodes[0].z_listunspent(0) # set minconf to zero
|
results = self.nodes[0].z_listunspent(0) # set minconf to zero
|
||||||
assert(len(results) == 1)
|
assert(len(results) == 1)
|
||||||
|
assert_equal(results[0]["type"], "sapling")
|
||||||
assert_equal(results[0]["address"], myzaddr)
|
assert_equal(results[0]["address"], myzaddr)
|
||||||
assert_equal(results[0]["amount"], shieldvalue)
|
assert_equal(results[0]["amount"], shieldvalue)
|
||||||
assert_equal(results[0]["confirmations"], 0)
|
assert_equal(results[0]["confirmations"], 0)
|
||||||
|
@ -140,6 +141,7 @@ class WalletShieldingCoinbaseTest (BitcoinTestFramework):
|
||||||
# Verify that z_listunspent returns one note which has been confirmed
|
# Verify that z_listunspent returns one note which has been confirmed
|
||||||
results = self.nodes[0].z_listunspent()
|
results = self.nodes[0].z_listunspent()
|
||||||
assert(len(results) == 1)
|
assert(len(results) == 1)
|
||||||
|
assert_equal(results[0]["type"], "sapling")
|
||||||
assert_equal(results[0]["address"], myzaddr)
|
assert_equal(results[0]["address"], myzaddr)
|
||||||
assert_equal(results[0]["amount"], shieldvalue)
|
assert_equal(results[0]["amount"], shieldvalue)
|
||||||
assert_equal(results[0]["confirmations"], 1)
|
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.
|
# Verify that z_listunspent returns note for watchonly address on node 3.
|
||||||
results = self.nodes[3].z_listunspent(1, 999, True)
|
results = self.nodes[3].z_listunspent(1, 999, True)
|
||||||
assert(len(results) == 1)
|
assert(len(results) == 1)
|
||||||
|
assert_equal(results[0]["type"], "sapling")
|
||||||
assert_equal(results[0]["address"], myzaddr)
|
assert_equal(results[0]["address"], myzaddr)
|
||||||
assert_equal(results[0]["amount"], shieldvalue)
|
assert_equal(results[0]["amount"], shieldvalue)
|
||||||
assert_equal(results[0]["confirmations"], 1)
|
assert_equal(results[0]["confirmations"], 1)
|
||||||
|
|
|
@ -2256,21 +2256,22 @@ UniValue z_listunspent(const UniValue& params, bool fHelp)
|
||||||
"Optionally filter to only include notes sent to specified addresses.\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"
|
"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"
|
"Results are an array of Objects, each of which has:\n"
|
||||||
"{txid, jsindex, jsoutindex, confirmations, address, amount, memo} (Sprout)\n"
|
"{txid, type, jsindex, jsoutindex, confirmations, address, amount, memo} (Sprout)\n"
|
||||||
"{txid, outindex, confirmations, address, amount, memo} (Sapling)\n"
|
"{txid, type, outindex, confirmations, address, amount, memo} (Sapling)\n"
|
||||||
"\nArguments:\n"
|
"\nArguments:\n"
|
||||||
"1. minconf (numeric, optional, default=1) The minimum confirmations to filter\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"
|
"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"
|
"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"
|
" [\n"
|
||||||
" \"address\" (string) zaddr\n"
|
" \"address\" (string) Sprout, Sapling, or Unified address\n"
|
||||||
" ,...\n"
|
" ,...\n"
|
||||||
" ]\n"
|
" ]\n"
|
||||||
"\nResult (output indices for only one pool will be present):\n"
|
"\nResult (output indices for only one pool will be present):\n"
|
||||||
"[ (array of json object)\n"
|
"[ (array of json object)\n"
|
||||||
" {\n"
|
" {\n"
|
||||||
" \"txid\" : \"txid\", (string) the transaction id \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"
|
" \"jsindex\" (sprout) : n, (numeric) the joinsplit index\n"
|
||||||
" \"jsoutindex\" (sprout) : 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"
|
" \"outindex\" (sapling) : n, (numeric) the output index\n"
|
||||||
|
@ -2373,6 +2374,7 @@ UniValue z_listunspent(const UniValue& params, bool fHelp)
|
||||||
for (auto & entry : sproutEntries) {
|
for (auto & entry : sproutEntries) {
|
||||||
UniValue obj(UniValue::VOBJ);
|
UniValue obj(UniValue::VOBJ);
|
||||||
obj.pushKV("txid", entry.jsop.hash.ToString());
|
obj.pushKV("txid", entry.jsop.hash.ToString());
|
||||||
|
obj.pushKV("type", ADDR_TYPE_SPROUT);
|
||||||
obj.pushKV("jsindex", (int)entry.jsop.js );
|
obj.pushKV("jsindex", (int)entry.jsop.js );
|
||||||
obj.pushKV("jsoutindex", (int)entry.jsop.n);
|
obj.pushKV("jsoutindex", (int)entry.jsop.n);
|
||||||
obj.pushKV("confirmations", entry.confirmations);
|
obj.pushKV("confirmations", entry.confirmations);
|
||||||
|
@ -2391,12 +2393,19 @@ UniValue z_listunspent(const UniValue& params, bool fHelp)
|
||||||
for (auto & entry : saplingEntries) {
|
for (auto & entry : saplingEntries) {
|
||||||
UniValue obj(UniValue::VOBJ);
|
UniValue obj(UniValue::VOBJ);
|
||||||
obj.pushKV("txid", entry.op.hash.ToString());
|
obj.pushKV("txid", entry.op.hash.ToString());
|
||||||
|
obj.pushKV("type", ADDR_TYPE_SAPLING);
|
||||||
obj.pushKV("outindex", (int)entry.op.n);
|
obj.pushKV("outindex", (int)entry.op.n);
|
||||||
obj.pushKV("confirmations", entry.confirmations);
|
obj.pushKV("confirmations", entry.confirmations);
|
||||||
bool hasSaplingSpendingKey = pwalletMain->HaveSaplingSpendingKeyForAddress(entry.address);
|
bool hasSaplingSpendingKey = pwalletMain->HaveSaplingSpendingKeyForAddress(entry.address);
|
||||||
obj.pushKV("spendable", hasSaplingSpendingKey);
|
obj.pushKV("spendable", hasSaplingSpendingKey);
|
||||||
// TODO: If we found this entry via a UA, show that instead.
|
obj.pushKV("address", keyIO.EncodePaymentAddress([&]() {
|
||||||
obj.pushKV("address", keyIO.EncodePaymentAddress(entry.address));
|
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("amount", ValueFromAmount(CAmount(entry.note.value()))); // note.value() is equivalent to plaintext.value()
|
||||||
obj.pushKV("memo", HexStr(entry.memo));
|
obj.pushKV("memo", HexStr(entry.memo));
|
||||||
if (hasSaplingSpendingKey) {
|
if (hasSaplingSpendingKey) {
|
||||||
|
@ -4067,13 +4076,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
|
// If the note belongs to a Sapling address that is part of an account in the
|
||||||
// wallet, show the corresponding Unified Address.
|
// wallet, show the corresponding Unified Address.
|
||||||
std::string address;
|
std::string address = keyIO.EncodePaymentAddress([&]() {
|
||||||
const auto ua = pwalletMain->FindUnifiedAddressByReceiver(pa);
|
auto ua = pwalletMain->FindUnifiedAddressByReceiver(pa);
|
||||||
if (ua.has_value()) {
|
if (ua.has_value()) {
|
||||||
address = keyIO.EncodePaymentAddress(ua.value());
|
return libzcash::PaymentAddress{ua.value()};
|
||||||
} else {
|
} else {
|
||||||
address = keyIO.EncodePaymentAddress(pa);
|
return libzcash::PaymentAddress{pa};
|
||||||
}
|
}
|
||||||
|
}());
|
||||||
|
|
||||||
UniValue entry(UniValue::VOBJ);
|
UniValue entry(UniValue::VOBJ);
|
||||||
entry.pushKV("type", ADDR_TYPE_SAPLING);
|
entry.pushKV("type", ADDR_TYPE_SAPLING);
|
||||||
|
@ -4120,13 +4130,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
|
// If the note belongs to a Sapling address that is part of an account in the
|
||||||
// wallet, show the corresponding Unified Address.
|
// wallet, show the corresponding Unified Address.
|
||||||
std::string address;
|
std::string address = keyIO.EncodePaymentAddress([&]() {
|
||||||
const auto ua = pwalletMain->FindUnifiedAddressByReceiver(pa);
|
auto ua = pwalletMain->FindUnifiedAddressByReceiver(pa);
|
||||||
if (ua.has_value()) {
|
if (ua.has_value()) {
|
||||||
address = keyIO.EncodePaymentAddress(ua.value());
|
return libzcash::PaymentAddress{ua.value()};
|
||||||
} else {
|
} else {
|
||||||
address = keyIO.EncodePaymentAddress(pa);
|
return libzcash::PaymentAddress{pa};
|
||||||
}
|
}
|
||||||
|
}());
|
||||||
|
|
||||||
UniValue entry(UniValue::VOBJ);
|
UniValue entry(UniValue::VOBJ);
|
||||||
entry.pushKV("type", ADDR_TYPE_SAPLING);
|
entry.pushKV("type", ADDR_TYPE_SAPLING);
|
||||||
|
|
Loading…
Reference in New Issue