From f7e83bd5c892415484bb2fca0a635c6965c464c4 Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Tue, 3 Nov 2026 23:29:56 +0700 Subject: [PATCH 1/7] Merge bitcoin/bitcoin#27419: move-only: Extract common/args from util/system MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Co-authored-by: fanquake --- src/Makefile.am | 5 + src/addrdb.cpp | 2 +- src/banman.cpp | 1 + src/bench/bench_bitcoin.cpp | 2 +- src/bench/checkblock.cpp | 2 +- src/bitcoin-chainstate.cpp | 1 + src/bitcoin-cli.cpp | 4 +- src/bitcoin-tx.cpp | 1 + src/bitcoin-util.cpp | 1 + src/bitcoin-wallet.cpp | 3 +- src/bitcoind.cpp | 3 +- src/chainparams.cpp | 1 + src/chainparamsbase.cpp | 2 +- src/coinjoin/client.cpp | 1 + src/coinjoin/interfaces.cpp | 1 + src/coinjoin/options.cpp | 1 + src/common/args.cpp | 884 ++++++++++++++ src/common/args.h | 487 ++++++++ src/common/config.cpp | 216 ++++ src/common/init.cpp | 1 + src/dummywallet.cpp | 1 + src/evo/netinfo.cpp | 1 + src/flat-database.h | 1 + src/httprpc.cpp | 2 +- src/httpserver.cpp | 1 + src/i2p.cpp | 2 +- src/index/addressindex.cpp | 1 + src/index/base.cpp | 1 + src/index/blockfilterindex.cpp | 2 +- src/index/coinstatsindex.cpp | 2 +- src/index/govcollateralindex.cpp | 5 +- src/index/spentindex.cpp | 1 + src/index/timestampindex.cpp | 1 + src/index/txindex.cpp | 2 +- src/init.cpp | 1 + src/init/bitcoin-gui.cpp | 1 + src/init/bitcoin-node.cpp | 2 +- src/init/bitcoin-qt.cpp | 1 + src/init/bitcoind.cpp | 2 +- src/init/common.cpp | 2 +- src/llmq/options.cpp | 1 + src/net.cpp | 1 + src/net_processing.cpp | 2 +- src/node/blockmanager_args.cpp | 2 +- src/node/blockstorage.cpp | 1 + src/node/caches.cpp | 2 +- src/node/chainstatemanager_args.cpp | 2 +- src/node/coins_view_args.cpp | 2 +- src/node/database_args.cpp | 2 +- src/node/interfaces.cpp | 1 + src/node/mempool_args.cpp | 2 +- src/node/mempool_persist_args.cpp | 2 +- src/node/miner.cpp | 2 +- src/node/sync_manager.cpp | 1 + src/node/txreconciliation.cpp | 1 + src/node/utxo_snapshot.cpp | 1 + src/node/validation_cache_args.cpp | 2 +- src/policy/fees_args.cpp | 2 +- src/qt/bitcoin.cpp | 3 +- src/qt/bitcoingui.cpp | 1 + src/qt/clientmodel.cpp | 1 + src/qt/guiutil.cpp | 3 +- src/qt/guiutil_font.cpp | 1 + src/qt/intro.cpp | 2 +- src/qt/networkstyle.cpp | 1 + src/qt/optionsmodel.cpp | 3 +- src/qt/paymentserver.cpp | 1 + src/qt/rpcconsole.cpp | 1 + src/qt/test/masternodetestutil.cpp | 1 + src/qt/test/masternodewidgettests.cpp | 1 + src/qt/test/optiontests.cpp | 2 +- src/qt/utilitydialog.cpp | 3 +- src/qt/walletmodel.cpp | 2 +- src/rpc/blockchain.cpp | 2 +- src/rpc/client.cpp | 6 +- src/rpc/coinjoin.cpp | 8 +- src/rpc/evo.cpp | 1 + src/rpc/external_signer.cpp | 4 +- src/rpc/mempool.cpp | 1 + src/rpc/request.cpp | 3 +- src/rpc/server.cpp | 2 + src/rpc/server_util.cpp | 1 + src/rpc/util.cpp | 2 +- src/script/descriptor.cpp | 1 + src/script/sigcache.cpp | 1 + src/stats/client.cpp | 1 + src/test/argsman_tests.cpp | 2 +- src/test/checkqueue_tests.cpp | 3 +- src/test/denialofservice_tests.cpp | 2 +- src/test/flatfile_tests.cpp | 2 +- src/test/fuzz/addrman.cpp | 2 +- src/test/fuzz/banman.cpp | 2 +- src/test/fuzz/connman.cpp | 2 +- src/test/fuzz/deserialize.cpp | 2 +- src/test/fuzz/integer.cpp | 1 + src/test/fuzz/string.cpp | 1 + src/test/fuzz/system.cpp | 2 +- src/test/fuzz/versionbits.cpp | 2 +- src/test/getarg_tests.cpp | 3 +- src/test/i2p_tests.cpp | 1 + src/test/llmq_params_tests.cpp | 1 + src/test/masternode_params_tests.cpp | 1 + src/test/miner_tests.cpp | 1 + src/test/net_tests.cpp | 2 +- src/test/settings_tests.cpp | 2 +- src/test/util/setup_common.cpp | 2 + src/test/util/setup_common.h | 3 + src/test/validationinterface_tests.cpp | 2 + src/timedata.cpp | 3 +- src/torcontrol.cpp | 2 + src/txdb.cpp | 2 +- src/util/system.cpp | 1083 +---------------- src/util/system.h | 466 ------- src/validation.cpp | 1 + src/wallet/bdb.cpp | 3 + src/wallet/coincontrol.cpp | 2 +- src/wallet/coinselection.cpp | 3 +- src/wallet/db.cpp | 2 +- src/wallet/dump.cpp | 2 +- .../external_signer_scriptpubkeyman.cpp | 2 + src/wallet/hdchain.cpp | 1 + src/wallet/init.cpp | 1 + src/wallet/interfaces.cpp | 2 +- src/wallet/load.cpp | 2 +- src/wallet/spend.cpp | 2 + src/wallet/test/coinjoin_tests.cpp | 5 +- src/wallet/test/init_test_fixture.cpp | 2 +- src/wallet/test/init_tests.cpp | 1 + src/wallet/wallet.cpp | 1 + src/wallet/wallettool.cpp | 1 + src/wallet/walletutil.cpp | 2 +- src/zmq/zmqnotificationinterface.cpp | 2 +- test/lint/lint-circular-dependencies.py | 2 +- 133 files changed, 1757 insertions(+), 1618 deletions(-) create mode 100644 src/common/args.cpp create mode 100644 src/common/args.h create mode 100644 src/common/config.cpp diff --git a/src/Makefile.am b/src/Makefile.am index 0724e19a22da..9e46963b99fb 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -205,6 +205,7 @@ BITCOIN_CORE_H = \ coinjoin/util.h \ coinjoin/walletman.h \ coins.h \ + common/args.h \ common/bloom.h \ common/init.h \ common/run_command.h \ @@ -999,7 +1000,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 \ @@ -1284,7 +1287,9 @@ libdashkernel_la_SOURCES = \ chainparamsbase.cpp \ clientversion.cpp \ coins.cpp \ + common/args.cpp \ common/bloom.cpp \ + common/config.cpp \ compressor.cpp \ consensus/merkle.cpp \ consensus/tx_check.cpp \ diff --git a/src/addrdb.cpp b/src/addrdb.cpp index db476cc3f0b1..79cc562c7bfb 100644 --- a/src/addrdb.cpp +++ b/src/addrdb.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -24,7 +25,6 @@ #include #include #include -#include #include #include diff --git a/src/banman.cpp b/src/banman.cpp index f1c0eac20fbd..10fd9699cffc 100644 --- a/src/banman.cpp +++ b/src/banman.cpp @@ -5,6 +5,7 @@ #include +#include #include #include #include diff --git a/src/bench/bench_bitcoin.cpp b/src/bench/bench_bitcoin.cpp index 38eb9e682014..785c98c87440 100644 --- a/src/bench/bench_bitcoin.cpp +++ b/src/bench/bench_bitcoin.cpp @@ -6,11 +6,11 @@ #include #include +#include #include #include #include #include -#include #include #include diff --git a/src/bench/checkblock.cpp b/src/bench/checkblock.cpp index a297fbea8363..bb3fbbf8391f 100644 --- a/src/bench/checkblock.cpp +++ b/src/bench/checkblock.cpp @@ -6,10 +6,10 @@ #include #include +#include #include #include #include -#include #include #include diff --git a/src/bitcoin-chainstate.cpp b/src/bitcoin-chainstate.cpp index de391c18bf52..713864ca958e 100644 --- a/src/bitcoin-chainstate.cpp +++ b/src/bitcoin-chainstate.cpp @@ -18,6 +18,7 @@ #include #include +#include #include #include #include diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp index ed477475189e..cf6f3af39a2e 100644 --- a/src/bitcoin-cli.cpp +++ b/src/bitcoin-cli.cpp @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -23,6 +24,7 @@ #include #include #include +#include #include #include @@ -1254,7 +1256,7 @@ MAIN_FUNCTION RegisterPrettySignalHandlers(); #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 5cff3c7ac2d5..bad0d99e5fb8 100644 --- a/src/bitcoin-tx.cpp +++ b/src/bitcoin-tx.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include diff --git a/src/bitcoin-util.cpp b/src/bitcoin-util.cpp index 1637f444a7f6..e813c2dca7a1 100644 --- a/src/bitcoin-util.cpp +++ b/src/bitcoin-util.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include diff --git a/src/bitcoin-wallet.cpp b/src/bitcoin-wallet.cpp index 8c99ba61a936..40075f80e7fb 100644 --- a/src/bitcoin-wallet.cpp +++ b/src/bitcoin-wallet.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -98,7 +99,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 2584cbd52161..23251f46b3dd 100644 --- a/src/bitcoind.cpp +++ b/src/bitcoind.cpp @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -252,7 +253,7 @@ MAIN_FUNCTION RegisterPrettySignalHandlers(); #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 b6bd830ec539..30b81aa97bd6 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -11,6 +11,7 @@ #include #include +#include #include #include #include diff --git a/src/chainparamsbase.cpp b/src/chainparamsbase.cpp index 1a5fb9a8a4b2..5812b8db6d09 100644 --- a/src/chainparamsbase.cpp +++ b/src/chainparamsbase.cpp @@ -5,8 +5,8 @@ #include +#include #include -#include #include diff --git a/src/coinjoin/client.cpp b/src/coinjoin/client.cpp index 8f4cf4b4e558..ae2ca4db762e 100644 --- a/src/coinjoin/client.cpp +++ b/src/coinjoin/client.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include #include diff --git a/src/coinjoin/interfaces.cpp b/src/coinjoin/interfaces.cpp index 5ddb127f4217..80731ac7c60b 100644 --- a/src/coinjoin/interfaces.cpp +++ b/src/coinjoin/interfaces.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include diff --git a/src/coinjoin/options.cpp b/src/coinjoin/options.cpp index deec629deb00..87d87f0ced6c 100644 --- a/src/coinjoin/options.cpp +++ b/src/coinjoin/options.cpp @@ -4,6 +4,7 @@ #include +#include #include #include diff --git a/src/common/args.cpp b/src/common/args.cpp new file mode 100644 index 000000000000..81870d3cfa8b --- /dev/null +++ b/src/common/args.cpp @@ -0,0 +1,884 @@ +// 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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef WIN32 +#include /* for codecvt_utf8_utf16 */ +#include /* for CommandLineToArgvW */ +#include /* for CSIDL_APPDATA */ +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +const char * const BITCOIN_CONF_FILENAME = "dash.conf"; +const char * const BITCOIN_SETTINGS_FILENAME = "settings.json"; + +ArgsManager gArgs; + +/** + * Interpret a string argument as a boolean. + * + * The definition of LocaleIndependentAtoi() 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(...) 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(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 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 ArgsManager::GetUnsuitableSectionOnlyArgs() const +{ + std::set unsuitables; + + LOCK(cs_args); + + // if there's no section selected, don't worry + if (m_network.empty()) return std::set {}; + + // if it's okay to use the default section for this network, don't worry + if (m_network == CBaseChainParams::MAIN) return std::set {}; + + for (const auto& arg : m_network_only_args) { + if (OnlyHasDefaultSectionSetting(m_settings, m_network, SettingName(arg))) { + unsuitables.insert(arg); + } + } + return unsuitables; +} + +std::list ArgsManager::GetUnrecognizedSections() const +{ + // Section names to be recognized in the config file. + static const std::set available_sections{ + CBaseChainParams::REGTEST, + CBaseChainParams::DEVNET, + CBaseChainParams::TESTNET, + CBaseChainParams::MAIN, + }; + + LOCK(cs_args); + std::list unrecognized = m_config_sections; + unrecognized.remove_if([](const SectionInfo& appeared){ return available_sections.find(appeared.m_name) != available_sections.end(); }); + return unrecognized; +} + +std::map> ArgsManager::GetCommandLineArgs() const { + LOCK(cs_args); + return m_settings.command_line_options; +} + +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]); + if (key == "-") break; //dash-tx using stdin + +#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 + + std::optional 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 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.emplace_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 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 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 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(); +} + +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; +} + +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; +} + +fs::path ArgsManager::GetBackupsDirPath() +{ + if (!IsArgSet("-walletbackupsdir")) + return GetDataDirNet() / "backups"; + + return fs::absolute(GetPathArg("-walletbackupsdir")); +} +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 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 ArgsManager::GetArgs(const std::string& strArg) const +{ + std::vector 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 errors, std::vector* 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* 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 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* 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 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 ArgsManager::GetArg(const std::string& strArg) const +{ + const util::SettingsValue value = GetSetting(strArg); + return SettingToString(value); +} + +std::optional 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 ArgsManager::GetIntArg(const std::string& strArg) const +{ + const util::SettingsValue value = GetSetting(strArg); + return SettingToInt(value); +} + +std::optional 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(); + return LocaleIndependentAtoi(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 ArgsManager::GetBoolArg(const std::string& strArg) const +{ + const util::SettingsValue value = GetSetting(strArg); + return SettingToBool(value); +} + +std::optional 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& 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& 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& 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::INDEXING: + usage += HelpMessageGroup("Indexing options:"); + break; + case OptionsCategory::MASTERNODE: + usage += HelpMessageGroup("Masternode options:"); + break; + case OptionsCategory::STATSD: + usage += HelpMessageGroup("Statsd 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_FEE: + usage += HelpMessageGroup("Wallet fee options:"); + break; + case OptionsCategory::WALLET_HD: + usage += HelpMessageGroup("HD wallet options:"); + break; + case OptionsCategory::WALLET_COINJOIN: + usage += HelpMessageGroup("CoinJoin 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; +} + +void ArgsManager::ForceRemoveArg(const std::string& strArg) +{ + LOCK(cs_args); + const auto& ov = m_settings.forced_settings.find(strArg); + if (ov != m_settings.forced_settings.end()) { + m_settings.forced_settings.erase(ov); + } + + for (const auto& network : { CBaseChainParams::MAIN, CBaseChainParams::TESTNET, CBaseChainParams::REGTEST, CBaseChainParams::DEVNET }) { + if (auto* section = util::FindKey(m_settings.ro_config, network)) { + if (util::FindKey(*section, strArg)) { + section->erase(strArg); + } + } + } +} + +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", false, 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\DashCore + // macOS: ~/Library/Application Support/DashCore + // Unix-like: ~/.dashcore +#ifdef WIN32 + // Windows + return GetSpecialFolderPath(CSIDL_APPDATA) / "DashCore"; +#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/DashCore"; +#else + // Unix-like + return pathRet / ".dashcore"; +#endif +#endif +} + +fs::path GetBackupsDir() +{ + return gArgs.GetBackupsDirPath(); +} + +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 +{ + LOCK(cs_args); + return *Assert(m_config_path); +} + +std::string ArgsManager::GetChainName() const +{ + auto get_net = [&](const std::string& arg, bool interpret_bool = true) { + 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() : (!interpret_bool || InterpretBool(value.get_str())); + }; + + const bool fRegTest = get_net("-regtest"); + const bool fDevNet = get_net("-devnet", false); + const bool fTestNet = get_net("-testnet"); + const bool is_chain_arg_set = IsArgSet("-chain"); + + int nameParamsCount = (fRegTest ? 1 : 0) + (fDevNet ? 1 : 0) + (fTestNet ? 1 : 0) + (is_chain_arg_set ? 1 : 0); + if (nameParamsCount > 1) + throw std::runtime_error("Only one of -regtest, -testnet, -devnet or -chain can be used."); + + if (fRegTest) + return CBaseChainParams::REGTEST; + if (fDevNet) { + return CBaseChainParams::DEVNET; + } + if (fTestNet) + return CBaseChainParams::TESTNET; + + return GetArg("-chain", CBaseChainParams::MAIN); +} + +std::string ArgsManager::GetDevNetName() const +{ + std::string devNetName = GetArg("-devnet", ""); + return "devnet" + (devNetName.empty() ? "" : "-" + devNetName); +} + + +void ArgsManager::logArgsPrefix( + const std::string& prefix, + const std::string& section, + const std::map>& args) const +{ + std::string section_str = section.empty() ? "" : "[" + section + "] "; + for (const auto& arg : args) { + for (const auto& value : arg.second) { + std::optional 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); +} + +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 ArgsManager::GetSettingsList(const std::string& arg) const +{ + LOCK(cs_args); + return util::GetSettingsList(m_settings, m_network, SettingName(arg), !UseDefaultSection(arg)); +} + +namespace common { +#ifdef WIN32 +WinCmdLineArgs::WinCmdLineArgs() +{ + wchar_t** wargv = CommandLineToArgvW(GetCommandLineW(), &argc); + std::wstring_convert, 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 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 000000000000..f77d89063b31 --- /dev/null +++ b/src/common/args.h @@ -0,0 +1,487 @@ +// 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 +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +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); + +/** + * 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, + INDEXING, + MASTERNODE, + STATSD, + WALLET, + WALLET_FEE, + WALLET_HD, + WALLET_COINJOIN, + 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 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 SettingToString(const util::SettingsValue&); + +int64_t SettingToInt(const util::SettingsValue&, int64_t); +std::optional SettingToInt(const util::SettingsValue&); + +bool SettingToBool(const util::SettingsValue&, bool); +std::optional 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 m_command GUARDED_BY(cs_args); + std::string m_network GUARDED_BY(cs_args); + std::set m_network_only_args GUARDED_BY(cs_args); + std::map> m_available_args GUARDED_BY(cs_args); + bool m_accept_any_command GUARDED_BY(cs_args){true}; + std::list m_config_sections GUARDED_BY(cs_args); + std::optional m_config_path 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 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 GetUnsuitableSectionOnlyArgs() const; + + /** + * Log warnings for unrecognized section names in the config file. + */ + std::list 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 args; + }; + /** + * Get the command and command args (returns std::nullopt if no command provided) + */ + std::optional GetCommand() const; + + /** + * Return the map of all the args passed via the command line + */ + std::map> GetCommandLineArgs() const; + + /** + * Get blocks directory path + * + * @return Blocks path which is network specific + */ + 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 + */ + 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 + */ + fs::path GetDataDirNet() const { return GetDataDir(true); } + + fs::path GetBackupsDirPath(); + + /** + * 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 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 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 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 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); + void ForceRemoveArg(const std::string& strArg); + + /** + * 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; + + /** + * Looks for -devnet and returns either "devnet-" or simply "devnet" if no name was specified. + * This function should never be called for non-devnets. + * @return either "devnet-" or "devnet"; raises runtime error if no -devent was specified. + */ + std::string GetDevNetName() 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& 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 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* errors = nullptr); + + /** + * Write settings file or backup settings file. Push errors to vector, or + * log them if null. + */ + bool WriteSettingsFile(std::vector* 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 + 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 + */ + fs::path GetDataDir(bool net_specific) const; + + // Helper function for LogArgs(). + void logArgsPrefix( + const std::string& prefix, + const std::string& section, + const std::map>& 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=") + * @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 get(); + +private: + int argc; + char** argv; + std::vector 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 000000000000..6bc71ffa0df3 --- /dev/null +++ b/src/common/config.cpp @@ -0,0 +1,216 @@ +// 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 + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static bool GetConfigOptions(std::istream& stream, const std::string& filepath, std::string& error, std::vector>& options, std::list& 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> options; + if (!GetConfigOptions(stream, filepath, error, options, m_config_sections)) { + return false; + } + for (const std::pair& option : options) { + KeyInfo key = InterpretKey(option.first); + std::optional flags = GetArgFlags('-' + key.name); + if (!IsConfSupported(key, error)) return false; + if (flags) { + std::optional 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(); + m_config_path = AbsPathForConfigVal(*this, GetPathArg("-conf", BITCOIN_CONF_FILENAME), /*net_specific=*/false); + } + + const auto conf_path{GetConfigFilePath()}; + std::ifstream stream{conf_path}; + + // not ok to have a config file specified that cannot be opened + if (IsArgSet("-conf") && !stream.good()) { + 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 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{AbsPathForConfigVal(*this, fs::PathFromString(conf_file_name), /*net_specific=*/false)}; + 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 7cebff8927d0..f147bd2e5aec 100644 --- a/src/common/init.cpp +++ b/src/common/init.cpp @@ -2,6 +2,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include #include #include #include diff --git a/src/dummywallet.cpp b/src/dummywallet.cpp index 6f9e18d8b27e..9b9ec12fb6e0 100644 --- a/src/dummywallet.cpp +++ b/src/dummywallet.cpp @@ -2,6 +2,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include #include #include #include diff --git a/src/evo/netinfo.cpp b/src/evo/netinfo.cpp index 029c60e8a2a7..c34618ced8b7 100644 --- a/src/evo/netinfo.cpp +++ b/src/evo/netinfo.cpp @@ -2,6 +2,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include #include #include diff --git a/src/flat-database.h b/src/flat-database.h index 2c484e3c37e7..da103529d9aa 100644 --- a/src/flat-database.h +++ b/src/flat-database.h @@ -7,6 +7,7 @@ #include #include +#include #include #include #include diff --git a/src/httprpc.cpp b/src/httprpc.cpp index 295656ff73a7..75342c3b9a6e 100644 --- a/src/httprpc.cpp +++ b/src/httprpc.cpp @@ -4,6 +4,7 @@ #include +#include #include #include #include @@ -11,7 +12,6 @@ #include #include #include -#include #include #include diff --git a/src/httpserver.cpp b/src/httpserver.cpp index b3d6c8d0d405..82bead9fd082 100644 --- a/src/httpserver.cpp +++ b/src/httpserver.cpp @@ -9,6 +9,7 @@ #include #include +#include #include #include #include // For HTTP status codes diff --git a/src/i2p.cpp b/src/i2p.cpp index 8f963f538cc8..acd2195452e8 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 +#include #include #include #include @@ -18,7 +19,6 @@ #include #include #include -#include #include #include diff --git a/src/index/addressindex.cpp b/src/index/addressindex.cpp index 8ce3783ea36f..3f0b5c18b86c 100644 --- a/src/index/addressindex.cpp +++ b/src/index/addressindex.cpp @@ -2,6 +2,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include #include #include diff --git a/src/index/base.cpp b/src/index/base.cpp index bbdc430b0218..73188f4e5891 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 +#include #include #include #include diff --git a/src/index/blockfilterindex.cpp b/src/index/blockfilterindex.cpp index 2ffec43aaab8..09726a5b08af 100644 --- a/src/index/blockfilterindex.cpp +++ b/src/index/blockfilterindex.cpp @@ -4,6 +4,7 @@ #include +#include #include #include #include @@ -11,7 +12,6 @@ #include #include #include -#include #include using node::UndoReadFromDisk; diff --git a/src/index/coinstatsindex.cpp b/src/index/coinstatsindex.cpp index 050dd3d0e987..33893502dcb1 100644 --- a/src/index/coinstatsindex.cpp +++ b/src/index/coinstatsindex.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -12,7 +13,6 @@ #include #include #include -#include #include #include diff --git a/src/index/govcollateralindex.cpp b/src/index/govcollateralindex.cpp index 64913943b3c9..cffccb500366 100644 --- a/src/index/govcollateralindex.cpp +++ b/src/index/govcollateralindex.cpp @@ -2,14 +2,13 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include - #include #include +#include +#include #include #include #include -#include #include #include diff --git a/src/index/spentindex.cpp b/src/index/spentindex.cpp index 06af32143709..9d5e12432161 100644 --- a/src/index/spentindex.cpp +++ b/src/index/spentindex.cpp @@ -2,6 +2,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include #include #include diff --git a/src/index/timestampindex.cpp b/src/index/timestampindex.cpp index dca38910eb02..0920ffb3cafb 100644 --- a/src/index/timestampindex.cpp +++ b/src/index/timestampindex.cpp @@ -2,6 +2,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include #include #include diff --git a/src/index/txindex.cpp b/src/index/txindex.cpp index 0baa3f953cbc..db5a4d596dc0 100644 --- a/src/index/txindex.cpp +++ b/src/index/txindex.cpp @@ -4,11 +4,11 @@ #include +#include #include #include #include #include -#include #include using node::OpenBlockFile; diff --git a/src/init.cpp b/src/init.cpp index a29b3c24a8f0..28d8399e86a8 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include diff --git a/src/init/bitcoin-gui.cpp b/src/init/bitcoin-gui.cpp index e4deb06e490f..4cbf018a4e8a 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 #include #include #include diff --git a/src/init/bitcoin-node.cpp b/src/init/bitcoin-node.cpp index 01ee2fa8a262..154d901dd4c4 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 #include #include #include @@ -11,7 +12,6 @@ #include #include #include -#include #include diff --git a/src/init/bitcoin-qt.cpp b/src/init/bitcoin-qt.cpp index 1b75221b1e4f..ec3702b686dd 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 #include #include #include diff --git a/src/init/bitcoind.cpp b/src/init/bitcoind.cpp index 9eedba161e6c..98e973ae40b6 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 #include #include #include @@ -10,7 +11,6 @@ #include #include #include -#include #include diff --git a/src/init/common.cpp b/src/init/common.cpp index 828b11a87d9b..38ace0f66aad 100644 --- a/src/init/common.cpp +++ b/src/init/common.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -15,7 +16,6 @@ #include #include #include -#include #include #include diff --git a/src/llmq/options.cpp b/src/llmq/options.cpp index 53ab140e1061..eb528ac8bdbe 100644 --- a/src/llmq/options.cpp +++ b/src/llmq/options.cpp @@ -2,6 +2,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include #include #include diff --git a/src/net.cpp b/src/net.cpp index 012f8de5d207..6e07d1be3f74 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include diff --git a/src/net_processing.cpp b/src/net_processing.cpp index d4004d3112bc..70ce1a116506 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -41,7 +42,6 @@ #include #include #include -#include #include #include diff --git a/src/node/blockmanager_args.cpp b/src/node/blockmanager_args.cpp index 407eefbe09d9..62a12f88058b 100644 --- a/src/node/blockmanager_args.cpp +++ b/src/node/blockmanager_args.cpp @@ -4,7 +4,7 @@ #include -#include +#include #include namespace node { diff --git a/src/node/blockstorage.cpp b/src/node/blockstorage.cpp index 841896893eb4..fa4bb1644302 100644 --- a/src/node/blockstorage.cpp +++ b/src/node/blockstorage.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include #include diff --git a/src/node/caches.cpp b/src/node/caches.cpp index 0d0d5e8bd91a..64e79b85f20b 100644 --- a/src/node/caches.cpp +++ b/src/node/caches.cpp @@ -2,6 +2,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include #include #include @@ -9,7 +10,6 @@ #include #include #include -#include 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 9801e6e959d2..b97344c9aa1b 100644 --- a/src/node/chainstatemanager_args.cpp +++ b/src/node/chainstatemanager_args.cpp @@ -5,13 +5,13 @@ #include #include +#include #include #include #include #include #include #include -#include #include #include diff --git a/src/node/coins_view_args.cpp b/src/node/coins_view_args.cpp index 67c9b8dbacf4..5d55143e8325 100644 --- a/src/node/coins_view_args.cpp +++ b/src/node/coins_view_args.cpp @@ -4,8 +4,8 @@ #include +#include #include -#include namespace node { void ReadCoinsViewArgs(const ArgsManager& args, CoinsViewOptions& options) diff --git a/src/node/database_args.cpp b/src/node/database_args.cpp index 2c53b4b47e4d..aba3c38ff3f1 100644 --- a/src/node/database_args.cpp +++ b/src/node/database_args.cpp @@ -4,8 +4,8 @@ #include +#include #include -#include namespace node { void ReadDatabaseArgs(const ArgsManager& args, DBOptions& options) diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp index f459b8181f69..bedb80635c17 100644 --- a/src/node/interfaces.cpp +++ b/src/node/interfaces.cpp @@ -2,6 +2,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include #include #include diff --git a/src/node/mempool_args.cpp b/src/node/mempool_args.cpp index 800312abc896..9bcdd1aed3bf 100644 --- a/src/node/mempool_args.cpp +++ b/src/node/mempool_args.cpp @@ -2,6 +2,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include #include #include @@ -18,7 +19,6 @@ #include #include #include -#include #include #include diff --git a/src/node/mempool_persist_args.cpp b/src/node/mempool_persist_args.cpp index 78e3472644fb..97ecdd651bcd 100644 --- a/src/node/mempool_persist_args.cpp +++ b/src/node/mempool_persist_args.cpp @@ -4,8 +4,8 @@ #include +#include #include -#include #include namespace node { diff --git a/src/node/miner.cpp b/src/node/miner.cpp index 75fb1e8fa05a..63ed3323dd03 100644 --- a/src/node/miner.cpp +++ b/src/node/miner.cpp @@ -4,6 +4,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include #include #include @@ -22,7 +23,6 @@ #include #include #include -#include #include #include diff --git a/src/node/sync_manager.cpp b/src/node/sync_manager.cpp index c8159d2d6b55..5c7aeb16407e 100644 --- a/src/node/sync_manager.cpp +++ b/src/node/sync_manager.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include #include diff --git a/src/node/txreconciliation.cpp b/src/node/txreconciliation.cpp index ed04a78cecfa..993875907432 100644 --- a/src/node/txreconciliation.cpp +++ b/src/node/txreconciliation.cpp @@ -4,6 +4,7 @@ #include +#include #include #include diff --git a/src/node/utxo_snapshot.cpp b/src/node/utxo_snapshot.cpp index 08a6976aadb9..dda9fe802de3 100644 --- a/src/node/utxo_snapshot.cpp +++ b/src/node/utxo_snapshot.cpp @@ -4,6 +4,7 @@ #include +#include #include #include #include diff --git a/src/node/validation_cache_args.cpp b/src/node/validation_cache_args.cpp index e13b7988a09a..79c035b469c0 100644 --- a/src/node/validation_cache_args.cpp +++ b/src/node/validation_cache_args.cpp @@ -6,7 +6,7 @@ #include -#include +#include #include #include diff --git a/src/policy/fees_args.cpp b/src/policy/fees_args.cpp index 1aeb2ab98300..988b6d443a5d 100644 --- a/src/policy/fees_args.cpp +++ b/src/policy/fees_args.cpp @@ -4,7 +4,7 @@ #include -#include +#include namespace { const char* FEE_ESTIMATES_FILENAME = "fee_estimates.dat"; diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index fb598416f066..a2d248cd2b5c 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -518,7 +519,7 @@ int GuiMain(int argc, char* argv[]) RegisterPrettySignalHandlers(); #ifdef WIN32 - util::WinCmdLineArgs winArgs; + common::WinCmdLineArgs winArgs; std::tie(argc, argv) = winArgs.get(); #endif diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 0ad815bd8bcf..5bd29b71d70f 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -11,6 +11,7 @@ #include #include +#include #include #include #include diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index 014fcde34b29..f1f06f94330f 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -17,6 +17,7 @@ #include #include +#include #include #include #include diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index edfa4f5eeb40..e6f5e322c9fd 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -16,8 +16,10 @@ #include #include +#include #include #include +#include #include #include #include @@ -26,7 +28,6 @@ #include #include #include -#include #include #include diff --git a/src/qt/guiutil_font.cpp b/src/qt/guiutil_font.cpp index ea1e64ca748f..76dcb7b7422e 100644 --- a/src/qt/guiutil_font.cpp +++ b/src/qt/guiutil_font.cpp @@ -2,6 +2,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include #include #include diff --git a/src/qt/intro.cpp b/src/qt/intro.cpp index 77a98c606ca6..cda78d8b50a2 100644 --- a/src/qt/intro.cpp +++ b/src/qt/intro.cpp @@ -16,9 +16,9 @@ #include #include +#include #include #include -#include #include #include diff --git a/src/qt/networkstyle.cpp b/src/qt/networkstyle.cpp index ab88f7a1c60e..a120d21607e9 100644 --- a/src/qt/networkstyle.cpp +++ b/src/qt/networkstyle.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 #include #include diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index fa9f1ebe8bc7..52768e5f4500 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -13,11 +13,12 @@ #include #include +#include #include #include #include #include -#include // for -dbcache defaults +#include // for -dbcache defaults #include #include #include // For DEFAULT_SCRIPTCHECK_THREADS diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp index 9c1edd4841cc..58d26278d6ab 100644 --- a/src/qt/paymentserver.cpp +++ b/src/qt/paymentserver.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 #include #include diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index aa19de5109a7..db193e71d392 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -23,6 +23,7 @@ #include #include +#include #include #include #include diff --git a/src/qt/test/masternodetestutil.cpp b/src/qt/test/masternodetestutil.cpp index 739ada691674..aa75c2704fc7 100644 --- a/src/qt/test/masternodetestutil.cpp +++ b/src/qt/test/masternodetestutil.cpp @@ -2,6 +2,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include #include #include diff --git a/src/qt/test/masternodewidgettests.cpp b/src/qt/test/masternodewidgettests.cpp index 8532984d4d3f..1d98796f37d3 100644 --- a/src/qt/test/masternodewidgettests.cpp +++ b/src/qt/test/masternodewidgettests.cpp @@ -2,6 +2,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include #include #include diff --git a/src/qt/test/optiontests.cpp b/src/qt/test/optiontests.cpp index 626b5d1079d1..6ff5cbf11964 100644 --- a/src/qt/test/optiontests.cpp +++ b/src/qt/test/optiontests.cpp @@ -6,12 +6,12 @@ #include #endif +#include #include #include #include #include #include -#include #include #include diff --git a/src/qt/utilitydialog.cpp b/src/qt/utilitydialog.cpp index 3aaebe18d49d..d05a7da88afe 100644 --- a/src/qt/utilitydialog.cpp +++ b/src/qt/utilitydialog.cpp @@ -14,11 +14,12 @@ #include #include +#include #include -#include #include #include +#include #include #include diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index f8c77be578eb..a0dd3a1424bb 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.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 #include #include @@ -21,7 +22,6 @@ #include #include #include -#include // for GetBoolArg #include #include #include // for CRecipient diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index d92c87444550..b7af186b8824 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -43,7 +44,6 @@ #include #include #include -#include #include #include #include diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index 7fe8d09cb306..39a5f85f0129 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -4,9 +4,13 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#if defined(HAVE_CONFIG_H) +#include +#endif + +#include #include #include -#include #include #include diff --git a/src/rpc/coinjoin.cpp b/src/rpc/coinjoin.cpp index c72ff05396af..f272ee9eba61 100644 --- a/src/rpc/coinjoin.cpp +++ b/src/rpc/coinjoin.cpp @@ -2,6 +2,10 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include +#include +#include +#include #include #include #include @@ -12,10 +16,6 @@ #include #include -#include -#include -#include - #ifdef ENABLE_WALLET #include #include diff --git a/src/rpc/evo.cpp b/src/rpc/evo.cpp index 1d9fb83bda6e..bc4deeefff14 100644 --- a/src/rpc/evo.cpp +++ b/src/rpc/evo.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include #include diff --git a/src/rpc/external_signer.cpp b/src/rpc/external_signer.cpp index 29d2ee645de0..a5269a02f656 100644 --- a/src/rpc/external_signer.cpp +++ b/src/rpc/external_signer.cpp @@ -8,10 +8,12 @@ #include +#include #include +#include #include #include -#include +#include #include #include diff --git a/src/rpc/mempool.cpp b/src/rpc/mempool.cpp index 536dde24d37b..28ab6d89f8c6 100644 --- a/src/rpc/mempool.cpp +++ b/src/rpc/mempool.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 #include #include diff --git a/src/rpc/request.cpp b/src/rpc/request.cpp index 847486894629..548d09134cd3 100644 --- a/src/rpc/request.cpp +++ b/src/rpc/request.cpp @@ -8,11 +8,12 @@ #include +#include +#include #include #include #include #include -#include #include #include diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index 5dfe27db2756..a8e592963b0e 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -10,6 +10,8 @@ #include +#include +#include #include #include #include diff --git a/src/rpc/server_util.cpp b/src/rpc/server_util.cpp index 1cee5f109dc6..1642f13adf64 100644 --- a/src/rpc/server_util.cpp +++ b/src/rpc/server_util.cpp @@ -2,6 +2,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include #include #include diff --git a/src/rpc/util.cpp b/src/rpc/util.cpp index 8bb5e2ff4967..d76f94cab6c1 100644 --- a/src/rpc/util.cpp +++ b/src/rpc/util.cpp @@ -7,6 +7,7 @@ #include #endif #include +#include #include #include #include