Skip to content

Commit fb52023

Browse files
committed
Merge bitcoin/bitcoin#30684: init: fix init fatal error on invalid negated option value
ee47ca2 init: fix fatal error on '-wallet' negated option value (furszy) Pull request description: Currently, if users provide a double negated value such as '-nowallet=0' or a non-boolean convertible value to a negated option such as '-nowallet=not_a_boolean', the initialization process results in a fatal error, causing an unclean shutdown and displaying a poorly descriptive error message: "JSON value of type bool is not of expected type string." (On bitcoind. The GUI does not display any error msg - upcoming PR -). This PR fixes the issue by ensuring that only string values are returned in the the "wallet" settings list, failing otherwise. It also improves the clarity of the returned error message. Note: This bug was introduced in bitcoin/bitcoin#22217. Where the `GetArgs("-wallet")` call was replaced by `GetSettingsList("-wallet")`. ACKs for top commit: achow101: ACK ee47ca2 ryanofsky: Code review ACK ee47ca2, just adding the suggested test since last review TheCharlatan: ACK ee47ca2 ismaelsadeeq: Tested ACK ee47ca2 Tree-SHA512: 5f01076f74a048019bb70791160f0accc2db7a457d969cb23687bed81ccbbdec1dda68311e7c6e2dd56250e23e8d926d4066e5014b2a99a2fc202e24ed264fbd
2 parents 746f880 + ee47ca2 commit fb52023

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)