aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorfanquake <fanquake@gmail.com>2023-04-21 11:04:26 +0100
committerfanquake <fanquake@gmail.com>2023-04-21 11:19:08 +0100
commit669af326329b01a739aa5ee79c2e8002818fa4cc (patch)
treec40fe3188f52938875b3404ee7dcbd232ab21db2
parent4c40837a454996c9f704ebf060efd6b249f2e362 (diff)
parentbe55f545d53d44fdcf2d8ae802e9eae551d120c6 (diff)
Merge bitcoin/bitcoin#27419: move-only: Extract common/args from util/system
be55f545d53d44fdcf2d8ae802e9eae551d120c6 move-only: Extract common/args and common/config.cpp from util/system (TheCharlatan) Pull request description: This pull request is part of the `libbitcoinkernel` project https://github.com/bitcoin/bitcoin/issues/24303 https://github.com/bitcoin/bitcoin/projects/18 and more specifically its "Step 2: Decouple most non-consensus code from libbitcoinkernel". It is part of a series of patches splitting up the `util/system` files. Its preceding pull request is https://github.com/bitcoin/bitcoin/pull/27254. The pull request contains an extraction of ArgsManager related functions from util/system into their own common/ file. The background of this commit is an ongoing effort to decouple the libbitcoinkernel library from the ArgsManager. The ArgsManager belongs into the common library, since the kernel library should not depend on it. See [doc/design/libraries.md](https://github.com/bitcoin/bitcoin/blob/master/doc/design/libraries.md) for more information on this rationale. ACKs for top commit: MarcoFalke: re-ACK be55f545d53d44fdcf2d8ae802e9eae551d120c6 🚲 ryanofsky: Code review ACK be55f545d53d44fdcf2d8ae802e9eae551d120c6. Just small cleanups since the last review. hebasto: ACK be55f545d53d44fdcf2d8ae802e9eae551d120c6, I have reviewed the code and it looks OK, I agree it can be merged. Tree-SHA512: 90eb03334af0155b823030b4f2ecf286d35058d700ee2ddbbaa445be19e31eb0fe982656f35bd14ecee3ad2c3d0db3746855cb8f3777eff7253713e42873e111
-rwxr-xr-xci/test/06_script_b.sh2
-rw-r--r--src/Makefile.am5
-rw-r--r--src/addrdb.cpp2
-rw-r--r--src/banman.cpp1
-rw-r--r--src/bench/bench_bitcoin.cpp2
-rw-r--r--src/bench/checkblock.cpp2
-rw-r--r--src/bitcoin-chainstate.cpp2
-rw-r--r--src/bitcoin-cli.cpp4
-rw-r--r--src/bitcoin-tx.cpp1
-rw-r--r--src/bitcoin-util.cpp1
-rw-r--r--src/bitcoin-wallet.cpp3
-rw-r--r--src/bitcoind.cpp3
-rw-r--r--src/chainparams.cpp3
-rw-r--r--src/chainparamsbase.cpp2
-rw-r--r--src/common/args.cpp823
-rw-r--r--src/common/args.h465
-rw-r--r--src/common/config.cpp220
-rw-r--r--src/common/init.cpp2
-rw-r--r--src/dummywallet.cpp3
-rw-r--r--src/httprpc.cpp3
-rw-r--r--src/httpserver.cpp3
-rw-r--r--src/i2p.cpp2
-rw-r--r--src/index/base.cpp2
-rw-r--r--src/index/blockfilterindex.cpp2
-rw-r--r--src/index/coinstatsindex.cpp2
-rw-r--r--src/index/txindex.cpp2
-rw-r--r--src/init.cpp1
-rw-r--r--src/init/bitcoin-gui.cpp2
-rw-r--r--src/init/bitcoin-node.cpp2
-rw-r--r--src/init/bitcoin-qt.cpp2
-rw-r--r--src/init/bitcoind.cpp2
-rw-r--r--src/init/common.cpp2
-rw-r--r--src/net.cpp2
-rw-r--r--src/net_processing.cpp2
-rw-r--r--src/node/blockmanager_args.cpp2
-rw-r--r--src/node/blockstorage.cpp3
-rw-r--r--src/node/caches.cpp2
-rw-r--r--src/node/chainstatemanager_args.cpp2
-rw-r--r--src/node/coins_view_args.cpp2
-rw-r--r--src/node/database_args.cpp2
-rw-r--r--src/node/interfaces.cpp2
-rw-r--r--src/node/mempool_args.cpp2
-rw-r--r--src/node/mempool_persist_args.cpp2
-rw-r--r--src/node/miner.cpp2
-rw-r--r--src/node/txreconciliation.cpp1
-rw-r--r--src/node/utxo_snapshot.cpp2
-rw-r--r--src/node/validation_cache_args.cpp2
-rw-r--r--src/policy/fees_args.cpp2
-rw-r--r--src/protocol.cpp2
-rw-r--r--src/qt/bitcoin.cpp3
-rw-r--r--src/qt/clientmodel.cpp1
-rw-r--r--src/qt/guiutil.cpp3
-rw-r--r--src/qt/intro.cpp2
-rw-r--r--src/qt/optionsmodel.cpp6
-rw-r--r--src/qt/paymentserver.cpp2
-rw-r--r--src/qt/test/optiontests.cpp2
-rw-r--r--src/qt/utilitydialog.cpp2
-rw-r--r--src/qt/walletmodel.cpp2
-rw-r--r--src/rpc/blockchain.cpp2
-rw-r--r--src/rpc/client.cpp2
-rw-r--r--src/rpc/external_signer.cpp4
-rw-r--r--src/rpc/request.cpp3
-rw-r--r--src/rpc/server.cpp2
-rw-r--r--src/rpc/server_util.cpp1
-rw-r--r--src/rpc/util.cpp2
-rw-r--r--src/script/descriptor.cpp2
-rw-r--r--src/script/sigcache.cpp1
-rw-r--r--src/signet.cpp5
-rw-r--r--src/test/argsman_tests.cpp2
-rw-r--r--src/test/checkqueue_tests.cpp2
-rw-r--r--src/test/denialofservice_tests.cpp2
-rw-r--r--src/test/flatfile_tests.cpp2
-rw-r--r--src/test/fuzz/addrman.cpp2
-rw-r--r--src/test/fuzz/banman.cpp2
-rw-r--r--src/test/fuzz/connman.cpp2
-rw-r--r--src/test/fuzz/deserialize.cpp2
-rw-r--r--src/test/fuzz/i2p.cpp2
-rw-r--r--src/test/fuzz/integer.cpp1
-rw-r--r--src/test/fuzz/string.cpp1
-rw-r--r--src/test/fuzz/system.cpp2
-rw-r--r--src/test/fuzz/versionbits.cpp2
-rw-r--r--src/test/getarg_tests.cpp3
-rw-r--r--src/test/i2p_tests.cpp2
-rw-r--r--src/test/net_tests.cpp2
-rw-r--r--src/test/random_tests.cpp1
-rw-r--r--src/test/settings_tests.cpp2
-rw-r--r--src/test/util/setup_common.cpp1
-rw-r--r--src/test/util/setup_common.h2
-rw-r--r--src/test/validationinterface_tests.cpp2
-rw-r--r--src/timedata.cpp3
-rw-r--r--src/torcontrol.cpp3
-rw-r--r--src/txmempool.cpp1
-rw-r--r--src/util/system.cpp1018
-rw-r--r--src/util/system.h444
-rw-r--r--src/validation.cpp1
-rw-r--r--src/wallet/bdb.cpp3
-rw-r--r--src/wallet/bdb.h1
-rw-r--r--src/wallet/coincontrol.cpp2
-rw-r--r--src/wallet/coinselection.cpp3
-rw-r--r--src/wallet/db.cpp2
-rw-r--r--src/wallet/dump.cpp2
-rw-r--r--src/wallet/external_signer_scriptpubkeyman.cpp2
-rw-r--r--src/wallet/init.cpp2
-rw-r--r--src/wallet/interfaces.cpp2
-rw-r--r--src/wallet/load.cpp2
-rw-r--r--src/wallet/spend.cpp2
-rw-r--r--src/wallet/test/init_test_fixture.cpp2
-rw-r--r--src/wallet/test/init_tests.cpp2
-rw-r--r--src/wallet/wallet.cpp2
-rw-r--r--src/wallet/wallettool.cpp2
-rw-r--r--src/wallet/walletutil.cpp2
-rw-r--r--src/zmq/zmqnotificationinterface.cpp2
-rwxr-xr-xtest/lint/lint-circular-dependencies.py2
113 files changed, 1655 insertions, 1545 deletions
diff --git a/ci/test/06_script_b.sh b/ci/test/06_script_b.sh
index f7dcbcee5e..e0fae18b8e 100755
--- a/ci/test/06_script_b.sh
+++ b/ci/test/06_script_b.sh
@@ -42,6 +42,8 @@ if [ "${RUN_TIDY}" = "true" ]; then
( CI_EXEC run-clang-tidy-16 -quiet "${MAKEJOBS}" ) | grep -C5 "error"
export P_CI_DIR="${BASE_BUILD_DIR}/bitcoin-$HOST/"
CI_EXEC "python3 ${DIR_IWYU}/include-what-you-use/iwyu_tool.py"\
+ " src/common/args.cpp"\
+ " src/common/config.cpp"\
" src/common/init.cpp"\
" src/common/url.cpp"\
" src/compat"\
diff --git a/src/Makefile.am b/src/Makefile.am
index 964b65851d..d12edca64e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -133,6 +133,7 @@ BITCOIN_CORE_H = \
checkqueue.h \
clientversion.h \
coins.h \
+ common/args.h \
common/bloom.h \
common/init.h \
common/run_command.h \
@@ -647,7 +648,9 @@ libbitcoin_common_a_SOURCES = \
bech32.cpp \
chainparams.cpp \
coins.cpp \
+ common/args.cpp \
common/bloom.cpp \
+ common/config.cpp \
common/init.cpp \
common/interfaces.cpp \
common/run_command.cpp \
@@ -902,6 +905,8 @@ libbitcoinkernel_la_SOURCES = \
chainparams.cpp \
clientversion.cpp \
coins.cpp \
+ common/args.cpp \
+ common/config.cpp \
compressor.cpp \
consensus/merkle.cpp \
consensus/tx_check.cpp \
diff --git a/src/addrdb.cpp b/src/addrdb.cpp
index 8ecccd4d22..b679ad0602 100644
--- a/src/addrdb.cpp
+++ b/src/addrdb.cpp
@@ -8,6 +8,7 @@
#include <addrman.h>
#include <chainparams.h>
#include <clientversion.h>
+#include <common/args.h>
#include <cstdint>
#include <hash.h>
#include <logging.h>
@@ -21,7 +22,6 @@
#include <util/fs.h>
#include <util/fs_helpers.h>
#include <util/settings.h>
-#include <util/system.h>
#include <util/translation.h>
namespace {
diff --git a/src/banman.cpp b/src/banman.cpp
index ece949d997..5b2049d654 100644
--- a/src/banman.cpp
+++ b/src/banman.cpp
@@ -5,6 +5,7 @@
#include <banman.h>
+#include <logging.h>
#include <netaddress.h>
#include <node/interface_ui.h>
#include <sync.h>
diff --git a/src/bench/bench_bitcoin.cpp b/src/bench/bench_bitcoin.cpp
index 7faaa1fb14..8c421c3fec 100644
--- a/src/bench/bench_bitcoin.cpp
+++ b/src/bench/bench_bitcoin.cpp
@@ -5,10 +5,10 @@
#include <bench/bench.h>
#include <clientversion.h>
+#include <common/args.h>
#include <crypto/sha256.h>
#include <util/fs.h>
#include <util/strencodings.h>
-#include <util/system.h>
#include <chrono>
#include <cstdint>
diff --git a/src/bench/checkblock.cpp b/src/bench/checkblock.cpp
index ee76f7b767..260c8991ce 100644
--- a/src/bench/checkblock.cpp
+++ b/src/bench/checkblock.cpp
@@ -6,9 +6,9 @@
#include <bench/data.h>
#include <chainparams.h>
+#include <common/args.h>
#include <consensus/validation.h>
#include <streams.h>
-#include <util/system.h>
#include <validation.h>
// These are the two major time-sinks which happen after we have fully received
diff --git a/src/bitcoin-chainstate.cpp b/src/bitcoin-chainstate.cpp
index abe3af70c3..04f6aae4f7 100644
--- a/src/bitcoin-chainstate.cpp
+++ b/src/bitcoin-chainstate.cpp
@@ -17,6 +17,7 @@
#include <kernel/validation_cache_sizes.h>
#include <chainparams.h>
+#include <common/args.h>
#include <consensus/validation.h>
#include <core_io.h>
#include <node/blockstorage.h>
@@ -24,7 +25,6 @@
#include <node/chainstate.h>
#include <scheduler.h>
#include <script/sigcache.h>
-#include <util/system.h>
#include <util/thread.h>
#include <validation.h>
#include <validationinterface.h>
diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp
index 94ed765455..63ba6a935d 100644
--- a/src/bitcoin-cli.cpp
+++ b/src/bitcoin-cli.cpp
@@ -9,6 +9,7 @@
#include <chainparamsbase.h>
#include <clientversion.h>
+#include <common/args.h>
#include <common/url.h>
#include <compat/compat.h>
#include <compat/stdin.h>
@@ -22,6 +23,7 @@
#include <util/exception.h>
#include <util/strencodings.h>
#include <util/system.h>
+#include <util/time.h>
#include <util/translation.h>
#include <algorithm>
@@ -1228,7 +1230,7 @@ static int CommandLineRPC(int argc, char *argv[])
MAIN_FUNCTION
{
#ifdef WIN32
- util::WinCmdLineArgs winArgs;
+ common::WinCmdLineArgs winArgs;
std::tie(argc, argv) = winArgs.get();
#endif
SetupEnvironment();
diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp
index a05443a2e5..c35a111313 100644
--- a/src/bitcoin-tx.cpp
+++ b/src/bitcoin-tx.cpp
@@ -8,6 +8,7 @@
#include <clientversion.h>
#include <coins.h>
+#include <common/args.h>
#include <compat/compat.h>
#include <consensus/amount.h>
#include <consensus/consensus.h>
diff --git a/src/bitcoin-util.cpp b/src/bitcoin-util.cpp
index c0ba4df2be..e3f70e1b76 100644
--- a/src/bitcoin-util.cpp
+++ b/src/bitcoin-util.cpp
@@ -11,6 +11,7 @@
#include <chainparams.h>
#include <chainparamsbase.h>
#include <clientversion.h>
+#include <common/args.h>
#include <compat/compat.h>
#include <core_io.h>
#include <streams.h>
diff --git a/src/bitcoin-wallet.cpp b/src/bitcoin-wallet.cpp
index 1ebe98b920..5dbf8a8616 100644
--- a/src/bitcoin-wallet.cpp
+++ b/src/bitcoin-wallet.cpp
@@ -9,6 +9,7 @@
#include <chainparams.h>
#include <chainparamsbase.h>
#include <clientversion.h>
+#include <common/args.h>
#include <common/url.h>
#include <compat/compat.h>
#include <interfaces/init.h>
@@ -99,7 +100,7 @@ MAIN_FUNCTION
{
ArgsManager& args = gArgs;
#ifdef WIN32
- util::WinCmdLineArgs winArgs;
+ common::WinCmdLineArgs winArgs;
std::tie(argc, argv) = winArgs.get();
#endif
diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp
index 2ff34125e1..e476b06017 100644
--- a/src/bitcoind.cpp
+++ b/src/bitcoind.cpp
@@ -9,6 +9,7 @@
#include <chainparams.h>
#include <clientversion.h>
+#include <common/args.h>
#include <common/init.h>
#include <common/url.h>
#include <compat/compat.h>
@@ -247,7 +248,7 @@ static bool AppInit(NodeContext& node, int argc, char* argv[])
MAIN_FUNCTION
{
#ifdef WIN32
- util::WinCmdLineArgs winArgs;
+ common::WinCmdLineArgs winArgs;
std::tie(argc, argv) = winArgs.get();
#endif
diff --git a/src/chainparams.cpp b/src/chainparams.cpp
index 6f48ee41b3..d3d358a3f0 100644
--- a/src/chainparams.cpp
+++ b/src/chainparams.cpp
@@ -6,12 +6,13 @@
#include <chainparams.h>
#include <chainparamsseeds.h>
+#include <common/args.h>
#include <consensus/merkle.h>
#include <deploymentinfo.h>
#include <hash.h> // for signet block challenge hash
+#include <logging.h>
#include <script/interpreter.h>
#include <util/string.h>
-#include <util/system.h>
#include <assert.h>
diff --git a/src/chainparamsbase.cpp b/src/chainparamsbase.cpp
index 71978081ce..eb7b31923d 100644
--- a/src/chainparamsbase.cpp
+++ b/src/chainparamsbase.cpp
@@ -5,8 +5,8 @@
#include <chainparamsbase.h>
+#include <common/args.h>
#include <tinyformat.h>
-#include <util/system.h>
#include <assert.h>
diff --git a/src/common/args.cpp b/src/common/args.cpp
new file mode 100644
index 0000000000..d29b8648bf
--- /dev/null
+++ b/src/common/args.cpp
@@ -0,0 +1,823 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2022 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <common/args.h>
+
+#include <chainparamsbase.h>
+#include <logging.h>
+#include <sync.h>
+#include <tinyformat.h>
+#include <univalue.h>
+#include <util/check.h>
+#include <util/fs.h>
+#include <util/fs_helpers.h>
+#include <util/settings.h>
+#include <util/strencodings.h>
+
+#ifdef WIN32
+#include <codecvt> /* for codecvt_utf8_utf16 */
+#include <shellapi.h> /* for CommandLineToArgvW */
+#include <shlobj.h> /* for CSIDL_APPDATA */
+#endif
+
+#include <algorithm>
+#include <cassert>
+#include <cstdint>
+#include <cstdlib>
+#include <cstring>
+#include <filesystem>
+#include <map>
+#include <optional>
+#include <stdexcept>
+#include <string>
+#include <utility>
+
+const char * const BITCOIN_CONF_FILENAME = "bitcoin.conf";
+const char * const BITCOIN_SETTINGS_FILENAME = "settings.json";
+
+ArgsManager gArgs;
+
+/**
+ * Interpret a string argument as a boolean.
+ *
+ * The definition of LocaleIndependentAtoi<int>() requires that non-numeric string values
+ * like "foo", return 0. This means that if a user unintentionally supplies a
+ * non-integer argument here, the return value is always false. This means that
+ * -foo=false does what the user probably expects, but -foo=true is well defined
+ * but does not do what they probably expected.
+ *
+ * The return value of LocaleIndependentAtoi<int>(...) is zero when given input not
+ * representable as an int.
+ *
+ * For a more extensive discussion of this topic (and a wide range of opinions
+ * on the Right Way to change this code), see PR12713.
+ */
+static bool InterpretBool(const std::string& strValue)
+{
+ if (strValue.empty())
+ return true;
+ return (LocaleIndependentAtoi<int>(strValue) != 0);
+}
+
+static std::string SettingName(const std::string& arg)
+{
+ return arg.size() > 0 && arg[0] == '-' ? arg.substr(1) : arg;
+}
+
+/**
+ * Parse "name", "section.name", "noname", "section.noname" settings keys.
+ *
+ * @note Where an option was negated can be later checked using the
+ * IsArgNegated() method. One use case for this is to have a way to disable
+ * options that are not normally boolean (e.g. using -nodebuglogfile to request
+ * that debug log output is not sent to any file at all).
+ */
+KeyInfo InterpretKey(std::string key)
+{
+ KeyInfo result;
+ // Split section name from key name for keys like "testnet.foo" or "regtest.bar"
+ size_t option_index = key.find('.');
+ if (option_index != std::string::npos) {
+ result.section = key.substr(0, option_index);
+ key.erase(0, option_index + 1);
+ }
+ if (key.substr(0, 2) == "no") {
+ key.erase(0, 2);
+ result.negated = true;
+ }
+ result.name = key;
+ return result;
+}
+
+/**
+ * Interpret settings value based on registered flags.
+ *
+ * @param[in] key key information to know if key was negated
+ * @param[in] value string value of setting to be parsed
+ * @param[in] flags ArgsManager registered argument flags
+ * @param[out] error Error description if settings value is not valid
+ *
+ * @return parsed settings value if it is valid, otherwise nullopt accompanied
+ * by a descriptive error string
+ */
+std::optional<util::SettingsValue> InterpretValue(const KeyInfo& key, const std::string* value,
+ unsigned int flags, std::string& error)
+{
+ // Return negated settings as false values.
+ if (key.negated) {
+ if (flags & ArgsManager::DISALLOW_NEGATION) {
+ error = strprintf("Negating of -%s is meaningless and therefore forbidden", key.name);
+ return std::nullopt;
+ }
+ // Double negatives like -nofoo=0 are supported (but discouraged)
+ if (value && !InterpretBool(*value)) {
+ LogPrintf("Warning: parsed potentially confusing double-negative -%s=%s\n", key.name, *value);
+ return true;
+ }
+ return false;
+ }
+ if (!value && (flags & ArgsManager::DISALLOW_ELISION)) {
+ error = strprintf("Can not set -%s with no value. Please specify value with -%s=value.", key.name, key.name);
+ return std::nullopt;
+ }
+ return value ? *value : "";
+}
+
+// Define default constructor and destructor that are not inline, so code instantiating this class doesn't need to
+// #include class definitions for all members.
+// For example, m_settings has an internal dependency on univalue.
+ArgsManager::ArgsManager() = default;
+ArgsManager::~ArgsManager() = default;
+
+std::set<std::string> ArgsManager::GetUnsuitableSectionOnlyArgs() const
+{
+ std::set<std::string> unsuitables;
+
+ LOCK(cs_args);
+
+ // if there's no section selected, don't worry
+ if (m_network.empty()) return std::set<std::string> {};
+
+ // if it's okay to use the default section for this network, don't worry
+ if (m_network == CBaseChainParams::MAIN) return std::set<std::string> {};
+
+ for (const auto& arg : m_network_only_args) {
+ if (OnlyHasDefaultSectionSetting(m_settings, m_network, SettingName(arg))) {
+ unsuitables.insert(arg);
+ }
+ }
+ return unsuitables;
+}
+
+std::list<SectionInfo> ArgsManager::GetUnrecognizedSections() const
+{
+ // Section names to be recognized in the config file.
+ static const std::set<std::string> available_sections{
+ CBaseChainParams::REGTEST,
+ CBaseChainParams::SIGNET,
+ CBaseChainParams::TESTNET,
+ CBaseChainParams::MAIN
+ };
+
+ LOCK(cs_args);
+ std::list<SectionInfo> unrecognized = m_config_sections;
+ unrecognized.remove_if([](const SectionInfo& appeared){ return available_sections.find(appeared.m_name) != available_sections.end(); });
+ return unrecognized;
+}
+
+void ArgsManager::SelectConfigNetwork(const std::string& network)
+{
+ LOCK(cs_args);
+ m_network = network;
+}
+
+bool ArgsManager::ParseParameters(int argc, const char* const argv[], std::string& error)
+{
+ LOCK(cs_args);
+ m_settings.command_line_options.clear();
+
+ for (int i = 1; i < argc; i++) {
+ std::string key(argv[i]);
+
+#ifdef MAC_OSX
+ // At the first time when a user gets the "App downloaded from the
+ // internet" warning, and clicks the Open button, macOS passes
+ // a unique process serial number (PSN) as -psn_... command-line
+ // argument, which we filter out.
+ if (key.substr(0, 5) == "-psn_") continue;
+#endif
+
+ if (key == "-") break; //bitcoin-tx using stdin
+ std::optional<std::string> val;
+ size_t is_index = key.find('=');
+ if (is_index != std::string::npos) {
+ val = key.substr(is_index + 1);
+ key.erase(is_index);
+ }
+#ifdef WIN32
+ key = ToLower(key);
+ if (key[0] == '/')
+ key[0] = '-';
+#endif
+
+ if (key[0] != '-') {
+ if (!m_accept_any_command && m_command.empty()) {
+ // The first non-dash arg is a registered command
+ std::optional<unsigned int> flags = GetArgFlags(key);
+ if (!flags || !(*flags & ArgsManager::COMMAND)) {
+ error = strprintf("Invalid command '%s'", argv[i]);
+ return false;
+ }
+ }
+ m_command.push_back(key);
+ while (++i < argc) {
+ // The remaining args are command args
+ m_command.push_back(argv[i]);
+ }
+ break;
+ }
+
+ // Transform --foo to -foo
+ if (key.length() > 1 && key[1] == '-')
+ key.erase(0, 1);
+
+ // Transform -foo to foo
+ key.erase(0, 1);
+ KeyInfo keyinfo = InterpretKey(key);
+ std::optional<unsigned int> flags = GetArgFlags('-' + keyinfo.name);
+
+ // Unknown command line options and command line options with dot
+ // characters (which are returned from InterpretKey with nonempty
+ // section strings) are not valid.
+ if (!flags || !keyinfo.section.empty()) {
+ error = strprintf("Invalid parameter %s", argv[i]);
+ return false;
+ }
+
+ std::optional<util::SettingsValue> value = InterpretValue(keyinfo, val ? &*val : nullptr, *flags, error);
+ if (!value) return false;
+
+ m_settings.command_line_options[keyinfo.name].push_back(*value);
+ }
+
+ // we do not allow -includeconf from command line, only -noincludeconf
+ if (auto* includes = util::FindKey(m_settings.command_line_options, "includeconf")) {
+ const util::SettingsSpan values{*includes};
+ // Range may be empty if -noincludeconf was passed
+ if (!values.empty()) {
+ error = "-includeconf cannot be used from commandline; -includeconf=" + values.begin()->write();
+ return false; // pick first value as example
+ }
+ }
+ return true;
+}
+
+std::optional<unsigned int> ArgsManager::GetArgFlags(const std::string& name) const
+{
+ LOCK(cs_args);
+ for (const auto& arg_map : m_available_args) {
+ const auto search = arg_map.second.find(name);
+ if (search != arg_map.second.end()) {
+ return search->second.m_flags;
+ }
+ }
+ return std::nullopt;
+}
+
+fs::path ArgsManager::GetPathArg(std::string arg, const fs::path& default_value) const
+{
+ if (IsArgNegated(arg)) return fs::path{};
+ std::string path_str = GetArg(arg, "");
+ if (path_str.empty()) return default_value;
+ fs::path result = fs::PathFromString(path_str).lexically_normal();
+ // Remove trailing slash, if present.
+ return result.has_filename() ? result : result.parent_path();
+}
+
+const fs::path& ArgsManager::GetBlocksDirPath() const
+{
+ LOCK(cs_args);
+ fs::path& path = m_cached_blocks_path;
+
+ // Cache the path to avoid calling fs::create_directories on every call of
+ // this function
+ if (!path.empty()) return path;
+
+ if (IsArgSet("-blocksdir")) {
+ path = fs::absolute(GetPathArg("-blocksdir"));
+ if (!fs::is_directory(path)) {
+ path = "";
+ return path;
+ }
+ } else {
+ path = GetDataDirBase();
+ }
+
+ path /= fs::PathFromString(BaseParams().DataDir());
+ path /= "blocks";
+ fs::create_directories(path);
+ return path;
+}
+
+const fs::path& ArgsManager::GetDataDir(bool net_specific) const
+{
+ LOCK(cs_args);
+ fs::path& path = net_specific ? m_cached_network_datadir_path : m_cached_datadir_path;
+
+ // Used cached path if available
+ if (!path.empty()) return path;
+
+ const fs::path datadir{GetPathArg("-datadir")};
+ if (!datadir.empty()) {
+ path = fs::absolute(datadir);
+ if (!fs::is_directory(path)) {
+ path = "";
+ return path;
+ }
+ } else {
+ path = GetDefaultDataDir();
+ }
+
+ if (net_specific && !BaseParams().DataDir().empty()) {
+ path /= fs::PathFromString(BaseParams().DataDir());
+ }
+
+ return path;
+}
+
+void ArgsManager::ClearPathCache()
+{
+ LOCK(cs_args);
+
+ m_cached_datadir_path = fs::path();
+ m_cached_network_datadir_path = fs::path();
+ m_cached_blocks_path = fs::path();
+}
+
+std::optional<const ArgsManager::Command> ArgsManager::GetCommand() const
+{
+ Command ret;
+ LOCK(cs_args);
+ auto it = m_command.begin();
+ if (it == m_command.end()) {
+ // No command was passed
+ return std::nullopt;
+ }
+ if (!m_accept_any_command) {
+ // The registered command
+ ret.command = *(it++);
+ }
+ while (it != m_command.end()) {
+ // The unregistered command and args (if any)
+ ret.args.push_back(*(it++));
+ }
+ return ret;
+}
+
+std::vector<std::string> ArgsManager::GetArgs(const std::string& strArg) const
+{
+ std::vector<std::string> result;
+ for (const util::SettingsValue& value : GetSettingsList(strArg)) {
+ result.push_back(value.isFalse() ? "0" : value.isTrue() ? "1" : value.get_str());
+ }
+ return result;
+}
+
+bool ArgsManager::IsArgSet(const std::string& strArg) const
+{
+ return !GetSetting(strArg).isNull();
+}
+
+bool ArgsManager::GetSettingsPath(fs::path* filepath, bool temp, bool backup) const
+{
+ fs::path settings = GetPathArg("-settings", BITCOIN_SETTINGS_FILENAME);
+ if (settings.empty()) {
+ return false;
+ }
+ if (backup) {
+ settings += ".bak";
+ }
+ if (filepath) {
+ *filepath = fsbridge::AbsPathJoin(GetDataDirNet(), temp ? settings + ".tmp" : settings);
+ }
+ return true;
+}
+
+static void SaveErrors(const std::vector<std::string> errors, std::vector<std::string>* error_out)
+{
+ for (const auto& error : errors) {
+ if (error_out) {
+ error_out->emplace_back(error);
+ } else {
+ LogPrintf("%s\n", error);
+ }
+ }
+}
+
+bool ArgsManager::ReadSettingsFile(std::vector<std::string>* errors)
+{
+ fs::path path;
+ if (!GetSettingsPath(&path, /* temp= */ false)) {
+ return true; // Do nothing if settings file disabled.
+ }
+
+ LOCK(cs_args);
+ m_settings.rw_settings.clear();
+ std::vector<std::string> read_errors;
+ if (!util::ReadSettings(path, m_settings.rw_settings, read_errors)) {
+ SaveErrors(read_errors, errors);
+ return false;
+ }
+ for (const auto& setting : m_settings.rw_settings) {
+ KeyInfo key = InterpretKey(setting.first); // Split setting key into section and argname
+ if (!GetArgFlags('-' + key.name)) {
+ LogPrintf("Ignoring unknown rw_settings value %s\n", setting.first);
+ }
+ }
+ return true;
+}
+
+bool ArgsManager::WriteSettingsFile(std::vector<std::string>* errors, bool backup) const
+{
+ fs::path path, path_tmp;
+ if (!GetSettingsPath(&path, /*temp=*/false, backup) || !GetSettingsPath(&path_tmp, /*temp=*/true, backup)) {
+ throw std::logic_error("Attempt to write settings file when dynamic settings are disabled.");
+ }
+
+ LOCK(cs_args);
+ std::vector<std::string> write_errors;
+ if (!util::WriteSettings(path_tmp, m_settings.rw_settings, write_errors)) {
+ SaveErrors(write_errors, errors);
+ return false;
+ }
+ if (!RenameOver(path_tmp, path)) {
+ SaveErrors({strprintf("Failed renaming settings file %s to %s\n", fs::PathToString(path_tmp), fs::PathToString(path))}, errors);
+ return false;
+ }
+ return true;
+}
+
+util::SettingsValue ArgsManager::GetPersistentSetting(const std::string& name) const
+{
+ LOCK(cs_args);
+ return util::GetSetting(m_settings, m_network, name, !UseDefaultSection("-" + name),
+ /*ignore_nonpersistent=*/true, /*get_chain_name=*/false);
+}
+
+bool ArgsManager::IsArgNegated(const std::string& strArg) const
+{
+ return GetSetting(strArg).isFalse();
+}
+
+std::string ArgsManager::GetArg(const std::string& strArg, const std::string& strDefault) const
+{
+ return GetArg(strArg).value_or(strDefault);
+}
+
+std::optional<std::string> ArgsManager::GetArg(const std::string& strArg) const
+{
+ const util::SettingsValue value = GetSetting(strArg);
+ return SettingToString(value);
+}
+
+std::optional<std::string> SettingToString(const util::SettingsValue& value)
+{
+ if (value.isNull()) return std::nullopt;
+ if (value.isFalse()) return "0";
+ if (value.isTrue()) return "1";
+ if (value.isNum()) return value.getValStr();
+ return value.get_str();
+}
+
+std::string SettingToString(const util::SettingsValue& value, const std::string& strDefault)
+{
+ return SettingToString(value).value_or(strDefault);
+}
+
+int64_t ArgsManager::GetIntArg(const std::string& strArg, int64_t nDefault) const
+{
+ return GetIntArg(strArg).value_or(nDefault);
+}
+
+std::optional<int64_t> ArgsManager::GetIntArg(const std::string& strArg) const
+{
+ const util::SettingsValue value = GetSetting(strArg);
+ return SettingToInt(value);
+}
+
+std::optional<int64_t> SettingToInt(const util::SettingsValue& value)
+{
+ if (value.isNull()) return std::nullopt;
+ if (value.isFalse()) return 0;
+ if (value.isTrue()) return 1;
+ if (value.isNum()) return value.getInt<int64_t>();
+ return LocaleIndependentAtoi<int64_t>(value.get_str());
+}
+
+int64_t SettingToInt(const util::SettingsValue& value, int64_t nDefault)
+{
+ return SettingToInt(value).value_or(nDefault);
+}
+
+bool ArgsManager::GetBoolArg(const std::string& strArg, bool fDefault) const
+{
+ return GetBoolArg(strArg).value_or(fDefault);
+}
+
+std::optional<bool> ArgsManager::GetBoolArg(const std::string& strArg) const
+{
+ const util::SettingsValue value = GetSetting(strArg);
+ return SettingToBool(value);
+}
+
+std::optional<bool> SettingToBool(const util::SettingsValue& value)
+{
+ if (value.isNull()) return std::nullopt;
+ if (value.isBool()) return value.get_bool();
+ return InterpretBool(value.get_str());
+}
+
+bool SettingToBool(const util::SettingsValue& value, bool fDefault)
+{
+ return SettingToBool(value).value_or(fDefault);
+}
+
+bool ArgsManager::SoftSetArg(const std::string& strArg, const std::string& strValue)
+{
+ LOCK(cs_args);
+ if (IsArgSet(strArg)) return false;
+ ForceSetArg(strArg, strValue);
+ return true;
+}
+
+bool ArgsManager::SoftSetBoolArg(const std::string& strArg, bool fValue)
+{
+ if (fValue)
+ return SoftSetArg(strArg, std::string("1"));
+ else
+ return SoftSetArg(strArg, std::string("0"));
+}
+
+void ArgsManager::ForceSetArg(const std::string& strArg, const std::string& strValue)
+{
+ LOCK(cs_args);
+ m_settings.forced_settings[SettingName(strArg)] = strValue;
+}
+
+void ArgsManager::AddCommand(const std::string& cmd, const std::string& help)
+{
+ Assert(cmd.find('=') == std::string::npos);
+ Assert(cmd.at(0) != '-');
+
+ LOCK(cs_args);
+ m_accept_any_command = false; // latch to false
+ std::map<std::string, Arg>& arg_map = m_available_args[OptionsCategory::COMMANDS];
+ auto ret = arg_map.emplace(cmd, Arg{"", help, ArgsManager::COMMAND});
+ Assert(ret.second); // Fail on duplicate commands
+}
+
+void ArgsManager::AddArg(const std::string& name, const std::string& help, unsigned int flags, const OptionsCategory& cat)
+{
+ Assert((flags & ArgsManager::COMMAND) == 0); // use AddCommand
+
+ // Split arg name from its help param
+ size_t eq_index = name.find('=');
+ if (eq_index == std::string::npos) {
+ eq_index = name.size();
+ }
+ std::string arg_name = name.substr(0, eq_index);
+
+ LOCK(cs_args);
+ std::map<std::string, Arg>& arg_map = m_available_args[cat];
+ auto ret = arg_map.emplace(arg_name, Arg{name.substr(eq_index, name.size() - eq_index), help, flags});
+ assert(ret.second); // Make sure an insertion actually happened
+
+ if (flags & ArgsManager::NETWORK_ONLY) {
+ m_network_only_args.emplace(arg_name);
+ }
+}
+
+void ArgsManager::AddHiddenArgs(const std::vector<std::string>& names)
+{
+ for (const std::string& name : names) {
+ AddArg(name, "", ArgsManager::ALLOW_ANY, OptionsCategory::HIDDEN);
+ }
+}
+
+std::string ArgsManager::GetHelpMessage() const
+{
+ const bool show_debug = GetBoolArg("-help-debug", false);
+
+ std::string usage;
+ LOCK(cs_args);
+ for (const auto& arg_map : m_available_args) {
+ switch(arg_map.first) {
+ case OptionsCategory::OPTIONS:
+ usage += HelpMessageGroup("Options:");
+ break;
+ case OptionsCategory::CONNECTION:
+ usage += HelpMessageGroup("Connection options:");
+ break;
+ case OptionsCategory::ZMQ:
+ usage += HelpMessageGroup("ZeroMQ notification options:");
+ break;
+ case OptionsCategory::DEBUG_TEST:
+ usage += HelpMessageGroup("Debugging/Testing options:");
+ break;
+ case OptionsCategory::NODE_RELAY:
+ usage += HelpMessageGroup("Node relay options:");
+ break;
+ case OptionsCategory::BLOCK_CREATION:
+ usage += HelpMessageGroup("Block creation options:");
+ break;
+ case OptionsCategory::RPC:
+ usage += HelpMessageGroup("RPC server options:");
+ break;
+ case OptionsCategory::WALLET:
+ usage += HelpMessageGroup("Wallet options:");
+ break;
+ case OptionsCategory::WALLET_DEBUG_TEST:
+ if (show_debug) usage += HelpMessageGroup("Wallet debugging/testing options:");
+ break;
+ case OptionsCategory::CHAINPARAMS:
+ usage += HelpMessageGroup("Chain selection options:");
+ break;
+ case OptionsCategory::GUI:
+ usage += HelpMessageGroup("UI Options:");
+ break;
+ case OptionsCategory::COMMANDS:
+ usage += HelpMessageGroup("Commands:");
+ break;
+ case OptionsCategory::REGISTER_COMMANDS:
+ usage += HelpMessageGroup("Register Commands:");
+ break;
+ default:
+ break;
+ }
+
+ // When we get to the hidden options, stop
+ if (arg_map.first == OptionsCategory::HIDDEN) break;
+
+ for (const auto& arg : arg_map.second) {
+ if (show_debug || !(arg.second.m_flags & ArgsManager::DEBUG_ONLY)) {
+ std::string name;
+ if (arg.second.m_help_param.empty()) {
+ name = arg.first;
+ } else {
+ name = arg.first + arg.second.m_help_param;
+ }
+ usage += HelpMessageOpt(name, arg.second.m_help_text);
+ }
+ }
+ }
+ return usage;
+}
+
+bool HelpRequested(const ArgsManager& args)
+{
+ return args.IsArgSet("-?") || args.IsArgSet("-h") || args.IsArgSet("-help") || args.IsArgSet("-help-debug");
+}
+
+void SetupHelpOptions(ArgsManager& args)
+{
+ args.AddArg("-?", "Print this help message and exit", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
+ args.AddHiddenArgs({"-h", "-help"});
+}
+
+static const int screenWidth = 79;
+static const int optIndent = 2;
+static const int msgIndent = 7;
+
+std::string HelpMessageGroup(const std::string &message) {
+ return std::string(message) + std::string("\n\n");
+}
+
+std::string HelpMessageOpt(const std::string &option, const std::string &message) {
+ return std::string(optIndent,' ') + std::string(option) +
+ std::string("\n") + std::string(msgIndent,' ') +
+ FormatParagraph(message, screenWidth - msgIndent, msgIndent) +
+ std::string("\n\n");
+}
+
+fs::path GetDefaultDataDir()
+{
+ // Windows: C:\Users\Username\AppData\Roaming\Bitcoin
+ // macOS: ~/Library/Application Support/Bitcoin
+ // Unix-like: ~/.bitcoin
+#ifdef WIN32
+ // Windows
+ return GetSpecialFolderPath(CSIDL_APPDATA) / "Bitcoin";
+#else
+ fs::path pathRet;
+ char* pszHome = getenv("HOME");
+ if (pszHome == nullptr || strlen(pszHome) == 0)
+ pathRet = fs::path("/");
+ else
+ pathRet = fs::path(pszHome);
+#ifdef MAC_OSX
+ // macOS
+ return pathRet / "Library/Application Support/Bitcoin";
+#else
+ // Unix-like
+ return pathRet / ".bitcoin";
+#endif
+#endif
+}
+
+bool CheckDataDirOption(const ArgsManager& args)
+{
+ const fs::path datadir{args.GetPathArg("-datadir")};
+ return datadir.empty() || fs::is_directory(fs::absolute(datadir));
+}
+
+fs::path ArgsManager::GetConfigFilePath() const
+{
+ return GetConfigFile(*this, GetPathArg("-conf", BITCOIN_CONF_FILENAME));
+}
+
+std::string ArgsManager::GetChainName() const
+{
+ auto get_net = [&](const std::string& arg) {
+ LOCK(cs_args);
+ util::SettingsValue value = util::GetSetting(m_settings, /* section= */ "", SettingName(arg),
+ /* ignore_default_section_config= */ false,
+ /*ignore_nonpersistent=*/false,
+ /* get_chain_name= */ true);
+ return value.isNull() ? false : value.isBool() ? value.get_bool() : InterpretBool(value.get_str());
+ };
+
+ const bool fRegTest = get_net("-regtest");
+ const bool fSigNet = get_net("-signet");
+ const bool fTestNet = get_net("-testnet");
+ const bool is_chain_arg_set = IsArgSet("-chain");
+
+ if ((int)is_chain_arg_set + (int)fRegTest + (int)fSigNet + (int)fTestNet > 1) {
+ throw std::runtime_error("Invalid combination of -regtest, -signet, -testnet and -chain. Can use at most one.");
+ }
+ if (fRegTest)
+ return CBaseChainParams::REGTEST;
+ if (fSigNet) {
+ return CBaseChainParams::SIGNET;
+ }
+ if (fTestNet)
+ return CBaseChainParams::TESTNET;
+
+ return GetArg("-chain", CBaseChainParams::MAIN);
+}
+
+bool ArgsManager::UseDefaultSection(const std::string& arg) const
+{
+ return m_network == CBaseChainParams::MAIN || m_network_only_args.count(arg) == 0;
+}
+
+util::SettingsValue ArgsManager::GetSetting(const std::string& arg) const
+{
+ LOCK(cs_args);
+ return util::GetSetting(
+ m_settings, m_network, SettingName(arg), !UseDefaultSection(arg),
+ /*ignore_nonpersistent=*/false, /*get_chain_name=*/false);
+}
+
+std::vector<util::SettingsValue> ArgsManager::GetSettingsList(const std::string& arg) const
+{
+ LOCK(cs_args);
+ return util::GetSettingsList(m_settings, m_network, SettingName(arg), !UseDefaultSection(arg));
+}
+
+void ArgsManager::logArgsPrefix(
+ const std::string& prefix,
+ const std::string& section,
+ const std::map<std::string, std::vector<util::SettingsValue>>& args) const
+{
+ std::string section_str = section.empty() ? "" : "[" + section + "] ";
+ for (const auto& arg : args) {
+ for (const auto& value : arg.second) {
+ std::optional<unsigned int> flags = GetArgFlags('-' + arg.first);
+ if (flags) {
+ std::string value_str = (*flags & SENSITIVE) ? "****" : value.write();
+ LogPrintf("%s %s%s=%s\n", prefix, section_str, arg.first, value_str);
+ }
+ }
+ }
+}
+
+void ArgsManager::LogArgs() const
+{
+ LOCK(cs_args);
+ for (const auto& section : m_settings.ro_config) {
+ logArgsPrefix("Config file arg:", section.first, section.second);
+ }
+ for (const auto& setting : m_settings.rw_settings) {
+ LogPrintf("Setting file arg: %s = %s\n", setting.first, setting.second.write());
+ }
+ logArgsPrefix("Command-line arg:", "", m_settings.command_line_options);
+}
+
+namespace common {
+#ifdef WIN32
+WinCmdLineArgs::WinCmdLineArgs()
+{
+ wchar_t** wargv = CommandLineToArgvW(GetCommandLineW(), &argc);
+ std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, wchar_t> utf8_cvt;
+ argv = new char*[argc];
+ args.resize(argc);
+ for (int i = 0; i < argc; i++) {
+ args[i] = utf8_cvt.to_bytes(wargv[i]);
+ argv[i] = &*args[i].begin();
+ }
+ LocalFree(wargv);
+}
+
+WinCmdLineArgs::~WinCmdLineArgs()
+{
+ delete[] argv;
+}
+
+std::pair<int, char**> WinCmdLineArgs::get()
+{
+ return std::make_pair(argc, argv);
+}
+#endif
+} // namespace common
diff --git a/src/common/args.h b/src/common/args.h
new file mode 100644
index 0000000000..430c392e2b
--- /dev/null
+++ b/src/common/args.h
@@ -0,0 +1,465 @@
+// Copyright (c) 2023 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_COMMON_ARGS_H
+#define BITCOIN_COMMON_ARGS_H
+
+#include <compat/compat.h>
+#include <sync.h>
+#include <util/fs.h>
+#include <util/settings.h>
+
+#include <iosfwd>
+#include <list>
+#include <map>
+#include <optional>
+#include <set>
+#include <stdint.h>
+#include <string>
+#include <vector>
+
+class ArgsManager;
+
+extern const char * const BITCOIN_CONF_FILENAME;
+extern const char * const BITCOIN_SETTINGS_FILENAME;
+
+// Return true if -datadir option points to a valid directory or is not specified.
+bool CheckDataDirOption(const ArgsManager& args);
+fs::path GetConfigFile(const ArgsManager& args, const fs::path& configuration_file_path);
+
+/**
+ * Most paths passed as configuration arguments are treated as relative to
+ * the datadir if they are not absolute.
+ *
+ * @param args Parsed arguments and settings.
+ * @param path The path to be conditionally prefixed with datadir.
+ * @param net_specific Use network specific datadir variant
+ * @return The normalized path.
+ */
+fs::path AbsPathForConfigVal(const ArgsManager& args, const fs::path& path, bool net_specific = true);
+
+inline bool IsSwitchChar(char c)
+{
+#ifdef WIN32
+ return c == '-' || c == '/';
+#else
+ return c == '-';
+#endif
+}
+
+enum class OptionsCategory {
+ OPTIONS,
+ CONNECTION,
+ WALLET,
+ WALLET_DEBUG_TEST,
+ ZMQ,
+ DEBUG_TEST,
+ CHAINPARAMS,
+ NODE_RELAY,
+ BLOCK_CREATION,
+ RPC,
+ GUI,
+ COMMANDS,
+ REGISTER_COMMANDS,
+
+ HIDDEN // Always the last option to avoid printing these in the help
+};
+
+struct KeyInfo {
+ std::string name;
+ std::string section;
+ bool negated{false};
+};
+
+KeyInfo InterpretKey(std::string key);
+
+std::optional<util::SettingsValue> InterpretValue(const KeyInfo& key, const std::string* value,
+ unsigned int flags, std::string& error);
+
+struct SectionInfo {
+ std::string m_name;
+ std::string m_file;
+ int m_line;
+};
+
+std::string SettingToString(const util::SettingsValue&, const std::string&);
+std::optional<std::string> SettingToString(const util::SettingsValue&);
+
+int64_t SettingToInt(const util::SettingsValue&, int64_t);
+std::optional<int64_t> SettingToInt(const util::SettingsValue&);
+
+bool SettingToBool(const util::SettingsValue&, bool);
+std::optional<bool> SettingToBool(const util::SettingsValue&);
+
+class ArgsManager
+{
+public:
+ /**
+ * Flags controlling how config and command line arguments are validated and
+ * interpreted.
+ */
+ enum Flags : uint32_t {
+ ALLOW_ANY = 0x01, //!< disable validation
+ // ALLOW_BOOL = 0x02, //!< unimplemented, draft implementation in #16545
+ // ALLOW_INT = 0x04, //!< unimplemented, draft implementation in #16545
+ // ALLOW_STRING = 0x08, //!< unimplemented, draft implementation in #16545
+ // ALLOW_LIST = 0x10, //!< unimplemented, draft implementation in #16545
+ DISALLOW_NEGATION = 0x20, //!< disallow -nofoo syntax
+ DISALLOW_ELISION = 0x40, //!< disallow -foo syntax that doesn't assign any value
+
+ DEBUG_ONLY = 0x100,
+ /* Some options would cause cross-contamination if values for
+ * mainnet were used while running on regtest/testnet (or vice-versa).
+ * Setting them as NETWORK_ONLY ensures that sharing a config file
+ * between mainnet and regtest/testnet won't cause problems due to these
+ * parameters by accident. */
+ NETWORK_ONLY = 0x200,
+ // This argument's value is sensitive (such as a password).
+ SENSITIVE = 0x400,
+ COMMAND = 0x800,
+ };
+
+protected:
+ struct Arg
+ {
+ std::string m_help_param;
+ std::string m_help_text;
+ unsigned int m_flags;
+ };
+
+ mutable RecursiveMutex cs_args;
+ util::Settings m_settings GUARDED_BY(cs_args);
+ std::vector<std::string> m_command GUARDED_BY(cs_args);
+ std::string m_network GUARDED_BY(cs_args);
+ std::set<std::string> m_network_only_args GUARDED_BY(cs_args);
+ std::map<OptionsCategory, std::map<std::string, Arg>> m_available_args GUARDED_BY(cs_args);
+ bool m_accept_any_command GUARDED_BY(cs_args){true};
+ std::list<SectionInfo> m_config_sections GUARDED_BY(cs_args);
+ mutable fs::path m_cached_blocks_path GUARDED_BY(cs_args);
+ mutable fs::path m_cached_datadir_path GUARDED_BY(cs_args);
+ mutable fs::path m_cached_network_datadir_path GUARDED_BY(cs_args);
+
+ [[nodiscard]] bool ReadConfigStream(std::istream& stream, const std::string& filepath, std::string& error, bool ignore_invalid_keys = false);
+
+ /**
+ * Returns true if settings values from the default section should be used,
+ * depending on the current network and whether the setting is
+ * network-specific.
+ */
+ bool UseDefaultSection(const std::string& arg) const EXCLUSIVE_LOCKS_REQUIRED(cs_args);
+
+ public:
+ /**
+ * Get setting value.
+ *
+ * Result will be null if setting was unset, true if "-setting" argument was passed
+ * false if "-nosetting" argument was passed, and a string if a "-setting=value"
+ * argument was passed.
+ */
+ util::SettingsValue GetSetting(const std::string& arg) const;
+
+ /**
+ * Get list of setting values.
+ */
+ std::vector<util::SettingsValue> GetSettingsList(const std::string& arg) const;
+
+ ArgsManager();
+ ~ArgsManager();
+
+ /**
+ * Select the network in use
+ */
+ void SelectConfigNetwork(const std::string& network);
+
+ [[nodiscard]] bool ParseParameters(int argc, const char* const argv[], std::string& error);
+
+ /**
+ * Return config file path (read-only)
+ */
+ fs::path GetConfigFilePath() const;
+ [[nodiscard]] bool ReadConfigFiles(std::string& error, bool ignore_invalid_keys = false);
+
+ /**
+ * Log warnings for options in m_section_only_args when
+ * they are specified in the default section but not overridden
+ * on the command line or in a network-specific section in the
+ * config file.
+ */
+ std::set<std::string> GetUnsuitableSectionOnlyArgs() const;
+
+ /**
+ * Log warnings for unrecognized section names in the config file.
+ */
+ std::list<SectionInfo> GetUnrecognizedSections() const;
+
+ struct Command {
+ /** The command (if one has been registered with AddCommand), or empty */
+ std::string command;
+ /**
+ * If command is non-empty: Any args that followed it
+ * If command is empty: The unregistered command and any args that followed it
+ */
+ std::vector<std::string> args;
+ };
+ /**
+ * Get the command and command args (returns std::nullopt if no command provided)
+ */
+ std::optional<const Command> GetCommand() const;
+
+ /**
+ * Get blocks directory path
+ *
+ * @return Blocks path which is network specific
+ */
+ const fs::path& GetBlocksDirPath() const;
+
+ /**
+ * Get data directory path
+ *
+ * @return Absolute path on success, otherwise an empty path when a non-directory path would be returned
+ */
+ const fs::path& GetDataDirBase() const { return GetDataDir(false); }
+
+ /**
+ * Get data directory path with appended network identifier
+ *
+ * @return Absolute path on success, otherwise an empty path when a non-directory path would be returned
+ */
+ const fs::path& GetDataDirNet() const { return GetDataDir(true); }
+
+ /**
+ * Clear cached directory paths
+ */
+ void ClearPathCache();
+
+ /**
+ * Return a vector of strings of the given argument
+ *
+ * @param strArg Argument to get (e.g. "-foo")
+ * @return command-line arguments
+ */
+ std::vector<std::string> GetArgs(const std::string& strArg) const;
+
+ /**
+ * Return true if the given argument has been manually set
+ *
+ * @param strArg Argument to get (e.g. "-foo")
+ * @return true if the argument has been set
+ */
+ bool IsArgSet(const std::string& strArg) const;
+
+ /**
+ * Return true if the argument was originally passed as a negated option,
+ * i.e. -nofoo.
+ *
+ * @param strArg Argument to get (e.g. "-foo")
+ * @return true if the argument was passed negated
+ */
+ bool IsArgNegated(const std::string& strArg) const;
+
+ /**
+ * Return string argument or default value
+ *
+ * @param strArg Argument to get (e.g. "-foo")
+ * @param strDefault (e.g. "1")
+ * @return command-line argument or default value
+ */
+ std::string GetArg(const std::string& strArg, const std::string& strDefault) const;
+ std::optional<std::string> GetArg(const std::string& strArg) const;
+
+ /**
+ * Return path argument or default value
+ *
+ * @param arg Argument to get a path from (e.g., "-datadir", "-blocksdir" or "-walletdir")
+ * @param default_value Optional default value to return instead of the empty path.
+ * @return normalized path if argument is set, with redundant "." and ".."
+ * path components and trailing separators removed (see patharg unit test
+ * for examples or implementation for details). If argument is empty or not
+ * set, default_value is returned unchanged.
+ */
+ fs::path GetPathArg(std::string arg, const fs::path& default_value = {}) const;
+
+ /**
+ * Return integer argument or default value
+ *
+ * @param strArg Argument to get (e.g. "-foo")
+ * @param nDefault (e.g. 1)
+ * @return command-line argument (0 if invalid number) or default value
+ */
+ int64_t GetIntArg(const std::string& strArg, int64_t nDefault) const;
+ std::optional<int64_t> GetIntArg(const std::string& strArg) const;
+
+ /**
+ * Return boolean argument or default value
+ *
+ * @param strArg Argument to get (e.g. "-foo")
+ * @param fDefault (true or false)
+ * @return command-line argument or default value
+ */
+ bool GetBoolArg(const std::string& strArg, bool fDefault) const;
+ std::optional<bool> GetBoolArg(const std::string& strArg) const;
+
+ /**
+ * Set an argument if it doesn't already have a value
+ *
+ * @param strArg Argument to set (e.g. "-foo")
+ * @param strValue Value (e.g. "1")
+ * @return true if argument gets set, false if it already had a value
+ */
+ bool SoftSetArg(const std::string& strArg, const std::string& strValue);
+
+ /**
+ * Set a boolean argument if it doesn't already have a value
+ *
+ * @param strArg Argument to set (e.g. "-foo")
+ * @param fValue Value (e.g. false)
+ * @return true if argument gets set, false if it already had a value
+ */
+ bool SoftSetBoolArg(const std::string& strArg, bool fValue);
+
+ // Forces an arg setting. Called by SoftSetArg() if the arg hasn't already
+ // been set. Also called directly in testing.
+ void ForceSetArg(const std::string& strArg, const std::string& strValue);
+
+ /**
+ * Returns the appropriate chain name from the program arguments.
+ * @return CBaseChainParams::MAIN by default; raises runtime error if an invalid combination is given.
+ */
+ std::string GetChainName() const;
+
+ /**
+ * Add argument
+ */
+ void AddArg(const std::string& name, const std::string& help, unsigned int flags, const OptionsCategory& cat);
+
+ /**
+ * Add subcommand
+ */
+ void AddCommand(const std::string& cmd, const std::string& help);
+
+ /**
+ * Add many hidden arguments
+ */
+ void AddHiddenArgs(const std::vector<std::string>& args);
+
+ /**
+ * Clear available arguments
+ */
+ void ClearArgs() {
+ LOCK(cs_args);
+ m_available_args.clear();
+ m_network_only_args.clear();
+ }
+
+ /**
+ * Get the help string
+ */
+ std::string GetHelpMessage() const;
+
+ /**
+ * Return Flags for known arg.
+ * Return nullopt for unknown arg.
+ */
+ std::optional<unsigned int> GetArgFlags(const std::string& name) const;
+
+ /**
+ * Get settings file path, or return false if read-write settings were
+ * disabled with -nosettings.
+ */
+ bool GetSettingsPath(fs::path* filepath = nullptr, bool temp = false, bool backup = false) const;
+
+ /**
+ * Read settings file. Push errors to vector, or log them if null.
+ */
+ bool ReadSettingsFile(std::vector<std::string>* errors = nullptr);
+
+ /**
+ * Write settings file or backup settings file. Push errors to vector, or
+ * log them if null.
+ */
+ bool WriteSettingsFile(std::vector<std::string>* errors = nullptr, bool backup = false) const;
+
+ /**
+ * Get current setting from config file or read/write settings file,
+ * ignoring nonpersistent command line or forced settings values.
+ */
+ util::SettingsValue GetPersistentSetting(const std::string& name) const;
+
+ /**
+ * Access settings with lock held.
+ */
+ template <typename Fn>
+ void LockSettings(Fn&& fn)
+ {
+ LOCK(cs_args);
+ fn(m_settings);
+ }
+
+ /**
+ * Log the config file options and the command line arguments,
+ * useful for troubleshooting.
+ */
+ void LogArgs() const;
+
+private:
+ /**
+ * Get data directory path
+ *
+ * @param net_specific Append network identifier to the returned path
+ * @return Absolute path on success, otherwise an empty path when a non-directory path would be returned
+ */
+ const fs::path& GetDataDir(bool net_specific) const;
+
+ // Helper function for LogArgs().
+ void logArgsPrefix(
+ const std::string& prefix,
+ const std::string& section,
+ const std::map<std::string, std::vector<util::SettingsValue>>& args) const;
+};
+
+extern ArgsManager gArgs;
+
+/**
+ * @return true if help has been requested via a command-line arg
+ */
+bool HelpRequested(const ArgsManager& args);
+
+/** Add help options to the args manager */
+void SetupHelpOptions(ArgsManager& args);
+
+/**
+ * Format a string to be used as group of options in help messages
+ *
+ * @param message Group name (e.g. "RPC server options:")
+ * @return the formatted string
+ */
+std::string HelpMessageGroup(const std::string& message);
+
+/**
+ * Format a string to be used as option description in help messages
+ *
+ * @param option Option message (e.g. "-rpcuser=<user>")
+ * @param message Option description (e.g. "Username for JSON-RPC connections")
+ * @return the formatted string
+ */
+std::string HelpMessageOpt(const std::string& option, const std::string& message);
+
+namespace common {
+#ifdef WIN32
+class WinCmdLineArgs
+{
+public:
+ WinCmdLineArgs();
+ ~WinCmdLineArgs();
+ std::pair<int, char**> get();
+
+private:
+ int argc;
+ char** argv;
+ std::vector<std::string> args;
+};
+#endif
+} // namespace common
+
+#endif // BITCOIN_COMMON_ARGS_H
diff --git a/src/common/config.cpp b/src/common/config.cpp
new file mode 100644
index 0000000000..747503ad2a
--- /dev/null
+++ b/src/common/config.cpp
@@ -0,0 +1,220 @@
+// Copyright (c) 2023 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <common/args.h>
+
+#include <logging.h>
+#include <sync.h>
+#include <tinyformat.h>
+#include <univalue.h>
+#include <util/fs.h>
+#include <util/settings.h>
+#include <util/string.h>
+
+#include <algorithm>
+#include <cassert>
+#include <cstdlib>
+#include <fstream>
+#include <iostream>
+#include <list>
+#include <map>
+#include <memory>
+#include <optional>
+#include <string>
+#include <string_view>
+#include <utility>
+#include <vector>
+
+fs::path GetConfigFile(const ArgsManager& args, const fs::path& configuration_file_path)
+{
+ return AbsPathForConfigVal(args, configuration_file_path, /*net_specific=*/false);
+}
+
+static bool GetConfigOptions(std::istream& stream, const std::string& filepath, std::string& error, std::vector<std::pair<std::string, std::string>>& options, std::list<SectionInfo>& sections)
+{
+ std::string str, prefix;
+ std::string::size_type pos;
+ int linenr = 1;
+ while (std::getline(stream, str)) {
+ bool used_hash = false;
+ if ((pos = str.find('#')) != std::string::npos) {
+ str = str.substr(0, pos);
+ used_hash = true;
+ }
+ const static std::string pattern = " \t\r\n";
+ str = TrimString(str, pattern);
+ if (!str.empty()) {
+ if (*str.begin() == '[' && *str.rbegin() == ']') {
+ const std::string section = str.substr(1, str.size() - 2);
+ sections.emplace_back(SectionInfo{section, filepath, linenr});
+ prefix = section + '.';
+ } else if (*str.begin() == '-') {
+ error = strprintf("parse error on line %i: %s, options in configuration file must be specified without leading -", linenr, str);
+ return false;
+ } else if ((pos = str.find('=')) != std::string::npos) {
+ std::string name = prefix + TrimString(std::string_view{str}.substr(0, pos), pattern);
+ std::string_view value = TrimStringView(std::string_view{str}.substr(pos + 1), pattern);
+ if (used_hash && name.find("rpcpassword") != std::string::npos) {
+ error = strprintf("parse error on line %i, using # in rpcpassword can be ambiguous and should be avoided", linenr);
+ return false;
+ }
+ options.emplace_back(name, value);
+ if ((pos = name.rfind('.')) != std::string::npos && prefix.length() <= pos) {
+ sections.emplace_back(SectionInfo{name.substr(0, pos), filepath, linenr});
+ }
+ } else {
+ error = strprintf("parse error on line %i: %s", linenr, str);
+ if (str.size() >= 2 && str.substr(0, 2) == "no") {
+ error += strprintf(", if you intended to specify a negated option, use %s=1 instead", str);
+ }
+ return false;
+ }
+ }
+ ++linenr;
+ }
+ return true;
+}
+
+bool IsConfSupported(KeyInfo& key, std::string& error) {
+ if (key.name == "conf") {
+ error = "conf cannot be set in the configuration file; use includeconf= if you want to include additional config files";
+ return false;
+ }
+ if (key.name == "reindex") {
+ // reindex can be set in a config file but it is strongly discouraged as this will cause the node to reindex on
+ // every restart. Allow the config but throw a warning
+ LogPrintf("Warning: reindex=1 is set in the configuration file, which will significantly slow down startup. Consider removing or commenting out this option for better performance, unless there is currently a condition which makes rebuilding the indexes necessary\n");
+ return true;
+ }
+ return true;
+}
+
+bool ArgsManager::ReadConfigStream(std::istream& stream, const std::string& filepath, std::string& error, bool ignore_invalid_keys)
+{
+ LOCK(cs_args);
+ std::vector<std::pair<std::string, std::string>> options;
+ if (!GetConfigOptions(stream, filepath, error, options, m_config_sections)) {
+ return false;
+ }
+ for (const std::pair<std::string, std::string>& option : options) {
+ KeyInfo key = InterpretKey(option.first);
+ std::optional<unsigned int> flags = GetArgFlags('-' + key.name);
+ if (!IsConfSupported(key, error)) return false;
+ if (flags) {
+ std::optional<util::SettingsValue> value = InterpretValue(key, &option.second, *flags, error);
+ if (!value) {
+ return false;
+ }
+ m_settings.ro_config[key.section][key.name].push_back(*value);
+ } else {
+ if (ignore_invalid_keys) {
+ LogPrintf("Ignoring unknown configuration value %s\n", option.first);
+ } else {
+ error = strprintf("Invalid configuration value %s", option.first);
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+bool ArgsManager::ReadConfigFiles(std::string& error, bool ignore_invalid_keys)
+{
+ {
+ LOCK(cs_args);
+ m_settings.ro_config.clear();
+ m_config_sections.clear();
+ }
+
+ 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()) {
+ error = strprintf("specified config file \"%s\" could not be opened.", fs::PathToString(conf_path));
+ return false;
+ }
+ // ok to not have a config file
+ if (stream.good()) {
+ if (!ReadConfigStream(stream, fs::PathToString(conf_path), error, ignore_invalid_keys)) {
+ return false;
+ }
+ // `-includeconf` cannot be included in the command line arguments except
+ // as `-noincludeconf` (which indicates that no included conf file should be used).
+ bool use_conf_file{true};
+ {
+ LOCK(cs_args);
+ if (auto* includes = util::FindKey(m_settings.command_line_options, "includeconf")) {
+ // ParseParameters() fails if a non-negated -includeconf is passed on the command-line
+ assert(util::SettingsSpan(*includes).last_negated());
+ use_conf_file = false;
+ }
+ }
+ if (use_conf_file) {
+ std::string chain_id = GetChainName();
+ std::vector<std::string> conf_file_names;
+
+ auto add_includes = [&](const std::string& network, size_t skip = 0) {
+ size_t num_values = 0;
+ LOCK(cs_args);
+ if (auto* section = util::FindKey(m_settings.ro_config, network)) {
+ if (auto* values = util::FindKey(*section, "includeconf")) {
+ for (size_t i = std::max(skip, util::SettingsSpan(*values).negated()); i < values->size(); ++i) {
+ conf_file_names.push_back((*values)[i].get_str());
+ }
+ num_values = values->size();
+ }
+ }
+ return num_values;
+ };
+
+ // We haven't set m_network yet (that happens in SelectParams()), so manually check
+ // for network.includeconf args.
+ const size_t chain_includes = add_includes(chain_id);
+ const size_t default_includes = add_includes({});
+
+ for (const std::string& conf_file_name : conf_file_names) {
+ std::ifstream conf_file_stream{GetConfigFile(*this, fs::PathFromString(conf_file_name))};
+ if (conf_file_stream.good()) {
+ if (!ReadConfigStream(conf_file_stream, conf_file_name, error, ignore_invalid_keys)) {
+ return false;
+ }
+ LogPrintf("Included configuration file %s\n", conf_file_name);
+ } else {
+ error = "Failed to include configuration file " + conf_file_name;
+ return false;
+ }
+ }
+
+ // Warn about recursive -includeconf
+ conf_file_names.clear();
+ add_includes(chain_id, /* skip= */ chain_includes);
+ add_includes({}, /* skip= */ default_includes);
+ std::string chain_id_final = GetChainName();
+ if (chain_id_final != chain_id) {
+ // Also warn about recursive includeconf for the chain that was specified in one of the includeconfs
+ add_includes(chain_id_final);
+ }
+ for (const std::string& conf_file_name : conf_file_names) {
+ tfm::format(std::cerr, "warning: -includeconf cannot be used from included files; ignoring -includeconf=%s\n", conf_file_name);
+ }
+ }
+ }
+
+ // If datadir is changed in .conf file:
+ ClearPathCache();
+ if (!CheckDataDirOption(*this)) {
+ error = strprintf("specified data directory \"%s\" does not exist.", GetArg("-datadir", ""));
+ return false;
+ }
+ return true;
+}
+
+fs::path AbsPathForConfigVal(const ArgsManager& args, const fs::path& path, bool net_specific)
+{
+ if (path.is_absolute()) {
+ return path;
+ }
+ return fsbridge::AbsPathJoin(net_specific ? args.GetDataDirNet() : args.GetDataDirBase(), path);
+}
diff --git a/src/common/init.cpp b/src/common/init.cpp
index e8fa7a14fd..6ffa44847a 100644
--- a/src/common/init.cpp
+++ b/src/common/init.cpp
@@ -3,10 +3,10 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <chainparams.h>
+#include <common/args.h>
#include <common/init.h>
#include <tinyformat.h>
#include <util/fs.h>
-#include <util/system.h>
#include <util/translation.h>
#include <algorithm>
diff --git a/src/dummywallet.cpp b/src/dummywallet.cpp
index 028c6ebae1..9160ec19e6 100644
--- a/src/dummywallet.cpp
+++ b/src/dummywallet.cpp
@@ -2,7 +2,8 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <util/system.h>
+#include <common/args.h>
+#include <logging.h>
#include <walletinitinterface.h>
class ArgsManager;
diff --git a/src/httprpc.cpp b/src/httprpc.cpp
index 86166a5ca4..bf3fa6298d 100644
--- a/src/httprpc.cpp
+++ b/src/httprpc.cpp
@@ -4,13 +4,14 @@
#include <httprpc.h>
+#include <common/args.h>
#include <crypto/hmac_sha256.h>
#include <httpserver.h>
+#include <logging.h>
#include <rpc/protocol.h>
#include <rpc/server.h>
#include <util/strencodings.h>
#include <util/string.h>
-#include <util/system.h>
#include <walletinitinterface.h>
#include <algorithm>
diff --git a/src/httpserver.cpp b/src/httpserver.cpp
index 8e49f9c0f4..4f8a2b4d8d 100644
--- a/src/httpserver.cpp
+++ b/src/httpserver.cpp
@@ -9,7 +9,9 @@
#include <httpserver.h>
#include <chainparamsbase.h>
+#include <common/args.h>
#include <compat/compat.h>
+#include <logging.h>
#include <netbase.h>
#include <node/interface_ui.h>
#include <rpc/protocol.h> // For HTTP status codes
@@ -17,7 +19,6 @@
#include <sync.h>
#include <util/strencodings.h>
#include <util/syscall_sandbox.h>
-#include <util/system.h>
#include <util/threadnames.h>
#include <util/translation.h>
diff --git a/src/i2p.cpp b/src/i2p.cpp
index 76fbb89536..c67b6ed185 100644
--- a/src/i2p.cpp
+++ b/src/i2p.cpp
@@ -3,6 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <chainparams.h>
+#include <common/args.h>
#include <compat/compat.h>
#include <compat/endian.h>
#include <crypto/sha256.h>
@@ -17,7 +18,6 @@
#include <util/sock.h>
#include <util/spanparsing.h>
#include <util/strencodings.h>
-#include <util/system.h>
#include <util/threadinterrupt.h>
#include <chrono>
diff --git a/src/index/base.cpp b/src/index/base.cpp
index 8a311296c2..237c8e8be0 100644
--- a/src/index/base.cpp
+++ b/src/index/base.cpp
@@ -3,6 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <chainparams.h>
+#include <common/args.h>
#include <index/base.h>
#include <interfaces/chain.h>
#include <kernel/chain.h>
@@ -14,7 +15,6 @@
#include <shutdown.h>
#include <tinyformat.h>
#include <util/syscall_sandbox.h>
-#include <util/system.h>
#include <util/thread.h>
#include <util/translation.h>
#include <validation.h> // For g_chainman
diff --git a/src/index/blockfilterindex.cpp b/src/index/blockfilterindex.cpp
index 43c2215338..e6300ce3dd 100644
--- a/src/index/blockfilterindex.cpp
+++ b/src/index/blockfilterindex.cpp
@@ -4,12 +4,12 @@
#include <map>
+#include <common/args.h>
#include <dbwrapper.h>
#include <hash.h>
#include <index/blockfilterindex.h>
#include <node/blockstorage.h>
#include <util/fs_helpers.h>
-#include <util/system.h>
#include <validation.h>
using node::UndoReadFromDisk;
diff --git a/src/index/coinstatsindex.cpp b/src/index/coinstatsindex.cpp
index 4d637e217a..5bc6ad3d31 100644
--- a/src/index/coinstatsindex.cpp
+++ b/src/index/coinstatsindex.cpp
@@ -4,6 +4,7 @@
#include <chainparams.h>
#include <coins.h>
+#include <common/args.h>
#include <crypto/muhash.h>
#include <index/coinstatsindex.h>
#include <kernel/coinstats.h>
@@ -12,7 +13,6 @@
#include <serialize.h>
#include <txdb.h>
#include <undo.h>
-#include <util/system.h>
#include <validation.h>
using kernel::CCoinsStats;
diff --git a/src/index/txindex.cpp b/src/index/txindex.cpp
index 9095e7afeb..49bddf2d4d 100644
--- a/src/index/txindex.cpp
+++ b/src/index/txindex.cpp
@@ -4,10 +4,10 @@
#include <index/txindex.h>
+#include <common/args.h>
#include <index/disktxpos.h>
#include <logging.h>
#include <node/blockstorage.h>
-#include <util/system.h>
#include <validation.h>
using node::OpenBlockFile;
diff --git a/src/init.cpp b/src/init.cpp
index 1122496539..525648b812 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -18,6 +18,7 @@
#include <blockfilter.h>
#include <chain.h>
#include <chainparams.h>
+#include <common/args.h>
#include <consensus/amount.h>
#include <deploymentstatus.h>
#include <hash.h>
diff --git a/src/init/bitcoin-gui.cpp b/src/init/bitcoin-gui.cpp
index 100b4ef7ee..ddbdaa6cd0 100644
--- a/src/init/bitcoin-gui.cpp
+++ b/src/init/bitcoin-gui.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 <common/args.h>
#include <interfaces/chain.h>
#include <interfaces/echo.h>
#include <interfaces/init.h>
@@ -10,7 +11,6 @@
#include <interfaces/wallet.h>
#include <node/context.h>
#include <util/check.h>
-#include <util/system.h>
#include <memory>
diff --git a/src/init/bitcoin-node.cpp b/src/init/bitcoin-node.cpp
index 1418e63777..b04596f986 100644
--- a/src/init/bitcoin-node.cpp
+++ b/src/init/bitcoin-node.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 <common/args.h>
#include <interfaces/chain.h>
#include <interfaces/echo.h>
#include <interfaces/init.h>
@@ -10,7 +11,6 @@
#include <interfaces/wallet.h>
#include <node/context.h>
#include <util/check.h>
-#include <util/system.h>
#include <memory>
diff --git a/src/init/bitcoin-qt.cpp b/src/init/bitcoin-qt.cpp
index e27be0e598..dd5826d982 100644
--- a/src/init/bitcoin-qt.cpp
+++ b/src/init/bitcoin-qt.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 <common/args.h>
#include <interfaces/chain.h>
#include <interfaces/echo.h>
#include <interfaces/init.h>
@@ -9,7 +10,6 @@
#include <interfaces/wallet.h>
#include <node/context.h>
#include <util/check.h>
-#include <util/system.h>
#include <memory>
diff --git a/src/init/bitcoind.cpp b/src/init/bitcoind.cpp
index 7ad1f64e64..210608370c 100644
--- a/src/init/bitcoind.cpp
+++ b/src/init/bitcoind.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 <common/args.h>
#include <interfaces/chain.h>
#include <interfaces/echo.h>
#include <interfaces/init.h>
@@ -9,7 +10,6 @@
#include <interfaces/wallet.h>
#include <node/context.h>
#include <util/check.h>
-#include <util/system.h>
#include <memory>
diff --git a/src/init/common.cpp b/src/init/common.cpp
index 33a5cec3f1..9a52a09cea 100644
--- a/src/init/common.cpp
+++ b/src/init/common.cpp
@@ -7,13 +7,13 @@
#endif
#include <clientversion.h>
+#include <common/args.h>
#include <logging.h>
#include <node/interface_ui.h>
#include <tinyformat.h>
#include <util/fs.h>
#include <util/fs_helpers.h>
#include <util/string.h>
-#include <util/system.h>
#include <util/time.h>
#include <util/translation.h>
diff --git a/src/net.cpp b/src/net.cpp
index f56de6d605..337cf60680 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -13,6 +13,7 @@
#include <addrman.h>
#include <banman.h>
#include <clientversion.h>
+#include <common/args.h>
#include <compat/compat.h>
#include <consensus/consensus.h>
#include <crypto/sha256.h>
@@ -30,7 +31,6 @@
#include <util/sock.h>
#include <util/strencodings.h>
#include <util/syscall_sandbox.h>
-#include <util/system.h>
#include <util/thread.h>
#include <util/threadinterrupt.h>
#include <util/trace.h>
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index c9d75c7fbf..c50aa2e4f9 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -10,6 +10,7 @@
#include <blockencodings.h>
#include <blockfilter.h>
#include <chainparams.h>
+#include <common/args.h>
#include <consensus/amount.h>
#include <consensus/validation.h>
#include <deploymentstatus.h>
@@ -39,7 +40,6 @@
#include <txrequest.h>
#include <util/check.h> // For NDEBUG compile time check
#include <util/strencodings.h>
-#include <util/system.h>
#include <util/trace.h>
#include <validation.h>
diff --git a/src/node/blockmanager_args.cpp b/src/node/blockmanager_args.cpp
index 5fb5c8beed..06a1934947 100644
--- a/src/node/blockmanager_args.cpp
+++ b/src/node/blockmanager_args.cpp
@@ -4,7 +4,7 @@
#include <node/blockmanager_args.h>
-#include <util/system.h>
+#include <common/args.h>
#include <validation.h>
namespace node {
diff --git a/src/node/blockstorage.cpp b/src/node/blockstorage.cpp
index af84e6d7e7..38859f1b0d 100644
--- a/src/node/blockstorage.cpp
+++ b/src/node/blockstorage.cpp
@@ -6,11 +6,12 @@
#include <chain.h>
#include <clientversion.h>
+#include <common/args.h>
#include <consensus/validation.h>
#include <flatfile.h>
#include <hash.h>
-#include <logging.h>
#include <kernel/chainparams.h>
+#include <logging.h>
#include <pow.h>
#include <reverse_iterator.h>
#include <shutdown.h>
diff --git a/src/node/caches.cpp b/src/node/caches.cpp
index 7622a03e19..7403f7ddea 100644
--- a/src/node/caches.cpp
+++ b/src/node/caches.cpp
@@ -4,9 +4,9 @@
#include <node/caches.h>
+#include <common/args.h>
#include <index/txindex.h>
#include <txdb.h>
-#include <util/system.h>
namespace node {
CacheSizes CalculateCacheSizes(const ArgsManager& args, size_t n_indexes)
diff --git a/src/node/chainstatemanager_args.cpp b/src/node/chainstatemanager_args.cpp
index 9801e6e959..b97344c9aa 100644
--- a/src/node/chainstatemanager_args.cpp
+++ b/src/node/chainstatemanager_args.cpp
@@ -5,13 +5,13 @@
#include <node/chainstatemanager_args.h>
#include <arith_uint256.h>
+#include <common/args.h>
#include <kernel/chainstatemanager_opts.h>
#include <node/coins_view_args.h>
#include <node/database_args.h>
#include <tinyformat.h>
#include <uint256.h>
#include <util/strencodings.h>
-#include <util/system.h>
#include <util/translation.h>
#include <validation.h>
diff --git a/src/node/coins_view_args.cpp b/src/node/coins_view_args.cpp
index 67c9b8dbac..5d55143e83 100644
--- a/src/node/coins_view_args.cpp
+++ b/src/node/coins_view_args.cpp
@@ -4,8 +4,8 @@
#include <node/coins_view_args.h>
+#include <common/args.h>
#include <txdb.h>
-#include <util/system.h>
namespace node {
void ReadCoinsViewArgs(const ArgsManager& args, CoinsViewOptions& options)
diff --git a/src/node/database_args.cpp b/src/node/database_args.cpp
index 2c53b4b47e..aba3c38ff3 100644
--- a/src/node/database_args.cpp
+++ b/src/node/database_args.cpp
@@ -4,8 +4,8 @@
#include <node/database_args.h>
+#include <common/args.h>
#include <dbwrapper.h>
-#include <util/system.h>
namespace node {
void ReadDatabaseArgs(const ArgsManager& args, DBOptions& options)
diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp
index 50ed4c2ab8..5fcace833f 100644
--- a/src/node/interfaces.cpp
+++ b/src/node/interfaces.cpp
@@ -7,6 +7,7 @@
#include <blockfilter.h>
#include <chain.h>
#include <chainparams.h>
+#include <common/args.h>
#include <deploymentstatus.h>
#include <external_signer.h>
#include <index/blockfilterindex.h>
@@ -43,7 +44,6 @@
#include <uint256.h>
#include <univalue.h>
#include <util/check.h>
-#include <util/system.h>
#include <util/translation.h>
#include <validation.h>
#include <validationinterface.h>
diff --git a/src/node/mempool_args.cpp b/src/node/mempool_args.cpp
index a0a2e43107..f193469506 100644
--- a/src/node/mempool_args.cpp
+++ b/src/node/mempool_args.cpp
@@ -7,6 +7,7 @@
#include <kernel/mempool_limits.h>
#include <kernel/mempool_options.h>
+#include <common/args.h>
#include <consensus/amount.h>
#include <kernel/chainparams.h>
#include <logging.h>
@@ -16,7 +17,6 @@
#include <tinyformat.h>
#include <util/error.h>
#include <util/moneystr.h>
-#include <util/system.h>
#include <util/translation.h>
#include <chrono>
diff --git a/src/node/mempool_persist_args.cpp b/src/node/mempool_persist_args.cpp
index 78e3472644..97ecdd651b 100644
--- a/src/node/mempool_persist_args.cpp
+++ b/src/node/mempool_persist_args.cpp
@@ -4,8 +4,8 @@
#include <node/mempool_persist_args.h>
+#include <common/args.h>
#include <util/fs.h>
-#include <util/system.h>
#include <validation.h>
namespace node {
diff --git a/src/node/miner.cpp b/src/node/miner.cpp
index c7bc9a9a3d..aa1a9a155c 100644
--- a/src/node/miner.cpp
+++ b/src/node/miner.cpp
@@ -8,6 +8,7 @@
#include <chain.h>
#include <chainparams.h>
#include <coins.h>
+#include <common/args.h>
#include <consensus/amount.h>
#include <consensus/consensus.h>
#include <consensus/merkle.h>
@@ -20,7 +21,6 @@
#include <primitives/transaction.h>
#include <timedata.h>
#include <util/moneystr.h>
-#include <util/system.h>
#include <validation.h>
#include <algorithm>
diff --git a/src/node/txreconciliation.cpp b/src/node/txreconciliation.cpp
index ed04a78cec..9938759074 100644
--- a/src/node/txreconciliation.cpp
+++ b/src/node/txreconciliation.cpp
@@ -4,6 +4,7 @@
#include <node/txreconciliation.h>
+#include <logging.h>
#include <util/check.h>
#include <util/system.h>
diff --git a/src/node/utxo_snapshot.cpp b/src/node/utxo_snapshot.cpp
index 591c1dad6e..3dae46fb84 100644
--- a/src/node/utxo_snapshot.cpp
+++ b/src/node/utxo_snapshot.cpp
@@ -4,6 +4,7 @@
#include <node/utxo_snapshot.h>
+#include <common/args.h>
#include <logging.h>
#include <streams.h>
#include <sync.h>
@@ -11,7 +12,6 @@
#include <txdb.h>
#include <uint256.h>
#include <util/fs.h>
-#include <util/system.h>
#include <validation.h>
#include <cassert>
diff --git a/src/node/validation_cache_args.cpp b/src/node/validation_cache_args.cpp
index 5ea0a8ca0a..ddf24f798d 100644
--- a/src/node/validation_cache_args.cpp
+++ b/src/node/validation_cache_args.cpp
@@ -6,7 +6,7 @@
#include <kernel/validation_cache_sizes.h>
-#include <util/system.h>
+#include <common/args.h>
#include <algorithm>
#include <cstddef>
diff --git a/src/policy/fees_args.cpp b/src/policy/fees_args.cpp
index 1aeb2ab983..988b6d443a 100644
--- a/src/policy/fees_args.cpp
+++ b/src/policy/fees_args.cpp
@@ -4,7 +4,7 @@
#include <policy/fees_args.h>
-#include <util/system.h>
+#include <common/args.h>
namespace {
const char* FEE_ESTIMATES_FILENAME = "fee_estimates.dat";
diff --git a/src/protocol.cpp b/src/protocol.cpp
index aa59bae6ff..5725813b7e 100644
--- a/src/protocol.cpp
+++ b/src/protocol.cpp
@@ -7,6 +7,8 @@
#include <util/system.h>
+#include <atomic>
+
static std::atomic<bool> g_initial_block_download_completed(false);
namespace NetMsgType {
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index f604039427..2f00009596 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -9,6 +9,7 @@
#include <qt/bitcoin.h>
#include <chainparams.h>
+#include <common/args.h>
#include <common/init.h>
#include <init.h>
#include <interfaces/handler.h>
@@ -494,7 +495,7 @@ static void SetupUIArgs(ArgsManager& argsman)
int GuiMain(int argc, char* argv[])
{
#ifdef WIN32
- util::WinCmdLineArgs winArgs;
+ common::WinCmdLineArgs winArgs;
std::tie(argc, argv) = winArgs.get();
#endif
diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp
index 8411ec4696..837e5f4fed 100644
--- a/src/qt/clientmodel.cpp
+++ b/src/qt/clientmodel.cpp
@@ -11,6 +11,7 @@
#include <qt/peertablesortproxy.h>
#include <clientversion.h>
+#include <common/args.h>
#include <interfaces/handler.h>
#include <interfaces/node.h>
#include <net.h>
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index e98d953fd2..dc7daed4bc 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -12,8 +12,10 @@
#include <base58.h>
#include <chainparams.h>
+#include <common/args.h>
#include <interfaces/node.h>
#include <key_io.h>
+#include <logging.h>
#include <policy/policy.h>
#include <primitives/transaction.h>
#include <protocol.h>
@@ -22,7 +24,6 @@
#include <util/exception.h>
#include <util/fs.h>
#include <util/fs_helpers.h>
-#include <util/system.h>
#include <util/time.h>
#ifdef WIN32
diff --git a/src/qt/intro.cpp b/src/qt/intro.cpp
index 6423e457aa..a54ba19354 100644
--- a/src/qt/intro.cpp
+++ b/src/qt/intro.cpp
@@ -15,9 +15,9 @@
#include <qt/guiutil.h>
#include <qt/optionsmodel.h>
+#include <common/args.h>
#include <interfaces/node.h>
#include <util/fs_helpers.h>
-#include <util/system.h>
#include <validation.h>
#include <QFileDialog>
diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp
index bee8fafddc..87a7e703b8 100644
--- a/src/qt/optionsmodel.cpp
+++ b/src/qt/optionsmodel.cpp
@@ -12,14 +12,14 @@
#include <qt/guiconstants.h>
#include <qt/guiutil.h>
+#include <common/args.h>
#include <interfaces/node.h>
#include <mapport.h>
#include <net.h>
#include <netbase.h>
-#include <txdb.h> // for -dbcache defaults
+#include <txdb.h> // for -dbcache defaults
#include <util/string.h>
-#include <util/system.h>
-#include <validation.h> // For DEFAULT_SCRIPTCHECK_THREADS
+#include <validation.h> // For DEFAULT_SCRIPTCHECK_THREADS
#include <wallet/wallet.h> // For DEFAULT_SPEND_ZEROCONF_CHANGE
#include <QDebug>
diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp
index 3f9d1b040b..592e591edb 100644
--- a/src/qt/paymentserver.cpp
+++ b/src/qt/paymentserver.cpp
@@ -13,11 +13,11 @@
#include <qt/optionsmodel.h>
#include <chainparams.h>
+#include <common/args.h>
#include <interfaces/node.h>
#include <key_io.h>
#include <node/interface_ui.h>
#include <policy/policy.h>
-#include <util/system.h>
#include <wallet/wallet.h>
#include <cstdlib>
diff --git a/src/qt/test/optiontests.cpp b/src/qt/test/optiontests.cpp
index dc7c8928c5..0838e21678 100644
--- a/src/qt/test/optiontests.cpp
+++ b/src/qt/test/optiontests.cpp
@@ -2,12 +2,12 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <common/args.h>
#include <init.h>
#include <qt/bitcoin.h>
#include <qt/guiutil.h>
#include <qt/test/optiontests.h>
#include <test/util/setup_common.h>
-#include <util/system.h>
#include <QSettings>
#include <QTest>
diff --git a/src/qt/utilitydialog.cpp b/src/qt/utilitydialog.cpp
index eb2ab12a66..f43b993628 100644
--- a/src/qt/utilitydialog.cpp
+++ b/src/qt/utilitydialog.cpp
@@ -13,8 +13,8 @@
#include <qt/guiutil.h>
#include <clientversion.h>
+#include <common/args.h>
#include <init.h>
-#include <util/system.h>
#include <util/strencodings.h>
#include <cstdio>
diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp
index fdd96c664a..ee3327530c 100644
--- a/src/qt/walletmodel.cpp
+++ b/src/qt/walletmodel.cpp
@@ -18,12 +18,12 @@
#include <qt/sendcoinsdialog.h>
#include <qt/transactiontablemodel.h>
+#include <common/args.h> // for GetBoolArg
#include <interfaces/handler.h>
#include <interfaces/node.h>
#include <key_io.h>
#include <node/interface_ui.h>
#include <psbt.h>
-#include <util/system.h> // for GetBoolArg
#include <util/translation.h>
#include <wallet/coincontrol.h>
#include <wallet/wallet.h> // for CRecipient
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index fb22321d90..49921794bf 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -9,6 +9,7 @@
#include <chain.h>
#include <chainparams.h>
#include <coins.h>
+#include <common/args.h>
#include <consensus/amount.h>
#include <consensus/params.h>
#include <consensus/validation.h>
@@ -40,7 +41,6 @@
#include <util/check.h>
#include <util/fs.h>
#include <util/strencodings.h>
-#include <util/system.h>
#include <util/translation.h>
#include <validation.h>
#include <validationinterface.h>
diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp
index 4459dd71aa..f3c19003ff 100644
--- a/src/rpc/client.cpp
+++ b/src/rpc/client.cpp
@@ -3,9 +3,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <common/args.h>
#include <rpc/client.h>
#include <tinyformat.h>
-#include <util/system.h>
#include <set>
#include <stdint.h>
diff --git a/src/rpc/external_signer.cpp b/src/rpc/external_signer.cpp
index f5a6913572..1e139c9990 100644
--- a/src/rpc/external_signer.cpp
+++ b/src/rpc/external_signer.cpp
@@ -3,11 +3,13 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <chainparamsbase.h>
+#include <common/args.h>
#include <external_signer.h>
+#include <rpc/protocol.h>
#include <rpc/server.h>
#include <rpc/util.h>
#include <util/strencodings.h>
-#include <rpc/protocol.h>
+#include <util/system.h>
#include <string>
#include <vector>
diff --git a/src/rpc/request.cpp b/src/rpc/request.cpp
index 4c5ccbbdad..ad91ed0f23 100644
--- a/src/rpc/request.cpp
+++ b/src/rpc/request.cpp
@@ -7,11 +7,12 @@
#include <util/fs.h>
+#include <common/args.h>
+#include <logging.h>
#include <random.h>
#include <rpc/protocol.h>
#include <util/fs_helpers.h>
#include <util/strencodings.h>
-#include <util/system.h>
#include <fstream>
#include <stdexcept>
diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp
index 392238a1fd..354f949002 100644
--- a/src/rpc/server.cpp
+++ b/src/rpc/server.cpp
@@ -5,6 +5,8 @@
#include <rpc/server.h>
+#include <common/args.h>
+#include <logging.h>
#include <rpc/util.h>
#include <shutdown.h>
#include <sync.h>
diff --git a/src/rpc/server_util.cpp b/src/rpc/server_util.cpp
index 7a708ec813..13d007b496 100644
--- a/src/rpc/server_util.cpp
+++ b/src/rpc/server_util.cpp
@@ -4,6 +4,7 @@
#include <rpc/server_util.h>
+#include <common/args.h>
#include <net_processing.h>
#include <node/context.h>
#include <policy/fees.h>
diff --git a/src/rpc/util.cpp b/src/rpc/util.cpp
index f95ac4cb4b..1f3f37d0a0 100644
--- a/src/rpc/util.cpp
+++ b/src/rpc/util.cpp
@@ -3,6 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <clientversion.h>
+#include <common/args.h>
#include <consensus/amount.h>
#include <key_io.h>
#include <outputtype.h>
@@ -13,7 +14,6 @@
#include <util/check.h>
#include <util/strencodings.h>
#include <util/string.h>
-#include <util/system.h>
#include <util/translation.h>
#include <tuple>
diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp
index b4ad1e3f10..0951504ee0 100644
--- a/src/script/descriptor.cpp
+++ b/src/script/descriptor.cpp
@@ -12,10 +12,10 @@
#include <script/standard.h>
#include <uint256.h>
+#include <common/args.h>
#include <span.h>
#include <util/bip32.h>
#include <util/spanparsing.h>
-#include <util/system.h>
#include <util/strencodings.h>
#include <util/vector.h>
diff --git a/src/script/sigcache.cpp b/src/script/sigcache.cpp
index fef3601887..e52e8cd309 100644
--- a/src/script/sigcache.cpp
+++ b/src/script/sigcache.cpp
@@ -5,6 +5,7 @@
#include <script/sigcache.h>
+#include <logging.h>
#include <pubkey.h>
#include <random.h>
#include <uint256.h>
diff --git a/src/signet.cpp b/src/signet.cpp
index 747bd1b0a8..b76b1e342f 100644
--- a/src/signet.cpp
+++ b/src/signet.cpp
@@ -13,15 +13,16 @@
#include <consensus/validation.h>
#include <core_io.h>
#include <hash.h>
+#include <logging.h>
#include <primitives/block.h>
#include <primitives/transaction.h>
-#include <span.h>
#include <script/interpreter.h>
#include <script/standard.h>
+#include <span.h>
#include <streams.h>
+#include <uint256.h>
#include <util/strencodings.h>
#include <util/system.h>
-#include <uint256.h>
static constexpr uint8_t SIGNET_HEADER[4] = {0xec, 0xc7, 0xda, 0xa2};
diff --git a/src/test/argsman_tests.cpp b/src/test/argsman_tests.cpp
index 5bade94f37..6a0925f0bb 100644
--- a/src/test/argsman_tests.cpp
+++ b/src/test/argsman_tests.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 <common/args.h>
#include <sync.h>
#include <test/util/logging.h>
#include <test/util/setup_common.h>
@@ -9,7 +10,6 @@
#include <univalue.h>
#include <util/fs.h>
#include <util/strencodings.h>
-#include <util/system.h>
#include <array>
#include <optional>
diff --git a/src/test/checkqueue_tests.cpp b/src/test/checkqueue_tests.cpp
index 6bc4770f9b..9011e703e8 100644
--- a/src/test/checkqueue_tests.cpp
+++ b/src/test/checkqueue_tests.cpp
@@ -3,10 +3,10 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <checkqueue.h>
+#include <common/args.h>
#include <sync.h>
#include <test/util/random.h>
#include <test/util/setup_common.h>
-#include <util/system.h>
#include <util/time.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/denialofservice_tests.cpp b/src/test/denialofservice_tests.cpp
index aca2b8eff0..1a06f16155 100644
--- a/src/test/denialofservice_tests.cpp
+++ b/src/test/denialofservice_tests.cpp
@@ -6,6 +6,7 @@
#include <banman.h>
#include <chainparams.h>
+#include <common/args.h>
#include <net.h>
#include <net_processing.h>
#include <pubkey.h>
@@ -17,7 +18,6 @@
#include <test/util/setup_common.h>
#include <timedata.h>
#include <util/string.h>
-#include <util/system.h>
#include <util/time.h>
#include <validation.h>
diff --git a/src/test/flatfile_tests.cpp b/src/test/flatfile_tests.cpp
index 54c30ed314..3874b38f61 100644
--- a/src/test/flatfile_tests.cpp
+++ b/src/test/flatfile_tests.cpp
@@ -3,10 +3,10 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <clientversion.h>
+#include <common/args.h>
#include <flatfile.h>
#include <streams.h>
#include <test/util/setup_common.h>
-#include <util/system.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/fuzz/addrman.cpp b/src/test/fuzz/addrman.cpp
index a59e41dbb5..5ad7a25c53 100644
--- a/src/test/fuzz/addrman.cpp
+++ b/src/test/fuzz/addrman.cpp
@@ -6,6 +6,7 @@
#include <addrman.h>
#include <addrman_impl.h>
#include <chainparams.h>
+#include <common/args.h>
#include <merkleblock.h>
#include <random.h>
#include <test/fuzz/FuzzedDataProvider.h>
@@ -15,7 +16,6 @@
#include <test/util/setup_common.h>
#include <time.h>
#include <util/asmap.h>
-#include <util/system.h>
#include <cassert>
#include <cstdint>
diff --git a/src/test/fuzz/banman.cpp b/src/test/fuzz/banman.cpp
index b4a93499ed..cb5d29d9b8 100644
--- a/src/test/fuzz/banman.cpp
+++ b/src/test/fuzz/banman.cpp
@@ -3,6 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <banman.h>
+#include <common/args.h>
#include <netaddress.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
@@ -11,7 +12,6 @@
#include <test/util/setup_common.h>
#include <util/fs.h>
#include <util/readwritefile.h>
-#include <util/system.h>
#include <cassert>
#include <cstdint>
diff --git a/src/test/fuzz/connman.cpp b/src/test/fuzz/connman.cpp
index 7ce17c0b7c..0f3c850e66 100644
--- a/src/test/fuzz/connman.cpp
+++ b/src/test/fuzz/connman.cpp
@@ -5,6 +5,7 @@
#include <addrman.h>
#include <chainparams.h>
#include <chainparamsbase.h>
+#include <common/args.h>
#include <net.h>
#include <netaddress.h>
#include <protocol.h>
@@ -13,7 +14,6 @@
#include <test/fuzz/util.h>
#include <test/fuzz/util/net.h>
#include <test/util/setup_common.h>
-#include <util/system.h>
#include <util/translation.h>
#include <cstdint>
diff --git a/src/test/fuzz/deserialize.cpp b/src/test/fuzz/deserialize.cpp
index 7cd78e0461..177711c6e4 100644
--- a/src/test/fuzz/deserialize.cpp
+++ b/src/test/fuzz/deserialize.cpp
@@ -9,6 +9,7 @@
#include <blockfilter.h>
#include <chain.h>
#include <coins.h>
+#include <common/args.h>
#include <compressor.h>
#include <consensus/merkle.h>
#include <key.h>
@@ -25,7 +26,6 @@
#include <streams.h>
#include <test/util/setup_common.h>
#include <undo.h>
-#include <util/system.h>
#include <version.h>
#include <exception>
diff --git a/src/test/fuzz/i2p.cpp b/src/test/fuzz/i2p.cpp
index 6c2321cd68..3c6db96446 100644
--- a/src/test/fuzz/i2p.cpp
+++ b/src/test/fuzz/i2p.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 <common/args.h>
#include <i2p.h>
#include <netaddress.h>
#include <netbase.h>
@@ -10,7 +11,6 @@
#include <test/fuzz/util.h>
#include <test/fuzz/util/net.h>
#include <test/util/setup_common.h>
-#include <util/system.h>
#include <util/threadinterrupt.h>
void initialize_i2p()
diff --git a/src/test/fuzz/integer.cpp b/src/test/fuzz/integer.cpp
index c0aefe6067..ead877fe05 100644
--- a/src/test/fuzz/integer.cpp
+++ b/src/test/fuzz/integer.cpp
@@ -3,6 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <arith_uint256.h>
+#include <common/args.h>
#include <compressor.h>
#include <consensus/amount.h>
#include <consensus/merkle.h>
diff --git a/src/test/fuzz/string.cpp b/src/test/fuzz/string.cpp
index c7363f8f49..5de24a939d 100644
--- a/src/test/fuzz/string.cpp
+++ b/src/test/fuzz/string.cpp
@@ -4,6 +4,7 @@
#include <blockfilter.h>
#include <clientversion.h>
+#include <common/args.h>
#include <common/url.h>
#include <netbase.h>
#include <outputtype.h>
diff --git a/src/test/fuzz/system.cpp b/src/test/fuzz/system.cpp
index dc3f9c8b8f..935f0c21e1 100644
--- a/src/test/fuzz/system.cpp
+++ b/src/test/fuzz/system.cpp
@@ -2,11 +2,11 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <common/args.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
#include <test/util/setup_common.h>
-#include <util/system.h>
#include <cstdint>
#include <string>
diff --git a/src/test/fuzz/versionbits.cpp b/src/test/fuzz/versionbits.cpp
index 143027662f..e6a19d6e91 100644
--- a/src/test/fuzz/versionbits.cpp
+++ b/src/test/fuzz/versionbits.cpp
@@ -4,9 +4,9 @@
#include <chain.h>
#include <chainparams.h>
+#include <common/args.h>
#include <consensus/params.h>
#include <primitives/block.h>
-#include <util/system.h>
#include <versionbits.h>
#include <test/fuzz/FuzzedDataProvider.h>
diff --git a/src/test/getarg_tests.cpp b/src/test/getarg_tests.cpp
index 9106040b84..715b6885f5 100644
--- a/src/test/getarg_tests.cpp
+++ b/src/test/getarg_tests.cpp
@@ -2,11 +2,12 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <common/args.h>
+#include <logging.h>
#include <test/util/setup_common.h>
#include <univalue.h>
#include <util/settings.h>
#include <util/strencodings.h>
-#include <util/system.h>
#include <limits>
#include <string>
diff --git a/src/test/i2p_tests.cpp b/src/test/i2p_tests.cpp
index 3e20b527b5..b2e1ae43be 100644
--- a/src/test/i2p_tests.cpp
+++ b/src/test/i2p_tests.cpp
@@ -2,13 +2,13 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <common/args.h>
#include <i2p.h>
#include <logging.h>
#include <netaddress.h>
#include <test/util/logging.h>
#include <test/util/net.h>
#include <test/util/setup_common.h>
-#include <util/system.h>
#include <util/threadinterrupt.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp
index 4fbd9b3a6e..631c213627 100644
--- a/src/test/net_tests.cpp
+++ b/src/test/net_tests.cpp
@@ -4,6 +4,7 @@
#include <chainparams.h>
#include <clientversion.h>
+#include <common/args.h>
#include <compat/compat.h>
#include <cstdint>
#include <net.h>
@@ -19,7 +20,6 @@
#include <timedata.h>
#include <util/strencodings.h>
#include <util/string.h>
-#include <util/system.h>
#include <validation.h>
#include <version.h>
diff --git a/src/test/random_tests.cpp b/src/test/random_tests.cpp
index e5cf767614..414e4509f5 100644
--- a/src/test/random_tests.cpp
+++ b/src/test/random_tests.cpp
@@ -5,6 +5,7 @@
#include <random.h>
#include <test/util/setup_common.h>
+#include <util/time.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/settings_tests.cpp b/src/test/settings_tests.cpp
index 4d0d42ae38..604eb48df6 100644
--- a/src/test/settings_tests.cpp
+++ b/src/test/settings_tests.cpp
@@ -10,10 +10,10 @@
#include <boost/test/unit_test.hpp>
+#include <common/args.h>
#include <univalue.h>
#include <util/strencodings.h>
#include <util/string.h>
-#include <util/system.h>
#include <fstream>
#include <map>
diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp
index 58593c9d5b..80ad550717 100644
--- a/src/test/util/setup_common.cpp
+++ b/src/test/util/setup_common.cpp
@@ -44,6 +44,7 @@
#include <txmempool.h>
#include <util/strencodings.h>
#include <util/string.h>
+#include <util/system.h>
#include <util/thread.h>
#include <util/threadnames.h>
#include <util/time.h>
diff --git a/src/test/util/setup_common.h b/src/test/util/setup_common.h
index 948ebc097c..c576fc12c5 100644
--- a/src/test/util/setup_common.h
+++ b/src/test/util/setup_common.h
@@ -6,6 +6,7 @@
#define BITCOIN_TEST_UTIL_SETUP_COMMON_H
#include <chainparamsbase.h>
+#include <common/args.h>
#include <key.h>
#include <node/caches.h>
#include <node/context.h>
@@ -16,7 +17,6 @@
#include <util/check.h>
#include <util/fs.h>
#include <util/string.h>
-#include <util/system.h>
#include <util/vector.h>
#include <functional>
diff --git a/src/test/validationinterface_tests.cpp b/src/test/validationinterface_tests.cpp
index ceba689e52..576768a625 100644
--- a/src/test/validationinterface_tests.cpp
+++ b/src/test/validationinterface_tests.cpp
@@ -10,6 +10,8 @@
#include <util/check.h>
#include <validationinterface.h>
+#include <atomic>
+
BOOST_FIXTURE_TEST_SUITE(validationinterface_tests, TestingSetup)
struct TestSubscriberNoop final : public CValidationInterface {
diff --git a/src/timedata.cpp b/src/timedata.cpp
index a0646b4707..15ca90ee6a 100644
--- a/src/timedata.cpp
+++ b/src/timedata.cpp
@@ -8,11 +8,12 @@
#include <timedata.h>
+#include <common/args.h>
+#include <logging.h>
#include <netaddress.h>
#include <node/interface_ui.h>
#include <sync.h>
#include <tinyformat.h>
-#include <util/system.h>
#include <util/translation.h>
#include <warnings.h>
diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp
index d4daeacd3e..92b55f9fc4 100644
--- a/src/torcontrol.cpp
+++ b/src/torcontrol.cpp
@@ -7,15 +7,16 @@
#include <chainparams.h>
#include <chainparamsbase.h>
+#include <common/args.h>
#include <compat/compat.h>
#include <crypto/hmac_sha256.h>
+#include <logging.h>
#include <net.h>
#include <netaddress.h>
#include <netbase.h>
#include <util/readwritefile.h>
#include <util/strencodings.h>
#include <util/syscall_sandbox.h>
-#include <util/system.h>
#include <util/thread.h>
#include <util/time.h>
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index 032dfee3ea..da875c271e 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -10,6 +10,7 @@
#include <consensus/consensus.h>
#include <consensus/tx_verify.h>
#include <consensus/validation.h>
+#include <logging.h>
#include <policy/fees.h>
#include <policy/policy.h>
#include <policy/settings.h>
diff --git a/src/util/system.cpp b/src/util/system.cpp
index 630eff99e0..598e6adb88 100644
--- a/src/util/system.cpp
+++ b/src/util/system.cpp
@@ -5,17 +5,10 @@
#include <util/system.h>
-#include <chainparamsbase.h>
-#include <sync.h>
-#include <util/check.h>
-#include <util/fs.h>
-#include <util/fs_helpers.h>
-#include <util/getuniquepath.h>
-#include <util/strencodings.h>
+#include <logging.h>
#include <util/string.h>
#include <util/syserror.h>
-#include <util/translation.h>
-
+#include <util/time.h>
#if (defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__))
#include <pthread.h>
@@ -23,991 +16,25 @@
#endif
#ifndef WIN32
-#include <algorithm>
-#include <cassert>
-#include <fcntl.h>
#include <sched.h>
-#include <sys/resource.h>
#include <sys/stat.h>
-
#else
-
#include <codecvt>
-
-#include <shellapi.h>
-#include <shlobj.h>
#endif
#ifdef HAVE_MALLOPT_ARENA_MAX
#include <malloc.h>
#endif
-#include <univalue.h>
-
-#include <fstream>
-#include <map>
-#include <memory>
-#include <optional>
+#include <cstdlib>
+#include <locale>
+#include <stdexcept>
#include <string>
-#include <system_error>
#include <thread>
-#include <typeinfo>
// Application startup time (used for uptime calculation)
const int64_t nStartupTime = GetTime();
-const char * const BITCOIN_CONF_FILENAME = "bitcoin.conf";
-const char * const BITCOIN_SETTINGS_FILENAME = "settings.json";
-
-ArgsManager gArgs;
-
-/**
- * Interpret a string argument as a boolean.
- *
- * The definition of LocaleIndependentAtoi<int>() requires that non-numeric string values
- * like "foo", return 0. This means that if a user unintentionally supplies a
- * non-integer argument here, the return value is always false. This means that
- * -foo=false does what the user probably expects, but -foo=true is well defined
- * but does not do what they probably expected.
- *
- * The return value of LocaleIndependentAtoi<int>(...) is zero when given input not
- * representable as an int.
- *
- * For a more extensive discussion of this topic (and a wide range of opinions
- * on the Right Way to change this code), see PR12713.
- */
-static bool InterpretBool(const std::string& strValue)
-{
- if (strValue.empty())
- return true;
- return (LocaleIndependentAtoi<int>(strValue) != 0);
-}
-
-static std::string SettingName(const std::string& arg)
-{
- return arg.size() > 0 && arg[0] == '-' ? arg.substr(1) : arg;
-}
-
-struct KeyInfo {
- std::string name;
- std::string section;
- bool negated{false};
-};
-
-/**
- * Parse "name", "section.name", "noname", "section.noname" settings keys.
- *
- * @note Where an option was negated can be later checked using the
- * IsArgNegated() method. One use case for this is to have a way to disable
- * options that are not normally boolean (e.g. using -nodebuglogfile to request
- * that debug log output is not sent to any file at all).
- */
-KeyInfo InterpretKey(std::string key)
-{
- KeyInfo result;
- // Split section name from key name for keys like "testnet.foo" or "regtest.bar"
- size_t option_index = key.find('.');
- if (option_index != std::string::npos) {
- result.section = key.substr(0, option_index);
- key.erase(0, option_index + 1);
- }
- if (key.substr(0, 2) == "no") {
- key.erase(0, 2);
- result.negated = true;
- }
- result.name = key;
- return result;
-}
-
-/**
- * Interpret settings value based on registered flags.
- *
- * @param[in] key key information to know if key was negated
- * @param[in] value string value of setting to be parsed
- * @param[in] flags ArgsManager registered argument flags
- * @param[out] error Error description if settings value is not valid
- *
- * @return parsed settings value if it is valid, otherwise nullopt accompanied
- * by a descriptive error string
- */
-static std::optional<util::SettingsValue> InterpretValue(const KeyInfo& key, const std::string* value,
- unsigned int flags, std::string& error)
-{
- // Return negated settings as false values.
- if (key.negated) {
- if (flags & ArgsManager::DISALLOW_NEGATION) {
- error = strprintf("Negating of -%s is meaningless and therefore forbidden", key.name);
- return std::nullopt;
- }
- // Double negatives like -nofoo=0 are supported (but discouraged)
- if (value && !InterpretBool(*value)) {
- LogPrintf("Warning: parsed potentially confusing double-negative -%s=%s\n", key.name, *value);
- return true;
- }
- return false;
- }
- if (!value && (flags & ArgsManager::DISALLOW_ELISION)) {
- error = strprintf("Can not set -%s with no value. Please specify value with -%s=value.", key.name, key.name);
- return std::nullopt;
- }
- return value ? *value : "";
-}
-
-// Define default constructor and destructor that are not inline, so code instantiating this class doesn't need to
-// #include class definitions for all members.
-// For example, m_settings has an internal dependency on univalue.
-ArgsManager::ArgsManager() = default;
-ArgsManager::~ArgsManager() = default;
-
-std::set<std::string> ArgsManager::GetUnsuitableSectionOnlyArgs() const
-{
- std::set<std::string> unsuitables;
-
- LOCK(cs_args);
-
- // if there's no section selected, don't worry
- if (m_network.empty()) return std::set<std::string> {};
-
- // if it's okay to use the default section for this network, don't worry
- if (m_network == CBaseChainParams::MAIN) return std::set<std::string> {};
-
- for (const auto& arg : m_network_only_args) {
- if (OnlyHasDefaultSectionSetting(m_settings, m_network, SettingName(arg))) {
- unsuitables.insert(arg);
- }
- }
- return unsuitables;
-}
-
-std::list<SectionInfo> ArgsManager::GetUnrecognizedSections() const
-{
- // Section names to be recognized in the config file.
- static const std::set<std::string> available_sections{
- CBaseChainParams::REGTEST,
- CBaseChainParams::SIGNET,
- CBaseChainParams::TESTNET,
- CBaseChainParams::MAIN
- };
-
- LOCK(cs_args);
- std::list<SectionInfo> unrecognized = m_config_sections;
- unrecognized.remove_if([](const SectionInfo& appeared){ return available_sections.find(appeared.m_name) != available_sections.end(); });
- return unrecognized;
-}
-
-void ArgsManager::SelectConfigNetwork(const std::string& network)
-{
- LOCK(cs_args);
- m_network = network;
-}
-
-bool ArgsManager::ParseParameters(int argc, const char* const argv[], std::string& error)
-{
- LOCK(cs_args);
- m_settings.command_line_options.clear();
-
- for (int i = 1; i < argc; i++) {
- std::string key(argv[i]);
-
-#ifdef MAC_OSX
- // At the first time when a user gets the "App downloaded from the
- // internet" warning, and clicks the Open button, macOS passes
- // a unique process serial number (PSN) as -psn_... command-line
- // argument, which we filter out.
- if (key.substr(0, 5) == "-psn_") continue;
-#endif
-
- if (key == "-") break; //bitcoin-tx using stdin
- std::optional<std::string> val;
- size_t is_index = key.find('=');
- if (is_index != std::string::npos) {
- val = key.substr(is_index + 1);
- key.erase(is_index);
- }
-#ifdef WIN32
- key = ToLower(key);
- if (key[0] == '/')
- key[0] = '-';
-#endif
-
- if (key[0] != '-') {
- if (!m_accept_any_command && m_command.empty()) {
- // The first non-dash arg is a registered command
- std::optional<unsigned int> flags = GetArgFlags(key);
- if (!flags || !(*flags & ArgsManager::COMMAND)) {
- error = strprintf("Invalid command '%s'", argv[i]);
- return false;
- }
- }
- m_command.push_back(key);
- while (++i < argc) {
- // The remaining args are command args
- m_command.push_back(argv[i]);
- }
- break;
- }
-
- // Transform --foo to -foo
- if (key.length() > 1 && key[1] == '-')
- key.erase(0, 1);
-
- // Transform -foo to foo
- key.erase(0, 1);
- KeyInfo keyinfo = InterpretKey(key);
- std::optional<unsigned int> flags = GetArgFlags('-' + keyinfo.name);
-
- // Unknown command line options and command line options with dot
- // characters (which are returned from InterpretKey with nonempty
- // section strings) are not valid.
- if (!flags || !keyinfo.section.empty()) {
- error = strprintf("Invalid parameter %s", argv[i]);
- return false;
- }
-
- std::optional<util::SettingsValue> value = InterpretValue(keyinfo, val ? &*val : nullptr, *flags, error);
- if (!value) return false;
-
- m_settings.command_line_options[keyinfo.name].push_back(*value);
- }
-
- // we do not allow -includeconf from command line, only -noincludeconf
- if (auto* includes = util::FindKey(m_settings.command_line_options, "includeconf")) {
- const util::SettingsSpan values{*includes};
- // Range may be empty if -noincludeconf was passed
- if (!values.empty()) {
- error = "-includeconf cannot be used from commandline; -includeconf=" + values.begin()->write();
- return false; // pick first value as example
- }
- }
- return true;
-}
-
-std::optional<unsigned int> ArgsManager::GetArgFlags(const std::string& name) const
-{
- LOCK(cs_args);
- for (const auto& arg_map : m_available_args) {
- const auto search = arg_map.second.find(name);
- if (search != arg_map.second.end()) {
- return search->second.m_flags;
- }
- }
- return std::nullopt;
-}
-
-fs::path ArgsManager::GetPathArg(std::string arg, const fs::path& default_value) const
-{
- if (IsArgNegated(arg)) return fs::path{};
- std::string path_str = GetArg(arg, "");
- if (path_str.empty()) return default_value;
- fs::path result = fs::PathFromString(path_str).lexically_normal();
- // Remove trailing slash, if present.
- return result.has_filename() ? result : result.parent_path();
-}
-
-const fs::path& ArgsManager::GetBlocksDirPath() const
-{
- LOCK(cs_args);
- fs::path& path = m_cached_blocks_path;
-
- // Cache the path to avoid calling fs::create_directories on every call of
- // this function
- if (!path.empty()) return path;
-
- if (IsArgSet("-blocksdir")) {
- path = fs::absolute(GetPathArg("-blocksdir"));
- if (!fs::is_directory(path)) {
- path = "";
- return path;
- }
- } else {
- path = GetDataDirBase();
- }
-
- path /= fs::PathFromString(BaseParams().DataDir());
- path /= "blocks";
- fs::create_directories(path);
- return path;
-}
-
-const fs::path& ArgsManager::GetDataDir(bool net_specific) const
-{
- LOCK(cs_args);
- fs::path& path = net_specific ? m_cached_network_datadir_path : m_cached_datadir_path;
-
- // Used cached path if available
- if (!path.empty()) return path;
-
- const fs::path datadir{GetPathArg("-datadir")};
- if (!datadir.empty()) {
- path = fs::absolute(datadir);
- if (!fs::is_directory(path)) {
- path = "";
- return path;
- }
- } else {
- path = GetDefaultDataDir();
- }
-
- if (net_specific && !BaseParams().DataDir().empty()) {
- path /= fs::PathFromString(BaseParams().DataDir());
- }
-
- return path;
-}
-
-void ArgsManager::ClearPathCache()
-{
- LOCK(cs_args);
-
- m_cached_datadir_path = fs::path();
- m_cached_network_datadir_path = fs::path();
- m_cached_blocks_path = fs::path();
-}
-
-std::optional<const ArgsManager::Command> ArgsManager::GetCommand() const
-{
- Command ret;
- LOCK(cs_args);
- auto it = m_command.begin();
- if (it == m_command.end()) {
- // No command was passed
- return std::nullopt;
- }
- if (!m_accept_any_command) {
- // The registered command
- ret.command = *(it++);
- }
- while (it != m_command.end()) {
- // The unregistered command and args (if any)
- ret.args.push_back(*(it++));
- }
- return ret;
-}
-
-std::vector<std::string> ArgsManager::GetArgs(const std::string& strArg) const
-{
- std::vector<std::string> result;
- for (const util::SettingsValue& value : GetSettingsList(strArg)) {
- result.push_back(value.isFalse() ? "0" : value.isTrue() ? "1" : value.get_str());
- }
- return result;
-}
-
-bool ArgsManager::IsArgSet(const std::string& strArg) const
-{
- return !GetSetting(strArg).isNull();
-}
-
-bool ArgsManager::GetSettingsPath(fs::path* filepath, bool temp, bool backup) const
-{
- fs::path settings = GetPathArg("-settings", BITCOIN_SETTINGS_FILENAME);
- if (settings.empty()) {
- return false;
- }
- if (backup) {
- settings += ".bak";
- }
- if (filepath) {
- *filepath = fsbridge::AbsPathJoin(GetDataDirNet(), temp ? settings + ".tmp" : settings);
- }
- return true;
-}
-
-static void SaveErrors(const std::vector<std::string> errors, std::vector<std::string>* error_out)
-{
- for (const auto& error : errors) {
- if (error_out) {
- error_out->emplace_back(error);
- } else {
- LogPrintf("%s\n", error);
- }
- }
-}
-
-bool ArgsManager::ReadSettingsFile(std::vector<std::string>* errors)
-{
- fs::path path;
- if (!GetSettingsPath(&path, /* temp= */ false)) {
- return true; // Do nothing if settings file disabled.
- }
-
- LOCK(cs_args);
- m_settings.rw_settings.clear();
- std::vector<std::string> read_errors;
- if (!util::ReadSettings(path, m_settings.rw_settings, read_errors)) {
- SaveErrors(read_errors, errors);
- return false;
- }
- for (const auto& setting : m_settings.rw_settings) {
- KeyInfo key = InterpretKey(setting.first); // Split setting key into section and argname
- if (!GetArgFlags('-' + key.name)) {
- LogPrintf("Ignoring unknown rw_settings value %s\n", setting.first);
- }
- }
- return true;
-}
-
-bool ArgsManager::WriteSettingsFile(std::vector<std::string>* errors, bool backup) const
-{
- fs::path path, path_tmp;
- if (!GetSettingsPath(&path, /*temp=*/false, backup) || !GetSettingsPath(&path_tmp, /*temp=*/true, backup)) {
- throw std::logic_error("Attempt to write settings file when dynamic settings are disabled.");
- }
-
- LOCK(cs_args);
- std::vector<std::string> write_errors;
- if (!util::WriteSettings(path_tmp, m_settings.rw_settings, write_errors)) {
- SaveErrors(write_errors, errors);
- return false;
- }
- if (!RenameOver(path_tmp, path)) {
- SaveErrors({strprintf("Failed renaming settings file %s to %s\n", fs::PathToString(path_tmp), fs::PathToString(path))}, errors);
- return false;
- }
- return true;
-}
-
-util::SettingsValue ArgsManager::GetPersistentSetting(const std::string& name) const
-{
- LOCK(cs_args);
- return util::GetSetting(m_settings, m_network, name, !UseDefaultSection("-" + name),
- /*ignore_nonpersistent=*/true, /*get_chain_name=*/false);
-}
-
-bool ArgsManager::IsArgNegated(const std::string& strArg) const
-{
- return GetSetting(strArg).isFalse();
-}
-
-std::string ArgsManager::GetArg(const std::string& strArg, const std::string& strDefault) const
-{
- return GetArg(strArg).value_or(strDefault);
-}
-
-std::optional<std::string> ArgsManager::GetArg(const std::string& strArg) const
-{
- const util::SettingsValue value = GetSetting(strArg);
- return SettingToString(value);
-}
-
-std::optional<std::string> SettingToString(const util::SettingsValue& value)
-{
- if (value.isNull()) return std::nullopt;
- if (value.isFalse()) return "0";
- if (value.isTrue()) return "1";
- if (value.isNum()) return value.getValStr();
- return value.get_str();
-}
-
-std::string SettingToString(const util::SettingsValue& value, const std::string& strDefault)
-{
- return SettingToString(value).value_or(strDefault);
-}
-
-int64_t ArgsManager::GetIntArg(const std::string& strArg, int64_t nDefault) const
-{
- return GetIntArg(strArg).value_or(nDefault);
-}
-
-std::optional<int64_t> ArgsManager::GetIntArg(const std::string& strArg) const
-{
- const util::SettingsValue value = GetSetting(strArg);
- return SettingToInt(value);
-}
-
-std::optional<int64_t> SettingToInt(const util::SettingsValue& value)
-{
- if (value.isNull()) return std::nullopt;
- if (value.isFalse()) return 0;
- if (value.isTrue()) return 1;
- if (value.isNum()) return value.getInt<int64_t>();
- return LocaleIndependentAtoi<int64_t>(value.get_str());
-}
-
-int64_t SettingToInt(const util::SettingsValue& value, int64_t nDefault)
-{
- return SettingToInt(value).value_or(nDefault);
-}
-
-bool ArgsManager::GetBoolArg(const std::string& strArg, bool fDefault) const
-{
- return GetBoolArg(strArg).value_or(fDefault);
-}
-
-std::optional<bool> ArgsManager::GetBoolArg(const std::string& strArg) const
-{
- const util::SettingsValue value = GetSetting(strArg);
- return SettingToBool(value);
-}
-
-std::optional<bool> SettingToBool(const util::SettingsValue& value)
-{
- if (value.isNull()) return std::nullopt;
- if (value.isBool()) return value.get_bool();
- return InterpretBool(value.get_str());
-}
-
-bool SettingToBool(const util::SettingsValue& value, bool fDefault)
-{
- return SettingToBool(value).value_or(fDefault);
-}
-
-bool ArgsManager::SoftSetArg(const std::string& strArg, const std::string& strValue)
-{
- LOCK(cs_args);
- if (IsArgSet(strArg)) return false;
- ForceSetArg(strArg, strValue);
- return true;
-}
-
-bool ArgsManager::SoftSetBoolArg(const std::string& strArg, bool fValue)
-{
- if (fValue)
- return SoftSetArg(strArg, std::string("1"));
- else
- return SoftSetArg(strArg, std::string("0"));
-}
-
-void ArgsManager::ForceSetArg(const std::string& strArg, const std::string& strValue)
-{
- LOCK(cs_args);
- m_settings.forced_settings[SettingName(strArg)] = strValue;
-}
-
-void ArgsManager::AddCommand(const std::string& cmd, const std::string& help)
-{
- Assert(cmd.find('=') == std::string::npos);
- Assert(cmd.at(0) != '-');
-
- LOCK(cs_args);
- m_accept_any_command = false; // latch to false
- std::map<std::string, Arg>& arg_map = m_available_args[OptionsCategory::COMMANDS];
- auto ret = arg_map.emplace(cmd, Arg{"", help, ArgsManager::COMMAND});
- Assert(ret.second); // Fail on duplicate commands
-}
-
-void ArgsManager::AddArg(const std::string& name, const std::string& help, unsigned int flags, const OptionsCategory& cat)
-{
- Assert((flags & ArgsManager::COMMAND) == 0); // use AddCommand
-
- // Split arg name from its help param
- size_t eq_index = name.find('=');
- if (eq_index == std::string::npos) {
- eq_index = name.size();
- }
- std::string arg_name = name.substr(0, eq_index);
-
- LOCK(cs_args);
- std::map<std::string, Arg>& arg_map = m_available_args[cat];
- auto ret = arg_map.emplace(arg_name, Arg{name.substr(eq_index, name.size() - eq_index), help, flags});
- assert(ret.second); // Make sure an insertion actually happened
-
- if (flags & ArgsManager::NETWORK_ONLY) {
- m_network_only_args.emplace(arg_name);
- }
-}
-
-void ArgsManager::AddHiddenArgs(const std::vector<std::string>& names)
-{
- for (const std::string& name : names) {
- AddArg(name, "", ArgsManager::ALLOW_ANY, OptionsCategory::HIDDEN);
- }
-}
-
-std::string ArgsManager::GetHelpMessage() const
-{
- const bool show_debug = GetBoolArg("-help-debug", false);
-
- std::string usage;
- LOCK(cs_args);
- for (const auto& arg_map : m_available_args) {
- switch(arg_map.first) {
- case OptionsCategory::OPTIONS:
- usage += HelpMessageGroup("Options:");
- break;
- case OptionsCategory::CONNECTION:
- usage += HelpMessageGroup("Connection options:");
- break;
- case OptionsCategory::ZMQ:
- usage += HelpMessageGroup("ZeroMQ notification options:");
- break;
- case OptionsCategory::DEBUG_TEST:
- usage += HelpMessageGroup("Debugging/Testing options:");
- break;
- case OptionsCategory::NODE_RELAY:
- usage += HelpMessageGroup("Node relay options:");
- break;
- case OptionsCategory::BLOCK_CREATION:
- usage += HelpMessageGroup("Block creation options:");
- break;
- case OptionsCategory::RPC:
- usage += HelpMessageGroup("RPC server options:");
- break;
- case OptionsCategory::WALLET:
- usage += HelpMessageGroup("Wallet options:");
- break;
- case OptionsCategory::WALLET_DEBUG_TEST:
- if (show_debug) usage += HelpMessageGroup("Wallet debugging/testing options:");
- break;
- case OptionsCategory::CHAINPARAMS:
- usage += HelpMessageGroup("Chain selection options:");
- break;
- case OptionsCategory::GUI:
- usage += HelpMessageGroup("UI Options:");
- break;
- case OptionsCategory::COMMANDS:
- usage += HelpMessageGroup("Commands:");
- break;
- case OptionsCategory::REGISTER_COMMANDS:
- usage += HelpMessageGroup("Register Commands:");
- break;
- default:
- break;
- }
-
- // When we get to the hidden options, stop
- if (arg_map.first == OptionsCategory::HIDDEN) break;
-
- for (const auto& arg : arg_map.second) {
- if (show_debug || !(arg.second.m_flags & ArgsManager::DEBUG_ONLY)) {
- std::string name;
- if (arg.second.m_help_param.empty()) {
- name = arg.first;
- } else {
- name = arg.first + arg.second.m_help_param;
- }
- usage += HelpMessageOpt(name, arg.second.m_help_text);
- }
- }
- }
- return usage;
-}
-
-bool HelpRequested(const ArgsManager& args)
-{
- return args.IsArgSet("-?") || args.IsArgSet("-h") || args.IsArgSet("-help") || args.IsArgSet("-help-debug");
-}
-
-void SetupHelpOptions(ArgsManager& args)
-{
- args.AddArg("-?", "Print this help message and exit", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
- args.AddHiddenArgs({"-h", "-help"});
-}
-
-static const int screenWidth = 79;
-static const int optIndent = 2;
-static const int msgIndent = 7;
-
-std::string HelpMessageGroup(const std::string &message) {
- return std::string(message) + std::string("\n\n");
-}
-
-std::string HelpMessageOpt(const std::string &option, const std::string &message) {
- return std::string(optIndent,' ') + std::string(option) +
- std::string("\n") + std::string(msgIndent,' ') +
- FormatParagraph(message, screenWidth - msgIndent, msgIndent) +
- std::string("\n\n");
-}
-
-fs::path GetDefaultDataDir()
-{
- // Windows: C:\Users\Username\AppData\Roaming\Bitcoin
- // macOS: ~/Library/Application Support/Bitcoin
- // Unix-like: ~/.bitcoin
-#ifdef WIN32
- // Windows
- return GetSpecialFolderPath(CSIDL_APPDATA) / "Bitcoin";
-#else
- fs::path pathRet;
- char* pszHome = getenv("HOME");
- if (pszHome == nullptr || strlen(pszHome) == 0)
- pathRet = fs::path("/");
- else
- pathRet = fs::path(pszHome);
-#ifdef MAC_OSX
- // macOS
- return pathRet / "Library/Application Support/Bitcoin";
-#else
- // Unix-like
- return pathRet / ".bitcoin";
-#endif
-#endif
-}
-
-bool CheckDataDirOption(const ArgsManager& args)
-{
- const fs::path datadir{args.GetPathArg("-datadir")};
- return datadir.empty() || fs::is_directory(fs::absolute(datadir));
-}
-
-fs::path GetConfigFile(const ArgsManager& args, const fs::path& configuration_file_path)
-{
- return AbsPathForConfigVal(args, configuration_file_path, /*net_specific=*/false);
-}
-
-static bool GetConfigOptions(std::istream& stream, const std::string& filepath, std::string& error, std::vector<std::pair<std::string, std::string>>& options, std::list<SectionInfo>& sections)
-{
- std::string str, prefix;
- std::string::size_type pos;
- int linenr = 1;
- while (std::getline(stream, str)) {
- bool used_hash = false;
- if ((pos = str.find('#')) != std::string::npos) {
- str = str.substr(0, pos);
- used_hash = true;
- }
- const static std::string pattern = " \t\r\n";
- str = TrimString(str, pattern);
- if (!str.empty()) {
- if (*str.begin() == '[' && *str.rbegin() == ']') {
- const std::string section = str.substr(1, str.size() - 2);
- sections.emplace_back(SectionInfo{section, filepath, linenr});
- prefix = section + '.';
- } else if (*str.begin() == '-') {
- error = strprintf("parse error on line %i: %s, options in configuration file must be specified without leading -", linenr, str);
- return false;
- } else if ((pos = str.find('=')) != std::string::npos) {
- std::string name = prefix + TrimString(std::string_view{str}.substr(0, pos), pattern);
- std::string_view value = TrimStringView(std::string_view{str}.substr(pos + 1), pattern);
- if (used_hash && name.find("rpcpassword") != std::string::npos) {
- error = strprintf("parse error on line %i, using # in rpcpassword can be ambiguous and should be avoided", linenr);
- return false;
- }
- options.emplace_back(name, value);
- if ((pos = name.rfind('.')) != std::string::npos && prefix.length() <= pos) {
- sections.emplace_back(SectionInfo{name.substr(0, pos), filepath, linenr});
- }
- } else {
- error = strprintf("parse error on line %i: %s", linenr, str);
- if (str.size() >= 2 && str.substr(0, 2) == "no") {
- error += strprintf(", if you intended to specify a negated option, use %s=1 instead", str);
- }
- return false;
- }
- }
- ++linenr;
- }
- return true;
-}
-
-bool IsConfSupported(KeyInfo& key, std::string& error) {
- if (key.name == "conf") {
- error = "conf cannot be set in the configuration file; use includeconf= if you want to include additional config files";
- return false;
- }
- if (key.name == "reindex") {
- // reindex can be set in a config file but it is strongly discouraged as this will cause the node to reindex on
- // every restart. Allow the config but throw a warning
- LogPrintf("Warning: reindex=1 is set in the configuration file, which will significantly slow down startup. Consider removing or commenting out this option for better performance, unless there is currently a condition which makes rebuilding the indexes necessary\n");
- return true;
- }
- return true;
-}
-
-bool ArgsManager::ReadConfigStream(std::istream& stream, const std::string& filepath, std::string& error, bool ignore_invalid_keys)
-{
- LOCK(cs_args);
- std::vector<std::pair<std::string, std::string>> options;
- if (!GetConfigOptions(stream, filepath, error, options, m_config_sections)) {
- return false;
- }
- for (const std::pair<std::string, std::string>& option : options) {
- KeyInfo key = InterpretKey(option.first);
- std::optional<unsigned int> flags = GetArgFlags('-' + key.name);
- if (!IsConfSupported(key, error)) return false;
- if (flags) {
- std::optional<util::SettingsValue> value = InterpretValue(key, &option.second, *flags, error);
- if (!value) {
- return false;
- }
- m_settings.ro_config[key.section][key.name].push_back(*value);
- } else {
- if (ignore_invalid_keys) {
- LogPrintf("Ignoring unknown configuration value %s\n", option.first);
- } else {
- error = strprintf("Invalid configuration value %s", option.first);
- return false;
- }
- }
- }
- return true;
-}
-
-fs::path ArgsManager::GetConfigFilePath() const
-{
- return GetConfigFile(*this, GetPathArg("-conf", BITCOIN_CONF_FILENAME));
-}
-
-bool ArgsManager::ReadConfigFiles(std::string& error, bool ignore_invalid_keys)
-{
- {
- LOCK(cs_args);
- m_settings.ro_config.clear();
- m_config_sections.clear();
- }
-
- 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()) {
- error = strprintf("specified config file \"%s\" could not be opened.", fs::PathToString(conf_path));
- return false;
- }
- // ok to not have a config file
- if (stream.good()) {
- if (!ReadConfigStream(stream, fs::PathToString(conf_path), error, ignore_invalid_keys)) {
- return false;
- }
- // `-includeconf` cannot be included in the command line arguments except
- // as `-noincludeconf` (which indicates that no included conf file should be used).
- bool use_conf_file{true};
- {
- LOCK(cs_args);
- if (auto* includes = util::FindKey(m_settings.command_line_options, "includeconf")) {
- // ParseParameters() fails if a non-negated -includeconf is passed on the command-line
- assert(util::SettingsSpan(*includes).last_negated());
- use_conf_file = false;
- }
- }
- if (use_conf_file) {
- std::string chain_id = GetChainName();
- std::vector<std::string> conf_file_names;
-
- auto add_includes = [&](const std::string& network, size_t skip = 0) {
- size_t num_values = 0;
- LOCK(cs_args);
- if (auto* section = util::FindKey(m_settings.ro_config, network)) {
- if (auto* values = util::FindKey(*section, "includeconf")) {
- for (size_t i = std::max(skip, util::SettingsSpan(*values).negated()); i < values->size(); ++i) {
- conf_file_names.push_back((*values)[i].get_str());
- }
- num_values = values->size();
- }
- }
- return num_values;
- };
-
- // We haven't set m_network yet (that happens in SelectParams()), so manually check
- // for network.includeconf args.
- const size_t chain_includes = add_includes(chain_id);
- const size_t default_includes = add_includes({});
-
- for (const std::string& conf_file_name : conf_file_names) {
- std::ifstream conf_file_stream{GetConfigFile(*this, fs::PathFromString(conf_file_name))};
- if (conf_file_stream.good()) {
- if (!ReadConfigStream(conf_file_stream, conf_file_name, error, ignore_invalid_keys)) {
- return false;
- }
- LogPrintf("Included configuration file %s\n", conf_file_name);
- } else {
- error = "Failed to include configuration file " + conf_file_name;
- return false;
- }
- }
-
- // Warn about recursive -includeconf
- conf_file_names.clear();
- add_includes(chain_id, /* skip= */ chain_includes);
- add_includes({}, /* skip= */ default_includes);
- std::string chain_id_final = GetChainName();
- if (chain_id_final != chain_id) {
- // Also warn about recursive includeconf for the chain that was specified in one of the includeconfs
- add_includes(chain_id_final);
- }
- for (const std::string& conf_file_name : conf_file_names) {
- tfm::format(std::cerr, "warning: -includeconf cannot be used from included files; ignoring -includeconf=%s\n", conf_file_name);
- }
- }
- }
-
- // If datadir is changed in .conf file:
- ClearPathCache();
- if (!CheckDataDirOption(*this)) {
- error = strprintf("specified data directory \"%s\" does not exist.", GetArg("-datadir", ""));
- return false;
- }
- return true;
-}
-
-std::string ArgsManager::GetChainName() const
-{
- auto get_net = [&](const std::string& arg) {
- LOCK(cs_args);
- util::SettingsValue value = util::GetSetting(m_settings, /* section= */ "", SettingName(arg),
- /* ignore_default_section_config= */ false,
- /*ignore_nonpersistent=*/false,
- /* get_chain_name= */ true);
- return value.isNull() ? false : value.isBool() ? value.get_bool() : InterpretBool(value.get_str());
- };
-
- const bool fRegTest = get_net("-regtest");
- const bool fSigNet = get_net("-signet");
- const bool fTestNet = get_net("-testnet");
- const bool is_chain_arg_set = IsArgSet("-chain");
-
- if ((int)is_chain_arg_set + (int)fRegTest + (int)fSigNet + (int)fTestNet > 1) {
- throw std::runtime_error("Invalid combination of -regtest, -signet, -testnet and -chain. Can use at most one.");
- }
- if (fRegTest)
- return CBaseChainParams::REGTEST;
- if (fSigNet) {
- return CBaseChainParams::SIGNET;
- }
- if (fTestNet)
- return CBaseChainParams::TESTNET;
-
- return GetArg("-chain", CBaseChainParams::MAIN);
-}
-
-bool ArgsManager::UseDefaultSection(const std::string& arg) const
-{
- return m_network == CBaseChainParams::MAIN || m_network_only_args.count(arg) == 0;
-}
-
-util::SettingsValue ArgsManager::GetSetting(const std::string& arg) const
-{
- LOCK(cs_args);
- return util::GetSetting(
- m_settings, m_network, SettingName(arg), !UseDefaultSection(arg),
- /*ignore_nonpersistent=*/false, /*get_chain_name=*/false);
-}
-
-std::vector<util::SettingsValue> ArgsManager::GetSettingsList(const std::string& arg) const
-{
- LOCK(cs_args);
- return util::GetSettingsList(m_settings, m_network, SettingName(arg), !UseDefaultSection(arg));
-}
-
-void ArgsManager::logArgsPrefix(
- const std::string& prefix,
- const std::string& section,
- const std::map<std::string, std::vector<util::SettingsValue>>& args) const
-{
- std::string section_str = section.empty() ? "" : "[" + section + "] ";
- for (const auto& arg : args) {
- for (const auto& value : arg.second) {
- std::optional<unsigned int> flags = GetArgFlags('-' + arg.first);
- if (flags) {
- std::string value_str = (*flags & SENSITIVE) ? "****" : value.write();
- LogPrintf("%s %s%s=%s\n", prefix, section_str, arg.first, value_str);
- }
- }
- }
-}
-
-void ArgsManager::LogArgs() const
-{
- LOCK(cs_args);
- for (const auto& section : m_settings.ro_config) {
- logArgsPrefix("Config file arg:", section.first, section.second);
- }
- for (const auto& setting : m_settings.rw_settings) {
- LogPrintf("Setting file arg: %s = %s\n", setting.first, setting.second.write());
- }
- logArgsPrefix("Command-line arg:", "", m_settings.command_line_options);
-}
-
#ifndef WIN32
std::string ShellEscape(const std::string& arg)
{
@@ -1086,14 +113,6 @@ int64_t GetStartupTime()
return nStartupTime;
}
-fs::path AbsPathForConfigVal(const ArgsManager& args, const fs::path& path, bool net_specific)
-{
- if (path.is_absolute()) {
- return path;
- }
- return fsbridge::AbsPathJoin(net_specific ? args.GetDataDirNet() : args.GetDataDirBase(), path);
-}
-
void ScheduleBatchPriority()
{
#ifdef SCHED_BATCH
@@ -1104,30 +123,3 @@ void ScheduleBatchPriority()
}
#endif
}
-
-namespace util {
-#ifdef WIN32
-WinCmdLineArgs::WinCmdLineArgs()
-{
- wchar_t** wargv = CommandLineToArgvW(GetCommandLineW(), &argc);
- std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, wchar_t> utf8_cvt;
- argv = new char*[argc];
- args.resize(argc);
- for (int i = 0; i < argc; i++) {
- args[i] = utf8_cvt.to_bytes(wargv[i]);
- argv[i] = &*args[i].begin();
- }
- LocalFree(wargv);
-}
-
-WinCmdLineArgs::~WinCmdLineArgs()
-{
- delete[] argv;
-}
-
-std::pair<int, char**> WinCmdLineArgs::get()
-{
- return std::make_pair(argc, argv);
-}
-#endif
-} // namespace util
diff --git a/src/util/system.h b/src/util/system.h
index ff3155b498..e2fc3450f6 100644
--- a/src/util/system.h
+++ b/src/util/system.h
@@ -3,10 +3,6 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-/**
- * Server/client environment: argument handling, config file parsing,
- * thread wrappers, startup time
- */
#ifndef BITCOIN_UTIL_SYSTEM_H
#define BITCOIN_UTIL_SYSTEM_H
@@ -16,35 +12,17 @@
#include <compat/assumptions.h>
#include <compat/compat.h>
-#include <logging.h>
-#include <sync.h>
-#include <util/fs.h>
-#include <util/settings.h>
-#include <util/time.h>
#include <any>
-#include <map>
-#include <optional>
#include <set>
#include <stdint.h>
#include <string>
-#include <utility>
-#include <vector>
-
-class ArgsManager;
-class UniValue;
// Application startup time (used for uptime calculation)
int64_t GetStartupTime();
-extern const char * const BITCOIN_CONF_FILENAME;
-extern const char * const BITCOIN_SETTINGS_FILENAME;
-
void SetupEnvironment();
bool SetupNetworking();
-// Return true if -datadir option points to a valid directory or is not specified.
-bool CheckDataDirOption(const ArgsManager& args);
-fs::path GetConfigFile(const ArgsManager& args, const fs::path& configuration_file_path);
#ifndef WIN32
std::string ShellEscape(const std::string& arg);
#endif
@@ -53,413 +31,6 @@ void runCommand(const std::string& strCommand);
#endif
/**
- * Most paths passed as configuration arguments are treated as relative to
- * the datadir if they are not absolute.
- *
- * @param args Parsed arguments and settings.
- * @param path The path to be conditionally prefixed with datadir.
- * @param net_specific Use network specific datadir variant
- * @return The normalized path.
- */
-fs::path AbsPathForConfigVal(const ArgsManager& args, const fs::path& path, bool net_specific = true);
-
-inline bool IsSwitchChar(char c)
-{
-#ifdef WIN32
- return c == '-' || c == '/';
-#else
- return c == '-';
-#endif
-}
-
-enum class OptionsCategory {
- OPTIONS,
- CONNECTION,
- WALLET,
- WALLET_DEBUG_TEST,
- ZMQ,
- DEBUG_TEST,
- CHAINPARAMS,
- NODE_RELAY,
- BLOCK_CREATION,
- RPC,
- GUI,
- COMMANDS,
- REGISTER_COMMANDS,
-
- HIDDEN // Always the last option to avoid printing these in the help
-};
-
-struct SectionInfo
-{
- std::string m_name;
- std::string m_file;
- int m_line;
-};
-
-std::string SettingToString(const util::SettingsValue&, const std::string&);
-std::optional<std::string> SettingToString(const util::SettingsValue&);
-
-int64_t SettingToInt(const util::SettingsValue&, int64_t);
-std::optional<int64_t> SettingToInt(const util::SettingsValue&);
-
-bool SettingToBool(const util::SettingsValue&, bool);
-std::optional<bool> SettingToBool(const util::SettingsValue&);
-
-class ArgsManager
-{
-public:
- /**
- * Flags controlling how config and command line arguments are validated and
- * interpreted.
- */
- enum Flags : uint32_t {
- ALLOW_ANY = 0x01, //!< disable validation
- // ALLOW_BOOL = 0x02, //!< unimplemented, draft implementation in #16545
- // ALLOW_INT = 0x04, //!< unimplemented, draft implementation in #16545
- // ALLOW_STRING = 0x08, //!< unimplemented, draft implementation in #16545
- // ALLOW_LIST = 0x10, //!< unimplemented, draft implementation in #16545
- DISALLOW_NEGATION = 0x20, //!< disallow -nofoo syntax
- DISALLOW_ELISION = 0x40, //!< disallow -foo syntax that doesn't assign any value
-
- DEBUG_ONLY = 0x100,
- /* Some options would cause cross-contamination if values for
- * mainnet were used while running on regtest/testnet (or vice-versa).
- * Setting them as NETWORK_ONLY ensures that sharing a config file
- * between mainnet and regtest/testnet won't cause problems due to these
- * parameters by accident. */
- NETWORK_ONLY = 0x200,
- // This argument's value is sensitive (such as a password).
- SENSITIVE = 0x400,
- COMMAND = 0x800,
- };
-
-protected:
- struct Arg
- {
- std::string m_help_param;
- std::string m_help_text;
- unsigned int m_flags;
- };
-
- mutable RecursiveMutex cs_args;
- util::Settings m_settings GUARDED_BY(cs_args);
- std::vector<std::string> m_command GUARDED_BY(cs_args);
- std::string m_network GUARDED_BY(cs_args);
- std::set<std::string> m_network_only_args GUARDED_BY(cs_args);
- std::map<OptionsCategory, std::map<std::string, Arg>> m_available_args GUARDED_BY(cs_args);
- bool m_accept_any_command GUARDED_BY(cs_args){true};
- std::list<SectionInfo> m_config_sections GUARDED_BY(cs_args);
- mutable fs::path m_cached_blocks_path GUARDED_BY(cs_args);
- mutable fs::path m_cached_datadir_path GUARDED_BY(cs_args);
- mutable fs::path m_cached_network_datadir_path GUARDED_BY(cs_args);
-
- [[nodiscard]] bool ReadConfigStream(std::istream& stream, const std::string& filepath, std::string& error, bool ignore_invalid_keys = false);
-
- /**
- * Returns true if settings values from the default section should be used,
- * depending on the current network and whether the setting is
- * network-specific.
- */
- bool UseDefaultSection(const std::string& arg) const EXCLUSIVE_LOCKS_REQUIRED(cs_args);
-
- public:
- /**
- * Get setting value.
- *
- * Result will be null if setting was unset, true if "-setting" argument was passed
- * false if "-nosetting" argument was passed, and a string if a "-setting=value"
- * argument was passed.
- */
- util::SettingsValue GetSetting(const std::string& arg) const;
-
- /**
- * Get list of setting values.
- */
- std::vector<util::SettingsValue> GetSettingsList(const std::string& arg) const;
-
- ArgsManager();
- ~ArgsManager();
-
- /**
- * Select the network in use
- */
- void SelectConfigNetwork(const std::string& network);
-
- [[nodiscard]] bool ParseParameters(int argc, const char* const argv[], std::string& error);
-
- /**
- * Return config file path (read-only)
- */
- fs::path GetConfigFilePath() const;
- [[nodiscard]] bool ReadConfigFiles(std::string& error, bool ignore_invalid_keys = false);
-
- /**
- * Log warnings for options in m_section_only_args when
- * they are specified in the default section but not overridden
- * on the command line or in a network-specific section in the
- * config file.
- */
- std::set<std::string> GetUnsuitableSectionOnlyArgs() const;
-
- /**
- * Log warnings for unrecognized section names in the config file.
- */
- std::list<SectionInfo> GetUnrecognizedSections() const;
-
- struct Command {
- /** The command (if one has been registered with AddCommand), or empty */
- std::string command;
- /**
- * If command is non-empty: Any args that followed it
- * If command is empty: The unregistered command and any args that followed it
- */
- std::vector<std::string> args;
- };
- /**
- * Get the command and command args (returns std::nullopt if no command provided)
- */
- std::optional<const Command> GetCommand() const;
-
- /**
- * Get blocks directory path
- *
- * @return Blocks path which is network specific
- */
- const fs::path& GetBlocksDirPath() const;
-
- /**
- * Get data directory path
- *
- * @return Absolute path on success, otherwise an empty path when a non-directory path would be returned
- */
- const fs::path& GetDataDirBase() const { return GetDataDir(false); }
-
- /**
- * Get data directory path with appended network identifier
- *
- * @return Absolute path on success, otherwise an empty path when a non-directory path would be returned
- */
- const fs::path& GetDataDirNet() const { return GetDataDir(true); }
-
- /**
- * Clear cached directory paths
- */
- void ClearPathCache();
-
- /**
- * Return a vector of strings of the given argument
- *
- * @param strArg Argument to get (e.g. "-foo")
- * @return command-line arguments
- */
- std::vector<std::string> GetArgs(const std::string& strArg) const;
-
- /**
- * Return true if the given argument has been manually set
- *
- * @param strArg Argument to get (e.g. "-foo")
- * @return true if the argument has been set
- */
- bool IsArgSet(const std::string& strArg) const;
-
- /**
- * Return true if the argument was originally passed as a negated option,
- * i.e. -nofoo.
- *
- * @param strArg Argument to get (e.g. "-foo")
- * @return true if the argument was passed negated
- */
- bool IsArgNegated(const std::string& strArg) const;
-
- /**
- * Return string argument or default value
- *
- * @param strArg Argument to get (e.g. "-foo")
- * @param strDefault (e.g. "1")
- * @return command-line argument or default value
- */
- std::string GetArg(const std::string& strArg, const std::string& strDefault) const;
- std::optional<std::string> GetArg(const std::string& strArg) const;
-
- /**
- * Return path argument or default value
- *
- * @param arg Argument to get a path from (e.g., "-datadir", "-blocksdir" or "-walletdir")
- * @param default_value Optional default value to return instead of the empty path.
- * @return normalized path if argument is set, with redundant "." and ".."
- * path components and trailing separators removed (see patharg unit test
- * for examples or implementation for details). If argument is empty or not
- * set, default_value is returned unchanged.
- */
- fs::path GetPathArg(std::string arg, const fs::path& default_value = {}) const;
-
- /**
- * Return integer argument or default value
- *
- * @param strArg Argument to get (e.g. "-foo")
- * @param nDefault (e.g. 1)
- * @return command-line argument (0 if invalid number) or default value
- */
- int64_t GetIntArg(const std::string& strArg, int64_t nDefault) const;
- std::optional<int64_t> GetIntArg(const std::string& strArg) const;
-
- /**
- * Return boolean argument or default value
- *
- * @param strArg Argument to get (e.g. "-foo")
- * @param fDefault (true or false)
- * @return command-line argument or default value
- */
- bool GetBoolArg(const std::string& strArg, bool fDefault) const;
- std::optional<bool> GetBoolArg(const std::string& strArg) const;
-
- /**
- * Set an argument if it doesn't already have a value
- *
- * @param strArg Argument to set (e.g. "-foo")
- * @param strValue Value (e.g. "1")
- * @return true if argument gets set, false if it already had a value
- */
- bool SoftSetArg(const std::string& strArg, const std::string& strValue);
-
- /**
- * Set a boolean argument if it doesn't already have a value
- *
- * @param strArg Argument to set (e.g. "-foo")
- * @param fValue Value (e.g. false)
- * @return true if argument gets set, false if it already had a value
- */
- bool SoftSetBoolArg(const std::string& strArg, bool fValue);
-
- // Forces an arg setting. Called by SoftSetArg() if the arg hasn't already
- // been set. Also called directly in testing.
- void ForceSetArg(const std::string& strArg, const std::string& strValue);
-
- /**
- * Returns the appropriate chain name from the program arguments.
- * @return CBaseChainParams::MAIN by default; raises runtime error if an invalid combination is given.
- */
- std::string GetChainName() const;
-
- /**
- * Add argument
- */
- void AddArg(const std::string& name, const std::string& help, unsigned int flags, const OptionsCategory& cat);
-
- /**
- * Add subcommand
- */
- void AddCommand(const std::string& cmd, const std::string& help);
-
- /**
- * Add many hidden arguments
- */
- void AddHiddenArgs(const std::vector<std::string>& args);
-
- /**
- * Clear available arguments
- */
- void ClearArgs() {
- LOCK(cs_args);
- m_available_args.clear();
- m_network_only_args.clear();
- }
-
- /**
- * Get the help string
- */
- std::string GetHelpMessage() const;
-
- /**
- * Return Flags for known arg.
- * Return nullopt for unknown arg.
- */
- std::optional<unsigned int> GetArgFlags(const std::string& name) const;
-
- /**
- * Get settings file path, or return false if read-write settings were
- * disabled with -nosettings.
- */
- bool GetSettingsPath(fs::path* filepath = nullptr, bool temp = false, bool backup = false) const;
-
- /**
- * Read settings file. Push errors to vector, or log them if null.
- */
- bool ReadSettingsFile(std::vector<std::string>* errors = nullptr);
-
- /**
- * Write settings file or backup settings file. Push errors to vector, or
- * log them if null.
- */
- bool WriteSettingsFile(std::vector<std::string>* errors = nullptr, bool backup = false) const;
-
- /**
- * Get current setting from config file or read/write settings file,
- * ignoring nonpersistent command line or forced settings values.
- */
- util::SettingsValue GetPersistentSetting(const std::string& name) const;
-
- /**
- * Access settings with lock held.
- */
- template <typename Fn>
- void LockSettings(Fn&& fn)
- {
- LOCK(cs_args);
- fn(m_settings);
- }
-
- /**
- * Log the config file options and the command line arguments,
- * useful for troubleshooting.
- */
- void LogArgs() const;
-
-private:
- /**
- * Get data directory path
- *
- * @param net_specific Append network identifier to the returned path
- * @return Absolute path on success, otherwise an empty path when a non-directory path would be returned
- */
- const fs::path& GetDataDir(bool net_specific) const;
-
- // Helper function for LogArgs().
- void logArgsPrefix(
- const std::string& prefix,
- const std::string& section,
- const std::map<std::string, std::vector<util::SettingsValue>>& args) const;
-};
-
-extern ArgsManager gArgs;
-
-/**
- * @return true if help has been requested via a command-line arg
- */
-bool HelpRequested(const ArgsManager& args);
-
-/** Add help options to the args manager */
-void SetupHelpOptions(ArgsManager& args);
-
-/**
- * Format a string to be used as group of options in help messages
- *
- * @param message Group name (e.g. "RPC server options:")
- * @return the formatted string
- */
-std::string HelpMessageGroup(const std::string& message);
-
-/**
- * Format a string to be used as option description in help messages
- *
- * @param option Option message (e.g. "-rpcuser=<user>")
- * @param message Option description (e.g. "Username for JSON-RPC connections")
- * @return the formatted string
- */
-std::string HelpMessageOpt(const std::string& option, const std::string& message);
-
-/**
* Return the number of cores available on the current system.
* @note This does count virtual cores, such as those provided by HyperThreading.
*/
@@ -496,21 +67,6 @@ T* AnyPtr(const std::any& any) noexcept
return ptr ? *ptr : nullptr;
}
-#ifdef WIN32
-class WinCmdLineArgs
-{
-public:
- WinCmdLineArgs();
- ~WinCmdLineArgs();
- std::pair<int, char**> get();
-
-private:
- int argc;
- char** argv;
- std::vector<std::string> args;
-};
-#endif
-
} // namespace util
#endif // BITCOIN_UTIL_SYSTEM_H
diff --git a/src/validation.cpp b/src/validation.cpp
index 9f6095cb7b..56b5999557 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -11,6 +11,7 @@
#include <arith_uint256.h>
#include <chain.h>
#include <checkqueue.h>
+#include <common/args.h>
#include <consensus/amount.h>
#include <consensus/consensus.h>
#include <consensus/merkle.h>
diff --git a/src/wallet/bdb.cpp b/src/wallet/bdb.cpp
index dd425c1160..4eab342495 100644
--- a/src/wallet/bdb.cpp
+++ b/src/wallet/bdb.cpp
@@ -4,10 +4,13 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <compat/compat.h>
+#include <logging.h>
#include <util/fs.h>
+#include <util/time.h>
#include <wallet/bdb.h>
#include <wallet/db.h>
+#include <sync.h>
#include <util/check.h>
#include <util/fs_helpers.h>
#include <util/strencodings.h>
diff --git a/src/wallet/bdb.h b/src/wallet/bdb.h
index fbec0bb90b..ff24081696 100644
--- a/src/wallet/bdb.h
+++ b/src/wallet/bdb.h
@@ -14,6 +14,7 @@
#include <wallet/db.h>
#include <atomic>
+#include <condition_variable>
#include <map>
#include <memory>
#include <string>
diff --git a/src/wallet/coincontrol.cpp b/src/wallet/coincontrol.cpp
index 3b3c1f8da4..ad2fab4b7d 100644
--- a/src/wallet/coincontrol.cpp
+++ b/src/wallet/coincontrol.cpp
@@ -4,7 +4,7 @@
#include <wallet/coincontrol.h>
-#include <util/system.h>
+#include <common/args.h>
namespace wallet {
CCoinControl::CCoinControl()
diff --git a/src/wallet/coinselection.cpp b/src/wallet/coinselection.cpp
index f704d03b5f..832d24746f 100644
--- a/src/wallet/coinselection.cpp
+++ b/src/wallet/coinselection.cpp
@@ -6,10 +6,11 @@
#include <consensus/amount.h>
#include <consensus/consensus.h>
+#include <logging.h>
#include <policy/feerate.h>
#include <util/check.h>
-#include <util/system.h>
#include <util/moneystr.h>
+#include <util/system.h>
#include <numeric>
#include <optional>
diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp
index 92e1d61ac4..0c24920516 100644
--- a/src/wallet/db.cpp
+++ b/src/wallet/db.cpp
@@ -4,9 +4,9 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <chainparams.h>
+#include <common/args.h>
#include <logging.h>
#include <util/fs.h>
-#include <util/system.h>
#include <wallet/db.h>
#include <exception>
diff --git a/src/wallet/dump.cpp b/src/wallet/dump.cpp
index 31b6eb4ae1..865af0bb23 100644
--- a/src/wallet/dump.cpp
+++ b/src/wallet/dump.cpp
@@ -4,8 +4,8 @@
#include <wallet/dump.h>
+#include <common/args.h>
#include <util/fs.h>
-#include <util/system.h>
#include <util/translation.h>
#include <wallet/wallet.h>
diff --git a/src/wallet/external_signer_scriptpubkeyman.cpp b/src/wallet/external_signer_scriptpubkeyman.cpp
index cb861d835e..079e3baa4e 100644
--- a/src/wallet/external_signer_scriptpubkeyman.cpp
+++ b/src/wallet/external_signer_scriptpubkeyman.cpp
@@ -3,7 +3,9 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <chainparams.h>
+#include <common/args.h>
#include <external_signer.h>
+#include <util/system.h>
#include <wallet/external_signer_scriptpubkeyman.h>
#include <iostream>
diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp
index 5403e38950..0d0a8650ac 100644
--- a/src/wallet/init.cpp
+++ b/src/wallet/init.cpp
@@ -3,6 +3,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <common/args.h>
#include <init.h>
#include <interfaces/chain.h>
#include <interfaces/init.h>
@@ -14,7 +15,6 @@
#include <univalue.h>
#include <util/check.h>
#include <util/moneystr.h>
-#include <util/system.h>
#include <util/translation.h>
#ifdef USE_BDB
#include <wallet/bdb.h>
diff --git a/src/wallet/interfaces.cpp b/src/wallet/interfaces.cpp
index 086f6d9de8..1cde4207e2 100644
--- a/src/wallet/interfaces.cpp
+++ b/src/wallet/interfaces.cpp
@@ -4,6 +4,7 @@
#include <interfaces/wallet.h>
+#include <common/args.h>
#include <consensus/amount.h>
#include <interfaces/chain.h>
#include <interfaces/handler.h>
@@ -15,7 +16,6 @@
#include <sync.h>
#include <uint256.h>
#include <util/check.h>
-#include <util/system.h>
#include <util/translation.h>
#include <util/ui_change_type.h>
#include <wallet/coincontrol.h>
diff --git a/src/wallet/load.cpp b/src/wallet/load.cpp
index 2103fc64e4..2560dda87c 100644
--- a/src/wallet/load.cpp
+++ b/src/wallet/load.cpp
@@ -5,12 +5,12 @@
#include <wallet/load.h>
+#include <common/args.h>
#include <interfaces/chain.h>
#include <scheduler.h>
#include <util/check.h>
#include <util/fs.h>
#include <util/string.h>
-#include <util/system.h>
#include <util/translation.h>
#include <wallet/context.h>
#include <wallet/spend.h>
diff --git a/src/wallet/spend.cpp b/src/wallet/spend.cpp
index c3303419d4..748f40dce8 100644
--- a/src/wallet/spend.cpp
+++ b/src/wallet/spend.cpp
@@ -3,6 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <algorithm>
+#include <common/args.h>
#include <consensus/amount.h>
#include <consensus/validation.h>
#include <interfaces/chain.h>
@@ -14,6 +15,7 @@
#include <util/fees.h>
#include <util/moneystr.h>
#include <util/rbf.h>
+#include <util/system.h>
#include <util/trace.h>
#include <util/translation.h>
#include <wallet/coincontrol.h>
diff --git a/src/wallet/test/init_test_fixture.cpp b/src/wallet/test/init_test_fixture.cpp
index 1db2a06bf8..0adc63876c 100644
--- a/src/wallet/test/init_test_fixture.cpp
+++ b/src/wallet/test/init_test_fixture.cpp
@@ -2,10 +2,10 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <common/args.h>
#include <univalue.h>
#include <util/check.h>
#include <util/fs.h>
-#include <util/system.h>
#include <fstream>
#include <string>
diff --git a/src/wallet/test/init_tests.cpp b/src/wallet/test/init_tests.cpp
index 3dbc91fc68..10aeed49cb 100644
--- a/src/wallet/test/init_tests.cpp
+++ b/src/wallet/test/init_tests.cpp
@@ -4,10 +4,10 @@
#include <boost/test/unit_test.hpp>
+#include <common/args.h>
#include <noui.h>
#include <test/util/logging.h>
#include <test/util/setup_common.h>
-#include <util/system.h>
#include <wallet/test/init_test_fixture.h>
namespace wallet {
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 4e8c0c0e5e..1095529188 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -7,6 +7,7 @@
#include <blockfilter.h>
#include <chain.h>
+#include <common/args.h>
#include <consensus/amount.h>
#include <consensus/consensus.h>
#include <consensus/validation.h>
@@ -36,7 +37,6 @@
#include <util/moneystr.h>
#include <util/rbf.h>
#include <util/string.h>
-#include <util/system.h>
#include <util/translation.h>
#include <wallet/coincontrol.h>
#include <wallet/context.h>
diff --git a/src/wallet/wallettool.cpp b/src/wallet/wallettool.cpp
index acd817a311..2f3f8ef77d 100644
--- a/src/wallet/wallettool.cpp
+++ b/src/wallet/wallettool.cpp
@@ -8,8 +8,8 @@
#include <wallet/wallettool.h>
+#include <common/args.h>
#include <util/fs.h>
-#include <util/system.h>
#include <util/translation.h>
#include <wallet/dump.h>
#include <wallet/salvage.h>
diff --git a/src/wallet/walletutil.cpp b/src/wallet/walletutil.cpp
index 299c74d01c..fdd5bc36d8 100644
--- a/src/wallet/walletutil.cpp
+++ b/src/wallet/walletutil.cpp
@@ -4,8 +4,8 @@
#include <wallet/walletutil.h>
+#include <common/args.h>
#include <logging.h>
-#include <util/system.h>
namespace wallet {
fs::path GetWalletDir()
diff --git a/src/zmq/zmqnotificationinterface.cpp b/src/zmq/zmqnotificationinterface.cpp
index df129c0830..9920d80a69 100644
--- a/src/zmq/zmqnotificationinterface.cpp
+++ b/src/zmq/zmqnotificationinterface.cpp
@@ -4,10 +4,10 @@
#include <zmq/zmqnotificationinterface.h>
+#include <common/args.h>
#include <logging.h>
#include <primitives/block.h>
#include <primitives/transaction.h>
-#include <util/system.h>
#include <validationinterface.h>
#include <zmq/zmqabstractnotifier.h>
#include <zmq/zmqpublishnotifier.h>
diff --git a/test/lint/lint-circular-dependencies.py b/test/lint/lint-circular-dependencies.py
index cf6a5f81f1..307b4dca5a 100755
--- a/test/lint/lint-circular-dependencies.py
+++ b/test/lint/lint-circular-dependencies.py
@@ -12,7 +12,7 @@ import subprocess
import sys
EXPECTED_CIRCULAR_DEPENDENCIES = (
- "chainparamsbase -> util/system -> chainparamsbase",
+ "chainparamsbase -> common/args -> chainparamsbase",
"node/blockstorage -> validation -> node/blockstorage",
"node/utxo_snapshot -> validation -> node/utxo_snapshot",
"qt/addresstablemodel -> qt/walletmodel -> qt/addresstablemodel",