Skip to content

Commit cac38cd

Browse files
author
MarcoFalke
committed
Merge bitcoin/bitcoin#21832: cli: Improve -getinfo return format
a37e29d cli: Implement human readable -getinfo. (Klement Tan) Pull request description: # Overview **Description** This PR changes the return format of `-getinfo` **Rationale** - make `-getinfo` more user-friendly - uses less vertical screen space. Fixes: Issue 17314(Not linking issue to prevent it from closing) > Alternative, more human-friendly, format besides JSON? Colors, progress bars ### Return Format ```bash // Data from getblockchaininfo Chain: [getblockchaininfo.chain] Blocks: [getblockchaininfo.blocks] Headers: [getblockchaininfo.headers] Verification progress: [getblockchaininfo.verificationprogress] Difficulty: [getblockchaininfo.difficulty] # Data from getnetworkinfo Network: in [getnetworkinfo.connections_in], out [getnetworkinfo.connections_out], total [getnetworkinfo.connections] Version: [getnetworkinfo.version] Time offset (s): [getnetworkinfo.timeoffset] Proxy: [getnetworkinfo.proxy] // "N/A" if no proxy Min tx relay fee rate (BTC/kvB): [getnetworkinfo.relayfee] # Data from getwalletinfo. Will only be present when a single wallet is loaded Wallet: [getnetworkinfo.walletname] // "" if walletname is empty(default wallet) Keypool size: [getnetworkinfo.keypoolsize] Unlocked until: [getnetworkinfo.unlocked_until] Transaction fee rate (-paytxfee) (BTC/kvB): [getnetworkinfo.paytxfee] # Data from getbalances. Will only be present when a single wallet is loaded Balance: [getbalances.mine.trusted] # Data from listwallets then getbalances for each wallet. Will only be present for multiple wallets loaded Balances [getbalances.mine.trusted] [listwallets[i]] // Right justify on balance Warnings: [getnetworkinfo.warnings] ``` #### Coloring The following lines would be colored to better show the differences between the various `-getinfo` components. However, this will not apply for `WIN32`(ANSI code not supported) and users that connect the `stdout` to a non-terminal process. - `Chain: ...`: BLUE(`\x1B[34m`) - `Network: ...`: GREEN(`\x1B[32m`) - `Wallet: ...`: MAGENTA(`\x1B[35m`) - `Balance: ...` CYAN(`\x1B[36m`) - `Balances: ...` CYAN(`\x1B[36m`) - `Warnings: ...` Yellow(`\x1B[33m`) ### Screenshots *No wallet loaded:* ![image](https://user-images.githubusercontent.com/49265907/121794631-94b62080-cc3c-11eb-8627-d0d1c25f0878.png) *Single wallet loaded* ![image](https://user-images.githubusercontent.com/49265907/121794619-6df7ea00-cc3c-11eb-8420-d0c18236b188.png) *Multi wallet loaded* ![image](https://user-images.githubusercontent.com/49265907/121794626-810aba00-cc3c-11eb-8cd7-c15ede1918ac.png) # Reviewing Notes ## Testing Scenarios **1. No wallet loaded** - When there no wallets are loaded(Unload wallet with `./src/bitcoin-cli unloadwallet "YOUR_WALLETNAME"` - Test with `./src/bitcoin-cli -getinfo`. - Should only display `chain` and `network` segment **2. Single wallet loaded** - When only a single wallet loaded or `-rpcwallet` is set(Load wallet with `./src/bitcoin-cli loadwallet "YOUR_WALLETNAME"`) - Test with `./src/bitcoin-cli -rpcwallet="YOUR_WALLETNAME" -getinfo`(Load wallet with `./src/bitcoin-cli loadwallet "YOUR_WALLETNAME"`) - Should only display `chain`, `network`, `wallet` and `balance` segment **3. Multiple wallet loaded** - When there are multiple wallets loaded(Load wallet with `./src/bitcoin-cli loadwallet "YOUR_WALLETNAME"`) - Test with `./src/bitcoin-cli -getinfo` - Should only display `chain`, `network` and `balances` segment ## Implementation **Current Flow** 1. `GetinfoRequestHandler` is instantiated 2. `ConnectAndCallRPC` is called with `GetinfoRequestHandler`. It returns `UniValue::VOBJ result` 3. If `-rpcwallet` wallet is not set, `GetWalletBalances` is called with a pointer to `result` as a parameter. It adds the balances for all the wallets to `result` **New Flow** 1. `GetinfoRequestHandler` is instantiated 2. `ConnectAndCallRPC` is called with `GetinfoRequestHandler`. It returns `UniValue::VOBJ result` 3. If `-rpcwallet` wallet is not set, `GetWalletBalances` is called with a pointer to `result` as a parameter. It adds the balances for all the wallets to `result` 4. **New** `ParseGetInfoResult` is called with `result` as parameter. It converts results type from `UniValue::VOBJ` to `UniValue::VSTR` according to the format stated above. ACKs for top commit: theStack: re-ACK a37e29d Tree-SHA512: 5e90606a397abfc4e5921f6db70a0a4888cbebba9da9b70cfe72d593caf669fd090de3e58eecf1cb5c20d5f448ad278999165d32d01667037d09bd352d23ac5d
2 parents 1c046bb + a37e29d commit cac38cd

File tree

3 files changed

+211
-45
lines changed

3 files changed

+211
-45
lines changed

doc/release-notes.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ Updated settings
7575
Tools and Utilities
7676
-------------------
7777

78+
- Update `-getinfo` to return data in a user-friendly format that also reduces vertical space. (#21832)
79+
7880
Wallet
7981
------
8082

src/bitcoin-cli.cpp

Lines changed: 111 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
#include <chainparamsbase.h>
1111
#include <clientversion.h>
12+
#include <policy/feerate.h>
1213
#include <rpc/client.h>
1314
#include <rpc/mining.h>
1415
#include <rpc/protocol.h>
@@ -28,6 +29,10 @@
2829
#include <string>
2930
#include <tuple>
3031

32+
#ifndef WIN32
33+
#include <unistd.h>
34+
#endif
35+
3136
#include <event2/buffer.h>
3237
#include <event2/keyvalq_struct.h>
3338
#include <support/events.h>
@@ -48,6 +53,9 @@ static constexpr int8_t UNKNOWN_NETWORK{-1};
4853
/** Default number of blocks to generate for RPC generatetoaddress. */
4954
static const std::string DEFAULT_NBLOCKS = "1";
5055

56+
/** Default -color setting. */
57+
static const std::string DEFAULT_COLOR_SETTING{"auto"};
58+
5159
static void SetupCliArgs(ArgsManager& argsman)
5260
{
5361
SetupHelpOptions(argsman);
@@ -66,6 +74,7 @@ static void SetupCliArgs(ArgsManager& argsman)
6674
argsman.AddArg("-netinfo", "Get network peer connection information from the remote server. An optional integer argument from 0 to 4 can be passed for different peers listings (default: 0). Pass \"help\" for detailed help documentation.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
6775

6876
SetupChainParamsBaseOptions(argsman);
77+
argsman.AddArg("-color=<when>", strprintf("Color setting for CLI output (default: %s). Valid values: always, auto (add color codes when standard output is connected to a terminal and OS is not WIN32), never.", DEFAULT_COLOR_SETTING), ArgsManager::ALLOW_STRING, OptionsCategory::OPTIONS);
6978
argsman.AddArg("-named", strprintf("Pass named instead of positional arguments (default: %s)", DEFAULT_NAMED), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
7079
argsman.AddArg("-rpcclienttimeout=<n>", strprintf("Timeout in seconds during HTTP requests, or 0 for no timeout. (default: %d)", DEFAULT_HTTP_CLIENT_TIMEOUT), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
7180
argsman.AddArg("-rpcconnect=<ip>", strprintf("Send commands to node running on <ip> (default: %s)", DEFAULT_RPCCONNECT), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
@@ -338,7 +347,9 @@ class GetinfoRequestHandler: public BaseRequestHandler
338347
result.pushKV("difficulty", batch[ID_BLOCKCHAININFO]["result"]["difficulty"]);
339348
result.pushKV("chain", UniValue(batch[ID_BLOCKCHAININFO]["result"]["chain"]));
340349
if (!batch[ID_WALLETINFO]["result"].isNull()) {
350+
result.pushKV("has_wallet", true);
341351
result.pushKV("keypoolsize", batch[ID_WALLETINFO]["result"]["keypoolsize"]);
352+
result.pushKV("walletname", batch[ID_WALLETINFO]["result"]["walletname"]);
342353
if (!batch[ID_WALLETINFO]["result"]["unlocked_until"].isNull()) {
343354
result.pushKV("unlocked_until", batch[ID_WALLETINFO]["result"]["unlocked_until"]);
344355
}
@@ -873,6 +884,100 @@ static void GetWalletBalances(UniValue& result)
873884
result.pushKV("balances", balances);
874885
}
875886

887+
/**
888+
* ParseGetInfoResult takes in -getinfo result in UniValue object and parses it
889+
* into a user friendly UniValue string to be printed on the console.
890+
* @param[out] result Reference to UniValue result containing the -getinfo output.
891+
*/
892+
static void ParseGetInfoResult(UniValue& result)
893+
{
894+
if (!find_value(result, "error").isNull()) return;
895+
896+
std::string RESET, GREEN, BLUE, YELLOW, MAGENTA, CYAN;
897+
bool should_colorize = false;
898+
899+
#ifndef WIN32
900+
if (isatty(fileno(stdout))) {
901+
// By default, only print colored text if OS is not WIN32 and stdout is connected to a terminal.
902+
should_colorize = true;
903+
}
904+
#endif
905+
906+
if (gArgs.IsArgSet("-color")) {
907+
const std::string color{gArgs.GetArg("-color", DEFAULT_COLOR_SETTING)};
908+
if (color == "always") {
909+
should_colorize = true;
910+
} else if (color == "never") {
911+
should_colorize = false;
912+
} else if (color != "auto") {
913+
throw std::runtime_error("Invalid value for -color option. Valid values: always, auto, never.");
914+
}
915+
}
916+
917+
if (should_colorize) {
918+
RESET = "\x1B[0m";
919+
GREEN = "\x1B[32m";
920+
BLUE = "\x1B[34m";
921+
YELLOW = "\x1B[33m";
922+
MAGENTA = "\x1B[35m";
923+
CYAN = "\x1B[36m";
924+
}
925+
926+
std::string result_string = strprintf("%sChain: %s%s\n", BLUE, result["chain"].getValStr(), RESET);
927+
result_string += strprintf("Blocks: %s\n", result["blocks"].getValStr());
928+
result_string += strprintf("Headers: %s\n", result["headers"].getValStr());
929+
result_string += strprintf("Verification progress: %.4f%%\n", result["verificationprogress"].get_real() * 100);
930+
result_string += strprintf("Difficulty: %s\n\n", result["difficulty"].getValStr());
931+
932+
result_string += strprintf(
933+
"%sNetwork: in %s, out %s, total %s%s\n",
934+
GREEN,
935+
result["connections"]["in"].getValStr(),
936+
result["connections"]["out"].getValStr(),
937+
result["connections"]["total"].getValStr(),
938+
RESET);
939+
result_string += strprintf("Version: %s\n", result["version"].getValStr());
940+
result_string += strprintf("Time offset (s): %s\n", result["timeoffset"].getValStr());
941+
const std::string proxy = result["proxy"].getValStr();
942+
result_string += strprintf("Proxy: %s\n", proxy.empty() ? "N/A" : proxy);
943+
result_string += strprintf("Min tx relay fee rate (%s/kvB): %s\n\n", CURRENCY_UNIT, result["relayfee"].getValStr());
944+
945+
if (!result["has_wallet"].isNull()) {
946+
const std::string walletname = result["walletname"].getValStr();
947+
result_string += strprintf("%sWallet: %s%s\n", MAGENTA, walletname.empty() ? "\"\"" : walletname, RESET);
948+
949+
result_string += strprintf("Keypool size: %s\n", result["keypoolsize"].getValStr());
950+
if (!result["unlocked_until"].isNull()) {
951+
result_string += strprintf("Unlocked until: %s\n", result["unlocked_until"].getValStr());
952+
}
953+
result_string += strprintf("Transaction fee rate (-paytxfee) (%s/kvB): %s\n\n", CURRENCY_UNIT, result["paytxfee"].getValStr());
954+
}
955+
if (!result["balance"].isNull()) {
956+
result_string += strprintf("%sBalance:%s %s\n\n", CYAN, RESET, result["balance"].getValStr());
957+
}
958+
959+
if (!result["balances"].isNull()) {
960+
result_string += strprintf("%sBalances%s\n", CYAN, RESET);
961+
962+
size_t max_balance_length{10};
963+
964+
for (const std::string& wallet : result["balances"].getKeys()) {
965+
max_balance_length = std::max(result["balances"][wallet].getValStr().length(), max_balance_length);
966+
}
967+
968+
for (const std::string& wallet : result["balances"].getKeys()) {
969+
result_string += strprintf("%*s %s\n",
970+
max_balance_length,
971+
result["balances"][wallet].getValStr(),
972+
wallet.empty() ? "\"\"" : wallet);
973+
}
974+
result_string += "\n";
975+
}
976+
977+
result_string += strprintf("%sWarnings:%s %s", YELLOW, RESET, result["warnings"].getValStr());
978+
result.setStr(result_string);
979+
}
980+
876981
/**
877982
* Call RPC getnewaddress.
878983
* @returns getnewaddress response as a UniValue object.
@@ -994,9 +1099,13 @@ static int CommandLineRPC(int argc, char *argv[])
9941099
UniValue result = find_value(reply, "result");
9951100
const UniValue& error = find_value(reply, "error");
9961101
if (error.isNull()) {
997-
if (gArgs.IsArgSet("-getinfo") && !gArgs.IsArgSet("-rpcwallet")) {
998-
GetWalletBalances(result); // fetch multiwallet balances and append to result
1102+
if (gArgs.GetBoolArg("-getinfo", false)) {
1103+
if (!gArgs.IsArgSet("-rpcwallet")) {
1104+
GetWalletBalances(result); // fetch multiwallet balances and append to result
1105+
}
1106+
ParseGetInfoResult(result);
9991107
}
1108+
10001109
ParseResult(result, strPrint);
10011110
} else {
10021111
ParseError(error, strPrint, nRet);

test/functional/interface_bitcoin_cli.py

Lines changed: 98 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"""Test bitcoin-cli"""
66

77
from decimal import Decimal
8+
import re
89

910
from test_framework.blocktools import COINBASE_MATURITY
1011
from test_framework.test_framework import BitcoinTestFramework
@@ -29,6 +30,41 @@
2930
WALLET_NOT_LOADED = 'Requested wallet does not exist or is not loaded'
3031
WALLET_NOT_SPECIFIED = 'Wallet file not specified'
3132

33+
34+
def cli_get_info_string_to_dict(cli_get_info_string):
35+
"""Helper method to convert human-readable -getinfo into a dictionary"""
36+
cli_get_info = {}
37+
lines = cli_get_info_string.splitlines()
38+
line_idx = 0
39+
ansi_escape = re.compile(r'(\x9B|\x1B\[)[0-?]*[ -\/]*[@-~]')
40+
while line_idx < len(lines):
41+
# Remove ansi colour code
42+
line = ansi_escape.sub('', lines[line_idx])
43+
if "Balances" in line:
44+
# When "Balances" appears in a line, all of the following lines contain "balance: wallet" until an empty line
45+
cli_get_info["Balances"] = {}
46+
while line_idx < len(lines) and not (lines[line_idx + 1] == ''):
47+
line_idx += 1
48+
balance, wallet = lines[line_idx].strip().split(" ")
49+
# Remove right justification padding
50+
wallet = wallet.strip()
51+
if wallet == '""':
52+
# Set default wallet("") to empty string
53+
wallet = ''
54+
cli_get_info["Balances"][wallet] = balance.strip()
55+
elif ": " in line:
56+
key, value = line.split(": ")
57+
if key == 'Wallet' and value == '""':
58+
# Set default wallet("") to empty string
59+
value = ''
60+
if key == "Proxy" and value == "N/A":
61+
# Set N/A to empty string to represent no proxy
62+
value = ''
63+
cli_get_info[key.strip()] = value.strip()
64+
line_idx += 1
65+
return cli_get_info
66+
67+
3268
class TestBitcoinCli(BitcoinTestFramework):
3369
def set_test_params(self):
3470
self.setup_clean_chain = True
@@ -67,37 +103,43 @@ def run_test(self):
67103
self.log.info("Test -getinfo with arguments fails")
68104
assert_raises_process_error(1, "-getinfo takes no arguments", self.nodes[0].cli('-getinfo').help)
69105

106+
self.log.info("Test -getinfo with -color=never does not return ANSI escape codes")
107+
assert "\u001b[0m" not in self.nodes[0].cli('-getinfo', '-color=never').send_cli()
108+
109+
self.log.info("Test -getinfo with -color=always returns ANSI escape codes")
110+
assert "\u001b[0m" in self.nodes[0].cli('-getinfo', '-color=always').send_cli()
111+
112+
self.log.info("Test -getinfo with invalid value for -color option")
113+
assert_raises_process_error(1, "Invalid value for -color option. Valid values: always, auto, never.", self.nodes[0].cli('-getinfo', '-color=foo').send_cli)
114+
70115
self.log.info("Test -getinfo returns expected network and blockchain info")
71116
if self.is_wallet_compiled():
72117
self.nodes[0].encryptwallet(password)
73-
cli_get_info = self.nodes[0].cli('-getinfo').send_cli()
118+
cli_get_info_string = self.nodes[0].cli('-getinfo').send_cli()
119+
cli_get_info = cli_get_info_string_to_dict(cli_get_info_string)
120+
74121
network_info = self.nodes[0].getnetworkinfo()
75122
blockchain_info = self.nodes[0].getblockchaininfo()
76-
assert_equal(cli_get_info['version'], network_info['version'])
77-
assert_equal(cli_get_info['blocks'], blockchain_info['blocks'])
78-
assert_equal(cli_get_info['headers'], blockchain_info['headers'])
79-
assert_equal(cli_get_info['timeoffset'], network_info['timeoffset'])
80-
assert_equal(
81-
cli_get_info['connections'],
82-
{
83-
'in': network_info['connections_in'],
84-
'out': network_info['connections_out'],
85-
'total': network_info['connections']
86-
}
87-
)
88-
assert_equal(cli_get_info['proxy'], network_info['networks'][0]['proxy'])
89-
assert_equal(cli_get_info['difficulty'], blockchain_info['difficulty'])
90-
assert_equal(cli_get_info['chain'], blockchain_info['chain'])
123+
assert_equal(int(cli_get_info['Version']), network_info['version'])
124+
assert_equal(cli_get_info['Verification progress'], "%.4f%%" % (blockchain_info['verificationprogress'] * 100))
125+
assert_equal(int(cli_get_info['Blocks']), blockchain_info['blocks'])
126+
assert_equal(int(cli_get_info['Headers']), blockchain_info['headers'])
127+
assert_equal(int(cli_get_info['Time offset (s)']), network_info['timeoffset'])
128+
expected_network_info = f"in {network_info['connections_in']}, out {network_info['connections_out']}, total {network_info['connections']}"
129+
assert_equal(cli_get_info["Network"], expected_network_info)
130+
assert_equal(cli_get_info['Proxy'], network_info['networks'][0]['proxy'])
131+
assert_equal(Decimal(cli_get_info['Difficulty']), blockchain_info['difficulty'])
132+
assert_equal(cli_get_info['Chain'], blockchain_info['chain'])
91133

92134
if self.is_wallet_compiled():
93135
self.log.info("Test -getinfo and bitcoin-cli getwalletinfo return expected wallet info")
94-
assert_equal(cli_get_info['balance'], BALANCE)
95-
assert 'balances' not in cli_get_info.keys()
136+
assert_equal(Decimal(cli_get_info['Balance']), BALANCE)
137+
assert 'Balances' not in cli_get_info_string
96138
wallet_info = self.nodes[0].getwalletinfo()
97-
assert_equal(cli_get_info['keypoolsize'], wallet_info['keypoolsize'])
98-
assert_equal(cli_get_info['unlocked_until'], wallet_info['unlocked_until'])
99-
assert_equal(cli_get_info['paytxfee'], wallet_info['paytxfee'])
100-
assert_equal(cli_get_info['relayfee'], network_info['relayfee'])
139+
assert_equal(int(cli_get_info['Keypool size']), wallet_info['keypoolsize'])
140+
assert_equal(int(cli_get_info['Unlocked until']), wallet_info['unlocked_until'])
141+
assert_equal(Decimal(cli_get_info['Transaction fee rate (-paytxfee) (BTC/kvB)']), wallet_info['paytxfee'])
142+
assert_equal(Decimal(cli_get_info['Min tx relay fee rate (BTC/kvB)']), network_info['relayfee'])
101143
assert_equal(self.nodes[0].cli.getwalletinfo(), wallet_info)
102144

103145
# Setup to test -getinfo, -generate, and -rpcwallet= with multiple wallets.
@@ -120,44 +162,57 @@ def run_test(self):
120162

121163
self.log.info("Test -getinfo with multiple wallets and -rpcwallet returns specified wallet balance")
122164
for i in range(len(wallets)):
123-
cli_get_info = self.nodes[0].cli('-getinfo', '-rpcwallet={}'.format(wallets[i])).send_cli()
124-
assert 'balances' not in cli_get_info.keys()
125-
assert_equal(cli_get_info['balance'], amounts[i])
165+
cli_get_info_string = self.nodes[0].cli('-getinfo', '-rpcwallet={}'.format(wallets[i])).send_cli()
166+
cli_get_info = cli_get_info_string_to_dict(cli_get_info_string)
167+
assert 'Balances' not in cli_get_info_string
168+
assert_equal(cli_get_info["Wallet"], wallets[i])
169+
assert_equal(Decimal(cli_get_info['Balance']), amounts[i])
126170

127171
self.log.info("Test -getinfo with multiple wallets and -rpcwallet=non-existing-wallet returns no balances")
128-
cli_get_info_keys = self.nodes[0].cli('-getinfo', '-rpcwallet=does-not-exist').send_cli().keys()
129-
assert 'balance' not in cli_get_info_keys
130-
assert 'balances' not in cli_get_info_keys
172+
cli_get_info_string = self.nodes[0].cli('-getinfo', '-rpcwallet=does-not-exist').send_cli()
173+
assert 'Balance' not in cli_get_info_string
174+
assert 'Balances' not in cli_get_info_string
131175

132176
self.log.info("Test -getinfo with multiple wallets returns all loaded wallet names and balances")
133177
assert_equal(set(self.nodes[0].listwallets()), set(wallets))
134-
cli_get_info = self.nodes[0].cli('-getinfo').send_cli()
135-
assert 'balance' not in cli_get_info.keys()
136-
assert_equal(cli_get_info['balances'], {k: v for k, v in zip(wallets, amounts)})
178+
cli_get_info_string = self.nodes[0].cli('-getinfo').send_cli()
179+
cli_get_info = cli_get_info_string_to_dict(cli_get_info_string)
180+
assert 'Balance' not in cli_get_info
181+
for k, v in zip(wallets, amounts):
182+
assert_equal(Decimal(cli_get_info['Balances'][k]), v)
137183

138184
# Unload the default wallet and re-verify.
139185
self.nodes[0].unloadwallet(wallets[0])
140186
assert wallets[0] not in self.nodes[0].listwallets()
141-
cli_get_info = self.nodes[0].cli('-getinfo').send_cli()
142-
assert 'balance' not in cli_get_info.keys()
143-
assert_equal(cli_get_info['balances'], {k: v for k, v in zip(wallets[1:], amounts[1:])})
187+
cli_get_info_string = self.nodes[0].cli('-getinfo').send_cli()
188+
cli_get_info = cli_get_info_string_to_dict(cli_get_info_string)
189+
assert 'Balance' not in cli_get_info
190+
assert 'Balances' in cli_get_info_string
191+
for k, v in zip(wallets[1:], amounts[1:]):
192+
assert_equal(Decimal(cli_get_info['Balances'][k]), v)
193+
assert wallets[0] not in cli_get_info
144194

145195
self.log.info("Test -getinfo after unloading all wallets except a non-default one returns its balance")
146196
self.nodes[0].unloadwallet(wallets[2])
147197
assert_equal(self.nodes[0].listwallets(), [wallets[1]])
148-
cli_get_info = self.nodes[0].cli('-getinfo').send_cli()
149-
assert 'balances' not in cli_get_info.keys()
150-
assert_equal(cli_get_info['balance'], amounts[1])
198+
cli_get_info_string = self.nodes[0].cli('-getinfo').send_cli()
199+
cli_get_info = cli_get_info_string_to_dict(cli_get_info_string)
200+
assert 'Balances' not in cli_get_info_string
201+
assert_equal(cli_get_info['Wallet'], wallets[1])
202+
assert_equal(Decimal(cli_get_info['Balance']), amounts[1])
151203

152204
self.log.info("Test -getinfo with -rpcwallet=remaining-non-default-wallet returns only its balance")
153-
cli_get_info = self.nodes[0].cli('-getinfo', rpcwallet2).send_cli()
154-
assert 'balances' not in cli_get_info.keys()
155-
assert_equal(cli_get_info['balance'], amounts[1])
205+
cli_get_info_string = self.nodes[0].cli('-getinfo', rpcwallet2).send_cli()
206+
cli_get_info = cli_get_info_string_to_dict(cli_get_info_string)
207+
assert 'Balances' not in cli_get_info_string
208+
assert_equal(cli_get_info['Wallet'], wallets[1])
209+
assert_equal(Decimal(cli_get_info['Balance']), amounts[1])
156210

157211
self.log.info("Test -getinfo with -rpcwallet=unloaded wallet returns no balances")
158-
cli_get_info_keys = self.nodes[0].cli('-getinfo', rpcwallet3).send_cli().keys()
159-
assert 'balance' not in cli_get_info_keys
160-
assert 'balances' not in cli_get_info_keys
212+
cli_get_info_string = self.nodes[0].cli('-getinfo', rpcwallet3).send_cli()
213+
cli_get_info_keys = cli_get_info_string_to_dict(cli_get_info_string)
214+
assert 'Balance' not in cli_get_info_keys
215+
assert 'Balances' not in cli_get_info_string
161216

162217
# Test bitcoin-cli -generate.
163218
n1 = 3

0 commit comments

Comments
 (0)