Skip to content

Commit ee47ca2

Browse files
furszyryanofsky
andcommitted
init: fix fatal error on '-wallet' negated option value
Because we don't have type checking for command-line/settings/config args, strings are interpreted as 'false' for non-boolean args. By convention, this "forces" us to interpret negated strings as 'true', which conflicts with the negated option definition in all the settings classes (they expect negated options to always be false and ignore any other value preceding them). Consequently, when retrieving all "wallet" values from the command-line/settings/config, we also fetch the negated string boolean value, which is not of the expected 'string' type. This mismatch leads to an internal fatal error, resulting in an unclean shutdown during initialization. Furthermore, this error displays a poorly descriptive error message: "JSON value of type bool is not of expected type string" This commit fixes the fatal error by ensuring that only string values are returned in the "wallet" settings list, failing otherwise. It also improves the clarity of the returned error message. Co-authored-by: Ryan Ofsky <[email protected]>
1 parent d79ea80 commit ee47ca2

File tree

3 files changed

+40
-0
lines changed

3 files changed

+40
-0
lines changed

src/wallet/load.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,11 @@ bool VerifyWallets(WalletContext& context)
7777
std::set<fs::path> wallet_paths;
7878

7979
for (const auto& wallet : chain.getSettingsList("wallet")) {
80+
if (!wallet.isStr()) {
81+
chain.initError(_("Invalid value detected for '-wallet' or '-nowallet'. "
82+
"'-wallet' requires a string value, while '-nowallet' accepts only '1' to disable all wallets"));
83+
return false;
84+
}
8085
const auto& wallet_file = wallet.get_str();
8186
const fs::path path = fsbridge::AbsPathJoin(GetWalletDir(), fs::PathFromString(wallet_file));
8287

@@ -110,6 +115,11 @@ bool LoadWallets(WalletContext& context)
110115
try {
111116
std::set<fs::path> wallet_paths;
112117
for (const auto& wallet : chain.getSettingsList("wallet")) {
118+
if (!wallet.isStr()) {
119+
chain.initError(_("Invalid value detected for '-wallet' or '-nowallet'. "
120+
"'-wallet' requires a string value, while '-nowallet' accepts only '1' to disable all wallets"));
121+
return false;
122+
}
113123
const auto& name = wallet.get_str();
114124
if (!wallet_paths.insert(fs::PathFromString(name)).second) {
115125
continue;

test/functional/feature_config_args.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,13 @@ def test_invalid_command_line_options(self):
153153
expected_msg='Error: Error parsing command line arguments: Can not set -proxy with no value. Please specify value with -proxy=value.',
154154
extra_args=['-proxy'],
155155
)
156+
# Provide a value different from 1 to the -wallet negated option
157+
if self.is_wallet_compiled():
158+
for value in [0, 'not_a_boolean']:
159+
self.nodes[0].assert_start_raises_init_error(
160+
expected_msg="Error: Invalid value detected for '-wallet' or '-nowallet'. '-wallet' requires a string value, while '-nowallet' accepts only '1' to disable all wallets",
161+
extra_args=[f'-nowallet={value}'],
162+
)
156163

157164
def test_log_buffer(self):
158165
self.stop_node(0)

test/functional/feature_settings.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,32 @@
1313

1414

1515
class SettingsTest(BitcoinTestFramework):
16+
def add_options(self, parser):
17+
self.add_wallet_options(parser)
18+
1619
def set_test_params(self):
1720
self.setup_clean_chain = True
1821
self.num_nodes = 1
1922
self.wallet_names = []
2023

24+
def test_wallet_settings(self, settings_path):
25+
if not self.is_wallet_compiled():
26+
return
27+
28+
self.log.info("Testing wallet settings..")
29+
node = self.nodes[0]
30+
# Create wallet to use it during tests
31+
self.start_node(0)
32+
node.createwallet(wallet_name='w1')
33+
self.stop_node(0)
34+
35+
# Verify wallet settings can only be strings. Either names or paths. Not booleans, nums nor anything else.
36+
for wallets_data in [[10], [True], [[]], [{}], ["w1", 10], ["w1", False]]:
37+
with settings_path.open("w") as fp:
38+
json.dump({"wallet": wallets_data}, fp)
39+
node.assert_start_raises_init_error(expected_msg="Error: Invalid value detected for '-wallet' or '-nowallet'. '-wallet' requires a string value, while '-nowallet' accepts only '1' to disable all wallets",
40+
extra_args=[f'-settings={settings_path}'])
41+
2142
def run_test(self):
2243
node, = self.nodes
2344
settings = node.chain_path / "settings.json"
@@ -86,6 +107,8 @@ def run_test(self):
86107
self.start_node(0, extra_args=[f"-settings={altsettings}"])
87108
self.stop_node(0)
88109

110+
self.test_wallet_settings(settings)
111+
89112

90113
if __name__ == '__main__':
91114
SettingsTest(__file__).main()

0 commit comments

Comments
 (0)