diff --git a/qa/rpc-tests/wallet_accounts.py b/qa/rpc-tests/wallet_accounts.py index a8f41b0c9..4edc02618 100755 --- a/qa/rpc-tests/wallet_accounts.py +++ b/qa/rpc-tests/wallet_accounts.py @@ -35,14 +35,19 @@ class WalletAccountsTest(BitcoinTestFramework): # Remember that empty pools are omitted from the output. def _check_balance_for_rpc(self, rpcmethod, node, account, expected, minconf): rpc = getattr(self.nodes[node], rpcmethod) - actual = rpc(account) if minconf is None else rpc(account, minconf) + actual = rpc(account, minconf) assert_equal(set(expected), set(actual['pools'])) + total_balance = 0 for pool in expected: assert_equal(expected[pool] * COIN, actual['pools'][pool]['valueZat']) - assert_equal(actual['minimum_confirmations'], 1 if minconf is None else minconf) + total_balance += expected[pool] + assert_equal(actual['minimum_confirmations'], minconf) + return total_balance - def check_balance(self, node, account, address, expected, minconf=None): - self._check_balance_for_rpc('z_getbalanceforaccount', node, account, expected, minconf) + def check_balance(self, node, account, address, expected, minconf=1): + acct_balance = self._check_balance_for_rpc('z_getbalanceforaccount', node, account, expected, minconf) + z_getbalance = self.nodes[node].z_getbalance(address, minconf) + assert_equal(acct_balance, z_getbalance) fvk = self.nodes[node].z_exportviewingkey(address) self._check_balance_for_rpc('z_getbalanceforviewingkey', node, fvk, expected, minconf) diff --git a/qa/rpc-tests/wallet_shieldcoinbase_ua_nu5.py b/qa/rpc-tests/wallet_shieldcoinbase_ua_nu5.py index 81543ef62..30a7f22fb 100755 --- a/qa/rpc-tests/wallet_shieldcoinbase_ua_nu5.py +++ b/qa/rpc-tests/wallet_shieldcoinbase_ua_nu5.py @@ -23,7 +23,8 @@ class WalletShieldCoinbaseUANU5(WalletShieldCoinbaseTest): assert('transparent' not in balances['pools']) assert('sprout' not in balances['pools']) # assert('sapling' not in balances['pools']) - assert_equal(balances['pools']['sapling']['valueZat'], expected * COIN) + sapling_balance = balances['pools']['sapling']['valueZat'] + assert_equal(sapling_balance, expected * COIN) # assert_equal(balances['pools']['orchard']['valueZat'], expected * COIN) # While we're at it, check that z_listunspent only shows outputs with @@ -35,6 +36,8 @@ class WalletShieldCoinbaseUANU5(WalletShieldCoinbaseTest): [{'type': x['type'], 'address': x['address']} for x in unspent], ) + total_balance = node.z_getbalance(self.addr) * COIN + assert_equal(total_balance, sapling_balance) if __name__ == '__main__': print("Test shielding to a unified address with NU5 activated") diff --git a/qa/rpc-tests/wallet_shieldcoinbase_ua_sapling.py b/qa/rpc-tests/wallet_shieldcoinbase_ua_sapling.py index 6ef2baea6..f07ef656e 100755 --- a/qa/rpc-tests/wallet_shieldcoinbase_ua_sapling.py +++ b/qa/rpc-tests/wallet_shieldcoinbase_ua_sapling.py @@ -21,7 +21,8 @@ class WalletShieldCoinbaseUASapling(WalletShieldCoinbaseTest): balances = node.z_getbalanceforaccount(self.account) assert('transparent' not in balances['pools']) assert('sprout' not in balances['pools']) - assert_equal(balances['pools']['sapling']['valueZat'], expected * COIN) + sapling_balance = balances['pools']['sapling']['valueZat'] + assert_equal(sapling_balance, expected * COIN) assert('orchard' not in balances['pools']) # While we're at it, check that z_listunspent only shows outputs with @@ -33,6 +34,8 @@ class WalletShieldCoinbaseUASapling(WalletShieldCoinbaseTest): [{'type': x['type'], 'address': x['address']} for x in unspent], ) + total_balance = node.z_getbalance(self.addr) * COIN + assert_equal(total_balance, sapling_balance) if __name__ == '__main__': print("Test shielding to a unified address with sapling activated (but not NU5)") diff --git a/qa/rpc-tests/wallet_z_sendmany.py b/qa/rpc-tests/wallet_z_sendmany.py index 2ba397ec9..48df09cb0 100755 --- a/qa/rpc-tests/wallet_z_sendmany.py +++ b/qa/rpc-tests/wallet_z_sendmany.py @@ -27,14 +27,19 @@ class WalletZSendmanyTest(BitcoinTestFramework): # Remember that empty pools are omitted from the output. def _check_balance_for_rpc(self, rpcmethod, node, account, expected, minconf): rpc = getattr(self.nodes[node], rpcmethod) - actual = rpc(account) if minconf is None else rpc(account, minconf) + actual = rpc(account, minconf) assert_equal(set(expected), set(actual['pools'])) + total_balance = 0 for pool in expected: assert_equal(expected[pool] * COIN, actual['pools'][pool]['valueZat']) - assert_equal(actual['minimum_confirmations'], 1 if minconf is None else minconf) + total_balance += expected[pool] + assert_equal(actual['minimum_confirmations'], minconf) + return total_balance - def check_balance(self, node, account, address, expected, minconf=None): - self._check_balance_for_rpc('z_getbalanceforaccount', node, account, expected, minconf) + def check_balance(self, node, account, address, expected, minconf=1): + acct_balance = self._check_balance_for_rpc('z_getbalanceforaccount', node, account, expected, minconf) + z_getbalance = self.nodes[node].z_getbalance(address, minconf) + assert_equal(acct_balance, z_getbalance) fvk = self.nodes[node].z_exportviewingkey(address) self._check_balance_for_rpc('z_getbalanceforviewingkey', node, fvk, expected, minconf) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 3a1cc1e29..4be01f570 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -3649,11 +3649,10 @@ UniValue z_getbalance(const UniValue& params, bool fHelp) if (fHelp || params.size() == 0 || params.size() > 3) throw runtime_error( "z_getbalance \"address\" ( minconf inZat )\n" - "\nDEPRECATED\n" + "\nDEPRECATED; please use z_getbalanceforviewingkey instead.`\n" "\nReturns the balance of a taddr or zaddr belonging to the node's wallet.\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." - "\nThe argument address may not be a Unified Address; please use z_getbalanceforviewingkey instead.\n" "\nArguments:\n" "1. \"address\" (string) The selected address. It may be a transparent or shielded address.\n" "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n" @@ -3706,9 +3705,23 @@ UniValue z_getbalance(const UniValue& params, bool fHelp) nBalance = getBalanceZaddr(addr, nMinDepth, INT_MAX, false); }, [&](const libzcash::UnifiedAddress& addr) { - throw JSONRPCError( - RPC_INVALID_ADDRESS_OR_KEY, - "Unified addresses are not yet supported for z_getbalance."); + auto selector = pwalletMain->ZTXOSelectorForAddress(addr, true); + if (!selector.has_value()) { + throw JSONRPCError( + RPC_INVALID_ADDRESS_OR_KEY, + "Unified address does not correspond to an account in the wallet"); + } + auto spendableInputs = pwalletMain->FindSpendableInputs(selector.value(), true, nMinDepth); + + for (const auto& t : spendableInputs.utxos) { + nBalance += t.Value(); + } + for (const auto& t : spendableInputs.saplingNoteEntries) { + nBalance += t.note.value(); + } + for (const auto& t : spendableInputs.orchardNoteMetadata) { + nBalance += t.GetNoteValue(); + } }, }, pa.value()); diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index a84895780..ee9b3eeee 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -6341,6 +6341,9 @@ NoteFilter NoteFilter::ForPaymentAddresses(const std::vector