diff --git a/contrib/devtools/reg-settings.py b/contrib/devtools/reg-settings.py deleted file mode 100644 index 3b5f46f1bfad4..0000000000000 --- a/contrib/devtools/reg-settings.py +++ /dev/null @@ -1,677 +0,0 @@ -from __future__ import annotations -import collections -import enum -import os -import re -import subprocess -from dataclasses import dataclass, field - -@dataclass -class Call: - file: str - position: int - call_text: str - obj_name: str - arg_name: str - context: str - namespace: str - -class DataType(int, enum.Enum): - STRING_LIST = 1 - STRING = 2 - PATH = 3 - INT = 4 - BOOL = 5 - DISABLED = 6 - UNSET = 7 - -# What default value is returned by a particular GetArg call when the setting is -# unset. Either a string containing a c++ expression, or None to indicate that -# call returns std::nullopt, or True to indicate it returns whatever the -# default-constructed value for the setting type is (e.g. the empty vector, or -# string, or path) or False to indicate it doesn't specify any default. -DefaultValue = str | bool | None - -@dataclass -class SettingType: - name: str - primary: bool = False - defaults: set[str | None] = field(default_factory=set) - default_value: DefaultValue = False - -@dataclass -class AddArg: - call: Call - summary: str - help_text: str - help_args: tuple[str, ...] - flags: str - category: str - include_path: str | None = None - data_types: dict[DataType, SettingType] = field(default_factory=dict) - extern_args: list[str] = field(default_factory=list) - hidden_args: list[AddArg] | None = None - """One AddArg object is produced for each argument listed in a single - AddHiddenArgs({...}) call, but all the AddArg objects from the same call a - hidden_args member pointing to a shared list of related AddArgs.""" - nonhidden_arg: AddArg | None = None - """Reference to duplicate nonhidden argument, if this is a hidden argument duplicating a non-hidden one.""" - -@dataclass -class GetArg: - call: Call - function_name: str - data_type: DataType - default_value: DefaultValue - nots: int - add: AddArg | None = None - -@dataclass -class Setting: - arg_name: str - adds: list[AddArg] = field(default_factory=list) - gets: list[GetArg] = field(default_factory=list) - -def get_files_with_args(src_dir): - # Run git grep to find files containing AddArg/GetArg/GetIntArg/GetBoolArg/GetArgs - result = subprocess.run( - [ - "git", "grep", "-l", "AddArg(\|AddHiddenArgs(\|GetArg(\|GetPathArg(\|GetIntArg(\|GetBoolArg(\|GetArgs(\|IsArgSet(\|IsArgNegated(", "--", src_dir - ], - capture_output=True, - text=True - ) - return result.stdout.splitlines() - -def parse_function_args(arg_str): - args = [] - stack = [] - quot = False - for pos, c in enumerate(arg_str): - if c == '"': - quot = not quot - if quot: - pass - elif c == "(": - stack.append(")") - if len(stack) == 1: continue - elif c == "{": - stack.append("}") - if len(stack) == 1: continue - elif c == stack[-1]: - stack.pop() - if not stack: break - elif c == "," and len(stack) == 1: - args.append("") - continue - if not args: args.append("") - args[-1] += c - return pos, args - -def parse_calls(file_path): - adds = [] - gets = [] - context = get_file_context(file_path) - namespace = get_file_namespace(file_path) - with open(file_path, 'r') as f: - content = f.read() - for match in re.finditer(r'\b(\w+)\.AddArg\((")', content): - call_len, (summary, help_text, flags, category) = parse_function_args(content[match.start(2)-1:]) - call = Call( - file=file_path, - position=match.start(), - call_text=content[match.start():match.start(2)+call_len], - obj_name=match.group(1), - arg_name=re.match(r'"([^"=(]+).*', summary).group(1), - context=context, - namespace=namespace, - ) - help_text=help_text.strip() - help_args = [] - if m := re.match(r"strprintf\(", help_text): - _, help_args = parse_function_args(help_text[m.end()-1:]) - help_text = help_args[0].strip() - help_args = [a.strip() for a in help_args[1:]] - adds.append(AddArg( - call=call, - summary=summary.strip(), - help_text=help_text, - help_args=tuple(help_args), - flags=flags.strip(), - category=category.strip(), - )) - for match in re.finditer(r'( *)\b(\w+)\.AddHiddenArgs\((\{)', content): - call_len, call_args = parse_function_args(content[match.start(3):]) - hidden_args = [] - for summary in call_args: - summary = summary.strip() - if not summary: continue - call_text=content[match.start():match.start(3)+call_len+1] - call = Call( - file=file_path, - position=match.start(), - call_text=content[match.start():match.start(3)+call_len+2], - obj_name=match.group(2), - arg_name=re.match(r'"([^"=(]+).*', summary).group(1), - context=context, - namespace=namespace, - ) - hidden_args.append(AddArg( - call=call, - summary=summary, - help_text="", - help_args=(), - flags="ArgsManager::ALLOW_ANY", - category="OptionsCategory::HIDDEN", - hidden_args=hidden_args, - )) - adds.append(hidden_args[-1]) - - for match in re.finditer(r'(!*)\b(?:((?:\w|\.|->|\(\))+)(\.|->))?(GetArg|GetPathArg|GetIntArg|GetBoolArg|GetArgs|IsArgSet|IsArgNegated)\((.)', content): - call_len, call_args = parse_function_args(content[match.start(5)-1:]) - if not call_args: continue - nots, obj_name, op, function_name, _ = match.groups() - if op == "->": - obj_name = f"*{obj_name}" - elif obj_name is None: - obj_name = "*this" - call = Call( - file=file_path, - position=match.start(), - call_text=content[match.start():match.start(5)+call_len], - obj_name=obj_name, - arg_name=call_args[0].strip().strip('"'), - context=context, - namespace=namespace, - ) - data_type = (DataType.STRING_LIST if function_name == "GetArgs" else - DataType.STRING if function_name == "GetArg" else - DataType.PATH if function_name == "GetPathArg" else - DataType.INT if function_name == "GetIntArg" else - DataType.BOOL if function_name == "GetBoolArg" else - DataType.DISABLED if function_name == "IsArgNegated" else - DataType.UNSET if function_name == "IsArgSet" else - None) - default_arg = call_args[1].strip() if len(call_args) > 1 else None - default_value = ( - True if data_type == DataType.STRING and default_arg == '""' else - True if data_type == DataType.INT and default_arg == "0" else - True if data_type == DataType.BOOL and default_arg == "false" else - default_arg if default_arg is not None else - None if data_type in (DataType.STRING, DataType.INT, DataType.BOOL) else - True if data_type in (DataType.PATH, DataType.STRING_LIST) else - False) - gets.append(GetArg(call=call, function_name=function_name, data_type=data_type, default_value=default_value, nots=len(match.group(1)))) - return adds, gets - -def make_setting(settings, call): - name = call.arg_name.lstrip("-") - if name in settings: - setting = settings[name] - else: - setting = settings[name] = Setting(call.arg_name) - return setting - -def flags_to_options(flag_str): - flags = set() - for flag in flag_str.split("|"): - flags.add(flag.strip()) - - def pop(flag): - if flag in flags: - flags.remove(flag) - return True - return False - - options = [".legacy = true"] - if pop("ArgsManager::DEBUG_ONLY"): - options.append(".debug_only = true") - if pop("ArgsManager::NETWORK_ONLY"): - options.append(".network_only = true") - if pop("ArgsManager::SENSITIVE"): - options.append(".sensitive = true") - if pop("ArgsManager::DISALLOW_NEGATION"): - options.append(".disallow_negation = true") - if pop("ArgsManager::DISALLOW_ELISION"): - options.append(".disallow_elision = true") - pop("ArgsManager::ALLOW_ANY") - if flags: - raise Exception("Unknown flags {flags!r}") - return options - -def collect_argument_information(src_dir): - files = get_files_with_args(src_dir) - settings: Dict[str, Setting] = {} - for file in files: - adds, gets = parse_calls(file) - for add in adds: - setting = make_setting(settings, add.call) - setting.adds.append(add) - for get in gets: - setting = make_setting(settings, get.call) - setting.gets.append(get) - - for arg_name, setting in settings.items(): - # Find duplicate hidden/nonhidden settings - for hadd in setting.adds: - if hadd.hidden_args is not None: - for add in setting.adds: - if add.hidden_args is None and add.call.context == hadd.call.context and add.call.arg_name == hadd.call.arg_name: - hadd.nonhidden_arg = add - break - - # Link GetArg/AddArg calls and figure out setting types and default values. - setting_name = ''.join(word.capitalize() for word in arg_name.replace('?', 'Q').split('-')) + "Setting" - counter = collections.Counter() - for add in setting.adds: - add.include_path = add.call.file.replace(".cpp", "_settings.h") - key = add.call.context, add.call.arg_name - add_setting_name = setting_name - if add.hidden_args is None: - counter[key] += 1 - if counter[key] > 1: add_setting_name += str(counter[key]) - elif add.nonhidden_arg is not None: - continue - else: - add_setting_name += "Hidden" - - for get in setting.gets: - if add.call.context != get.call.context and (add.call.context != "main" or get.call.context == "test" or add.hidden_args is not None): - continue - if get.add is None: - get.add = add - if get.data_type in add.data_types: - setting_type = add.data_types[get.data_type] - else: - setting_type = add.data_types[get.data_type] = SettingType(add_setting_name) - if get.default_value is not False: - setting_type.defaults.add(get.default_value) - - # Clean up data types. Add if empty, remove if redundant, set primary - if len(add.data_types) == 0: - add.data_types[DataType.UNSET] = SettingType(add_setting_name) - add.data_types[min(add.data_types.keys())].primary = True - for data_type in (DataType.DISABLED, DataType.UNSET): - if data_type in add.data_types and not add.data_types[data_type].primary: - del add.data_types[data_type] - - for data_type, setting_type in add.data_types.items(): - # If same setting is retrieved as different types, add suffixes to distinguish setting names - if not setting_type.primary: - setting_type.name += ( - "List" if data_type == DataType.STRING_LIST else - "Str" if data_type == DataType.STRING else - "Path" if data_type == DataType.PATH else - "Int" if data_type == DataType.INT else - "Bool" if data_type == DataType.BOOL else - "Disabled" if data_type == DataType.DISABLED else - "Unset" if data_type == DataType.UNSET else - None - ) - # Only set ::Default<> if there are no GetArg calls returning - # std::optional and there is a single consistent default. - if None not in setting_type.defaults: - defaults = set() - for default_value in setting_type.defaults: - if isinstance(default_value, str): - for pattern, options in ARG_PATTERNS.items(): - if re.search(pattern, default_value) and options.extern: - default_value = False - break - if pattern == default_value and options.namespace: - default_value = f"{options.namespace}::{default_value}" - break - defaults.add(default_value) - if len(defaults) == 1: - default_value = next(iter(defaults)) - assert default_value is not None - setting_type.default_value = default_value - return settings - -@dataclass -class SettingsHeader: - includes: set[str] = field(default_factory=set) - defs: list[str] = field(default_factory=list) - -def generate_setting_headers(settings): - headers_content = collections.defaultdict(SettingsHeader) - for setting in settings.values(): - for add in setting.adds: - if add.nonhidden_arg is not None: continue - header = headers_content[add.include_path] - help_runtime = False - extern = [] - for pattern, options in ARG_PATTERNS.items(): - if re.search(pattern, add.help_text) or any(re.search(pattern, a) for a in add.help_args): - if options.include_path: - header.includes.add(options.include_path) - help_runtime = help_runtime or options.runtime - if options.extern: - extern.append(pattern) - add.extern_args.append(pattern) - - for data_type, setting_type in sorted(add.data_types.items(), key=lambda p: p[0]): - ctype = ("std::vector" if data_type == DataType.STRING_LIST else - "std::string" if data_type == DataType.STRING else - "fs::path" if data_type == DataType.PATH else - "int64_t" if data_type == DataType.INT else - "bool" if data_type == DataType.BOOL else - "common::Disabled" if data_type == DataType.DISABLED else - "common::Unset" if data_type == DataType.UNSET else - None) - if None in setting_type.defaults: - ctype = f"std::optional<{ctype}>" - help_str = "" - if setting_type.primary and add.help_text: - help_str = f",\n {add.help_text}" - extra = "" - help_args = ', '.join(a for a in add.help_args) - default_arg = (setting_type.default_value if setting_type.default_value is not True else - '""' if data_type == DataType.STRING else - "0" if data_type == DataType.INT else - "false" if data_type == DataType.BOOL else - f"{ctype}{{}}") - if setting_type.default_value is True and (not help_args or help_args != default_arg): - default_arg = False - if default_arg: - default_runtime = False - for pattern, options in ARG_PATTERNS.items(): - if setting_type.default_value is not True and re.search(pattern, setting_type.default_value): - if options.include_path: - header.includes.add(options.include_path) - default_runtime = default_runtime or options.runtime - assert not options.extern - namespace = get_file_namespace(add.include_path) - prefix = f"{namespace}::" - if default_arg.startswith(prefix): - default_arg = default_arg[len(prefix):] - if default_runtime: - extra += f"\n ::DefaultFn<[] {{ return {default_arg}; }}>" - else: - extra += f"\n ::Default<{default_arg}>" - if ((help_args and setting_type.primary) or default_arg) and help_args != default_arg: - if help_runtime or extern: - lambda_args = ", ".join(f"const auto& {a}" for a in ["fmt"] + extern) - extra += f"\n ::HelpFn<[]({lambda_args}) {{ return strprintf(fmt, {help_args}); }}>" - else: - extra += f"\n ::HelpArgs<{help_args}>" - if add.category != "OptionsCategory::OPTIONS" and setting_type.primary: - extra += f"\n ::Category<{add.category}>" - options = flags_to_options(add.flags) - # Writing common::SettingOptions{...} instead of just {...} - # should be unneccesary because latter is valid initialization - # syntax in C++20, but unfortunately it is only supported as of - # clang 18. clang 17 and early versions do not seem to allow - # using designated initializers to initialize template - # parameters. - options_str = f"common::SettingOptions{{{', '.join(options)}}}" if options else "" - setting_definition = f"\nusing {setting_type.name} = common::Setting<\n {add.summary}, {ctype}, {options_str}{help_str}>{extra};\n" - header.defs.append(setting_definition) - - for header_file_path, header in headers_content.items(): - if not os.path.exists(header_file_path): - guard = "BITCOIN_" + re.sub("^src/", "", header_file_path).replace('/', '_').replace('.', '_').replace('-', '_').upper() - namespace = get_file_namespace(header_file_path) - namespace_str = "" - if namespace: - namespace_str = f"namespace {namespace} {{\n}} // namespace {namespace}\n" - with open(header_file_path, 'w') as f: - f.write(f"#ifndef {guard}\n#define {guard}\n{namespace_str}\n#endif // {guard}\n") - add_to_file( - header_file_path, - [f"#include <{include}>\n" for include in header.includes | {"common/setting.h"}], - ["#include \n", "#include \n"], - header.defs) - -def add_to_file(file_path, local_includes, system_includes=(), defs=()): - with open(file_path, 'r') as f: - lines = f.readlines() - # Identify the include blocks and their positions - local_include_start, local_include_end = None, None - system_include_start, system_include_end = None, None - self_include = f"#include <{file_path.replace('src/', '').replace('.cpp', '.h')}>" - first = last = self = None - for i, line in enumerate(lines): - if line.startswith('#include') and "IWYU pragma: keep" not in line and not line.startswith(self_include): - if local_include_start is None: - local_include_start = i - elif system_include_start is None and local_include_end is not None: - system_include_start = i - elif system_include_start is not None and system_include_end is None: - system_include_end = i - elif local_include_start is not None and local_include_end is None: - local_include_end = i - elif line.startswith('#include'): - self = True - if first is None and not line.startswith("//") and not line.startswith("#ifndef") and not line.startswith("#define") and line != "\n": - first = i - if line != "\n" and not line.startswith("#endif") and not line.startswith("} // namespace "): - last = i + 1 - - if system_include_start is None and system_include_end is None and not self: - system_include_start, system_include_end = local_include_start, local_include_end - local_include_end = system_include_start - - lines[last:last] = defs - - if system_includes: - head = [] - tail = [] - if system_include_start is None and system_include_end is None: - system_include_start = system_include_end = min(first, last) - head += ["\n"] - if first < last + 1: tail += ["\n"] - elif local_include_end == system_include_start: - head += ["\n"] - existing_includes = lines[system_include_start:system_include_end] - lines[system_include_start:system_include_end] = head + sorted(set(system_includes) | set(existing_includes)) + tail - - if local_includes: - head = [] - if local_include_start is None and local_include_end is None: - local_include_start = local_include_end = min(first, last) - if lines[local_include_start-1:local_include_start+1] != ["\n", "\n"]: head = ["\n"] - existing_includes = lines[local_include_start:local_include_end] - lines[local_include_start:local_include_end] = head + sorted(set(local_includes) | set(existing_includes)) - - with open(file_path, 'w') as f: - f.writelines(lines) - -def register_str(add, hidden=False): - register_args = ", ".join([add.call.obj_name] + add.extern_args) - default_data_type = min(add.data_types.keys()) - return f"{add.data_types[default_data_type].name}{'::Hidden' if hidden else ''}::Register({register_args})" - -def modify_source_files(settings): - includes_to_add = {} - for setting in settings.values(): - for add in setting.adds: - if add.include_path is not None: - header_file_path = add.include_path - relative_include = os.path.relpath(header_file_path, start="src/").replace(os.sep, '/') - file_path = add.call.file - if file_path not in includes_to_add: - includes_to_add[file_path] = set() - includes_to_add[file_path].add(f"#include <{relative_include}>\n") - - if add.hidden_args is None: - new_call = register_str(add) - elif add.hidden_args: - new_call = "" - for hadd in add.hidden_args: - if new_call: new_call += ";\n" - spaces=re.match(" *", hadd.call.call_text).group() - new_call += f"{spaces}{register_str(hadd.nonhidden_arg or hadd, hidden=hadd.nonhidden_arg is not None)}" - del add.hidden_args[:] - else: - continue - - with open(file_path, 'r') as f: - content = f.read() - new_content = content.replace( - add.call.call_text, - new_call, - ) - with open(file_path, 'w') as f: - f.write(new_content) - # map file path -> list (old, new) replacement tuples made so far - replacements = collections.defaultdict(list) - for setting in settings.values(): - for get in setting.gets: - # FIXME handle these by generating synthetic AddArg calls without corresponding Register() - if get.add is None: - #import pprint - #print("*"*80) - #print(f"Bad get call with no corresponding type") - #pprint.pprint(get) - continue - header_file_path = get.add.include_path - relative_include = os.path.relpath(header_file_path, start="src/").replace(os.sep, '/') - file_path = get.call.file - if file_path not in includes_to_add: - includes_to_add[file_path] = set() - includes_to_add[file_path].add(f"#include <{relative_include}>\n") - with open(file_path, 'r') as f: - content = f.read() - if get.data_type == DataType.UNSET: - method = "Value" - suffix = ".isNull()" - elif get.data_type == DataType.DISABLED: - method = "Value" - suffix = ".isFalse()" - else: - method = "Get" - suffix = "" - setting_type = get.add.data_types.get(get.data_type) or get.add.data_types[min(get.add.data_types.keys())] - default_arg = "" - if get.default_value and not setting_type.default_value: - default_arg = (get.default_value if get.default_value is not True else - '""' if get.data_type == DataType.STRING else - "0" if get.data_type == DataType.INT else - "false" if get.data_type == DataType.BOOL else "{}") - default_arg = f", {default_arg}" - old = get.call.call_text - new = ((get.nots + (get.data_type == DataType.UNSET)) % 2) * "!" - if get.add.call.namespace and get.call.namespace != get.add.call.namespace: - new += f"{get.add.call.namespace}::" - new += f"{setting_type.name}::{method}({get.call.obj_name}{default_arg}){suffix}" - for o, n in replacements[file_path]: - old = old.replace(o, n) - new = new.replace(o, n) - replacements[file_path].append((old, new)) - new_content = content.replace(old, new) - with open(file_path, 'w') as f: - f.write(new_content) - # Add necessary includes to files - for file_path, includes in includes_to_add.items(): - add_to_file(file_path, includes) - -def get_file_context(path): - if path in ["src/bitcoin-cli.cpp"]: return "cli" - if path in ["src/bitcoin-tx.cpp"]: return "tx" - if path in ["src/bitcoin-util.cpp"]: return "util" - if path in ["src/bitcoin-wallet.cpp", "src/wallet/wallettool.cpp"]: return "wallet" - if path in ["src/dummywallet.cpp"]: return "dummywallet" - if path.startswith("src/qt/"): return "gui" - if path in ["src/test/argsman_tests.cpp", "src/test/logging_tests.cpp,", "src/test/fuzz/system.cpp", "src/test/getarg_tests.cpp"]: return "test" - if path in ["src/zmq/zmqnotificationinterface.cpp"]: return "test" # FIX - return "main" - -def get_file_namespace(path): - if path.startswith("src/wallet/"): return "wallet" - return "" - -@dataclass -class PatternOptions: - include_path: str | None = None - runtime: bool = False - extern: bool = False - namespace: str | None = None - -# Expression patterns to look for in AddArg / GetArg calls, and options -# controlling what to do when patterns are matched. -ARG_PATTERNS = { - # Constants - "BITCOIN_CONF_FILENAME": PatternOptions(include_path="common/args.h", runtime=True), - "BITCOIN_PID_FILENAME": PatternOptions(include_path="init.h", runtime=True), - "BITCOIN_SETTINGS_FILENAME": PatternOptions(include_path="common/args.h", runtime=True), - "COOKIEAUTH_FILE": PatternOptions(extern=True), - "CURRENCY_UNIT": PatternOptions(include_path="policy/feerate.h", runtime=True), - "DEFAULT_ACCEPT_STALE_FEE_ESTIMATES": PatternOptions(include_path="policy/fees.h"), - "DEFAULT_ADDRESS_TYPE": PatternOptions(include_path="wallet/wallet.h"), - "DEFAULT_ADDRMAN_CONSISTENCY_CHECKS": PatternOptions(include_path="addrman.h"), - "DEFAULT_ASMAP_FILENAME": PatternOptions(include_path="init.h", runtime=True), - "DEFAULT_AVOIDPARTIALSPENDS": PatternOptions(include_path="wallet/coincontrol.h", runtime=True), - "DEFAULT_BENCH_FILTER": PatternOptions(runtime=True), - "DEFAULT_BLOCKFILTERINDEX": PatternOptions(include_path="index/blockfilterindex.h"), - "DEFAULT_BLOCKFILTERINDEX": PatternOptions(include_path="index/blockfilterindex.h", runtime=True), - "DEFAULT_BLOCK_RECONSTRUCTION_EXTRA_TXN": PatternOptions(include_path="net_processing.h"), - "DEFAULT_CHOOSE_DATADIR": PatternOptions(include_path="qt/intro.h"), - "DEFAULT_COINSTATSINDEX": PatternOptions(include_path="index/coinstatsindex.h"), - "DEFAULT_COLOR_SETTING": PatternOptions(runtime=True), - "DEFAULT_DAEMON": PatternOptions(include_path="init.h"), - "DEFAULT_DEBUGLOGFILE": PatternOptions(include_path="logging.h", runtime=True), - "DEFAULT_DISABLE_WALLET": PatternOptions(include_path="wallet/wallet.h", namespace="wallet"), - "DEFAULT_HTTP_SERVER_TIMEOUT": PatternOptions(include_path="httpserver.h"), - "DEFAULT_LISTEN": PatternOptions(include_path="net.h"), - "DEFAULT_MAX_MEMPOOL_SIZE_MB": PatternOptions(include_path="kernel/mempool_options.h"), - "DEFAULT_MAX_TRIES": PatternOptions(include_path="rpc/mining.h"), - "DEFAULT_MAX_UPLOAD_TARGET": PatternOptions(include_path="net.h", runtime=True), - "DEFAULT_MISBEHAVING_BANTIME": PatternOptions(include_path="banman.h"), - "DEFAULT_NATPMP": PatternOptions(include_path="mapport.h"), - "DEFAULT_NBLOCKS": PatternOptions(runtime=True), - "DEFAULT_PERSIST_MEMPOOL": PatternOptions(include_path="node/mempool_persist_args.h", namespace="node"), - "DEFAULT_PRINT_MODIFIED_FEE": PatternOptions(include_path="node/miner.h"), - "DEFAULT_PRIORITY": PatternOptions(runtime=True), - "DEFAULT_SPLASHSCREEN": PatternOptions(include_path="qt/guiconstants.h"), - "DEFAULT_STOPATHEIGHT": PatternOptions(include_path="node/kernel_notifications.h"), - "DEFAULT_TOR_CONTROL": PatternOptions(include_path="torcontrol.h", runtime=True), - "DEFAULT_TOR_CONTROL_PORT": PatternOptions(include_path="torcontrol.h"), - "DEFAULT_TXINDEX": PatternOptions(include_path="index/txindex.h"), - "DEFAULT_UIPLATFORM": PatternOptions(include_path="qt/bitcoingui.h", runtime=True), - "DEFAULT_VALIDATION_CACHE_BYTES": PatternOptions(include_path="script/sigcache.h"), - "DEFAULT_XOR_BLOCKSDIR": PatternOptions(include_path="kernel/blockmanager_opts.h"), - "DEFAULT_ZMQ_SNDHWM": PatternOptions(include_path="zmq/zmqabstractnotifier.h"), - "LIST_CHAIN_NAMES": PatternOptions(include_path="chainparamsbase.h"), - "MAX_SCRIPTCHECK_THREADS": PatternOptions(include_path="node/chainstatemanager_args.h"), - "UNIX_EPOCH_TIME": PatternOptions(include_path="rpc/util.h", runtime=True), - - # Chain parameters - "defaultChainParams": PatternOptions(extern=True), - "testnetChainParams": PatternOptions(extern=True), - "testnet4ChainParams": PatternOptions(extern=True), - "signetChainParams": PatternOptions(extern=True), - "regtestChainParams": PatternOptions(extern=True), - "defaultBaseParams": PatternOptions(extern=True), - "testnetBaseParams": PatternOptions(extern=True), - "testnet4BaseParams": PatternOptions(extern=True), - "signetBaseParams": PatternOptions(extern=True), - "regtestBaseParams": PatternOptions(extern=True), - - # Misc expressions used as defaults - "args.": PatternOptions(extern=True), - "BaseParams\\(\\)": PatternOptions(include_path="chainparamsbase.h", runtime=True), - "DatabaseOptions": PatternOptions(include_path="wallet/db.h", runtime=True), - "FormatMoney\\(": PatternOptions(include_path="util/moneystr.h", runtime=True), - "FormatOutputType\\(": PatternOptions(include_path="outputtype.h", runtime=True), - "gArgs": PatternOptions(extern=True), - "Join\\(": PatternOptions(include_path="util/string.h", runtime=True), - "lang_territory": PatternOptions(extern=True), - "ListBlockFilterTypes\\(\\)": PatternOptions(include_path="blockfilter.h", runtime=True), - "LogInstance\\(\\)": PatternOptions(include_path="logging.h", runtime=True), - "mempool_limits.": PatternOptions(extern=True), - "mempool_opts.": PatternOptions(extern=True), - "nBytesPerSigOp": PatternOptions(include_path="policy/settings.h", runtime=True), - "nDefaultDbBatchSize": PatternOptions(include_path="txdb.h"), - "options\\.": PatternOptions(extern=True), - "PathToString\\(": PatternOptions(include_path="util/fs.h", runtime=True), - "pblock->nVersion": PatternOptions(extern=True), - '"regtest only; "': PatternOptions(runtime=True), - '"xxx"': PatternOptions(extern=True), -} - -if __name__ == "__main__": - src_dir = "src/" - settings = collect_argument_information(src_dir) - generate_setting_headers(settings) - modify_source_files(settings) diff --git a/src/addrdb.cpp b/src/addrdb.cpp index 889f7b3859b14..5c9e2ee19adee 100644 --- a/src/addrdb.cpp +++ b/src/addrdb.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -190,7 +191,7 @@ void ReadFromStream(AddrMan& addr, DataStream& ssPeers) util::Result> LoadAddrman(const NetGroupManager& netgroupman, const ArgsManager& args) { - auto check_addrman = std::clamp(args.GetIntArg("-checkaddrman", DEFAULT_ADDRMAN_CONSISTENCY_CHECKS), 0, 1000000); + auto check_addrman = std::clamp(CheckaddrmanSetting::Get(args, DEFAULT_ADDRMAN_CONSISTENCY_CHECKS), 0, 1000000); bool deterministic = HasTestOption(args, "addrman"); // use a deterministic addrman only for tests auto addrman{std::make_unique(netgroupman, deterministic, /*consistency_check_ratio=*/check_addrman)}; diff --git a/src/bench/bench_bitcoin.cpp b/src/bench/bench_bitcoin.cpp index 51f1370fbc596..5c657e737bc80 100644 --- a/src/bench/bench_bitcoin.cpp +++ b/src/bench/bench_bitcoin.cpp @@ -2,14 +2,14 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include #include +#include #include #include +#include #include #include #include -#include #include #include @@ -26,15 +26,14 @@ static void SetupBenchArgs(ArgsManager& argsman) SetupHelpOptions(argsman); SetupCommonTestArgs(argsman); - argsman.AddArg("-asymptote=", "Test asymptotic growth of the runtime of an algorithm, if supported by the benchmark", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - argsman.AddArg("-filter=", strprintf("Regular expression filter to select benchmark by name (default: %s)", DEFAULT_BENCH_FILTER), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - argsman.AddArg("-list", "List benchmarks without executing them", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - argsman.AddArg("-min-time=", strprintf("Minimum runtime per benchmark, in milliseconds (default: %d)", DEFAULT_MIN_TIME_MS), ArgsManager::ALLOW_ANY | ArgsManager::DISALLOW_NEGATION, OptionsCategory::OPTIONS); - argsman.AddArg("-output-csv=", "Generate CSV file with the most important benchmark results", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - argsman.AddArg("-output-json=", "Generate JSON file with all benchmark results", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - argsman.AddArg("-sanity-check", "Run benchmarks for only one iteration with no output", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - argsman.AddArg("-priority-level=", strprintf("Run benchmarks of one or multiple priority level(s) (%s), default: '%s'", - benchmark::ListPriorities(), DEFAULT_PRIORITY), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); + AsymptoteSetting::Register(argsman); + FilterSetting::Register(argsman); + ListSetting::Register(argsman); + MinTimeSetting::Register(argsman); + OutputCsvSetting::Register(argsman); + OutputJsonSetting::Register(argsman); + SanityCheckSetting::Register(argsman); + PriorityLevelSetting::Register(argsman); } // parses a comma separated list like "10,20,30,50" @@ -133,14 +132,14 @@ int main(int argc, char** argv) try { benchmark::Args args; - args.asymptote = parseAsymptote(argsman.GetArg("-asymptote", "")); - args.is_list_only = argsman.GetBoolArg("-list", false); - args.min_time = std::chrono::milliseconds(argsman.GetIntArg("-min-time", DEFAULT_MIN_TIME_MS)); - args.output_csv = argsman.GetPathArg("-output-csv"); - args.output_json = argsman.GetPathArg("-output-json"); - args.regex_filter = argsman.GetArg("-filter", DEFAULT_BENCH_FILTER); - args.sanity_check = argsman.GetBoolArg("-sanity-check", false); - args.priority = parsePriorityLevel(argsman.GetArg("-priority-level", DEFAULT_PRIORITY)); + args.asymptote = parseAsymptote(AsymptoteSetting::Get(argsman)); + args.is_list_only = ListSetting::Get(argsman); + args.min_time = std::chrono::milliseconds(MinTimeSetting::Get(argsman)); + args.output_csv = OutputCsvSetting::Get(argsman); + args.output_json = OutputJsonSetting::Get(argsman); + args.regex_filter = FilterSetting::Get(argsman); + args.sanity_check = SanityCheckSetting::Get(argsman); + args.priority = parsePriorityLevel(PriorityLevelSetting::Get(argsman)); args.setup_args = parseTestSetupArgs(argsman); benchmark::BenchRunner::RunAll(args); diff --git a/src/bench/bench_bitcoin_settings.h b/src/bench/bench_bitcoin_settings.h index 457d90f57cd10..3c92bff13dcf2 100644 --- a/src/bench/bench_bitcoin_settings.h +++ b/src/bench/bench_bitcoin_settings.h @@ -5,12 +5,51 @@ #ifndef BITCOIN_BENCH_BENCH_BITCOIN_SETTINGS_H #define BITCOIN_BENCH_BENCH_BITCOIN_SETTINGS_H +#include + #include #include +#include static const char* DEFAULT_BENCH_FILTER = ".*"; static constexpr int64_t DEFAULT_MIN_TIME_MS{10}; /** Priority level default value, run "all" priority levels */ static constexpr auto DEFAULT_PRIORITY{"all"}; +using AsymptoteSetting = common::Setting< + "-asymptote=", std::string, common::SettingOptions{.legacy = true}, + "Test asymptotic growth of the runtime of an algorithm, if supported by the benchmark">; + +using FilterSetting = common::Setting< + "-filter=", std::string, common::SettingOptions{.legacy = true}, + "Regular expression filter to select benchmark by name (default: %s)"> + ::DefaultFn<[] { return DEFAULT_BENCH_FILTER; }>; + +using ListSetting = common::Setting< + "-list", bool, common::SettingOptions{.legacy = true}, + "List benchmarks without executing them">; + +using MinTimeSetting = common::Setting< + "-min-time=", int64_t, common::SettingOptions{.legacy = true, .disallow_negation = true}, + "Minimum runtime per benchmark, in milliseconds (default: %d)"> + ::Default; + +using OutputCsvSetting = common::Setting< + "-output-csv=", fs::path, common::SettingOptions{.legacy = true}, + "Generate CSV file with the most important benchmark results">; + +using OutputJsonSetting = common::Setting< + "-output-json=", fs::path, common::SettingOptions{.legacy = true}, + "Generate JSON file with all benchmark results">; + +using SanityCheckSetting = common::Setting< + "-sanity-check", bool, common::SettingOptions{.legacy = true}, + "Run benchmarks for only one iteration with no output">; + +using PriorityLevelSetting = common::Setting< + "-priority-level=", std::string, common::SettingOptions{.legacy = true}, + "Run benchmarks of one or multiple priority level(s) (%s), default: '%s'"> + ::DefaultFn<[] { return DEFAULT_PRIORITY; }> + ::HelpFn<[](const auto& fmt) { return strprintf(fmt, benchmark::ListPriorities(), DEFAULT_PRIORITY); }>; + #endif // BITCOIN_BENCH_BENCH_BITCOIN_SETTINGS_H diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp index 829a728bfa4cf..10c475b1a9ac0 100644 --- a/src/bitcoin-cli.cpp +++ b/src/bitcoin-cli.cpp @@ -70,34 +70,29 @@ static void SetupCliArgs(ArgsManager& argsman) const auto signetBaseParams = CreateBaseChainParams(ChainType::SIGNET); const auto regtestBaseParams = CreateBaseChainParams(ChainType::REGTEST); - argsman.AddArg("-version", "Print version and exit", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - argsman.AddArg("-conf=", strprintf("Specify configuration file. Relative paths will be prefixed by datadir location. (default: %s)", BITCOIN_CONF_FILENAME), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - argsman.AddArg("-datadir=", "Specify data directory", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - argsman.AddArg("-generate", - strprintf("Generate blocks, equivalent to RPC getnewaddress followed by RPC generatetoaddress. Optional positional integer " - "arguments are number of blocks to generate (default: %s) and maximum iterations to try (default: %s), equivalent to " - "RPC generatetoaddress nblocks and maxtries arguments. Example: bitcoin-cli -generate 4 1000", - DEFAULT_NBLOCKS, DEFAULT_MAX_TRIES), - ArgsManager::ALLOW_ANY, OptionsCategory::CLI_COMMANDS); - argsman.AddArg("-addrinfo", "Get the number of addresses known to the node, per network and total, after filtering for quality and recency. The total number of addresses known to the node may be higher.", ArgsManager::ALLOW_ANY, OptionsCategory::CLI_COMMANDS); - argsman.AddArg("-getinfo", "Get general information from the remote server. Note that unlike server-side RPC calls, the output of -getinfo is the result of multiple non-atomic requests. Some entries in the output may represent results from different states (e.g. wallet balance may be as of a different block from the chain state reported)", ArgsManager::ALLOW_ANY, OptionsCategory::CLI_COMMANDS); - argsman.AddArg("-netinfo", strprintf("Get network peer connection information from the remote server. An optional argument from 0 to %d can be passed for different peers listings (default: 0). If a non-zero value is passed, an additional \"outonly\" (or \"o\") argument can be passed to see outbound peers only. Pass \"help\" (or \"h\") for detailed help documentation.", NETINFO_MAX_LEVEL), ArgsManager::ALLOW_ANY, OptionsCategory::CLI_COMMANDS); + VersionSetting::Register(argsman); + ConfSetting::Register(argsman); + DatadirSetting::Register(argsman); + GenerateSetting::Register(argsman); + AddrinfoSetting::Register(argsman); + GetinfoSetting::Register(argsman); + NetinfoSetting::Register(argsman); SetupChainParamsBaseOptions(argsman); - argsman.AddArg("-color=", 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_ANY | ArgsManager::DISALLOW_NEGATION, OptionsCategory::OPTIONS); - argsman.AddArg("-named", strprintf("Pass named instead of positional arguments (default: %s)", DEFAULT_NAMED), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - argsman.AddArg("-rpcclienttimeout=", strprintf("Timeout in seconds during HTTP requests, or 0 for no timeout. (default: %d)", DEFAULT_HTTP_CLIENT_TIMEOUT), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - argsman.AddArg("-rpcconnect=", strprintf("Send commands to node running on (default: %s)", DEFAULT_RPCCONNECT), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - argsman.AddArg("-rpccookiefile=", "Location of the auth cookie. Relative paths will be prefixed by a net-specific datadir location. (default: data dir)", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - argsman.AddArg("-rpcpassword=", "Password for JSON-RPC connections", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - argsman.AddArg("-rpcport=", strprintf("Connect to JSON-RPC on (default: %u, testnet: %u, testnet4: %u, signet: %u, regtest: %u)", defaultBaseParams->RPCPort(), testnetBaseParams->RPCPort(), testnet4BaseParams->RPCPort(), signetBaseParams->RPCPort(), regtestBaseParams->RPCPort()), ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::OPTIONS); - argsman.AddArg("-rpcuser=", "Username for JSON-RPC connections", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - argsman.AddArg("-rpcwait", "Wait for RPC server to start", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - argsman.AddArg("-rpcwaittimeout=", strprintf("Timeout in seconds to wait for the RPC server to start, or 0 for no timeout. (default: %d)", DEFAULT_WAIT_CLIENT_TIMEOUT), ArgsManager::ALLOW_ANY | ArgsManager::DISALLOW_NEGATION, OptionsCategory::OPTIONS); - argsman.AddArg("-rpcwallet=", "Send RPC for non-default wallet on RPC server (needs to exactly match corresponding -wallet option passed to bitcoind). This changes the RPC endpoint used, e.g. http://127.0.0.1:8332/wallet/", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - argsman.AddArg("-stdin", "Read extra arguments from standard input, one per line until EOF/Ctrl-D (recommended for sensitive information such as passphrases). When combined with -stdinrpcpass, the first line from standard input is used for the RPC password.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - argsman.AddArg("-stdinrpcpass", "Read RPC password from standard input as a single line. When combined with -stdin, the first line from standard input is used for the RPC password. When combined with -stdinwalletpassphrase, -stdinrpcpass consumes the first line, and -stdinwalletpassphrase consumes the second.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - argsman.AddArg("-stdinwalletpassphrase", "Read wallet passphrase from standard input as a single line. When combined with -stdin, the first line from standard input is used for the wallet passphrase.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); + ColorSetting::Register(argsman); + NamedSetting::Register(argsman); + RpcclienttimeoutSetting::Register(argsman); + RpcconnectSetting::Register(argsman); + RpccookiefileSetting::Register(argsman); + RpcpasswordSetting::Register(argsman); + RpcportSetting::Register(argsman, defaultBaseParams, testnetBaseParams, testnet4BaseParams, signetBaseParams, regtestBaseParams); + RpcuserSetting::Register(argsman); + RpcwaitSetting::Register(argsman); + RpcwaittimeoutSetting::Register(argsman); + RpcwalletSetting::Register(argsman); + StdinSetting::Register(argsman); + StdinrpcpassSetting::Register(argsman); + StdinwalletpassphraseSetting::Register(argsman); } /** libevent event log callback */ @@ -135,10 +130,10 @@ static int AppInitRPC(int argc, char* argv[]) tfm::format(std::cerr, "Error parsing command line arguments: %s\n", error); return EXIT_FAILURE; } - if (argc < 2 || HelpRequested(gArgs) || gArgs.IsArgSet("-version")) { + if (argc < 2 || HelpRequested(gArgs) || !VersionSetting::Value(gArgs).isNull()) { std::string strUsage = CLIENT_NAME " RPC client version " + FormatFullVersion() + "\n"; - if (gArgs.IsArgSet("-version")) { + if (!VersionSetting::Value(gArgs).isNull()) { strUsage += FormatParagraph(LicenseInfo()); } else { strUsage += "\n" @@ -163,7 +158,7 @@ static int AppInitRPC(int argc, char* argv[]) return EXIT_SUCCESS; } if (!CheckDataDirOption(gArgs)) { - tfm::format(std::cerr, "Error: Specified data directory \"%s\" does not exist.\n", gArgs.GetArg("-datadir", "")); + tfm::format(std::cerr, "Error: Specified data directory \"%s\" does not exist.\n", DatadirSetting::Get(gArgs)); return EXIT_FAILURE; } if (!gArgs.ReadConfigFiles(error, true)) { @@ -763,7 +758,7 @@ class DefaultRequestHandler: public BaseRequestHandler { UniValue PrepareRequest(const std::string& method, const std::vector& args) override { UniValue params; - if(gArgs.GetBoolArg("-named", DEFAULT_NAMED)) { + if(NamedSetting::Get(gArgs)) { params = RPCConvertNamedValues(method, args); } else { params = RPCConvertValues(method, args); @@ -787,7 +782,7 @@ static UniValue CallRPC(BaseRequestHandler* rh, const std::string& strMethod, co uint16_t port{BaseParams().RPCPort()}; { uint16_t rpcconnect_port{0}; - const std::string rpcconnect_str = gArgs.GetArg("-rpcconnect", DEFAULT_RPCCONNECT); + const std::string rpcconnect_str = RpcconnectSetting::Get(gArgs); if (!SplitHostPort(rpcconnect_str, rpcconnect_port, host)) { // Uses argument provided as-is // (rather than value parsed) @@ -800,7 +795,7 @@ static UniValue CallRPC(BaseRequestHandler* rh, const std::string& strMethod, co } // else, no port was provided in rpcconnect (continue using default one) } - if (std::optional rpcport_arg = gArgs.GetArg("-rpcport")) { + if (std::optional rpcport_arg = RpcportSetting::Get(gArgs)) { // -rpcport was specified const uint16_t rpcport_int{ToIntegral(rpcport_arg.value()).value_or(0)}; if (rpcport_int == 0) { @@ -829,7 +824,7 @@ static UniValue CallRPC(BaseRequestHandler* rh, const std::string& strMethod, co // Set connection timeout { - const int timeout = gArgs.GetIntArg("-rpcclienttimeout", DEFAULT_HTTP_CLIENT_TIMEOUT); + const int timeout = RpcclienttimeoutSetting::Get(gArgs); if (timeout > 0) { evhttp_connection_set_timeout(evcon.get(), timeout); } else { @@ -852,13 +847,13 @@ static UniValue CallRPC(BaseRequestHandler* rh, const std::string& strMethod, co // Get credentials std::string strRPCUserColonPass; bool failedToGetAuthCookie = false; - if (gArgs.GetArg("-rpcpassword", "") == "") { + if (RpcpasswordSetting::Get(gArgs) == "") { // Try fall back to cookie-based authentication if no password is provided if (!GetAuthCookie(&strRPCUserColonPass)) { failedToGetAuthCookie = true; } } else { - strRPCUserColonPass = gArgs.GetArg("-rpcuser", "") + ":" + gArgs.GetArg("-rpcpassword", ""); + strRPCUserColonPass = RpcuserSetting::Get(gArgs) + ":" + RpcpasswordSetting::Get(gArgs); } struct evkeyvalq* output_headers = evhttp_request_get_output_headers(req.get()); @@ -941,8 +936,8 @@ static UniValue ConnectAndCallRPC(BaseRequestHandler* rh, const std::string& str { UniValue response(UniValue::VOBJ); // Execute and handle connection failures with -rpcwait. - const bool fWait = gArgs.GetBoolArg("-rpcwait", false); - const int timeout = gArgs.GetIntArg("-rpcwaittimeout", DEFAULT_WAIT_CLIENT_TIMEOUT); + const bool fWait = RpcwaitSetting::Get(gArgs); + const int timeout = RpcwaittimeoutSetting::Get(gArgs); const auto deadline{std::chrono::steady_clock::now() + 1s * timeout}; do { @@ -1061,8 +1056,8 @@ static void ParseGetInfoResult(UniValue& result) } #endif - if (gArgs.IsArgSet("-color")) { - const std::string color{gArgs.GetArg("-color", DEFAULT_COLOR_SETTING)}; + if (!ColorSetting::Value(gArgs).isNull()) { + const std::string color{ColorSetting::Get(gArgs)}; if (color == "always") { should_colorize = true; } else if (color == "never") { @@ -1174,7 +1169,7 @@ static void ParseGetInfoResult(UniValue& result) static UniValue GetNewAddress() { std::optional wallet_name{}; - if (gArgs.IsArgSet("-rpcwallet")) wallet_name = gArgs.GetArg("-rpcwallet", ""); + if (!RpcwalletSetting::Value(gArgs).isNull()) wallet_name = RpcwalletSetting::Get(gArgs); DefaultRequestHandler rh; return ConnectAndCallRPC(&rh, "getnewaddress", /* args=*/{}, wallet_name); } @@ -1206,7 +1201,7 @@ static int CommandLineRPC(int argc, char *argv[]) argv++; } std::string rpcPass; - if (gArgs.GetBoolArg("-stdinrpcpass", false)) { + if (StdinrpcpassSetting::Get(gArgs)) { NO_STDIN_ECHO(); if (!StdinReady()) { fputs("RPC password> ", stderr); @@ -1221,7 +1216,7 @@ static int CommandLineRPC(int argc, char *argv[]) gArgs.ForceSetArg("-rpcpassword", rpcPass); } std::vector args = std::vector(&argv[1], &argv[argc]); - if (gArgs.GetBoolArg("-stdinwalletpassphrase", false)) { + if (StdinwalletpassphraseSetting::Get(gArgs)) { NO_STDIN_ECHO(); std::string walletPass; if (args.size() < 1 || args[0].substr(0, 16) != "walletpassphrase") { @@ -1239,7 +1234,7 @@ static int CommandLineRPC(int argc, char *argv[]) } args.insert(args.begin() + 1, walletPass); } - if (gArgs.GetBoolArg("-stdin", false)) { + if (StdinSetting::Get(gArgs)) { // Read one arg per line from stdin and append std::string line; while (std::getline(std::cin, line)) { @@ -1252,15 +1247,15 @@ static int CommandLineRPC(int argc, char *argv[]) gArgs.CheckMultipleCLIArgs(); std::unique_ptr rh; std::string method; - if (gArgs.IsArgSet("-getinfo")) { + if (!GetinfoSetting::Value(gArgs).isNull()) { rh.reset(new GetinfoRequestHandler()); - } else if (gArgs.GetBoolArg("-netinfo", false)) { + } else if (NetinfoSetting::Get(gArgs)) { if (!args.empty() && (args.at(0) == "h" || args.at(0) == "help")) { tfm::format(std::cout, "%s\n", NetinfoRequestHandler().m_help_doc); return 0; } rh.reset(new NetinfoRequestHandler()); - } else if (gArgs.GetBoolArg("-generate", false)) { + } else if (GenerateSetting::Get(gArgs)) { const UniValue getnewaddress{GetNewAddress()}; const UniValue& error{getnewaddress.find_value("error")}; if (error.isNull()) { @@ -1269,7 +1264,7 @@ static int CommandLineRPC(int argc, char *argv[]) } else { ParseError(error, strPrint, nRet); } - } else if (gArgs.GetBoolArg("-addrinfo", false)) { + } else if (AddrinfoSetting::Get(gArgs)) { rh.reset(new AddrinfoRequestHandler()); } else { rh.reset(new DefaultRequestHandler()); @@ -1282,15 +1277,15 @@ static int CommandLineRPC(int argc, char *argv[]) if (nRet == 0) { // Perform RPC call std::optional wallet_name{}; - if (gArgs.IsArgSet("-rpcwallet")) wallet_name = gArgs.GetArg("-rpcwallet", ""); + if (!RpcwalletSetting::Value(gArgs).isNull()) wallet_name = RpcwalletSetting::Get(gArgs); const UniValue reply = ConnectAndCallRPC(rh.get(), method, args, wallet_name); // Parse reply UniValue result = reply.find_value("result"); const UniValue& error = reply.find_value("error"); if (error.isNull()) { - if (gArgs.GetBoolArg("-getinfo", false)) { - if (!gArgs.IsArgSet("-rpcwallet")) { + if (GetinfoSetting::Get(gArgs)) { + if (RpcwalletSetting::Value(gArgs).isNull()) { GetWalletBalances(result); // fetch multiwallet balances and append to result } ParseGetInfoResult(result); diff --git a/src/bitcoin-cli_settings.h b/src/bitcoin-cli_settings.h index b214dbe98adb7..3705a2834ed54 100644 --- a/src/bitcoin-cli_settings.h +++ b/src/bitcoin-cli_settings.h @@ -5,8 +5,13 @@ #ifndef BITCOIN_BITCOIN_CLI_SETTINGS_H #define BITCOIN_BITCOIN_CLI_SETTINGS_H +#include +#include +#include + #include #include +#include static const char DEFAULT_RPCCONNECT[] = "127.0.0.1"; static const int DEFAULT_HTTP_CLIENT_TIMEOUT=900; @@ -20,4 +25,103 @@ static constexpr auto DEFAULT_NBLOCKS = "1"; /** Default -color setting. */ static constexpr auto DEFAULT_COLOR_SETTING{"auto"}; +using VersionSetting = common::Setting< + "-version", common::Unset, common::SettingOptions{.legacy = true}, + "Print version and exit">; + +using ConfSetting = common::Setting< + "-conf=", common::Unset, common::SettingOptions{.legacy = true}, + "Specify configuration file. Relative paths will be prefixed by datadir location. (default: %s)"> + ::HelpFn<[](const auto& fmt) { return strprintf(fmt, BITCOIN_CONF_FILENAME); }>; + +using DatadirSetting = common::Setting< + "-datadir=", std::string, common::SettingOptions{.legacy = true}, + "Specify data directory">; + +using GenerateSetting = common::Setting< + "-generate", bool, common::SettingOptions{.legacy = true}, + "Generate blocks, equivalent to RPC getnewaddress followed by RPC generatetoaddress. Optional positional integer " + "arguments are number of blocks to generate (default: %s) and maximum iterations to try (default: %s), equivalent to " + "RPC generatetoaddress nblocks and maxtries arguments. Example: bitcoin-cli -generate 4 1000"> + ::HelpFn<[](const auto& fmt) { return strprintf(fmt, DEFAULT_NBLOCKS, DEFAULT_MAX_TRIES); }> + ::Category; + +using AddrinfoSetting = common::Setting< + "-addrinfo", bool, common::SettingOptions{.legacy = true}, + "Get the number of addresses known to the node, per network and total, after filtering for quality and recency. The total number of addresses known to the node may be higher."> + ::Category; + +using GetinfoSetting = common::Setting< + "-getinfo", bool, common::SettingOptions{.legacy = true}, + "Get general information from the remote server. Note that unlike server-side RPC calls, the output of -getinfo is the result of multiple non-atomic requests. Some entries in the output may represent results from different states (e.g. wallet balance may be as of a different block from the chain state reported)"> + ::Category; + +using NetinfoSetting = common::Setting< + "-netinfo", bool, common::SettingOptions{.legacy = true}, + "Get network peer connection information from the remote server. An optional argument from 0 to %d can be passed for different peers listings (default: 0). If a non-zero value is passed, an additional \"outonly\" (or \"o\") argument can be passed to see outbound peers only. Pass \"help\" (or \"h\") for detailed help documentation."> + ::HelpArgs + ::Category; + +using ColorSetting = common::Setting< + "-color=", std::string, common::SettingOptions{.legacy = true, .disallow_negation = true}, + "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."> + ::DefaultFn<[] { return DEFAULT_COLOR_SETTING; }>; + +using NamedSetting = common::Setting< + "-named", bool, common::SettingOptions{.legacy = true}, + "Pass named instead of positional arguments (default: %s)"> + ::Default; + +using RpcclienttimeoutSetting = common::Setting< + "-rpcclienttimeout=", int64_t, common::SettingOptions{.legacy = true}, + "Timeout in seconds during HTTP requests, or 0 for no timeout. (default: %d)"> + ::Default; + +using RpcconnectSetting = common::Setting< + "-rpcconnect=", std::string, common::SettingOptions{.legacy = true}, + "Send commands to node running on (default: %s)"> + ::Default; + +using RpccookiefileSetting = common::Setting< + "-rpccookiefile=", common::Unset, common::SettingOptions{.legacy = true}, + "Location of the auth cookie. Relative paths will be prefixed by a net-specific datadir location. (default: data dir)">; + +using RpcpasswordSetting = common::Setting< + "-rpcpassword=", std::string, common::SettingOptions{.legacy = true}, + "Password for JSON-RPC connections">; + +using RpcportSetting = common::Setting< + "-rpcport=", std::optional, common::SettingOptions{.legacy = true, .network_only = true}, + "Connect to JSON-RPC on (default: %u, testnet: %u, testnet4: %u, signet: %u, regtest: %u)"> + ::HelpFn<[](const auto& fmt, const auto& defaultBaseParams, const auto& testnetBaseParams, const auto& testnet4BaseParams, const auto& signetBaseParams, const auto& regtestBaseParams) { return strprintf(fmt, defaultBaseParams->RPCPort(), testnetBaseParams->RPCPort(), testnet4BaseParams->RPCPort(), signetBaseParams->RPCPort(), regtestBaseParams->RPCPort()); }>; + +using RpcuserSetting = common::Setting< + "-rpcuser=", std::string, common::SettingOptions{.legacy = true}, + "Username for JSON-RPC connections">; + +using RpcwaitSetting = common::Setting< + "-rpcwait", bool, common::SettingOptions{.legacy = true}, + "Wait for RPC server to start">; + +using RpcwaittimeoutSetting = common::Setting< + "-rpcwaittimeout=", int64_t, common::SettingOptions{.legacy = true, .disallow_negation = true}, + "Timeout in seconds to wait for the RPC server to start, or 0 for no timeout. (default: %d)"> + ::Default; + +using RpcwalletSetting = common::Setting< + "-rpcwallet=", std::string, common::SettingOptions{.legacy = true}, + "Send RPC for non-default wallet on RPC server (needs to exactly match corresponding -wallet option passed to bitcoind). This changes the RPC endpoint used, e.g. http://127.0.0.1:8332/wallet/">; + +using StdinSetting = common::Setting< + "-stdin", bool, common::SettingOptions{.legacy = true}, + "Read extra arguments from standard input, one per line until EOF/Ctrl-D (recommended for sensitive information such as passphrases). When combined with -stdinrpcpass, the first line from standard input is used for the RPC password.">; + +using StdinrpcpassSetting = common::Setting< + "-stdinrpcpass", bool, common::SettingOptions{.legacy = true}, + "Read RPC password from standard input as a single line. When combined with -stdin, the first line from standard input is used for the RPC password. When combined with -stdinwalletpassphrase, -stdinrpcpass consumes the first line, and -stdinwalletpassphrase consumes the second.">; + +using StdinwalletpassphraseSetting = common::Setting< + "-stdinwalletpassphrase", bool, common::SettingOptions{.legacy = true}, + "Read wallet passphrase from standard input as a single line. When combined with -stdin, the first line from standard input is used for the wallet passphrase.">; + #endif // BITCOIN_BITCOIN_CLI_SETTINGS_H diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp index 1561510db8bf4..672430ef11d16 100644 --- a/src/bitcoin-tx.cpp +++ b/src/bitcoin-tx.cpp @@ -4,6 +4,7 @@ #include // IWYU pragma: keep +#include #include #include #include @@ -47,39 +48,27 @@ static void SetupBitcoinTxArgs(ArgsManager &argsman) { SetupHelpOptions(argsman); - argsman.AddArg("-version", "Print version and exit", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - argsman.AddArg("-create", "Create new, empty TX.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - argsman.AddArg("-json", "Select JSON output", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - argsman.AddArg("-txid", "Output only the hex-encoded transaction id of the resultant transaction.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); + VersionSetting::Register(argsman); + CreateSetting::Register(argsman); + JsonSetting::Register(argsman); + TxidSetting::Register(argsman); SetupChainParamsBaseOptions(argsman); - argsman.AddArg("delin=N", "Delete input N from TX", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS); - argsman.AddArg("delout=N", "Delete output N from TX", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS); - argsman.AddArg("in=TXID:VOUT(:SEQUENCE_NUMBER)", "Add input to TX", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS); - argsman.AddArg("locktime=N", "Set TX lock time to N", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS); - argsman.AddArg("nversion=N", "Set TX version to N", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS); - argsman.AddArg("outaddr=VALUE:ADDRESS", "Add address-based output to TX", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS); - argsman.AddArg("outdata=[VALUE:]DATA", "Add data-based output to TX", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS); - argsman.AddArg("outmultisig=VALUE:REQUIRED:PUBKEYS:PUBKEY1:PUBKEY2:....[:FLAGS]", "Add Pay To n-of-m Multi-sig output to TX. n = REQUIRED, m = PUBKEYS. " - "Optionally add the \"W\" flag to produce a pay-to-witness-script-hash output. " - "Optionally add the \"S\" flag to wrap the output in a pay-to-script-hash.", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS); - argsman.AddArg("outpubkey=VALUE:PUBKEY[:FLAGS]", "Add pay-to-pubkey output to TX. " - "Optionally add the \"W\" flag to produce a pay-to-witness-pubkey-hash output. " - "Optionally add the \"S\" flag to wrap the output in a pay-to-script-hash.", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS); - argsman.AddArg("outscript=VALUE:SCRIPT[:FLAGS]", "Add raw script output to TX. " - "Optionally add the \"W\" flag to produce a pay-to-witness-script-hash output. " - "Optionally add the \"S\" flag to wrap the output in a pay-to-script-hash.", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS); - argsman.AddArg("replaceable(=N)", "Sets Replace-By-Fee (RBF) opt-in sequence number for input N. " - "If N is not provided, the command attempts to opt-in all available inputs for RBF. " - "If the transaction has no inputs, this option is ignored.", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS); - argsman.AddArg("sign=SIGHASH-FLAGS", "Add zero or more signatures to transaction. " - "This command requires JSON registers:" - "prevtxs=JSON object, " - "privatekeys=JSON object. " - "See signrawtransactionwithkey docs for format of sighash flags, JSON objects.", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS); - - argsman.AddArg("load=NAME:FILENAME", "Load JSON file FILENAME into register NAME", ArgsManager::ALLOW_ANY, OptionsCategory::REGISTER_COMMANDS); - argsman.AddArg("set=NAME:JSON-STRING", "Set register NAME to given JSON-STRING", ArgsManager::ALLOW_ANY, OptionsCategory::REGISTER_COMMANDS); + DelinSetting::Register(argsman); + DeloutSetting::Register(argsman); + InSetting::Register(argsman); + LocktimeSetting::Register(argsman); + NversionSetting::Register(argsman); + OutaddrSetting::Register(argsman); + OutdataSetting::Register(argsman); + OutmultisigSetting::Register(argsman); + OutpubkeySetting::Register(argsman); + OutscriptSetting::Register(argsman); + ReplaceableSetting::Register(argsman); + SignSetting::Register(argsman); + + LoadSetting::Register(argsman); + SetSetting::Register(argsman); } // @@ -103,13 +92,13 @@ static int AppInitRawTx(int argc, char* argv[]) return EXIT_FAILURE; } - fCreateBlank = gArgs.GetBoolArg("-create", false); + fCreateBlank = CreateSetting::Get(gArgs); - if (argc < 2 || HelpRequested(gArgs) || gArgs.IsArgSet("-version")) { + if (argc < 2 || HelpRequested(gArgs) || !VersionSetting::Value(gArgs).isNull()) { // First part of help message is specific to this utility std::string strUsage = CLIENT_NAME " bitcoin-tx utility version " + FormatFullVersion() + "\n"; - if (gArgs.IsArgSet("-version")) { + if (!VersionSetting::Value(gArgs).isNull()) { strUsage += FormatParagraph(LicenseInfo()); } else { strUsage += "\n" @@ -773,9 +762,9 @@ static void OutputTxHex(const CTransaction& tx) static void OutputTx(const CTransaction& tx) { - if (gArgs.GetBoolArg("-json", false)) + if (JsonSetting::Get(gArgs)) OutputTxJSON(tx); - else if (gArgs.GetBoolArg("-txid", false)) + else if (TxidSetting::Get(gArgs)) OutputTxHash(tx); else OutputTxHex(tx); diff --git a/src/bitcoin-tx_settings.h b/src/bitcoin-tx_settings.h new file mode 100644 index 0000000000000..f8c6390fe8ac4 --- /dev/null +++ b/src/bitcoin-tx_settings.h @@ -0,0 +1,107 @@ +#ifndef BITCOIN_BITCOIN_TX_SETTINGS_H +#define BITCOIN_BITCOIN_TX_SETTINGS_H + +#include + +#include +#include + +using VersionSetting = common::Setting< + "-version", common::Unset, common::SettingOptions{.legacy = true}, + "Print version and exit">; + +using CreateSetting = common::Setting< + "-create", bool, common::SettingOptions{.legacy = true}, + "Create new, empty TX.">; + +using JsonSetting = common::Setting< + "-json", bool, common::SettingOptions{.legacy = true}, + "Select JSON output">; + +using TxidSetting = common::Setting< + "-txid", bool, common::SettingOptions{.legacy = true}, + "Output only the hex-encoded transaction id of the resultant transaction.">; + +using DelinSetting = common::Setting< + "delin=N", common::Unset, common::SettingOptions{.legacy = true}, + "Delete input N from TX"> + ::Category; + +using DeloutSetting = common::Setting< + "delout=N", common::Unset, common::SettingOptions{.legacy = true}, + "Delete output N from TX"> + ::Category; + +using InSetting = common::Setting< + "in=TXID:VOUT(:SEQUENCE_NUMBER)", common::Unset, common::SettingOptions{.legacy = true}, + "Add input to TX"> + ::Category; + +using LocktimeSetting = common::Setting< + "locktime=N", common::Unset, common::SettingOptions{.legacy = true}, + "Set TX lock time to N"> + ::Category; + +using NversionSetting = common::Setting< + "nversion=N", common::Unset, common::SettingOptions{.legacy = true}, + "Set TX version to N"> + ::Category; + +using OutaddrSetting = common::Setting< + "outaddr=VALUE:ADDRESS", common::Unset, common::SettingOptions{.legacy = true}, + "Add address-based output to TX"> + ::Category; + +using OutdataSetting = common::Setting< + "outdata=[VALUE:]DATA", common::Unset, common::SettingOptions{.legacy = true}, + "Add data-based output to TX"> + ::Category; + +using OutmultisigSetting = common::Setting< + "outmultisig=VALUE:REQUIRED:PUBKEYS:PUBKEY1:PUBKEY2:....[:FLAGS]", common::Unset, common::SettingOptions{.legacy = true}, + "Add Pay To n-of-m Multi-sig output to TX. n = REQUIRED, m = PUBKEYS. " + "Optionally add the \"W\" flag to produce a pay-to-witness-script-hash output. " + "Optionally add the \"S\" flag to wrap the output in a pay-to-script-hash."> + ::Category; + +using OutpubkeySetting = common::Setting< + "outpubkey=VALUE:PUBKEY[:FLAGS]", common::Unset, common::SettingOptions{.legacy = true}, + "Add pay-to-pubkey output to TX. " + "Optionally add the \"W\" flag to produce a pay-to-witness-pubkey-hash output. " + "Optionally add the \"S\" flag to wrap the output in a pay-to-script-hash."> + ::Category; + +using OutscriptSetting = common::Setting< + "outscript=VALUE:SCRIPT[:FLAGS]", common::Unset, common::SettingOptions{.legacy = true}, + "Add raw script output to TX. " + "Optionally add the \"W\" flag to produce a pay-to-witness-script-hash output. " + "Optionally add the \"S\" flag to wrap the output in a pay-to-script-hash."> + ::Category; + +using ReplaceableSetting = common::Setting< + "replaceable(=N)", common::Unset, common::SettingOptions{.legacy = true}, + "Sets Replace-By-Fee (RBF) opt-in sequence number for input N. " + "If N is not provided, the command attempts to opt-in all available inputs for RBF. " + "If the transaction has no inputs, this option is ignored."> + ::Category; + +using SignSetting = common::Setting< + "sign=SIGHASH-FLAGS", common::Unset, common::SettingOptions{.legacy = true}, + "Add zero or more signatures to transaction. " + "This command requires JSON registers:" + "prevtxs=JSON object, " + "privatekeys=JSON object. " + "See signrawtransactionwithkey docs for format of sighash flags, JSON objects."> + ::Category; + +using LoadSetting = common::Setting< + "load=NAME:FILENAME", common::Unset, common::SettingOptions{.legacy = true}, + "Load JSON file FILENAME into register NAME"> + ::Category; + +using SetSetting = common::Setting< + "set=NAME:JSON-STRING", common::Unset, common::SettingOptions{.legacy = true}, + "Set register NAME to given JSON-STRING"> + ::Category; + +#endif // BITCOIN_BITCOIN_TX_SETTINGS_H diff --git a/src/bitcoin-util.cpp b/src/bitcoin-util.cpp index c7d10b6622b9e..85dcf73120e79 100644 --- a/src/bitcoin-util.cpp +++ b/src/bitcoin-util.cpp @@ -5,6 +5,7 @@ #include // IWYU pragma: keep #include +#include #include #include #include @@ -32,7 +33,7 @@ static void SetupBitcoinUtilArgs(ArgsManager &argsman) { SetupHelpOptions(argsman); - argsman.AddArg("-version", "Print version and exit", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); + VersionSetting::Register(argsman); argsman.AddCommand("grind", "Perform proof of work on hex header string"); @@ -50,11 +51,11 @@ static int AppInitUtil(ArgsManager& args, int argc, char* argv[]) return EXIT_FAILURE; } - if (HelpRequested(args) || args.IsArgSet("-version")) { + if (HelpRequested(args) || !VersionSetting::Value(args).isNull()) { // First part of help message is specific to this utility std::string strUsage = CLIENT_NAME " bitcoin-util utility version " + FormatFullVersion() + "\n"; - if (args.IsArgSet("-version")) { + if (!VersionSetting::Value(args).isNull()) { strUsage += FormatParagraph(LicenseInfo()); } else { strUsage += "\n" diff --git a/src/bitcoin-util_settings.h b/src/bitcoin-util_settings.h new file mode 100644 index 0000000000000..9171987b22b2a --- /dev/null +++ b/src/bitcoin-util_settings.h @@ -0,0 +1,13 @@ +#ifndef BITCOIN_BITCOIN_UTIL_SETTINGS_H +#define BITCOIN_BITCOIN_UTIL_SETTINGS_H + +#include + +#include +#include + +using VersionSetting = common::Setting< + "-version", common::Unset, common::SettingOptions{.legacy = true}, + "Print version and exit">; + +#endif // BITCOIN_BITCOIN_UTIL_SETTINGS_H diff --git a/src/bitcoin-wallet.cpp b/src/bitcoin-wallet.cpp index be3162094555f..6a7ca34ce985d 100644 --- a/src/bitcoin-wallet.cpp +++ b/src/bitcoin-wallet.cpp @@ -4,6 +4,7 @@ #include // IWYU pragma: keep +#include #include #include #include @@ -33,16 +34,16 @@ static void SetupWalletToolArgs(ArgsManager& argsman) SetupHelpOptions(argsman); SetupChainParamsBaseOptions(argsman); - argsman.AddArg("-version", "Print version and exit", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - argsman.AddArg("-datadir=", "Specify data directory", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - argsman.AddArg("-wallet=", "Specify wallet name", ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::OPTIONS); - argsman.AddArg("-dumpfile=", "When used with 'dump', writes out the records to this file. When used with 'createfromdump', loads the records into a new wallet.", ArgsManager::ALLOW_ANY | ArgsManager::DISALLOW_NEGATION, OptionsCategory::OPTIONS); - argsman.AddArg("-debug=", "Output debugging information (default: 0).", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); - argsman.AddArg("-descriptors", "Create descriptors wallet. Only for 'create'", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - argsman.AddArg("-legacy", "Create legacy wallet. Only for 'create'", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - argsman.AddArg("-format=", "The format of the wallet file to create. Either \"bdb\" or \"sqlite\". Only used with 'createfromdump'", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - argsman.AddArg("-printtoconsole", "Send trace/debug info to console (default: 1 when no -debug is true, 0 otherwise).", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); - argsman.AddArg("-withinternalbdb", "Use the internal Berkeley DB parser when dumping a Berkeley DB wallet file (default: false)", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); + VersionSetting::Register(argsman); + DatadirSetting::Register(argsman); + WalletSetting::Register(argsman); + DumpfileSetting::Register(argsman); + DebugSetting::Register(argsman); + DescriptorsSetting::Register(argsman); + LegacySetting::Register(argsman); + FormatSetting::Register(argsman); + PrinttoconsoleSetting::Register(argsman); + WithinternalbdbSetting::Register(argsman); argsman.AddCommand("info", "Get wallet info"); argsman.AddCommand("create", "Create new wallet file"); @@ -60,10 +61,10 @@ static std::optional WalletAppInit(ArgsManager& args, int argc, char* argv[ return EXIT_FAILURE; } const bool missing_args{argc < 2}; - if (missing_args || HelpRequested(args) || args.IsArgSet("-version")) { + if (missing_args || HelpRequested(args) || !VersionSetting::Value(args).isNull()) { std::string strUsage = strprintf("%s bitcoin-wallet utility version", CLIENT_NAME) + " " + FormatFullVersion() + "\n"; - if (args.IsArgSet("-version")) { + if (!VersionSetting::Value(args).isNull()) { strUsage += FormatParagraph(LicenseInfo()); } else { strUsage += "\n" @@ -84,10 +85,10 @@ static std::optional WalletAppInit(ArgsManager& args, int argc, char* argv[ } // check for printtoconsole, allow -debug - LogInstance().m_print_to_console = args.GetBoolArg("-printtoconsole", args.GetBoolArg("-debug", false)); + LogInstance().m_print_to_console = PrinttoconsoleSetting::Get(args, DebugSetting::Get(args)); if (!CheckDataDirOption(args)) { - tfm::format(std::cerr, "Error: Specified data directory \"%s\" does not exist.\n", args.GetArg("-datadir", "")); + tfm::format(std::cerr, "Error: Specified data directory \"%s\" does not exist.\n", DatadirSetting::Get(args)); return EXIT_FAILURE; } // Check for chain settings (Params() calls are only valid after this clause) diff --git a/src/bitcoin-wallet_settings.h b/src/bitcoin-wallet_settings.h new file mode 100644 index 0000000000000..e1e29af13f619 --- /dev/null +++ b/src/bitcoin-wallet_settings.h @@ -0,0 +1,54 @@ +#ifndef BITCOIN_BITCOIN_WALLET_SETTINGS_H +#define BITCOIN_BITCOIN_WALLET_SETTINGS_H + +#include + +#include +#include + +using VersionSetting = common::Setting< + "-version", common::Unset, common::SettingOptions{.legacy = true}, + "Print version and exit">; + +using DatadirSetting = common::Setting< + "-datadir=", std::string, common::SettingOptions{.legacy = true}, + "Specify data directory">; + +using WalletSetting = common::Setting< + "-wallet=", std::string, common::SettingOptions{.legacy = true, .network_only = true}, + "Specify wallet name">; + +using DumpfileSetting = common::Setting< + "-dumpfile=", common::Unset, common::SettingOptions{.legacy = true, .disallow_negation = true}, + "When used with 'dump', writes out the records to this file. When used with 'createfromdump', loads the records into a new wallet.">; + +using DebugSetting = common::Setting< + "-debug=", bool, common::SettingOptions{.legacy = true}, + "Output debugging information (default: 0)."> + ::Category; + +using DescriptorsSetting = common::Setting< + "-descriptors", bool, common::SettingOptions{.legacy = true}, + "Create descriptors wallet. Only for 'create'"> + ::Default + ::HelpArgs<>; + +using LegacySetting = common::Setting< + "-legacy", bool, common::SettingOptions{.legacy = true}, + "Create legacy wallet. Only for 'create'">; + +using FormatSetting = common::Setting< + "-format=", common::Unset, common::SettingOptions{.legacy = true}, + "The format of the wallet file to create. Either \"bdb\" or \"sqlite\". Only used with 'createfromdump'">; + +using PrinttoconsoleSetting = common::Setting< + "-printtoconsole", bool, common::SettingOptions{.legacy = true}, + "Send trace/debug info to console (default: 1 when no -debug is true, 0 otherwise)."> + ::Category; + +using WithinternalbdbSetting = common::Setting< + "-withinternalbdb", bool, common::SettingOptions{.legacy = true}, + "Use the internal Berkeley DB parser when dumping a Berkeley DB wallet file (default: false)"> + ::Category; + +#endif // BITCOIN_BITCOIN_WALLET_SETTINGS_H diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp index 09a35d4bad453..d5c899ddf9777 100644 --- a/src/bitcoind.cpp +++ b/src/bitcoind.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -135,10 +136,10 @@ static bool ParseArgs(NodeContext& node, int argc, char* argv[]) static bool ProcessInitCommands(ArgsManager& args) { // Process help and version before taking care about datadir - if (HelpRequested(args) || args.IsArgSet("-version")) { + if (HelpRequested(args) || !VersionSetting::Value(args).isNull()) { std::string strUsage = CLIENT_NAME " daemon version " + FormatFullVersion() + "\n"; - if (args.IsArgSet("-version")) { + if (!VersionSetting::Value(args).isNull()) { strUsage += FormatParagraph(LicenseInfo()); } else { strUsage += "\n" @@ -199,7 +200,7 @@ static bool AppInit(NodeContext& node) return false; } - if (args.GetBoolArg("-daemon", DEFAULT_DAEMON) || args.GetBoolArg("-daemonwait", DEFAULT_DAEMONWAIT)) { + if (DaemonSetting::Get(args, DEFAULT_DAEMON) || DaemonwaitSetting::Get(args)) { #if HAVE_DECL_FORK tfm::format(std::cout, CLIENT_NAME " starting\n"); @@ -207,7 +208,7 @@ static bool AppInit(NodeContext& node) switch (fork_daemon(1, 0, daemon_ep)) { // don't chdir (1), do close FDs (0) case 0: // Child: continue. // If -daemonwait is not enabled, immediately send a success token the parent. - if (!args.GetBoolArg("-daemonwait", DEFAULT_DAEMONWAIT)) { + if (!DaemonwaitSetting::Get(args)) { daemon_ep.TokenWrite(1); daemon_ep.Close(); } diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 7966b80a2735f..b060ea13fb9d5 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -6,9 +6,11 @@ #include #include +#include #include #include #include +#include #include #include #include @@ -25,11 +27,11 @@ using util::SplitString; void ReadSigNetArgs(const ArgsManager& args, CChainParams::SigNetOptions& options) { - if (args.IsArgSet("-signetseednode")) { - options.seeds.emplace(args.GetArgs("-signetseednode")); + if (!SignetseednodeSetting::Value(args).isNull()) { + options.seeds.emplace(SignetseednodeSetting::Get(args)); } - if (args.IsArgSet("-signetchallenge")) { - const auto signet_challenge = args.GetArgs("-signetchallenge"); + if (!SignetchallengeSetting::Value(args).isNull()) { + const auto signet_challenge = SignetchallengeSetting::Get(args); if (signet_challenge.size() != 1) { throw std::runtime_error("-signetchallenge cannot be multiple values."); } @@ -43,10 +45,10 @@ void ReadSigNetArgs(const ArgsManager& args, CChainParams::SigNetOptions& option void ReadRegTestArgs(const ArgsManager& args, CChainParams::RegTestOptions& options) { - if (auto value = args.GetBoolArg("-fastprune")) options.fastprune = *value; + if (auto value = FastpruneSetting::Get(args)) options.fastprune = *value; if (HasTestOption(args, "bip94")) options.enforce_bip94 = true; - for (const std::string& arg : args.GetArgs("-testactivationheight")) { + for (const std::string& arg : TestactivationheightSetting::Get(args)) { const auto found{arg.find('@')}; if (found == std::string::npos) { throw std::runtime_error(strprintf("Invalid format (%s) for -testactivationheight=name@height.", arg)); @@ -66,9 +68,9 @@ void ReadRegTestArgs(const ArgsManager& args, CChainParams::RegTestOptions& opti } } - if (!args.IsArgSet("-vbparams")) return; + if (VbparamsSetting::Value(args).isNull()) return; - for (const std::string& strDeployment : args.GetArgs("-vbparams")) { + for (const std::string& strDeployment : VbparamsSetting::Get(args)) { std::vector vDeploymentParams = SplitString(strDeployment, ':'); if (vDeploymentParams.size() < 3 || 4 < vDeploymentParams.size()) { throw std::runtime_error("Version bits parameters malformed, expecting deployment:start:end[:min_activation_height]"); diff --git a/src/chainparamsbase.cpp b/src/chainparamsbase.cpp index aadd04e509f22..5ebea02c872c9 100644 --- a/src/chainparamsbase.cpp +++ b/src/chainparamsbase.cpp @@ -5,6 +5,7 @@ #include +#include #include #include #include @@ -13,16 +14,15 @@ void SetupChainParamsBaseOptions(ArgsManager& argsman) { - argsman.AddArg("-chain=", "Use the chain (default: main). Allowed values: " LIST_CHAIN_NAMES, ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS); - argsman.AddArg("-regtest", "Enter regression test mode, which uses a special chain in which blocks can be solved instantly. " - "This is intended for regression testing tools and app development. Equivalent to -chain=regtest.", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CHAINPARAMS); - argsman.AddArg("-testactivationheight=name@height.", "Set the activation height of 'name' (segwit, bip34, dersig, cltv, csv). (regtest-only)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); - argsman.AddArg("-testnet", "Use the testnet3 chain. Equivalent to -chain=test. Support for testnet3 is deprecated and will be removed in an upcoming release. Consider moving to testnet4 now by using -testnet4.", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS); - argsman.AddArg("-testnet4", "Use the testnet4 chain. Equivalent to -chain=testnet4.", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS); - argsman.AddArg("-vbparams=deployment:start:end[:min_activation_height]", "Use given start/end times and min_activation_height for specified version bits deployment (regtest-only)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CHAINPARAMS); - argsman.AddArg("-signet", "Use the signet chain. Equivalent to -chain=signet. Note that the network is defined by the -signetchallenge parameter", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS); - argsman.AddArg("-signetchallenge", "Blocks must satisfy the given script to be considered valid (only for signet networks; defaults to the global default signet test network challenge)", ArgsManager::ALLOW_ANY | ArgsManager::DISALLOW_NEGATION, OptionsCategory::CHAINPARAMS); - argsman.AddArg("-signetseednode", "Specify a seed node for the signet network, in the hostname[:port] format, e.g. sig.net:1234 (may be used multiple times to specify multiple seed nodes; defaults to the global default signet test network seed node(s))", ArgsManager::ALLOW_ANY | ArgsManager::DISALLOW_NEGATION, OptionsCategory::CHAINPARAMS); + ChainSetting::Register(argsman); + RegtestSetting::Register(argsman); + TestactivationheightSetting::Register(argsman); + TestnetSetting::Register(argsman); + Testnet4Setting::Register(argsman); + VbparamsSetting::Register(argsman); + SignetSetting::Register(argsman); + SignetchallengeSetting::Register(argsman); + SignetseednodeSetting::Register(argsman); } static std::unique_ptr globalChainBaseParams; diff --git a/src/chainparamsbase_settings.h b/src/chainparamsbase_settings.h new file mode 100644 index 0000000000000..78f67a5f51e43 --- /dev/null +++ b/src/chainparamsbase_settings.h @@ -0,0 +1,56 @@ +#ifndef BITCOIN_CHAINPARAMSBASE_SETTINGS_H +#define BITCOIN_CHAINPARAMSBASE_SETTINGS_H + +#include +#include + +#include +#include + +using SignetseednodeSetting = common::Setting< + "-signetseednode", std::vector, common::SettingOptions{.legacy = true, .disallow_negation = true}, + "Specify a seed node for the signet network, in the hostname[:port] format, e.g. sig.net:1234 (may be used multiple times to specify multiple seed nodes; defaults to the global default signet test network seed node(s))"> + ::Category; + +using SignetchallengeSetting = common::Setting< + "-signetchallenge", std::vector, common::SettingOptions{.legacy = true, .disallow_negation = true}, + "Blocks must satisfy the given script to be considered valid (only for signet networks; defaults to the global default signet test network challenge)"> + ::Category; + +using TestactivationheightSetting = common::Setting< + "-testactivationheight=name@height.", std::vector, common::SettingOptions{.legacy = true, .debug_only = true}, + "Set the activation height of 'name' (segwit, bip34, dersig, cltv, csv). (regtest-only)"> + ::Category; + +using VbparamsSetting = common::Setting< + "-vbparams=deployment:start:end[:min_activation_height]", std::vector, common::SettingOptions{.legacy = true, .debug_only = true}, + "Use given start/end times and min_activation_height for specified version bits deployment (regtest-only)"> + ::Category; + +using ChainSetting = common::Setting< + "-chain=", std::optional, common::SettingOptions{.legacy = true}, + "Use the chain (default: main). Allowed values: " LIST_CHAIN_NAMES> + ::Category; + +using RegtestSetting = common::Setting< + "-regtest", common::Unset, common::SettingOptions{.legacy = true, .debug_only = true}, + "Enter regression test mode, which uses a special chain in which blocks can be solved instantly. " + "This is intended for regression testing tools and app development. Equivalent to -chain=regtest."> + ::Category; + +using TestnetSetting = common::Setting< + "-testnet", common::Unset, common::SettingOptions{.legacy = true}, + "Use the testnet3 chain. Equivalent to -chain=test. Support for testnet3 is deprecated and will be removed in an upcoming release. Consider moving to testnet4 now by using -testnet4."> + ::Category; + +using Testnet4Setting = common::Setting< + "-testnet4", common::Unset, common::SettingOptions{.legacy = true}, + "Use the testnet4 chain. Equivalent to -chain=testnet4."> + ::Category; + +using SignetSetting = common::Setting< + "-signet", common::Unset, common::SettingOptions{.legacy = true}, + "Use the signet chain. Equivalent to -chain=signet. Note that the network is defined by the -signetchallenge parameter"> + ::Category; + +#endif // BITCOIN_CHAINPARAMSBASE_SETTINGS_H diff --git a/src/common/args.cpp b/src/common/args.cpp index b7aa582e9a855..e7dee785dca2f 100644 --- a/src/common/args.cpp +++ b/src/common/args.cpp @@ -6,7 +6,10 @@ #include #include +#include +#include #include +#include #include #include #include @@ -293,8 +296,8 @@ fs::path ArgsManager::GetBlocksDirPath() const // this function if (!path.empty()) return path; - if (IsArgSet("-blocksdir")) { - path = fs::absolute(GetPathArg("-blocksdir")); + if (!BlocksdirSetting::Value(*this).isNull()) { + path = fs::absolute(BlocksdirSettingPath::Get(*this)); if (!fs::is_directory(path)) { path = ""; return path; @@ -317,7 +320,7 @@ fs::path ArgsManager::GetDataDir(bool net_specific) const // Used cached path if available if (!path.empty()) return path; - const fs::path datadir{GetPathArg("-datadir")}; + const fs::path datadir{DatadirSettingPath::Get(*this)}; if (!datadir.empty()) { path = fs::absolute(datadir); if (!fs::is_directory(path)) { @@ -380,7 +383,7 @@ bool ArgsManager::IsArgSet(const std::string& strArg) const bool ArgsManager::GetSettingsPath(fs::path* filepath, bool temp, bool backup) const { - fs::path settings = GetPathArg("-settings", BITCOIN_SETTINGS_FILENAME); + fs::path settings = SettingsSetting::Get(*this); if (settings.empty()) { return false; } @@ -613,7 +616,7 @@ void ArgsManager::CheckMultipleCLIArgs() const std::string ArgsManager::GetHelpMessage() const { - const bool show_debug = GetBoolArg("-help-debug", false); + const bool show_debug = HelpDebugSetting::Get(*this); std::string usage; LOCK(cs_args); @@ -688,13 +691,14 @@ std::string ArgsManager::GetHelpMessage() const bool HelpRequested(const ArgsManager& args) { - return args.IsArgSet("-?") || args.IsArgSet("-h") || args.IsArgSet("-help") || args.IsArgSet("-help-debug"); + return !QSettingHidden::Value(args).isNull() || !HSettingHidden::Value(args).isNull() || !HelpSetting::Value(args).isNull() || !HelpDebugSetting::Value(args).isNull(); } void SetupHelpOptions(ArgsManager& args) { - args.AddArg("-help", "Print this help message and exit (also -h or -?)", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - args.AddHiddenArgs({"-h", "-?"}); + HelpSetting::Register(args); + HSettingHidden::Register(args); + QSettingHidden::Register(args); } static const int screenWidth = 79; @@ -719,7 +723,7 @@ const std::vector TEST_OPTIONS_DOC{ bool HasTestOption(const ArgsManager& args, const std::string& test_option) { - const auto options = args.GetArgs("-test"); + const auto options = TestSetting::Get(args); return std::any_of(options.begin(), options.end(), [test_option](const auto& option) { return option == test_option; }); @@ -759,7 +763,7 @@ fs::path GetDefaultDataDir() bool CheckDataDirOption(const ArgsManager& args) { - const fs::path datadir{args.GetPathArg("-datadir")}; + const fs::path datadir{DatadirSettingPath::Get(args)}; return datadir.empty() || fs::is_directory(fs::absolute(datadir)); } @@ -805,7 +809,7 @@ std::variant ArgsManager::GetChainArg() const const bool fSigNet = get_net("-signet"); const bool fTestNet = get_net("-testnet"); const bool fTestNet4 = get_net("-testnet4"); - const auto chain_arg = GetArg("-chain"); + const auto chain_arg = ChainSetting::Get(*this); if ((int)chain_arg.has_value() + (int)fRegTest + (int)fSigNet + (int)fTestNet + (int)fTestNet4 > 1) { throw std::runtime_error("Invalid combination of -regtest, -signet, -testnet, -testnet4 and -chain. Can use at most one."); diff --git a/src/common/args_settings.h b/src/common/args_settings.h new file mode 100644 index 0000000000000..b44098ce7692d --- /dev/null +++ b/src/common/args_settings.h @@ -0,0 +1,21 @@ +#ifndef BITCOIN_COMMON_ARGS_SETTINGS_H +#define BITCOIN_COMMON_ARGS_SETTINGS_H + +#include + +#include +#include + +using HelpSetting = common::Setting< + "-help", common::Unset, common::SettingOptions{.legacy = true}, + "Print this help message and exit (also -h or -?)">; + +using HSettingHidden = common::Setting< + "-h", common::Unset, common::SettingOptions{.legacy = true}> + ::Category; + +using QSettingHidden = common::Setting< + "-?", common::Unset, common::SettingOptions{.legacy = true}> + ::Category; + +#endif // BITCOIN_COMMON_ARGS_SETTINGS_H diff --git a/src/common/config.cpp b/src/common/config.cpp index 98223fc3e3a59..ab19918b6fb5f 100644 --- a/src/common/config.cpp +++ b/src/common/config.cpp @@ -3,6 +3,7 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include +#include #include #include @@ -124,14 +125,14 @@ bool ArgsManager::ReadConfigFiles(std::string& error, bool ignore_invalid_keys) LOCK(cs_args); m_settings.ro_config.clear(); m_config_sections.clear(); - m_config_path = AbsPathForConfigVal(*this, GetPathArg("-conf", BITCOIN_CONF_FILENAME), /*net_specific=*/false); + m_config_path = AbsPathForConfigVal(*this, ConfSettingPath::Get(*this), /*net_specific=*/false); } const auto conf_path{GetConfigFilePath()}; std::ifstream stream{conf_path}; // not ok to have a config file specified that cannot be opened - if (IsArgSet("-conf") && !stream.good()) { + if (!ConfSetting::Value(*this).isNull() && !stream.good()) { error = strprintf("specified config file \"%s\" could not be opened.", fs::PathToString(conf_path)); return false; } @@ -205,7 +206,7 @@ bool ArgsManager::ReadConfigFiles(std::string& error, bool ignore_invalid_keys) // If datadir is changed in .conf file: ClearPathCache(); if (!CheckDataDirOption(*this)) { - error = strprintf("specified data directory \"%s\" does not exist.", GetArg("-datadir", "")); + error = strprintf("specified data directory \"%s\" does not exist.", DatadirSetting::Get(*this)); return false; } return true; diff --git a/src/common/init.cpp b/src/common/init.cpp index 412d73aec7016..1f14c68f4a82f 100644 --- a/src/common/init.cpp +++ b/src/common/init.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -19,7 +20,7 @@ std::optional InitConfig(ArgsManager& args, SettingsAbortFn setting { try { if (!CheckDataDirOption(args)) { - return ConfigError{ConfigStatus::FAILED, strprintf(_("Specified data directory \"%s\" does not exist."), args.GetArg("-datadir", ""))}; + return ConfigError{ConfigStatus::FAILED, strprintf(_("Specified data directory \"%s\" does not exist."), DatadirSetting::Get(args))}; } // Record original datadir and config paths before parsing the config @@ -32,7 +33,7 @@ std::optional InitConfig(ArgsManager& args, SettingsAbortFn setting // parse error, and specifying a datadir= location containing another // bitcoin.conf file just ignores the other file.) const fs::path orig_datadir_path{args.GetDataDirBase()}; - const fs::path orig_config_path{AbsPathForConfigVal(args, args.GetPathArg("-conf", BITCOIN_CONF_FILENAME), /*net_specific=*/false)}; + const fs::path orig_config_path{AbsPathForConfigVal(args, ConfSettingPath::Get(args), /*net_specific=*/false)}; std::string error; if (!args.ReadConfigFiles(error, true)) { @@ -66,7 +67,7 @@ std::optional InitConfig(ArgsManager& args, SettingsAbortFn setting // datadir that is being ignored. const fs::path base_config_path = base_path / BITCOIN_CONF_FILENAME; if (fs::exists(base_config_path) && !fs::equivalent(orig_config_path, base_config_path)) { - const std::string cli_config_path = args.GetArg("-conf", ""); + const std::string cli_config_path = ConfSetting::Get(args); const std::string config_source = cli_config_path.empty() ? strprintf("data directory %s", fs::quoted(fs::PathToString(orig_datadir_path))) : strprintf("command line argument %s", fs::quoted("-conf=" + cli_config_path)); @@ -81,7 +82,7 @@ std::optional InitConfig(ArgsManager& args, SettingsAbortFn setting fs::quoted(BITCOIN_CONF_FILENAME), fs::quoted(fs::PathToString(orig_config_path)), config_source); - if (args.GetBoolArg("-allowignoredconf", false)) { + if (AllowignoredconfSetting::Get(args)) { LogPrintf("Warning: %s\n", error); } else { return ConfigError{ConfigStatus::FAILED, Untranslated(error)}; diff --git a/src/dummywallet.cpp b/src/dummywallet.cpp index 42282c32d1bfb..d1ee635c720b4 100644 --- a/src/dummywallet.cpp +++ b/src/dummywallet.cpp @@ -2,6 +2,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include #include #include #include @@ -26,35 +27,33 @@ class DummyWalletInit : public WalletInitInterface { void DummyWalletInit::AddWalletOptions(ArgsManager& argsman) const { - argsman.AddHiddenArgs({ - "-addresstype", - "-avoidpartialspends", - "-changetype", - "-consolidatefeerate=", - "-disablewallet", - "-discardfee=", - "-fallbackfee=", - "-keypool=", - "-maxapsfee=", - "-maxtxfee=", - "-mintxfee=", - "-paytxfee=", - "-signer=", - "-spendzeroconfchange", - "-txconfirmtarget=", - "-wallet=", - "-walletbroadcast", - "-walletdir=", - "-walletnotify=", - "-walletrbf", - "-dblogsize=", - "-flushwallet", - "-privdb", - "-walletrejectlongchains", - "-walletcrosschain", - "-unsafesqlitesync", - "-swapbdbendian", - }); + AddresstypeSettingHidden::Register(argsman); + AvoidpartialspendsSettingHidden::Register(argsman); + ChangetypeSettingHidden::Register(argsman); + ConsolidatefeerateSettingHidden::Register(argsman); + DisablewalletSettingHidden::Register(argsman); + DiscardfeeSettingHidden::Register(argsman); + FallbackfeeSettingHidden::Register(argsman); + KeypoolSettingHidden::Register(argsman); + MaxapsfeeSettingHidden::Register(argsman); + MaxtxfeeSettingHidden::Register(argsman); + MintxfeeSettingHidden::Register(argsman); + PaytxfeeSettingHidden::Register(argsman); + SignerSettingHidden::Register(argsman); + SpendzeroconfchangeSettingHidden::Register(argsman); + TxconfirmtargetSettingHidden::Register(argsman); + WalletSettingHidden::Register(argsman); + WalletbroadcastSettingHidden::Register(argsman); + WalletdirSettingHidden::Register(argsman); + WalletnotifySettingHidden::Register(argsman); + WalletrbfSettingHidden::Register(argsman); + DblogsizeSettingHidden::Register(argsman); + FlushwalletSettingHidden::Register(argsman); + PrivdbSettingHidden::Register(argsman); + WalletrejectlongchainsSettingHidden::Register(argsman); + WalletcrosschainSettingHidden::Register(argsman); + UnsafesqlitesyncSettingHidden::Register(argsman); + SwapbdbendianSettingHidden::Register(argsman); } const WalletInitInterface& g_wallet_init_interface = DummyWalletInit(); diff --git a/src/dummywallet_settings.h b/src/dummywallet_settings.h new file mode 100644 index 0000000000000..1fab8a799a6a0 --- /dev/null +++ b/src/dummywallet_settings.h @@ -0,0 +1,117 @@ +#ifndef BITCOIN_DUMMYWALLET_SETTINGS_H +#define BITCOIN_DUMMYWALLET_SETTINGS_H + +#include + +#include +#include + +using WalletSettingHidden = common::Setting< + "-wallet=", common::Unset, common::SettingOptions{.legacy = true}> + ::Category; + +using AddresstypeSettingHidden = common::Setting< + "-addresstype", common::Unset, common::SettingOptions{.legacy = true}> + ::Category; + +using AvoidpartialspendsSettingHidden = common::Setting< + "-avoidpartialspends", common::Unset, common::SettingOptions{.legacy = true}> + ::Category; + +using ChangetypeSettingHidden = common::Setting< + "-changetype", common::Unset, common::SettingOptions{.legacy = true}> + ::Category; + +using ConsolidatefeerateSettingHidden = common::Setting< + "-consolidatefeerate=", common::Unset, common::SettingOptions{.legacy = true}> + ::Category; + +using DisablewalletSettingHidden = common::Setting< + "-disablewallet", common::Unset, common::SettingOptions{.legacy = true}> + ::Category; + +using DiscardfeeSettingHidden = common::Setting< + "-discardfee=", common::Unset, common::SettingOptions{.legacy = true}> + ::Category; + +using FallbackfeeSettingHidden = common::Setting< + "-fallbackfee=", common::Unset, common::SettingOptions{.legacy = true}> + ::Category; + +using KeypoolSettingHidden = common::Setting< + "-keypool=", common::Unset, common::SettingOptions{.legacy = true}> + ::Category; + +using MaxapsfeeSettingHidden = common::Setting< + "-maxapsfee=", common::Unset, common::SettingOptions{.legacy = true}> + ::Category; + +using MaxtxfeeSettingHidden = common::Setting< + "-maxtxfee=", common::Unset, common::SettingOptions{.legacy = true}> + ::Category; + +using MintxfeeSettingHidden = common::Setting< + "-mintxfee=", common::Unset, common::SettingOptions{.legacy = true}> + ::Category; + +using PaytxfeeSettingHidden = common::Setting< + "-paytxfee=", common::Unset, common::SettingOptions{.legacy = true}> + ::Category; + +using SignerSettingHidden = common::Setting< + "-signer=", common::Unset, common::SettingOptions{.legacy = true}> + ::Category; + +using SpendzeroconfchangeSettingHidden = common::Setting< + "-spendzeroconfchange", common::Unset, common::SettingOptions{.legacy = true}> + ::Category; + +using TxconfirmtargetSettingHidden = common::Setting< + "-txconfirmtarget=", common::Unset, common::SettingOptions{.legacy = true}> + ::Category; + +using WalletbroadcastSettingHidden = common::Setting< + "-walletbroadcast", common::Unset, common::SettingOptions{.legacy = true}> + ::Category; + +using WalletdirSettingHidden = common::Setting< + "-walletdir=", common::Unset, common::SettingOptions{.legacy = true}> + ::Category; + +using WalletnotifySettingHidden = common::Setting< + "-walletnotify=", common::Unset, common::SettingOptions{.legacy = true}> + ::Category; + +using WalletrbfSettingHidden = common::Setting< + "-walletrbf", common::Unset, common::SettingOptions{.legacy = true}> + ::Category; + +using DblogsizeSettingHidden = common::Setting< + "-dblogsize=", common::Unset, common::SettingOptions{.legacy = true}> + ::Category; + +using FlushwalletSettingHidden = common::Setting< + "-flushwallet", common::Unset, common::SettingOptions{.legacy = true}> + ::Category; + +using PrivdbSettingHidden = common::Setting< + "-privdb", common::Unset, common::SettingOptions{.legacy = true}> + ::Category; + +using WalletrejectlongchainsSettingHidden = common::Setting< + "-walletrejectlongchains", common::Unset, common::SettingOptions{.legacy = true}> + ::Category; + +using WalletcrosschainSettingHidden = common::Setting< + "-walletcrosschain", common::Unset, common::SettingOptions{.legacy = true}> + ::Category; + +using UnsafesqlitesyncSettingHidden = common::Setting< + "-unsafesqlitesync", common::Unset, common::SettingOptions{.legacy = true}> + ::Category; + +using SwapbdbendianSettingHidden = common::Setting< + "-swapbdbendian", common::Unset, common::SettingOptions{.legacy = true}> + ::Category; + +#endif // BITCOIN_DUMMYWALLET_SETTINGS_H diff --git a/src/httprpc.cpp b/src/httprpc.cpp index 69dd821dc0442..334b8cf67b44b 100644 --- a/src/httprpc.cpp +++ b/src/httprpc.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -292,12 +293,12 @@ static bool HTTPReq_JSONRPC(const std::any& context, HTTPRequest* req) static bool InitRPCAuthentication() { - if (gArgs.GetArg("-rpcpassword", "") == "") + if (RpcpasswordSetting::Get(gArgs) == "") { LogInfo("Using random cookie authentication.\n"); std::optional cookie_perms{std::nullopt}; - auto cookie_perms_arg{gArgs.GetArg("-rpccookieperms")}; + auto cookie_perms_arg{RpccookiepermsSetting::Get(gArgs)}; if (cookie_perms_arg) { auto perm_opt = InterpretPermString(*cookie_perms_arg); if (!perm_opt) { @@ -312,12 +313,12 @@ static bool InitRPCAuthentication() } } else { LogPrintf("Config options rpcuser and rpcpassword will soon be deprecated. Locally-run instances may remove rpcuser to use cookie-based auth, or may be replaced with rpcauth. Please see share/rpcauth for rpcauth auth generation.\n"); - strRPCUserColonPass = gArgs.GetArg("-rpcuser", "") + ":" + gArgs.GetArg("-rpcpassword", ""); + strRPCUserColonPass = RpcuserSetting::Get(gArgs) + ":" + RpcpasswordSetting::Get(gArgs); } - if (!gArgs.GetArgs("-rpcauth").empty()) { + if (!RpcauthSetting::Get(gArgs).empty()) { LogInfo("Using rpcauth authentication.\n"); - for (const std::string& rpcauth : gArgs.GetArgs("-rpcauth")) { + for (const std::string& rpcauth : RpcauthSetting::Get(gArgs)) { std::vector fields{SplitString(rpcauth, ':')}; const std::vector salt_hmac{SplitString(fields.back(), '$')}; if (fields.size() == 2 && salt_hmac.size() == 2) { @@ -331,8 +332,8 @@ static bool InitRPCAuthentication() } } - g_rpc_whitelist_default = gArgs.GetBoolArg("-rpcwhitelistdefault", gArgs.IsArgSet("-rpcwhitelist")); - for (const std::string& strRPCWhitelist : gArgs.GetArgs("-rpcwhitelist")) { + g_rpc_whitelist_default = RpcwhitelistdefaultSetting::Get(gArgs, !RpcwhitelistSetting::Value(gArgs).isNull()); + for (const std::string& strRPCWhitelist : RpcwhitelistSetting::Get(gArgs)) { auto pos = strRPCWhitelist.find(':'); std::string strUser = strRPCWhitelist.substr(0, pos); bool intersect = g_rpc_whitelist.count(strUser); diff --git a/src/httpserver.cpp b/src/httpserver.cpp index e37bc21dea64c..cdb4f854c16a7 100644 --- a/src/httpserver.cpp +++ b/src/httpserver.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -223,7 +224,7 @@ static bool InitHTTPAllowList() rpc_allow_subnets.clear(); rpc_allow_subnets.emplace_back(LookupHost("127.0.0.1", false).value(), 8); // always allow IPv4 local subnet rpc_allow_subnets.emplace_back(LookupHost("::1", false).value()); // always allow IPv6 localhost - for (const std::string& strAllow : gArgs.GetArgs("-rpcallowip")) { + for (const std::string& strAllow : RpcallowipSetting::Get(gArgs)) { const CSubNet subnet{LookupSubNet(strAllow)}; if (!subnet.IsValid()) { uiInterface.ThreadSafeMessageBox( @@ -358,21 +359,21 @@ static void ThreadHTTP(struct event_base* base) /** Bind HTTP server to specified addresses */ static bool HTTPBindAddresses(struct evhttp* http) { - uint16_t http_port{static_cast(gArgs.GetIntArg("-rpcport", BaseParams().RPCPort()))}; + uint16_t http_port{static_cast(RpcportSettingInt::Get(gArgs))}; std::vector> endpoints; // Determine what addresses to bind to - if (!(gArgs.IsArgSet("-rpcallowip") && gArgs.IsArgSet("-rpcbind"))) { // Default to loopback if not allowing external IPs + if (!(!RpcallowipSetting::Value(gArgs).isNull() && !RpcbindSetting::Value(gArgs).isNull())) { // Default to loopback if not allowing external IPs endpoints.emplace_back("::1", http_port); endpoints.emplace_back("127.0.0.1", http_port); - if (gArgs.IsArgSet("-rpcallowip")) { + if (!RpcallowipSetting::Value(gArgs).isNull()) { LogPrintf("WARNING: option -rpcallowip was specified without -rpcbind; this doesn't usually make sense\n"); } - if (gArgs.IsArgSet("-rpcbind")) { + if (!RpcbindSetting::Value(gArgs).isNull()) { LogPrintf("WARNING: option -rpcbind was ignored because -rpcallowip was not specified, refusing to allow everyone to connect\n"); } - } else if (gArgs.IsArgSet("-rpcbind")) { // Specific bind address - for (const std::string& strRPCBind : gArgs.GetArgs("-rpcbind")) { + } else if (!RpcbindSetting::Value(gArgs).isNull()) { // Specific bind address + for (const std::string& strRPCBind : RpcbindSetting::Get(gArgs)) { uint16_t port{http_port}; std::string host; if (!SplitHostPort(strRPCBind, port, host)) { @@ -460,7 +461,7 @@ bool InitHTTPServer(const util::SignalInterrupt& interrupt) return false; } - evhttp_set_timeout(http, gArgs.GetIntArg("-rpcservertimeout", DEFAULT_HTTP_SERVER_TIMEOUT)); + evhttp_set_timeout(http, RpcservertimeoutSetting::Get(gArgs)); evhttp_set_max_headers_size(http, MAX_HEADERS_SIZE); evhttp_set_max_body_size(http, MAX_SIZE); evhttp_set_gencb(http, http_request_cb, (void*)&interrupt); @@ -471,7 +472,7 @@ bool InitHTTPServer(const util::SignalInterrupt& interrupt) } LogDebug(BCLog::HTTP, "Initialized HTTP server\n"); - int workQueueDepth = std::max((long)gArgs.GetIntArg("-rpcworkqueue", DEFAULT_HTTP_WORKQUEUE), 1L); + int workQueueDepth = std::max((long)RpcworkqueueSetting::Get(gArgs), 1L); LogDebug(BCLog::HTTP, "creating work queue of depth %d\n", workQueueDepth); g_work_queue = std::make_unique>(workQueueDepth); @@ -494,7 +495,7 @@ static std::vector g_thread_http_workers; void StartHTTPServer() { - int rpcThreads = std::max((long)gArgs.GetIntArg("-rpcthreads", DEFAULT_HTTP_THREADS), 1L); + int rpcThreads = std::max((long)RpcthreadsSetting::Get(gArgs), 1L); LogInfo("Starting HTTP server with %d worker threads\n", rpcThreads); g_thread_http = std::thread(ThreadHTTP, eventBase); diff --git a/src/init.cpp b/src/init.cpp index 1b4e770e053bb..0c6ea7a7f0cbc 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -7,6 +7,7 @@ #include +#include #include #include @@ -159,7 +160,7 @@ static bool g_generated_pid{false}; static fs::path GetPidFile(const ArgsManager& args) { - return AbsPathForConfigVal(args, args.GetPathArg("-pid", BITCOIN_PID_FILENAME)); + return AbsPathForConfigVal(args, PidSetting::Get(args)); } [[nodiscard]] static bool CreatePidFile(const ArgsManager& args) @@ -238,7 +239,7 @@ bool ShutdownRequested(node::NodeContext& node) static void ShutdownNotify(const ArgsManager& args) { std::vector threads; - for (const auto& cmd : args.GetArgs("-shutdownnotify")) { + for (const auto& cmd : ShutdownnotifySetting::Get(args)) { threads.emplace_back(runCommand, cmd); } for (auto& t : threads) { @@ -430,7 +431,7 @@ static void registerSignalHandler(int signal, void(*handler)(int)) void SetupServerArgs(ArgsManager& argsman, bool can_listen_ipc) { SetupHelpOptions(argsman); - argsman.AddArg("-help-debug", "Print help message with debugging options and exit", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); // server-only for now + HelpDebugSetting::Register(argsman); // server-only for now init::AddLoggingArgs(argsman); @@ -446,236 +447,205 @@ void SetupServerArgs(ArgsManager& argsman, bool can_listen_ipc) const auto regtestChainParams = CreateChainParams(argsman, ChainType::REGTEST); // Hidden Options - argsman.AddHiddenArgs({"-dbcrashratio"}); - argsman.AddHiddenArgs({"-forcecompactdb"}); + DbcrashratioSettingHidden::Register(argsman); + ForcecompactdbSettingHidden::Register(argsman); // GUI args. These will be overwritten by SetupUIArgs for the GUI - argsman.AddHiddenArgs({"-choosedatadir"}); - argsman.AddHiddenArgs({"-lang="}); - argsman.AddHiddenArgs({"-min"}); - argsman.AddHiddenArgs({"-resetguisettings"}); - argsman.AddHiddenArgs({"-splash"}); - argsman.AddHiddenArgs({"-uiplatform"}); - - argsman.AddArg("-version", "Print version and exit", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); + ChoosedatadirSettingHidden::Register(argsman); + LangSettingHidden::Register(argsman); + MinSettingHidden::Register(argsman); + ResetguisettingsSettingHidden::Register(argsman); + SplashSettingHidden::Register(argsman); + UiplatformSettingHidden::Register(argsman); + + VersionSetting::Register(argsman); #if HAVE_SYSTEM - argsman.AddArg("-alertnotify=", "Execute command when an alert is raised (%s in cmd is replaced by message)", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); + AlertnotifySetting::Register(argsman); #endif - argsman.AddArg("-assumevalid=", strprintf("If this block is in the chain assume that it and its ancestors are valid and potentially skip their script verification (0 to verify all, default: %s, testnet3: %s, testnet4: %s, signet: %s)", defaultChainParams->GetConsensus().defaultAssumeValid.GetHex(), testnetChainParams->GetConsensus().defaultAssumeValid.GetHex(), testnet4ChainParams->GetConsensus().defaultAssumeValid.GetHex(), signetChainParams->GetConsensus().defaultAssumeValid.GetHex()), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - argsman.AddArg("-blocksdir=", "Specify directory to hold blocks subdirectory for *.dat files (default: )", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - argsman.AddArg("-blocksxor", - strprintf("Whether an XOR-key applies to blocksdir *.dat files. " - "The created XOR-key will be zeros for an existing blocksdir or when `-blocksxor=0` is " - "set, and random for a freshly initialized blocksdir. " - "(default: %u)", - kernel::DEFAULT_XOR_BLOCKSDIR), - ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - argsman.AddArg("-fastprune", "Use smaller block files and lower minimum prune height for testing purposes", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); + AssumevalidSetting::Register(argsman, defaultChainParams, testnetChainParams, testnet4ChainParams, signetChainParams); + BlocksdirSetting::Register(argsman); + BlocksxorSetting::Register(argsman); + FastpruneSetting::Register(argsman); #if HAVE_SYSTEM - argsman.AddArg("-blocknotify=", "Execute command when the best block changes (%s in cmd is replaced by block hash)", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); + BlocknotifySetting::Register(argsman); #endif - argsman.AddArg("-blockreconstructionextratxn=", strprintf("Extra transactions to keep in memory for compact block reconstructions (default: %u)", DEFAULT_BLOCK_RECONSTRUCTION_EXTRA_TXN), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - argsman.AddArg("-blocksonly", strprintf("Whether to reject transactions from network peers. Disables automatic broadcast and rebroadcast of transactions, unless the source peer has the 'forcerelay' permission. RPC transactions are not affected. (default: %u)", DEFAULT_BLOCKSONLY), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - argsman.AddArg("-coinstatsindex", strprintf("Maintain coinstats index used by the gettxoutsetinfo RPC (default: %u)", DEFAULT_COINSTATSINDEX), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - argsman.AddArg("-conf=", strprintf("Specify path to read-only configuration file. Relative paths will be prefixed by datadir location (only useable from command line, not configuration file) (default: %s)", BITCOIN_CONF_FILENAME), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - argsman.AddArg("-datadir=", "Specify data directory", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - argsman.AddArg("-dbbatchsize", strprintf("Maximum database write batch size in bytes (default: %u)", nDefaultDbBatchSize), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::OPTIONS); - argsman.AddArg("-dbcache=", strprintf("Maximum database cache size MiB (minimum %d, default: %d). Make sure you have enough RAM. In addition, unused memory allocated to the mempool is shared with this cache (see -maxmempool).", nMinDbCache, nDefaultDbCache), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - argsman.AddArg("-includeconf=", "Specify additional configuration file, relative to the -datadir path (only useable from configuration file, not command line)", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - argsman.AddArg("-allowignoredconf", strprintf("For backwards compatibility, treat an unused %s file in the datadir as a warning, not an error.", BITCOIN_CONF_FILENAME), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - argsman.AddArg("-loadblock=", "Imports blocks from external file on startup", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - argsman.AddArg("-maxmempool=", strprintf("Keep the transaction memory pool below megabytes (default: %u)", DEFAULT_MAX_MEMPOOL_SIZE_MB), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - argsman.AddArg("-maxorphantx=", strprintf("Keep at most unconnectable transactions in memory (default: %u)", DEFAULT_MAX_ORPHAN_TRANSACTIONS), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - argsman.AddArg("-mempoolexpiry=", strprintf("Do not keep transactions in the mempool longer than hours (default: %u)", DEFAULT_MEMPOOL_EXPIRY_HOURS), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - argsman.AddArg("-minimumchainwork=", strprintf("Minimum work assumed to exist on a valid chain in hex (default: %s, testnet3: %s, testnet4: %s, signet: %s)", defaultChainParams->GetConsensus().nMinimumChainWork.GetHex(), testnetChainParams->GetConsensus().nMinimumChainWork.GetHex(), testnet4ChainParams->GetConsensus().nMinimumChainWork.GetHex(), signetChainParams->GetConsensus().nMinimumChainWork.GetHex()), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::OPTIONS); - argsman.AddArg("-par=", strprintf("Set the number of script verification threads (0 = auto, up to %d, <0 = leave that many cores free, default: %d)", - MAX_SCRIPTCHECK_THREADS, DEFAULT_SCRIPTCHECK_THREADS), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - argsman.AddArg("-persistmempool", strprintf("Whether to save the mempool on shutdown and load on restart (default: %u)", node::DEFAULT_PERSIST_MEMPOOL), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - argsman.AddArg("-persistmempoolv1", - strprintf("Whether a mempool.dat file created by -persistmempool or the savemempool RPC will be written in the legacy format " - "(version 1) or the current format (version 2). This temporary option will be removed in the future. (default: %u)", - DEFAULT_PERSIST_V1_DAT), - ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - argsman.AddArg("-pid=", strprintf("Specify pid file. Relative paths will be prefixed by a net-specific datadir location. (default: %s)", BITCOIN_PID_FILENAME), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - argsman.AddArg("-prune=", strprintf("Reduce storage requirements by enabling pruning (deleting) of old blocks. This allows the pruneblockchain RPC to be called to delete specific blocks and enables automatic pruning of old blocks if a target size in MiB is provided. This mode is incompatible with -txindex. " - "Warning: Reverting this setting requires re-downloading the entire blockchain. " - "(default: 0 = disable pruning blocks, 1 = allow manual pruning via RPC, >=%u = automatically prune block files to stay under the specified target size in MiB)", MIN_DISK_SPACE_FOR_BLOCK_FILES / 1024 / 1024), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - argsman.AddArg("-reindex", "If enabled, wipe chain state and block index, and rebuild them from blk*.dat files on disk. Also wipe and rebuild other optional indexes that are active. If an assumeutxo snapshot was loaded, its chainstate will be wiped as well. The snapshot can then be reloaded via RPC.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - argsman.AddArg("-reindex-chainstate", "If enabled, wipe chain state, and rebuild it from blk*.dat files on disk. If an assumeutxo snapshot was loaded, its chainstate will be wiped as well. The snapshot can then be reloaded via RPC.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - argsman.AddArg("-settings=", strprintf("Specify path to dynamic settings data file. Can be disabled with -nosettings. File is written at runtime and not meant to be edited by users (use %s instead for custom settings). Relative paths will be prefixed by datadir location. (default: %s)", BITCOIN_CONF_FILENAME, BITCOIN_SETTINGS_FILENAME), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); + BlockreconstructionextratxnSetting::Register(argsman); + BlocksonlySetting::Register(argsman); + CoinstatsindexSetting::Register(argsman); + ConfSetting::Register(argsman); + DatadirSetting::Register(argsman); + DbbatchsizeSetting::Register(argsman); + DbcacheSetting::Register(argsman); + IncludeconfSetting::Register(argsman); + AllowignoredconfSetting::Register(argsman); + LoadblockSetting::Register(argsman); + MaxmempoolSetting::Register(argsman); + MaxorphantxSetting::Register(argsman); + MempoolexpirySetting::Register(argsman); + MinimumchainworkSetting::Register(argsman, defaultChainParams, testnetChainParams, testnet4ChainParams, signetChainParams); + ParSetting::Register(argsman); + PersistmempoolSetting::Register(argsman); + Persistmempoolv1Setting::Register(argsman); + PidSetting::Register(argsman); + PruneSetting::Register(argsman); + ReindexSetting::Register(argsman); + ReindexChainstateSetting::Register(argsman); + SettingsSetting::Register(argsman); #if HAVE_SYSTEM - argsman.AddArg("-startupnotify=", "Execute command on startup.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - argsman.AddArg("-shutdownnotify=", "Execute command immediately before beginning shutdown. The need for shutdown may be urgent, so be careful not to delay it long (if the command doesn't require interaction with the server, consider having it fork into the background).", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); + StartupnotifySetting::Register(argsman); + ShutdownnotifySetting::Register(argsman); #endif - argsman.AddArg("-txindex", strprintf("Maintain a full transaction index, used by the getrawtransaction rpc call (default: %u)", DEFAULT_TXINDEX), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - argsman.AddArg("-blockfilterindex=", - strprintf("Maintain an index of compact filters by block (default: %s, values: %s).", DEFAULT_BLOCKFILTERINDEX, ListBlockFilterTypes()) + - " If is not supplied or if = 1, indexes for all known types are enabled.", - ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - - argsman.AddArg("-addnode=", strprintf("Add a node to connect to and attempt to keep the connection open (see the addnode RPC help for more info). This option can be specified multiple times to add multiple nodes; connections are limited to %u at a time and are counted separately from the -maxconnections limit.", MAX_ADDNODE_CONNECTIONS), ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::CONNECTION); - argsman.AddArg("-asmap=", strprintf("Specify asn mapping used for bucketing of the peers (default: %s). Relative paths will be prefixed by the net-specific datadir location.", DEFAULT_ASMAP_FILENAME), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); - argsman.AddArg("-bantime=", strprintf("Default duration (in seconds) of manually configured bans (default: %u)", DEFAULT_MISBEHAVING_BANTIME), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); - argsman.AddArg("-bind=[:][=onion]", strprintf("Bind to given address and always listen on it (default: 0.0.0.0). Use [host]:port notation for IPv6. Append =onion to tag any incoming connections to that address and port as incoming Tor connections (default: 127.0.0.1:%u=onion, testnet3: 127.0.0.1:%u=onion, testnet4: 127.0.0.1:%u=onion, signet: 127.0.0.1:%u=onion, regtest: 127.0.0.1:%u=onion)", defaultBaseParams->OnionServiceTargetPort(), testnetBaseParams->OnionServiceTargetPort(), testnet4BaseParams->OnionServiceTargetPort(), signetBaseParams->OnionServiceTargetPort(), regtestBaseParams->OnionServiceTargetPort()), ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::CONNECTION); - argsman.AddArg("-cjdnsreachable", "If set, then this host is configured for CJDNS (connecting to fc00::/8 addresses would lead us to the CJDNS network, see doc/cjdns.md) (default: 0)", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); - argsman.AddArg("-connect=", "Connect only to the specified node; -noconnect disables automatic connections (the rules for this peer are the same as for -addnode). This option can be specified multiple times to connect to multiple nodes.", ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::CONNECTION); - argsman.AddArg("-discover", "Discover own IP addresses (default: 1 when listening and no -externalip or -proxy)", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); - argsman.AddArg("-dns", strprintf("Allow DNS lookups for -addnode, -seednode and -connect (default: %u)", DEFAULT_NAME_LOOKUP), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); - argsman.AddArg("-dnsseed", strprintf("Query for peer addresses via DNS lookup, if low on addresses (default: %u unless -connect used or -maxconnections=0)", DEFAULT_DNSSEED), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); - argsman.AddArg("-externalip=", "Specify your own public address", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); - argsman.AddArg("-fixedseeds", strprintf("Allow fixed seeds if DNS seeds don't provide peers (default: %u)", DEFAULT_FIXEDSEEDS), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); - argsman.AddArg("-forcednsseed", strprintf("Always query for peer addresses via DNS lookup (default: %u)", DEFAULT_FORCEDNSSEED), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); - argsman.AddArg("-listen", strprintf("Accept connections from outside (default: %u if no -proxy, -connect or -maxconnections=0)", DEFAULT_LISTEN), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); - argsman.AddArg("-listenonion", strprintf("Automatically create Tor onion service (default: %d)", DEFAULT_LISTEN_ONION), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); - argsman.AddArg("-maxconnections=", strprintf("Maintain at most automatic connections to peers (default: %u). This limit does not apply to connections manually added via -addnode or the addnode RPC, which have a separate limit of %u.", DEFAULT_MAX_PEER_CONNECTIONS, MAX_ADDNODE_CONNECTIONS), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); - argsman.AddArg("-maxreceivebuffer=", strprintf("Maximum per-connection receive buffer, *1000 bytes (default: %u)", DEFAULT_MAXRECEIVEBUFFER), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); - argsman.AddArg("-maxsendbuffer=", strprintf("Maximum per-connection memory usage for the send buffer, *1000 bytes (default: %u)", DEFAULT_MAXSENDBUFFER), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); - argsman.AddArg("-maxuploadtarget=", strprintf("Tries to keep outbound traffic under the given target per 24h. Limit does not apply to peers with 'download' permission or blocks created within past week. 0 = no limit (default: %s). Optional suffix units [k|K|m|M|g|G|t|T] (default: M). Lowercase is 1000 base while uppercase is 1024 base", DEFAULT_MAX_UPLOAD_TARGET), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); + TxindexSetting::Register(argsman); + BlockfilterindexSetting::Register(argsman); + + AddnodeSetting::Register(argsman); + AsmapSetting::Register(argsman); + BantimeSetting::Register(argsman); + BindSetting::Register(argsman, defaultBaseParams, testnetBaseParams, testnet4BaseParams, signetBaseParams, regtestBaseParams); + CjdnsreachableSetting::Register(argsman); + ConnectSetting::Register(argsman); + DiscoverSetting::Register(argsman); + DnsSetting::Register(argsman); + DnsseedSetting::Register(argsman); + ExternalipSetting::Register(argsman); + FixedseedsSetting::Register(argsman); + ForcednsseedSetting::Register(argsman); + ListenSetting::Register(argsman); + ListenonionSetting::Register(argsman); + MaxconnectionsSetting::Register(argsman); + MaxreceivebufferSetting::Register(argsman); + MaxsendbufferSetting::Register(argsman); + MaxuploadtargetSetting::Register(argsman); #ifdef HAVE_SOCKADDR_UN - argsman.AddArg("-onion=", "Use separate SOCKS5 proxy to reach peers via Tor onion services, set -noonion to disable (default: -proxy). May be a local file path prefixed with 'unix:'.", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); + OnionSetting::Register(argsman); #else - argsman.AddArg("-onion=", "Use separate SOCKS5 proxy to reach peers via Tor onion services, set -noonion to disable (default: -proxy)", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); + OnionSetting2::Register(argsman); #endif - argsman.AddArg("-i2psam=", "I2P SAM proxy to reach I2P peers and accept I2P connections (default: none)", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); - argsman.AddArg("-i2pacceptincoming", strprintf("Whether to accept inbound I2P connections (default: %i). Ignored if -i2psam is not set. Listening for inbound I2P connections is done through the SAM proxy, not by binding to a local address and port.", DEFAULT_I2P_ACCEPT_INCOMING), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); - argsman.AddArg("-onlynet=", strprintf("Make automatic outbound connections only to network (%s). Inbound and manual connections are not affected by this option. It can be specified multiple times to allow multiple networks.", util::Join(GetNetworkNames(), ", ")), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); - argsman.AddArg("-v2transport", strprintf("Support v2 transport (default: %u)", DEFAULT_V2_TRANSPORT), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); - argsman.AddArg("-peerbloomfilters", strprintf("Support filtering of blocks and transaction with bloom filters (default: %u)", DEFAULT_PEERBLOOMFILTERS), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); - argsman.AddArg("-peerblockfilters", strprintf("Serve compact block filters to peers per BIP 157 (default: %u)", DEFAULT_PEERBLOCKFILTERS), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); - argsman.AddArg("-txreconciliation", strprintf("Enable transaction reconciliations per BIP 330 (default: %d)", DEFAULT_TXRECONCILIATION_ENABLE), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CONNECTION); - argsman.AddArg("-port=", strprintf("Listen for connections on (default: %u, testnet3: %u, testnet4: %u, signet: %u, regtest: %u). Not relevant for I2P (see doc/i2p.md).", defaultChainParams->GetDefaultPort(), testnetChainParams->GetDefaultPort(), testnet4ChainParams->GetDefaultPort(), signetChainParams->GetDefaultPort(), regtestChainParams->GetDefaultPort()), ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::CONNECTION); + I2psamSetting::Register(argsman); + I2pacceptincomingSetting::Register(argsman); + OnlynetSetting::Register(argsman); + V2transportSetting::Register(argsman); + PeerbloomfiltersSetting::Register(argsman); + PeerblockfiltersSetting::Register(argsman); + TxreconciliationSetting::Register(argsman); + PortSetting::Register(argsman, defaultChainParams, testnetChainParams, testnet4ChainParams, signetChainParams, regtestChainParams); #ifdef HAVE_SOCKADDR_UN - argsman.AddArg("-proxy=", "Connect through SOCKS5 proxy, set -noproxy to disable (default: disabled). May be a local file path prefixed with 'unix:' if the proxy supports it.", ArgsManager::ALLOW_ANY | ArgsManager::DISALLOW_ELISION, OptionsCategory::CONNECTION); + ProxySetting::Register(argsman); #else - argsman.AddArg("-proxy=", "Connect through SOCKS5 proxy, set -noproxy to disable (default: disabled)", ArgsManager::ALLOW_ANY | ArgsManager::DISALLOW_ELISION, OptionsCategory::CONNECTION); + ProxySetting2::Register(argsman); #endif - argsman.AddArg("-proxyrandomize", strprintf("Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)", DEFAULT_PROXYRANDOMIZE), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); - argsman.AddArg("-seednode=", "Connect to a node to retrieve peer addresses, and disconnect. This option can be specified multiple times to connect to multiple nodes. During startup, seednodes will be tried before dnsseeds.", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); - argsman.AddArg("-networkactive", "Enable all P2P network activity (default: 1). Can be changed by the setnetworkactive RPC command", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); - argsman.AddArg("-timeout=", strprintf("Specify socket connection timeout in milliseconds. If an initial attempt to connect is unsuccessful after this amount of time, drop it (minimum: 1, default: %d)", DEFAULT_CONNECT_TIMEOUT), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); - argsman.AddArg("-peertimeout=", strprintf("Specify a p2p connection timeout delay in seconds. After connecting to a peer, wait this amount of time before considering disconnection based on inactivity (minimum: 1, default: %d)", DEFAULT_PEER_CONNECT_TIMEOUT), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CONNECTION); - argsman.AddArg("-torcontrol=:", strprintf("Tor control host and port to use if onion listening enabled (default: %s). If no port is specified, the default port of %i will be used.", DEFAULT_TOR_CONTROL, DEFAULT_TOR_CONTROL_PORT), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); - argsman.AddArg("-torpassword=", "Tor control port password (default: empty)", ArgsManager::ALLOW_ANY | ArgsManager::SENSITIVE, OptionsCategory::CONNECTION); + ProxyrandomizeSetting::Register(argsman); + SeednodeSetting::Register(argsman); + NetworkactiveSetting::Register(argsman); + TimeoutSetting::Register(argsman); + PeertimeoutSetting::Register(argsman); + TorcontrolSetting::Register(argsman); + TorpasswordSetting::Register(argsman); // UPnP support was dropped. We keep `-upnp` as a hidden arg to display a more user friendly error when set. TODO: remove (here and below) for 30.0. NOTE: removing this option may prevent the GUI from starting, see https://github.com/bitcoin-core/gui/issues/843. - argsman.AddArg("-upnp", "", ArgsManager::ALLOW_ANY, OptionsCategory::HIDDEN); - argsman.AddArg("-natpmp", strprintf("Use PCP or NAT-PMP to map the listening port (default: %u)", DEFAULT_NATPMP), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); - argsman.AddArg("-whitebind=<[permissions@]addr>", strprintf("Bind to the given address and add permission flags to the peers connecting to it. " - "Use [host]:port notation for IPv6. Allowed permissions: %s. " - "Specify multiple permissions separated by commas (default: download,noban,mempool,relay). Can be specified multiple times.", util::Join(NET_PERMISSIONS_DOC, ", ")), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); - - argsman.AddArg("-whitelist=<[permissions@]IP address or network>", "Add permission flags to the peers using the given IP address (e.g. 1.2.3.4) or " - "CIDR-notated network (e.g. 1.2.3.0/24). Uses the same permissions as " - "-whitebind. " - "Additional flags \"in\" and \"out\" control whether permissions apply to incoming connections and/or manual (default: incoming only). " - "Can be specified multiple times.", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); + UpnpSetting::Register(argsman); + NatpmpSetting::Register(argsman); + WhitebindSetting::Register(argsman); + + WhitelistSetting::Register(argsman); g_wallet_init_interface.AddWalletOptions(argsman); #ifdef ENABLE_ZMQ - argsman.AddArg("-zmqpubhashblock=
", "Enable publish hash block in
", ArgsManager::ALLOW_ANY, OptionsCategory::ZMQ); - argsman.AddArg("-zmqpubhashtx=
", "Enable publish hash transaction in
", ArgsManager::ALLOW_ANY, OptionsCategory::ZMQ); - argsman.AddArg("-zmqpubrawblock=
", "Enable publish raw block in
", ArgsManager::ALLOW_ANY, OptionsCategory::ZMQ); - argsman.AddArg("-zmqpubrawtx=
", "Enable publish raw transaction in
", ArgsManager::ALLOW_ANY, OptionsCategory::ZMQ); - argsman.AddArg("-zmqpubsequence=
", "Enable publish hash block and tx sequence in
", ArgsManager::ALLOW_ANY, OptionsCategory::ZMQ); - argsman.AddArg("-zmqpubhashblockhwm=", strprintf("Set publish hash block outbound message high water mark (default: %d)", CZMQAbstractNotifier::DEFAULT_ZMQ_SNDHWM), ArgsManager::ALLOW_ANY, OptionsCategory::ZMQ); - argsman.AddArg("-zmqpubhashtxhwm=", strprintf("Set publish hash transaction outbound message high water mark (default: %d)", CZMQAbstractNotifier::DEFAULT_ZMQ_SNDHWM), ArgsManager::ALLOW_ANY, OptionsCategory::ZMQ); - argsman.AddArg("-zmqpubrawblockhwm=", strprintf("Set publish raw block outbound message high water mark (default: %d)", CZMQAbstractNotifier::DEFAULT_ZMQ_SNDHWM), ArgsManager::ALLOW_ANY, OptionsCategory::ZMQ); - argsman.AddArg("-zmqpubrawtxhwm=", strprintf("Set publish raw transaction outbound message high water mark (default: %d)", CZMQAbstractNotifier::DEFAULT_ZMQ_SNDHWM), ArgsManager::ALLOW_ANY, OptionsCategory::ZMQ); - argsman.AddArg("-zmqpubsequencehwm=", strprintf("Set publish hash sequence message high water mark (default: %d)", CZMQAbstractNotifier::DEFAULT_ZMQ_SNDHWM), ArgsManager::ALLOW_ANY, OptionsCategory::ZMQ); + ZmqpubhashblockSetting::Register(argsman); + ZmqpubhashtxSetting::Register(argsman); + ZmqpubrawblockSetting::Register(argsman); + ZmqpubrawtxSetting::Register(argsman); + ZmqpubsequenceSetting::Register(argsman); + ZmqpubhashblockhwmSetting::Register(argsman); + ZmqpubhashtxhwmSetting::Register(argsman); + ZmqpubrawblockhwmSetting::Register(argsman); + ZmqpubrawtxhwmSetting::Register(argsman); + ZmqpubsequencehwmSetting::Register(argsman); #else - argsman.AddHiddenArgs({"-zmqpubhashblock=
"}); - argsman.AddHiddenArgs({"-zmqpubhashtx=
"}); - argsman.AddHiddenArgs({"-zmqpubrawblock=
"}); - argsman.AddHiddenArgs({"-zmqpubrawtx=
"}); - argsman.AddHiddenArgs({"-zmqpubsequence="}); - argsman.AddHiddenArgs({"-zmqpubhashblockhwm="}); - argsman.AddHiddenArgs({"-zmqpubhashtxhwm="}); - argsman.AddHiddenArgs({"-zmqpubrawblockhwm="}); - argsman.AddHiddenArgs({"-zmqpubrawtxhwm="}); - argsman.AddHiddenArgs({"-zmqpubsequencehwm="}); + ZmqpubhashblockSetting::Hidden::Register(argsman); + ZmqpubhashtxSetting::Hidden::Register(argsman); + ZmqpubrawblockSetting::Hidden::Register(argsman); + ZmqpubrawtxSetting::Hidden::Register(argsman); + ZmqpubsequenceSetting::Hidden::Register(argsman); + ZmqpubhashblockhwmSetting::Hidden::Register(argsman); + ZmqpubhashtxhwmSetting::Hidden::Register(argsman); + ZmqpubrawblockhwmSetting::Hidden::Register(argsman); + ZmqpubrawtxhwmSetting::Hidden::Register(argsman); + ZmqpubsequencehwmSetting::Hidden::Register(argsman); #endif - argsman.AddArg("-checkblocks=", strprintf("How many blocks to check at startup (default: %u, 0 = all)", DEFAULT_CHECKBLOCKS), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); - argsman.AddArg("-checklevel=", strprintf("How thorough the block verification of -checkblocks is: %s (0-4, default: %u)", util::Join(CHECKLEVEL_DOC, ", "), DEFAULT_CHECKLEVEL), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); - argsman.AddArg("-checkblockindex", strprintf("Do a consistency check for the block tree, chainstate, and other validation data structures every operations. Use 0 to disable. (default: %u, regtest: %u)", defaultChainParams->DefaultConsistencyChecks(), regtestChainParams->DefaultConsistencyChecks()), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); - argsman.AddArg("-checkaddrman=", strprintf("Run addrman consistency checks every operations. Use 0 to disable. (default: %u)", DEFAULT_ADDRMAN_CONSISTENCY_CHECKS), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); - argsman.AddArg("-checkmempool=", strprintf("Run mempool consistency checks every transactions. Use 0 to disable. (default: %u, regtest: %u)", defaultChainParams->DefaultConsistencyChecks(), regtestChainParams->DefaultConsistencyChecks()), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); - argsman.AddArg("-checkpoints", strprintf("Enable rejection of any forks from the known historical chain until block %s (default: %u)", defaultChainParams->Checkpoints().GetHeight(), DEFAULT_CHECKPOINTS_ENABLED), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); - argsman.AddArg("-deprecatedrpc=", "Allows deprecated RPC method(s) to be used", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); - argsman.AddArg("-stopafterblockimport", strprintf("Stop running after importing blocks from disk (default: %u)", DEFAULT_STOPAFTERBLOCKIMPORT), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); - argsman.AddArg("-stopatheight", strprintf("Stop running after reaching the given height in the main chain (default: %u)", node::DEFAULT_STOPATHEIGHT), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); - argsman.AddArg("-limitancestorcount=", strprintf("Do not accept transactions if number of in-mempool ancestors is or more (default: %u)", DEFAULT_ANCESTOR_LIMIT), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); - argsman.AddArg("-limitancestorsize=", strprintf("Do not accept transactions whose size with all in-mempool ancestors exceeds kilobytes (default: %u)", DEFAULT_ANCESTOR_SIZE_LIMIT_KVB), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); - argsman.AddArg("-limitdescendantcount=", strprintf("Do not accept transactions if any ancestor would have or more in-mempool descendants (default: %u)", DEFAULT_DESCENDANT_LIMIT), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); - argsman.AddArg("-limitdescendantsize=", strprintf("Do not accept transactions if any ancestor would have more than kilobytes of in-mempool descendants (default: %u).", DEFAULT_DESCENDANT_SIZE_LIMIT_KVB), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); - argsman.AddArg("-test=