From afa9b912dfcd4b24caeb8135533c86d50e3bc598 Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Sat, 11 Apr 2026 00:01:55 +0700 Subject: [PATCH 1/6] fix: RPC doc for listaddressbalances --- src/wallet/rpc/wallet.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/wallet/rpc/wallet.cpp b/src/wallet/rpc/wallet.cpp index c48a0d41b0f5..4f84196840db 100644 --- a/src/wallet/rpc/wallet.cpp +++ b/src/wallet/rpc/wallet.cpp @@ -50,10 +50,10 @@ static RPCHelpMan listaddressbalances() {"minamount", RPCArg::Type::NUM, RPCArg::Default{0}, "Minimum balance in " + CURRENCY_UNIT + " an address should have to be shown in the list"}, }, RPCResult{ - RPCResult::Type::ARR, "", "", - { - {RPCResult::Type::STR_AMOUNT, "amount", "The Dash address and the amount in " + CURRENCY_UNIT}, - } + RPCResult::Type::OBJ_DYN, "addresses", "Balances of addresses", + { + {RPCResult::Type::STR_AMOUNT, "address", "the amount in " + CURRENCY_UNIT}, + } }, RPCExamples{ HelpExampleCli("listaddressbalances", "") From f6c66c807da329066d0d8c0ae94e743b020c854c Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Sat, 11 Apr 2026 00:22:04 +0700 Subject: [PATCH 2/6] test: add exception for importelectrumwallet RPC coverage --- test/functional/test_runner.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index 90c8fbe8e49e..3dcd7035142c 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -926,6 +926,8 @@ def _get_uncovered_rpc_commands(self): covered_cmds = set({'generate'}) # TODO: implement functional tests for voteraw covered_cmds.add('voteraw') + # TODO: implement functional tests for importelectrumwallet + covered_cmds.add('importelectrumwallet') # TODO: implement functional tests for getmerkleblocks covered_cmds.add('getmerkleblocks') From 4b1a3353ca580d6f677de661f999cf87c7bad929 Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Sat, 11 Apr 2026 00:02:36 +0700 Subject: [PATCH 3/6] test: add coverage for RPC listaddressbalances --- test/functional/wallet_balance.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/functional/wallet_balance.py b/test/functional/wallet_balance.py index b039f147aa3b..5454a43406c9 100755 --- a/test/functional/wallet_balance.py +++ b/test/functional/wallet_balance.py @@ -109,6 +109,15 @@ def run_test(self): assert_equal(self.nodes[0].getbalance("*", 1, True), 500) assert_equal(self.nodes[1].getbalance(minconf=0, include_watchonly=True), 500) + self.log.info("Test listaddressbalances") + address_balances = {} + address_balances['yYdShjQSptFKitYLksFEUSwHe4hnbar5rf'] = Decimal('500.00000000') + if not self.options.descriptors: + address_balances['yVg3NBUHNEhgDceqwVUjsZHreC5PBHnUo9'] = Decimal('500.00000000') + assert_equal(address_balances, self.nodes[0].listaddressbalances()) + assert_equal(address_balances, self.nodes[0].listaddressbalances(500)) + assert_equal({}, self.nodes[0].listaddressbalances(501)) + # Send 490 BTC from 0 to 1 and 960 BTC from 1 to 0. txs = create_transactions(self.nodes[0], self.nodes[1].getnewaddress(), 490 , [Decimal('0.01')]) self.nodes[0].sendrawtransaction(txs[0]['hex']) From 2b3cdfbe5f34bca4bba4e088cec2596216059045 Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Sat, 11 Apr 2026 00:08:56 +0700 Subject: [PATCH 4/6] refactor: move listaddressbalances to wallet/rpc/coins.cpp where it belongs to --- src/wallet/rpc/coins.cpp | 45 ++++++++++++++++++++++++++++++++++++++ src/wallet/rpc/wallet.cpp | 46 +-------------------------------------- 2 files changed, 46 insertions(+), 45 deletions(-) diff --git a/src/wallet/rpc/coins.cpp b/src/wallet/rpc/coins.cpp index 51fd86088526..7f7f391e5ce5 100644 --- a/src/wallet/rpc/coins.cpp +++ b/src/wallet/rpc/coins.cpp @@ -162,6 +162,51 @@ RPCHelpMan getreceivedbylabel() }; } +RPCHelpMan listaddressbalances() +{ + return RPCHelpMan{"listaddressbalances", + "\nLists addresses of this wallet and their balances\n", + { + {"minamount", RPCArg::Type::NUM, RPCArg::Default{0}, "Minimum balance in " + CURRENCY_UNIT + " an address should have to be shown in the list"}, + }, + RPCResult{ + RPCResult::Type::OBJ_DYN, "addresses", "Balances of addresses", + { + {RPCResult::Type::STR_AMOUNT, "address", "the amount in " + CURRENCY_UNIT}, + } + }, + RPCExamples{ + HelpExampleCli("listaddressbalances", "") + + HelpExampleCli("listaddressbalances", "10") + + HelpExampleRpc("listaddressbalances", "") + + HelpExampleRpc("listaddressbalances", "10") + }, + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ + const std::shared_ptr pwallet = GetWalletForJSONRPCRequest(request); + if (!pwallet) return UniValue::VNULL; + + LOCK(pwallet->cs_wallet); + + CAmount nMinAmount = 0; + if (!request.params[0].isNull()) + nMinAmount = AmountFromValue(request.params[0]); + + if (nMinAmount < 0) + throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount"); + + UniValue jsonBalances(UniValue::VOBJ); + std::map balances = GetAddressBalances(*pwallet); + for (auto& balance : balances) + if (balance.second >= nMinAmount) + jsonBalances.pushKV(EncodeDestination(balance.first), ValueFromAmount(balance.second)); + + return jsonBalances; +}, + }; +} + + RPCHelpMan getbalance() { return RPCHelpMan{"getbalance", diff --git a/src/wallet/rpc/wallet.cpp b/src/wallet/rpc/wallet.cpp index 4f84196840db..a90712a3ac1e 100644 --- a/src/wallet/rpc/wallet.cpp +++ b/src/wallet/rpc/wallet.cpp @@ -42,51 +42,6 @@ bool HaveKey(const SigningProvider& wallet, const CKey& key) return wallet.HaveKey(key.GetPubKey().GetID()) || wallet.HaveKey(key2.GetPubKey().GetID()); } -static RPCHelpMan listaddressbalances() -{ - return RPCHelpMan{"listaddressbalances", - "\nLists addresses of this wallet and their balances\n", - { - {"minamount", RPCArg::Type::NUM, RPCArg::Default{0}, "Minimum balance in " + CURRENCY_UNIT + " an address should have to be shown in the list"}, - }, - RPCResult{ - RPCResult::Type::OBJ_DYN, "addresses", "Balances of addresses", - { - {RPCResult::Type::STR_AMOUNT, "address", "the amount in " + CURRENCY_UNIT}, - } - }, - RPCExamples{ - HelpExampleCli("listaddressbalances", "") - + HelpExampleCli("listaddressbalances", "10") - + HelpExampleRpc("listaddressbalances", "") - + HelpExampleRpc("listaddressbalances", "10") - }, - [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue -{ - const std::shared_ptr pwallet = GetWalletForJSONRPCRequest(request); - if (!pwallet) return UniValue::VNULL; - - LOCK(pwallet->cs_wallet); - - CAmount nMinAmount = 0; - if (!request.params[0].isNull()) - nMinAmount = AmountFromValue(request.params[0]); - - if (nMinAmount < 0) - throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount"); - - UniValue jsonBalances(UniValue::VOBJ); - std::map balances = GetAddressBalances(*pwallet); - for (auto& balance : balances) - if (balance.second >= nMinAmount) - jsonBalances.pushKV(EncodeDestination(balance.first), ValueFromAmount(balance.second)); - - return jsonBalances; -}, - }; -} - - static RPCHelpMan setcoinjoinrounds() { return RPCHelpMan{"setcoinjoinrounds", @@ -1138,6 +1093,7 @@ RPCHelpMan importelectrumwallet(); // coins RPCHelpMan getreceivedbyaddress(); RPCHelpMan getreceivedbylabel(); +RPCHelpMan listaddressbalances(); RPCHelpMan getbalance(); RPCHelpMan getunconfirmedbalance(); RPCHelpMan lockunspent(); From ff4302f89b66f4d9f580fe4007c017a7307ba702 Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Mon, 28 Jul 2025 10:53:07 +0100 Subject: [PATCH 5/6] Merge bitcoin/bitcoin#33064: test: fix RPC coverage check 8aed477c3322212a636ab69d4923f89e2d9a63a2 test: fix RPC coverage check (Brandon Odiwuor) 2630b64f8100b9a6652c99d5466b73a666d8cfca test: add abortrescan RPC test (Brandon Odiwuor) Pull request description: This is #27593 cleaned up / rebased, now that the legacy wallet has been dropped. Closes #27593. ACKs for top commit: maflcko: lgtm ACK 8aed477c3322212a636ab69d4923f89e2d9a63a2 cedwies: ACK 8aed477 Tree-SHA512: 14a28b1ef0c1f63236d04c2ff6c11adddc40642e4a23d30398e8a03fc47f911465af91affc6e66ee2d548515ef4f65fb1cb5d69985c5a771a17b1c9c009f48ad Co-authored-by: merge-script --- test/functional/create_cache.py | 1 + test/functional/test_framework/test_framework.py | 2 +- test/functional/wallet_transactiontime_rescan.py | 4 ++++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/test/functional/create_cache.py b/test/functional/create_cache.py index 1108a8e3544b..2179bb7815a7 100755 --- a/test/functional/create_cache.py +++ b/test/functional/create_cache.py @@ -16,6 +16,7 @@ class CreateCache(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 0 + self.uses_wallet = True def setup_network(self): pass diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py index de0e4ca70501..18ab13afed04 100755 --- a/test/functional/test_framework/test_framework.py +++ b/test/functional/test_framework/test_framework.py @@ -955,7 +955,7 @@ def _initialize_chain(self): cache_node_dir, chain=self.chain, extra_conf=["bind=127.0.0.1"], - extra_args=['-disablewallet', f"-mocktime={TIME_GENESIS_BLOCK}"], + extra_args=[f"-mocktime={TIME_GENESIS_BLOCK}"], extra_args_from_options=self.extra_args_from_options, rpchost=None, timewait=self.rpc_timeout, diff --git a/test/functional/wallet_transactiontime_rescan.py b/test/functional/wallet_transactiontime_rescan.py index 268e623cd90d..e7c57fb774ea 100755 --- a/test/functional/wallet_transactiontime_rescan.py +++ b/test/functional/wallet_transactiontime_rescan.py @@ -136,6 +136,10 @@ def run_test(self): restorewo_wallet.importaddress(wo2, rescan=False) restorewo_wallet.importaddress(wo3, rescan=False) + self.log.info('Testing abortrescan when no rescan is in progress') + assert_equal(restorewo_wallet.getwalletinfo()['scanning'], False) + assert_equal(restorewo_wallet.abortrescan(), False) + # check user has 0 balance and no transactions assert_equal(restorewo_wallet.getbalance(), 0) assert_equal(len(restorewo_wallet.listtransactions()), 0) From 53cd79259174f77af0305d56eb25f108136508a0 Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Fri, 10 Apr 2026 16:54:07 +0700 Subject: [PATCH 6/6] fix: pass uses_wallet correctly to fix coverage bug --- test/functional/test_framework/test_framework.py | 3 +++ test/functional/test_framework/test_node.py | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py index 18ab13afed04..45cdf8c9e142 100755 --- a/test/functional/test_framework/test_framework.py +++ b/test/functional/test_framework/test_framework.py @@ -144,6 +144,7 @@ def __init__(self): self._requires_wallet = False # Disable ThreadOpenConnections by default, so that adding entries to # addrman will not result in automatic connections to them. + self.uses_wallet = False self.disable_autoconnect = True self.set_test_params() assert self.wallet_names is None or len(self.wallet_names) <= self.num_nodes @@ -577,6 +578,7 @@ def get_bin_from_version(version, bin_name, bin_default): use_valgrind=self.options.valgrind, descriptors=self.options.descriptors, v2transport=self.options.v2transport, + uses_wallet=self.uses_wallet, ) self.nodes.append(test_node_i) if not test_node_i.version_is_at_least(160000): @@ -966,6 +968,7 @@ def _initialize_chain(self): coverage_dir=None, cwd=self.options.tmpdir, descriptors=self.options.descriptors, + uses_wallet=self.uses_wallet, )) self.start_node(CACHE_NODE_ID) cache_node = self.nodes[CACHE_NODE_ID] diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py index 52f785c14ce5..1d4c2c817255 100755 --- a/test/functional/test_framework/test_node.py +++ b/test/functional/test_framework/test_node.py @@ -69,7 +69,7 @@ class TestNode(): To make things easier for the test writer, any unrecognised messages will be dispatched to the RPC connection.""" - def __init__(self, i, datadir, extra_args_from_options, *, chain, rpchost, timewait, timeout_factor, bitcoind, bitcoin_cli, mocktime, coverage_dir, cwd, extra_conf=None, extra_args=None, use_cli=False, start_perf=False, use_valgrind=False, version=None, descriptors=False, v2transport=False): + def __init__(self, i, datadir, extra_args_from_options, *, chain, rpchost, timewait, timeout_factor, bitcoind, bitcoin_cli, mocktime, coverage_dir, cwd, extra_conf=None, extra_args=None, use_cli=False, start_perf=False, use_valgrind=False, version=None, descriptors=False, v2transport=False, uses_wallet=False): """ Kwargs: start_perf (bool): If True, begin profiling the node with `perf` as soon as @@ -114,7 +114,7 @@ def __init__(self, i, datadir, extra_args_from_options, *, chain, rpchost, timew if self.mocktime != 0: self.args.append(f"-mocktime={mocktime}") - if self.descriptors is None: + if uses_wallet is not None and not uses_wallet and self.descriptors is None: self.args.append("-disablewallet") # Use valgrind, expect for previous release binaries