mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-01-10 03:47:29 -03:00
ee47ca29d6
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 <ryan@ofsky.org>
114 lines
5.1 KiB
Python
Executable file
114 lines
5.1 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
# Copyright (c) 2017-2021 The Bitcoin Core developers
|
|
# Distributed under the MIT software license, see the accompanying
|
|
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
"""Test various command line arguments and configuration file parameters."""
|
|
|
|
import json
|
|
|
|
|
|
from test_framework.test_framework import BitcoinTestFramework
|
|
from test_framework.test_node import ErrorMatch
|
|
from test_framework.util import assert_equal
|
|
|
|
|
|
class SettingsTest(BitcoinTestFramework):
|
|
def add_options(self, parser):
|
|
self.add_wallet_options(parser)
|
|
|
|
def set_test_params(self):
|
|
self.setup_clean_chain = True
|
|
self.num_nodes = 1
|
|
self.wallet_names = []
|
|
|
|
def test_wallet_settings(self, settings_path):
|
|
if not self.is_wallet_compiled():
|
|
return
|
|
|
|
self.log.info("Testing wallet settings..")
|
|
node = self.nodes[0]
|
|
# Create wallet to use it during tests
|
|
self.start_node(0)
|
|
node.createwallet(wallet_name='w1')
|
|
self.stop_node(0)
|
|
|
|
# Verify wallet settings can only be strings. Either names or paths. Not booleans, nums nor anything else.
|
|
for wallets_data in [[10], [True], [[]], [{}], ["w1", 10], ["w1", False]]:
|
|
with settings_path.open("w") as fp:
|
|
json.dump({"wallet": wallets_data}, fp)
|
|
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",
|
|
extra_args=[f'-settings={settings_path}'])
|
|
|
|
def run_test(self):
|
|
node, = self.nodes
|
|
settings = node.chain_path / "settings.json"
|
|
conf = node.datadir_path / "bitcoin.conf"
|
|
|
|
# Assert default settings file was created
|
|
self.stop_node(0)
|
|
default_settings = {"_warning_": f"This file is automatically generated and updated by {self.config['environment']['PACKAGE_NAME']}. Please do not edit this file while the node is running, as any changes might be ignored or overwritten."}
|
|
with settings.open() as fp:
|
|
assert_equal(json.load(fp), default_settings)
|
|
|
|
# Assert settings are parsed and logged
|
|
with settings.open("w") as fp:
|
|
json.dump({"string": "string", "num": 5, "bool": True, "null": None, "list": [6, 7]}, fp)
|
|
with node.assert_debug_log(expected_msgs=[
|
|
'Ignoring unknown rw_settings value bool',
|
|
'Ignoring unknown rw_settings value list',
|
|
'Ignoring unknown rw_settings value null',
|
|
'Ignoring unknown rw_settings value num',
|
|
'Ignoring unknown rw_settings value string',
|
|
'Setting file arg: string = "string"',
|
|
'Setting file arg: num = 5',
|
|
'Setting file arg: bool = true',
|
|
'Setting file arg: null = null',
|
|
'Setting file arg: list = [6,7]',
|
|
]):
|
|
self.start_node(0)
|
|
self.stop_node(0)
|
|
|
|
# Assert settings are unchanged after shutdown
|
|
with settings.open() as fp:
|
|
assert_equal(json.load(fp), {**default_settings, **{"string": "string", "num": 5, "bool": True, "null": None, "list": [6, 7]}})
|
|
|
|
# Test invalid json
|
|
with settings.open("w") as fp:
|
|
fp.write("invalid json")
|
|
node.assert_start_raises_init_error(expected_msg='does not contain valid JSON. This is probably caused by disk corruption or a crash', match=ErrorMatch.PARTIAL_REGEX)
|
|
|
|
# Test invalid json object
|
|
with settings.open("w") as fp:
|
|
fp.write('"string"')
|
|
node.assert_start_raises_init_error(expected_msg='Found non-object value "string" in settings file', match=ErrorMatch.PARTIAL_REGEX)
|
|
|
|
# Test invalid settings file containing duplicate keys
|
|
with settings.open("w") as fp:
|
|
fp.write('{"key": 1, "key": 2}')
|
|
node.assert_start_raises_init_error(expected_msg='Found duplicate key key in settings file', match=ErrorMatch.PARTIAL_REGEX)
|
|
|
|
# Test invalid settings file is ignored with command line -nosettings
|
|
with node.assert_debug_log(expected_msgs=['Command-line arg: settings=false']):
|
|
self.start_node(0, extra_args=["-nosettings"])
|
|
self.stop_node(0)
|
|
|
|
# Test invalid settings file is ignored with config file -nosettings
|
|
with conf.open('a') as conf:
|
|
conf.write('nosettings=1\n')
|
|
with node.assert_debug_log(expected_msgs=['Config file arg: [regtest] settings=false']):
|
|
self.start_node(0)
|
|
self.stop_node(0)
|
|
|
|
# Test alternate settings path
|
|
altsettings = node.datadir_path / "altsettings.json"
|
|
with altsettings.open("w") as fp:
|
|
fp.write('{"key": "value"}')
|
|
with node.assert_debug_log(expected_msgs=['Setting file arg: key = "value"']):
|
|
self.start_node(0, extra_args=[f"-settings={altsettings}"])
|
|
self.stop_node(0)
|
|
|
|
self.test_wallet_settings(settings)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
SettingsTest(__file__).main()
|