mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-03-13 11:35:20 +01:00
Merge e064f20d8a
into a50af6e4c4
This commit is contained in:
commit
0023319162
15 changed files with 1164 additions and 188 deletions
8
doc/release-notes-17493.md
Normal file
8
doc/release-notes-17493.md
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
Configuration file
|
||||||
|
------------------
|
||||||
|
|
||||||
|
Repeated assignments of the same setting in the same section of the config file
|
||||||
|
which were previously ignored will now trigger errors on startup that look
|
||||||
|
like: "Multiple values specified for -setting in same section of config file."
|
||||||
|
Settings like `-debug=<category>` and `-rpcallowip=<addr>` which are meant to
|
||||||
|
be repeated are not affected by this change and will not trigger errors.
|
|
@ -16,13 +16,13 @@ void SetupChainParamsBaseOptions(ArgsManager& argsman)
|
||||||
argsman.AddArg("-chain=<chain>", "Use the chain <chain> (default: main). Allowed values: " LIST_CHAIN_NAMES, ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS);
|
argsman.AddArg("-chain=<chain>", "Use the chain <chain> (default: main). Allowed values: " LIST_CHAIN_NAMES, ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS);
|
||||||
argsman.AddArg("-regtest", "Enter regression test mode, which uses a special chain in which blocks can be solved instantly. "
|
argsman.AddArg("-regtest", "Enter regression test mode, which uses a special chain in which blocks can be solved instantly. "
|
||||||
"This is intended for regression testing tools and app development. Equivalent to -chain=regtest.", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CHAINPARAMS);
|
"This is intended for regression testing tools and app development. Equivalent to -chain=regtest.", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CHAINPARAMS);
|
||||||
argsman.AddArg("-testactivationheight=name@height.", "Set the activation height of 'name' (segwit, bip34, dersig, cltv, csv). (regtest-only)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
|
argsman.AddArg("-testactivationheight=name@height.", "Set the activation height of 'name' (segwit, bip34, dersig, cltv, csv). (regtest-only)", ArgsManager::ALLOW_ANY | ArgsManager::ALLOW_LIST | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
|
||||||
argsman.AddArg("-testnet", "Use the testnet3 chain. Equivalent to -chain=test. Support for testnet3 is deprecated and will be removed in an upcoming release. Consider moving to testnet4 now by using -testnet4.", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS);
|
argsman.AddArg("-testnet", "Use the testnet3 chain. Equivalent to -chain=test. Support for testnet3 is deprecated and will be removed in an upcoming release. Consider moving to testnet4 now by using -testnet4.", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS);
|
||||||
argsman.AddArg("-testnet4", "Use the testnet4 chain. Equivalent to -chain=testnet4.", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS);
|
argsman.AddArg("-testnet4", "Use the testnet4 chain. Equivalent to -chain=testnet4.", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS);
|
||||||
argsman.AddArg("-vbparams=deployment:start:end[:min_activation_height]", "Use given start/end times and min_activation_height for specified version bits deployment (regtest-only)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CHAINPARAMS);
|
argsman.AddArg("-vbparams=deployment:start:end[:min_activation_height]", "Use given start/end times and min_activation_height for specified version bits deployment (regtest-only)", ArgsManager::ALLOW_ANY | ArgsManager::ALLOW_LIST | ArgsManager::DEBUG_ONLY, OptionsCategory::CHAINPARAMS);
|
||||||
argsman.AddArg("-signet", "Use the signet chain. Equivalent to -chain=signet. Note that the network is defined by the -signetchallenge parameter", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS);
|
argsman.AddArg("-signet", "Use the signet chain. Equivalent to -chain=signet. Note that the network is defined by the -signetchallenge parameter", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS);
|
||||||
argsman.AddArg("-signetchallenge", "Blocks must satisfy the given script to be considered valid (only for signet networks; defaults to the global default signet test network challenge)", ArgsManager::ALLOW_ANY | ArgsManager::DISALLOW_NEGATION, OptionsCategory::CHAINPARAMS);
|
argsman.AddArg("-signetchallenge", "Blocks must satisfy the given script to be considered valid (only for signet networks; defaults to the global default signet test network challenge)", ArgsManager::ALLOW_ANY | ArgsManager::ALLOW_LIST | ArgsManager::DISALLOW_NEGATION, OptionsCategory::CHAINPARAMS);
|
||||||
argsman.AddArg("-signetseednode", "Specify a seed node for the signet network, in the hostname[:port] format, e.g. sig.net:1234 (may be used multiple times to specify multiple seed nodes; defaults to the global default signet test network seed node(s))", ArgsManager::ALLOW_ANY | ArgsManager::DISALLOW_NEGATION, OptionsCategory::CHAINPARAMS);
|
argsman.AddArg("-signetseednode", "Specify a seed node for the signet network, in the hostname[:port] format, e.g. sig.net:1234 (may be used multiple times to specify multiple seed nodes; defaults to the global default signet test network seed node(s))", ArgsManager::ALLOW_ANY | ArgsManager::ALLOW_LIST | ArgsManager::DISALLOW_NEGATION, OptionsCategory::CHAINPARAMS);
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::unique_ptr<CBaseChainParams> globalChainBaseParams;
|
static std::unique_ptr<CBaseChainParams> globalChainBaseParams;
|
||||||
|
|
|
@ -101,11 +101,43 @@ KeyInfo InterpretKey(std::string key)
|
||||||
* @param[in] flags ArgsManager registered argument flags
|
* @param[in] flags ArgsManager registered argument flags
|
||||||
* @param[out] error Error description if settings value is not valid
|
* @param[out] error Error description if settings value is not valid
|
||||||
*
|
*
|
||||||
* @return parsed settings value if it is valid, otherwise nullopt accompanied
|
* @return parsed settings value if it is valid, otherwise `nullopt` accompanied
|
||||||
* by a descriptive error string
|
* by a descriptive error string
|
||||||
|
*
|
||||||
|
* @note By design, the \ref InterpretValue function does mostly lossless
|
||||||
|
* conversions of command line arguments and configuration file values to JSON
|
||||||
|
* `common::SettingsValue` values, so higher level application code and GetArg
|
||||||
|
* helper methods can unambiguously determine original configuration strings
|
||||||
|
* from the JSON values, and flexibly interpret settings and provide good error
|
||||||
|
* feedback. Specifically:
|
||||||
|
* \n
|
||||||
|
* - JSON `null` value is never returned and is reserved for settings that were
|
||||||
|
* not configured at all.
|
||||||
|
*
|
||||||
|
* - JSON `false` value is returned for negated settings like `-nosetting` or
|
||||||
|
* `-nosetting=1`. `false` is also returned for boolean-only settings that
|
||||||
|
* have the ALLOW_BOOL flag and false values like `setting=0`.
|
||||||
|
*
|
||||||
|
* - JSON `true` value is returned for settings that have the ALLOW_BOOL flag
|
||||||
|
* and are specified on the command line without a value like `-setting`.
|
||||||
|
* `true` is also returned for boolean-only settings that have the ALLOW_BOOL
|
||||||
|
* flag and true values like `setting=1`. `true` is also returned for untyped
|
||||||
|
* legacy settings (see \ref IsTypedArg) that use double negation like
|
||||||
|
* `-nosetting=0`.
|
||||||
|
*
|
||||||
|
* - JSON `""` empty string value is returned for settings like `-setting=`
|
||||||
|
* that specify empty values. `""` is also returned for untyped legacy
|
||||||
|
* settings (see \ref IsTypedArg) that are specified on the command line
|
||||||
|
* without a value like `-setting`.
|
||||||
|
*
|
||||||
|
* - JSON strings like `"abc"` are returned for settings like `-setting=abc` if
|
||||||
|
* the setting has the ALLOW_STRING flag or is an untyped legacy setting.
|
||||||
|
*
|
||||||
|
* - JSON numbers like `123` are returned for settings like `-setting=123` if
|
||||||
|
* the setting enables integer parsing with the ALLOW_INT flag.
|
||||||
*/
|
*/
|
||||||
std::optional<common::SettingsValue> InterpretValue(const KeyInfo& key, const std::string* value,
|
std::optional<common::SettingsValue> InterpretValue(const KeyInfo& key, const std::string* value,
|
||||||
unsigned int flags, std::string& error)
|
unsigned int flags, std::string& error)
|
||||||
{
|
{
|
||||||
// Return negated settings as false values.
|
// Return negated settings as false values.
|
||||||
if (key.negated) {
|
if (key.negated) {
|
||||||
|
@ -113,6 +145,16 @@ std::optional<common::SettingsValue> InterpretValue(const KeyInfo& key, const st
|
||||||
error = strprintf("Negating of -%s is meaningless and therefore forbidden", key.name);
|
error = strprintf("Negating of -%s is meaningless and therefore forbidden", key.name);
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
if (IsTypedArg(flags)) {
|
||||||
|
// If argument is typed, only allow negation with no value or with
|
||||||
|
// literal "1" value. Avoid calling InterpretBool and accepting
|
||||||
|
// other values which could be ambiguous.
|
||||||
|
if (value && *value != "1") {
|
||||||
|
error = strprintf("Cannot negate -%s at the same time as setting a value ('%s').", key.name, *value);
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
// Double negatives like -nofoo=0 are supported (but discouraged)
|
// Double negatives like -nofoo=0 are supported (but discouraged)
|
||||||
if (value && !InterpretBool(*value)) {
|
if (value && !InterpretBool(*value)) {
|
||||||
LogPrintf("Warning: parsed potentially confusing double-negative -%s=%s\n", key.name, *value);
|
LogPrintf("Warning: parsed potentially confusing double-negative -%s=%s\n", key.name, *value);
|
||||||
|
@ -120,11 +162,63 @@ std::optional<common::SettingsValue> InterpretValue(const KeyInfo& key, const st
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!value && (flags & ArgsManager::DISALLOW_ELISION)) {
|
if (value) {
|
||||||
error = strprintf("Can not set -%s with no value. Please specify value with -%s=value.", key.name, key.name);
|
if ((flags & ArgsManager::ALLOW_STRING) || !IsTypedArg(flags) || value->empty()) return *value;
|
||||||
return std::nullopt;
|
if (flags & ArgsManager::ALLOW_INT) {
|
||||||
|
if (auto parsed_int = ToIntegral<int64_t>(*value)) return *parsed_int;
|
||||||
|
}
|
||||||
|
if (flags & ArgsManager::ALLOW_BOOL) {
|
||||||
|
if (*value == "0") return false;
|
||||||
|
if (*value == "1") return true;
|
||||||
|
}
|
||||||
|
error = strprintf("Cannot set -%s value to '%s'.", key.name, *value);
|
||||||
|
} else {
|
||||||
|
if (flags & ArgsManager::ALLOW_BOOL) return true;
|
||||||
|
if (!(flags & ArgsManager::DISALLOW_ELISION) && !IsTypedArg(flags)) return "";
|
||||||
|
error = strprintf("Cannot set -%s with no value. Please specify value with -%s=value.", key.name, key.name);
|
||||||
}
|
}
|
||||||
return value ? *value : "";
|
if (flags & ArgsManager::ALLOW_STRING) {
|
||||||
|
error = strprintf("%s %s", error, "It must be set to a string.");
|
||||||
|
} else if (flags & ArgsManager::ALLOW_INT) {
|
||||||
|
error = strprintf("%s %s", error, "It must be set to an integer.");
|
||||||
|
} else if (flags & ArgsManager::ALLOW_BOOL) {
|
||||||
|
error = strprintf("%s %s", error, "It must be set to 0 or 1.");
|
||||||
|
}
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Return string if setting is a nonempty string or number (-setting=abc,
|
||||||
|
//! -setting=123), "" if setting is false (-nosetting), otherwise return
|
||||||
|
//! nullopt. For legacy untyped args, coerce bool settings to strings as well.
|
||||||
|
static inline std::optional<std::string> ConvertToString(const common::SettingsValue& value, bool typed_arg)
|
||||||
|
{
|
||||||
|
if (value.isStr() && !value.get_str().empty()) return value.get_str();
|
||||||
|
if (value.isNum()) return value.getValStr();
|
||||||
|
if (typed_arg && value.isFalse()) return "";
|
||||||
|
if (!typed_arg && !value.isNull()) {
|
||||||
|
if (value.isBool()) return value.get_bool() ? "1" : "0";
|
||||||
|
return value.get_str();
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Return int64 if setting is a number or bool, otherwise return nullopt. For
|
||||||
|
//! legacy untyped args, coerce string settings as well.
|
||||||
|
static inline std::optional<int64_t> ConvertToInt(const common::SettingsValue& value, bool typed_arg)
|
||||||
|
{
|
||||||
|
if (value.isNum()) return value.getInt<int64_t>();
|
||||||
|
if (value.isBool()) return value.get_bool();
|
||||||
|
if (!typed_arg && !value.isNull()) return LocaleIndependentAtoi<int64_t>(value.get_str());
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Return bool if setting is a bool, otherwise return nullopt. For legacy
|
||||||
|
//! untyped args, coerce string settings as well.
|
||||||
|
static inline std::optional<bool> ConvertToBool(const common::SettingsValue& value, bool typed_arg)
|
||||||
|
{
|
||||||
|
if (value.isBool()) return value.get_bool();
|
||||||
|
if (!typed_arg && !value.isNull()) return InterpretBool(value.get_str());
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Define default constructor and destructor that are not inline, so code instantiating this class doesn't need to
|
// Define default constructor and destructor that are not inline, so code instantiating this class doesn't need to
|
||||||
|
@ -269,6 +363,30 @@ std::optional<unsigned int> ArgsManager::GetArgFlags(const std::string& name) co
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check that arg has the right flags for use in a given context. Raises
|
||||||
|
* logic_error if this isn't the case, indicating the argument was registered
|
||||||
|
* with bad AddArg flags.
|
||||||
|
*
|
||||||
|
* Returns true if the arg is registered and has type checking enabled. Returns
|
||||||
|
* false if the arg was never registered or is untyped.
|
||||||
|
*/
|
||||||
|
bool ArgsManager::CheckArgFlags(const std::string& name,
|
||||||
|
uint32_t require,
|
||||||
|
uint32_t forbid,
|
||||||
|
const char* context) const
|
||||||
|
{
|
||||||
|
std::optional<unsigned int> flags = GetArgFlags(name);
|
||||||
|
if (!flags) return false;
|
||||||
|
if (!IsTypedArg(*flags)) require &= ~(ALLOW_BOOL | ALLOW_INT | ALLOW_STRING);
|
||||||
|
if ((*flags & require) != require || (*flags & forbid) != 0) {
|
||||||
|
throw std::logic_error(
|
||||||
|
strprintf("Bug: Can't call %s on arg %s registered with flags 0x%08x (requires 0x%x, disallows 0x%x)",
|
||||||
|
context, name, *flags, require, forbid));
|
||||||
|
}
|
||||||
|
return IsTypedArg(*flags);
|
||||||
|
}
|
||||||
|
|
||||||
fs::path ArgsManager::GetPathArg(std::string arg, const fs::path& default_value) const
|
fs::path ArgsManager::GetPathArg(std::string arg, const fs::path& default_value) const
|
||||||
{
|
{
|
||||||
if (IsArgNegated(arg)) return fs::path{};
|
if (IsArgNegated(arg)) return fs::path{};
|
||||||
|
@ -361,9 +479,10 @@ std::optional<const ArgsManager::Command> ArgsManager::GetCommand() const
|
||||||
|
|
||||||
std::vector<std::string> ArgsManager::GetArgs(const std::string& strArg) const
|
std::vector<std::string> ArgsManager::GetArgs(const std::string& strArg) const
|
||||||
{
|
{
|
||||||
|
bool typed_arg = CheckArgFlags(strArg, /*require=*/ ALLOW_STRING | ALLOW_LIST, /*forbid=*/ 0, __func__);
|
||||||
std::vector<std::string> result;
|
std::vector<std::string> result;
|
||||||
for (const common::SettingsValue& value : GetSettingsList(strArg)) {
|
for (const common::SettingsValue& value : GetSettingsList(strArg)) {
|
||||||
result.push_back(value.isFalse() ? "0" : value.isTrue() ? "1" : value.get_str());
|
result.push_back(ConvertToString(value, typed_arg).value_or(""));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -461,22 +580,13 @@ std::string ArgsManager::GetArg(const std::string& strArg, const std::string& st
|
||||||
|
|
||||||
std::optional<std::string> ArgsManager::GetArg(const std::string& strArg) const
|
std::optional<std::string> ArgsManager::GetArg(const std::string& strArg) const
|
||||||
{
|
{
|
||||||
const common::SettingsValue value = GetSetting(strArg);
|
bool typed_arg = CheckArgFlags(strArg, /*require=*/ ALLOW_STRING, /*forbid=*/ ALLOW_LIST, __func__);
|
||||||
return SettingToString(value);
|
return ConvertToString(GetSetting(strArg), typed_arg);
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<std::string> SettingToString(const common::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 common::SettingsValue& value, const std::string& strDefault)
|
std::string SettingToString(const common::SettingsValue& value, const std::string& strDefault)
|
||||||
{
|
{
|
||||||
return SettingToString(value).value_or(strDefault);
|
return ConvertToString(value, /*typed_arg=*/false).value_or(strDefault);
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t ArgsManager::GetIntArg(const std::string& strArg, int64_t nDefault) const
|
int64_t ArgsManager::GetIntArg(const std::string& strArg, int64_t nDefault) const
|
||||||
|
@ -486,22 +596,13 @@ int64_t ArgsManager::GetIntArg(const std::string& strArg, int64_t nDefault) cons
|
||||||
|
|
||||||
std::optional<int64_t> ArgsManager::GetIntArg(const std::string& strArg) const
|
std::optional<int64_t> ArgsManager::GetIntArg(const std::string& strArg) const
|
||||||
{
|
{
|
||||||
const common::SettingsValue value = GetSetting(strArg);
|
bool typed_arg = CheckArgFlags(strArg, /*require=*/ ALLOW_INT, /*forbid=*/ ALLOW_LIST, __func__);
|
||||||
return SettingToInt(value);
|
return ConvertToInt(GetSetting(strArg), typed_arg);
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<int64_t> SettingToInt(const common::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 common::SettingsValue& value, int64_t nDefault)
|
int64_t SettingToInt(const common::SettingsValue& value, int64_t nDefault)
|
||||||
{
|
{
|
||||||
return SettingToInt(value).value_or(nDefault);
|
return ConvertToInt(value, /*typed_arg=*/false).value_or(nDefault);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ArgsManager::GetBoolArg(const std::string& strArg, bool fDefault) const
|
bool ArgsManager::GetBoolArg(const std::string& strArg, bool fDefault) const
|
||||||
|
@ -511,20 +612,13 @@ bool ArgsManager::GetBoolArg(const std::string& strArg, bool fDefault) const
|
||||||
|
|
||||||
std::optional<bool> ArgsManager::GetBoolArg(const std::string& strArg) const
|
std::optional<bool> ArgsManager::GetBoolArg(const std::string& strArg) const
|
||||||
{
|
{
|
||||||
const common::SettingsValue value = GetSetting(strArg);
|
bool typed_arg = CheckArgFlags(strArg, /*require=*/ ALLOW_BOOL, /*forbid=*/ ALLOW_LIST, __func__);
|
||||||
return SettingToBool(value);
|
return ConvertToBool(GetSetting(strArg), typed_arg);
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<bool> SettingToBool(const common::SettingsValue& value)
|
|
||||||
{
|
|
||||||
if (value.isNull()) return std::nullopt;
|
|
||||||
if (value.isBool()) return value.get_bool();
|
|
||||||
return InterpretBool(value.get_str());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SettingToBool(const common::SettingsValue& value, bool fDefault)
|
bool SettingToBool(const common::SettingsValue& value, bool fDefault)
|
||||||
{
|
{
|
||||||
return SettingToBool(value).value_or(fDefault);
|
return ConvertToBool(value, /*typed_arg=*/false).value_or(fDefault);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ArgsManager::SoftSetArg(const std::string& strArg, const std::string& strValue)
|
bool ArgsManager::SoftSetArg(const std::string& strArg, const std::string& strValue)
|
||||||
|
@ -537,15 +631,17 @@ bool ArgsManager::SoftSetArg(const std::string& strArg, const std::string& strVa
|
||||||
|
|
||||||
bool ArgsManager::SoftSetBoolArg(const std::string& strArg, bool fValue)
|
bool ArgsManager::SoftSetBoolArg(const std::string& strArg, bool fValue)
|
||||||
{
|
{
|
||||||
if (fValue)
|
LOCK(cs_args);
|
||||||
return SoftSetArg(strArg, std::string("1"));
|
CheckArgFlags(strArg, /*require=*/ ALLOW_BOOL, /*forbid=*/ ALLOW_LIST, __func__);
|
||||||
else
|
if (IsArgSet(strArg)) return false;
|
||||||
return SoftSetArg(strArg, std::string("0"));
|
m_settings.forced_settings[SettingName(strArg)] = fValue;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ArgsManager::ForceSetArg(const std::string& strArg, const std::string& strValue)
|
void ArgsManager::ForceSetArg(const std::string& strArg, const std::string& strValue)
|
||||||
{
|
{
|
||||||
LOCK(cs_args);
|
LOCK(cs_args);
|
||||||
|
CheckArgFlags(strArg, /*require=*/ ALLOW_STRING, /*forbid=*/ 0, __func__);
|
||||||
m_settings.forced_settings[SettingName(strArg)] = strValue;
|
m_settings.forced_settings[SettingName(strArg)] = strValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -580,6 +676,20 @@ void ArgsManager::AddArg(const std::string& name, const std::string& help, unsig
|
||||||
if (flags & ArgsManager::NETWORK_ONLY) {
|
if (flags & ArgsManager::NETWORK_ONLY) {
|
||||||
m_network_only_args.emplace(arg_name);
|
m_network_only_args.emplace(arg_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Disallow flag combinations that would result in nonsensical behavior or a bad UX.
|
||||||
|
if ((flags & ALLOW_ANY) && (flags & (ALLOW_BOOL | ALLOW_INT | ALLOW_STRING))) {
|
||||||
|
throw std::logic_error(strprintf("Bug: bad %s flags. ALLOW_{BOOL|INT|STRING} flags are incompatible with "
|
||||||
|
"ALLOW_ANY (typed arguments need to be type checked)", arg_name));
|
||||||
|
}
|
||||||
|
if ((flags & ALLOW_BOOL) && (flags & DISALLOW_ELISION)) {
|
||||||
|
throw std::logic_error(strprintf("Bug: bad %s flags. ALLOW_BOOL flag is incompatible with DISALLOW_ELISION "
|
||||||
|
"(boolean arguments should not require argument values)", arg_name));
|
||||||
|
}
|
||||||
|
if ((flags & ALLOW_INT) && (flags & ALLOW_STRING)) {
|
||||||
|
throw std::logic_error(strprintf("Bug: bad %s flags. ALLOW_INT flag is incompatible with ALLOW_STRING "
|
||||||
|
"(any valid integer is also a valid string)", arg_name));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ArgsManager::AddHiddenArgs(const std::vector<std::string>& names)
|
void ArgsManager::AddHiddenArgs(const std::vector<std::string>& names)
|
||||||
|
@ -793,7 +903,7 @@ std::variant<ChainType, std::string> ArgsManager::GetChainArg() const
|
||||||
/* ignore_default_section_config= */ false,
|
/* ignore_default_section_config= */ false,
|
||||||
/*ignore_nonpersistent=*/false,
|
/*ignore_nonpersistent=*/false,
|
||||||
/* get_chain_type= */ true);
|
/* get_chain_type= */ true);
|
||||||
return value.isNull() ? false : value.isBool() ? value.get_bool() : InterpretBool(value.get_str());
|
return ConvertToBool(value, /*typed_arg=*/false).value_or(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const bool fRegTest = get_net("-regtest");
|
const bool fRegTest = get_net("-regtest");
|
||||||
|
|
|
@ -87,27 +87,99 @@ struct SectionInfo {
|
||||||
};
|
};
|
||||||
|
|
||||||
std::string SettingToString(const common::SettingsValue&, const std::string&);
|
std::string SettingToString(const common::SettingsValue&, const std::string&);
|
||||||
std::optional<std::string> SettingToString(const common::SettingsValue&);
|
|
||||||
|
|
||||||
int64_t SettingToInt(const common::SettingsValue&, int64_t);
|
int64_t SettingToInt(const common::SettingsValue&, int64_t);
|
||||||
std::optional<int64_t> SettingToInt(const common::SettingsValue&);
|
|
||||||
|
|
||||||
bool SettingToBool(const common::SettingsValue&, bool);
|
bool SettingToBool(const common::SettingsValue&, bool);
|
||||||
std::optional<bool> SettingToBool(const common::SettingsValue&);
|
|
||||||
|
|
||||||
class ArgsManager
|
class ArgsManager
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* Flags controlling how config and command line arguments are validated and
|
* Flags controlling how config and command line arguments are parsed.
|
||||||
* interpreted.
|
*
|
||||||
|
* The flags below provide very basic type checking, designed to catch
|
||||||
|
* obvious configuration mistakes and provide helpful error messages.
|
||||||
|
* Specifying these flags is not a substitute for actually validating
|
||||||
|
* setting values that are parsed and making sure they are legitimate.
|
||||||
|
*
|
||||||
|
* Summary of recommended flags:
|
||||||
|
*
|
||||||
|
* - For most settings, just use standalone ALLOW_BOOL, ALLOW_INT, or
|
||||||
|
* ALLOW_STRING flags.
|
||||||
|
*
|
||||||
|
* - If your setting accepts multiple values and you want to read all the
|
||||||
|
* values, not just the last value, add | ALLOW_LIST to the flags.
|
||||||
|
*
|
||||||
|
* - If your setting causes a new action to be performed, and does not
|
||||||
|
* require a value, add | ALLOW_BOOL to the flags. Adding it just allows
|
||||||
|
* the setting to be specified alone on the command line without a value,
|
||||||
|
* as "-foo" instead of "-foo=value".
|
||||||
|
*
|
||||||
|
* - Only use the DISALLOW_NEGATION flag if your setting really cannot
|
||||||
|
* function without a value, so the command line interface will generally
|
||||||
|
* support negation and be more consistent.
|
||||||
|
*
|
||||||
|
* Detailed description of flags:
|
||||||
|
*
|
||||||
|
* The ALLOW_STRING, ALLOW_INT, and ALLOW_BOOL flags control what syntaxes are
|
||||||
|
* accepted, according to the following chart:
|
||||||
|
*
|
||||||
|
* | Syntax | STRING | INT | BOOL | STRING\|BOOL | INT\|BOOL |
|
||||||
|
* | -------- | :----: | :-: | :--: | :----------: | :-------: |
|
||||||
|
* | -foo=abc | X | | | X | |
|
||||||
|
* | -foo=123 | X | X | | X | X |
|
||||||
|
* | -foo=0 | X | X | X | X | X |
|
||||||
|
* | -foo=1 | X | X | X | X | X |
|
||||||
|
* | -foo | | | X | X | X |
|
||||||
|
* | -foo= | X | X | X | X | X |
|
||||||
|
* | -nofoo | X | X | X | X | X |
|
||||||
|
* | -nofoo=1 | X | X | X | X | X |
|
||||||
|
*
|
||||||
|
* Once validated, settings can be retrieved by called GetSetting(),
|
||||||
|
* GetArg(), GetIntArg(), and GetBoolArg(). GetSetting() is the most general
|
||||||
|
* way to access settings, returning them as JSON values. The other
|
||||||
|
* functions just wrap GetSetting() for convenience.
|
||||||
|
*
|
||||||
|
* As can be seen in the chart, the default behavior of the flags is not
|
||||||
|
* very restrictive, although it can be restricted further. It tries to
|
||||||
|
* accommodate parsing command lines and configuration files written by
|
||||||
|
* human beings, not just machines, understanding that users may have
|
||||||
|
* different configuration styles and debugging needs. So the flags do not
|
||||||
|
* mandate one way to configure things or try to prevent every possible
|
||||||
|
* error, but instead catch the most common and blatant errors, and allow
|
||||||
|
* application code to impose additional restrictions, since application
|
||||||
|
* code needs to parse settings and reject invalid values anyway.
|
||||||
|
*
|
||||||
|
* Specifically, by default:
|
||||||
|
*
|
||||||
|
* - All settings can be specified multiple times, not just ALLOW_LIST
|
||||||
|
* settings. This allows users to override the config file from the
|
||||||
|
* command line, and override earlier command line settings with later
|
||||||
|
* ones. Application code can disable this behavior by calling the
|
||||||
|
* GetArgs() function and raising an error if more than one value is
|
||||||
|
* returned.
|
||||||
|
*
|
||||||
|
* - All settings can be negated. This provides a consistent command line
|
||||||
|
* interface where settings support -nofoo syntax when meaningful.
|
||||||
|
* GetSetting() returns a false JSON value for negated settings, and
|
||||||
|
* GetArg(), GetIntArg(), and GetBoolArg() return "", 0, and false
|
||||||
|
* respectively. Application code can disallow negation by specifying the
|
||||||
|
* DISALLOW_NEGATION flag, or just handling "", 0, and false values and
|
||||||
|
* rejecting them if they do not make sense.
|
||||||
|
*
|
||||||
|
* - All settings can be empty. Since all settings are optional, it is
|
||||||
|
* useful to have a way to set them, and a way to unset them. It is also
|
||||||
|
* unambiguous in most cases to treat empty -foo= syntax as not setting a
|
||||||
|
* value, so by default this syntax is allowed and causes GetSetting() to
|
||||||
|
* return JSON "", and GetArg(), GetIntArg() and GetBoolArg() to return
|
||||||
|
* std::nullopt. Application code can override this behavior by rejecting
|
||||||
|
* these values.
|
||||||
*/
|
*/
|
||||||
enum Flags : uint32_t {
|
enum Flags : uint32_t {
|
||||||
ALLOW_ANY = 0x01, //!< disable validation
|
ALLOW_ANY = 0x01, //!< allow any argument value (no type checking)
|
||||||
// ALLOW_BOOL = 0x02, //!< unimplemented, draft implementation in #16545
|
ALLOW_BOOL = 0x02, //!< allow -foo=1, -foo=0, -foo, -nofoo, -nofoo=1, and -foo=
|
||||||
// ALLOW_INT = 0x04, //!< unimplemented, draft implementation in #16545
|
ALLOW_INT = 0x04, //!< allow -foo=123, -nofoo, -nofoo=1, and -foo=
|
||||||
// ALLOW_STRING = 0x08, //!< unimplemented, draft implementation in #16545
|
ALLOW_STRING = 0x08, //!< allow -foo=abc, -nofoo, -nofoo=1, and -foo=
|
||||||
// ALLOW_LIST = 0x10, //!< unimplemented, draft implementation in #16545
|
ALLOW_LIST = 0x10, //!< allow multiple -foo=bar -foo=baz values
|
||||||
DISALLOW_NEGATION = 0x20, //!< disallow -nofoo syntax
|
DISALLOW_NEGATION = 0x20, //!< disallow -nofoo syntax
|
||||||
DISALLOW_ELISION = 0x40, //!< disallow -foo syntax that doesn't assign any value
|
DISALLOW_ELISION = 0x40, //!< disallow -foo syntax that doesn't assign any value
|
||||||
|
|
||||||
|
@ -154,12 +226,73 @@ protected:
|
||||||
bool UseDefaultSection(const std::string& arg) const EXCLUSIVE_LOCKS_REQUIRED(cs_args);
|
bool UseDefaultSection(const std::string& arg) const EXCLUSIVE_LOCKS_REQUIRED(cs_args);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
ArgsManager();
|
||||||
|
~ArgsManager();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name GetArg Functions
|
||||||
|
*
|
||||||
|
* GetArg functions are an easy way to access most settings. They are
|
||||||
|
* wrappers around the lower-level GetSetting() function that provide
|
||||||
|
* greater convenience.
|
||||||
|
*
|
||||||
|
* Examples:
|
||||||
|
*
|
||||||
|
* GetArg("-foo") // returns "abc" if -foo=abc was specified, or nullopt if unset
|
||||||
|
* GetIntArg("-foo") // returns 123 if -foo=123 was specified, or nullopt if unset
|
||||||
|
* GetBoolArg("-foo") // returns true if -foo was specified, or nullopt if unset
|
||||||
|
* GetBoolArg("-foo") // returns false if -nofoo was specified, or nullopt if unset
|
||||||
|
*
|
||||||
|
* If no type flags (ALLOW_STRING, ALLOW_INT, or ALLOW_BOOL) are set, GetArg
|
||||||
|
* functions do many type coercions and can have surprising behaviors which
|
||||||
|
* legacy code relies on, like parsing -nofoo as string "0" or -foo=true as
|
||||||
|
* boolean false.
|
||||||
|
*
|
||||||
|
* If any type flags are set, then:
|
||||||
|
*
|
||||||
|
* - Only GetArg functions with types matching the flags can be called. For
|
||||||
|
* example, it is an error to call GetIntArg() if ALLOW_INT is not set.
|
||||||
|
*
|
||||||
|
* - GetArg functions act like std::get_if<T>(), returning null if the
|
||||||
|
* requested type is not available or the setting is unspecified or empty.
|
||||||
|
*
|
||||||
|
* - "Widening" type conversions from smaller to bigger types are done if
|
||||||
|
* unambiguous (bool -> int -> string). For example, if settings.json
|
||||||
|
* contains {"foo":123}, GetArg("-foo") will return "123". If it contains
|
||||||
|
* {"foo":true}, GetIntArg("-foo") will return 1.
|
||||||
|
*
|
||||||
|
* - "Narrowing" type conversions in the other direction are not done even
|
||||||
|
* when they would be unambiguous. This makes it possible to distinguish
|
||||||
|
* values by type by checking for narrow types first. For example, to
|
||||||
|
* handle boolean settings.json or command line values (-foo -nofoo)
|
||||||
|
* differently than string values (-foo=abc), you can write:
|
||||||
|
*
|
||||||
|
* if (auto foo{args.GetBoolArg("-foo")}) {
|
||||||
|
* // handle -foo or -nofoo bool in foo.value()
|
||||||
|
* } else if (auto foo{args.GetArg("-foo")}) {
|
||||||
|
* // handle -foo=abc string in foo.value()
|
||||||
|
* } else {
|
||||||
|
* // handle unset setting
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* More examples of GetArg function usage can be found in the
|
||||||
|
* @ref example_options::ReadOptions() function in
|
||||||
|
* @ref argsman_tests.cpp
|
||||||
|
*@{*/
|
||||||
|
std::optional<std::string> GetArg(const std::string& strArg) const;
|
||||||
|
std::optional<int64_t> GetIntArg(const std::string& strArg) const;
|
||||||
|
std::optional<bool> GetBoolArg(const std::string& strArg) const;
|
||||||
|
/**@}*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get setting value.
|
* Get setting value.
|
||||||
*
|
*
|
||||||
* Result will be null if setting was unset, true if "-setting" argument was passed
|
* Result will be null if setting was unspecified, true if `-setting`
|
||||||
* false if "-nosetting" argument was passed, and a string if a "-setting=value"
|
* argument was passed, false if `-nosetting` argument was passed, and will
|
||||||
* argument was passed.
|
* be a string, integer, or boolean if a `-setting=value` argument was
|
||||||
|
* passed (which of the three depends on ALLOW_STRING, ALLOW_INT, and
|
||||||
|
* ALLOW_BOOL flags). See \ref InterpretValue for a full description of how
|
||||||
|
* command line and configuration strings map to JSON values.
|
||||||
*/
|
*/
|
||||||
common::SettingsValue GetSetting(const std::string& arg) const;
|
common::SettingsValue GetSetting(const std::string& arg) const;
|
||||||
|
|
||||||
|
@ -168,9 +301,6 @@ protected:
|
||||||
*/
|
*/
|
||||||
std::vector<common::SettingsValue> GetSettingsList(const std::string& arg) const;
|
std::vector<common::SettingsValue> GetSettingsList(const std::string& arg) const;
|
||||||
|
|
||||||
ArgsManager();
|
|
||||||
~ArgsManager();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Select the network in use
|
* Select the network in use
|
||||||
*/
|
*/
|
||||||
|
@ -271,7 +401,6 @@ protected:
|
||||||
* @return command-line argument or default value
|
* @return command-line argument or default value
|
||||||
*/
|
*/
|
||||||
std::string GetArg(const std::string& strArg, const std::string& strDefault) const;
|
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
|
* Return path argument or default value
|
||||||
|
@ -293,7 +422,6 @@ protected:
|
||||||
* @return command-line argument (0 if invalid number) or default value
|
* @return command-line argument (0 if invalid number) or default value
|
||||||
*/
|
*/
|
||||||
int64_t GetIntArg(const std::string& strArg, int64_t nDefault) const;
|
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
|
* Return boolean argument or default value
|
||||||
|
@ -303,7 +431,6 @@ protected:
|
||||||
* @return command-line argument or default value
|
* @return command-line argument or default value
|
||||||
*/
|
*/
|
||||||
bool GetBoolArg(const std::string& strArg, bool fDefault) const;
|
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
|
* Set an argument if it doesn't already have a value
|
||||||
|
@ -423,6 +550,8 @@ protected:
|
||||||
void LogArgs() const;
|
void LogArgs() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool CheckArgFlags(const std::string& name, uint32_t require, uint32_t forbid, const char* context) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get data directory path
|
* Get data directory path
|
||||||
*
|
*
|
||||||
|
@ -446,6 +575,13 @@ private:
|
||||||
const std::map<std::string, std::vector<common::SettingsValue>>& args) const;
|
const std::map<std::string, std::vector<common::SettingsValue>>& args) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//! Whether the type of the argument has been specified and extra validation
|
||||||
|
//! rules should apply.
|
||||||
|
inline bool IsTypedArg(uint32_t flags)
|
||||||
|
{
|
||||||
|
return flags & (ArgsManager::ALLOW_BOOL | ArgsManager::ALLOW_INT | ArgsManager::ALLOW_STRING);
|
||||||
|
}
|
||||||
|
|
||||||
extern ArgsManager gArgs;
|
extern ArgsManager gArgs;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -102,6 +102,10 @@ bool ArgsManager::ReadConfigStream(std::istream& stream, const std::string& file
|
||||||
std::optional<unsigned int> flags = GetArgFlags('-' + key.name);
|
std::optional<unsigned int> flags = GetArgFlags('-' + key.name);
|
||||||
if (!IsConfSupported(key, error)) return false;
|
if (!IsConfSupported(key, error)) return false;
|
||||||
if (flags) {
|
if (flags) {
|
||||||
|
if (!(*flags & ALLOW_LIST) && m_settings.ro_config[key.section].count(key.name)) {
|
||||||
|
error = strprintf("Multiple values specified for -%s in same section of config file.", key.name);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
std::optional<common::SettingsValue> value = InterpretValue(key, &option.second, *flags, error);
|
std::optional<common::SettingsValue> value = InterpretValue(key, &option.second, *flags, error);
|
||||||
if (!value) {
|
if (!value) {
|
||||||
return false;
|
return false;
|
||||||
|
|
72
src/init.cpp
72
src/init.cpp
|
@ -489,9 +489,9 @@ void SetupServerArgs(ArgsManager& argsman, bool can_listen_ipc)
|
||||||
argsman.AddArg("-datadir=<dir>", "Specify data directory", ArgsManager::ALLOW_ANY | ArgsManager::DISALLOW_NEGATION, OptionsCategory::OPTIONS);
|
argsman.AddArg("-datadir=<dir>", "Specify data directory", ArgsManager::ALLOW_ANY | ArgsManager::DISALLOW_NEGATION, OptionsCategory::OPTIONS);
|
||||||
argsman.AddArg("-dbbatchsize", strprintf("Maximum database write batch size in bytes (default: %u)", nDefaultDbBatchSize), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::OPTIONS);
|
argsman.AddArg("-dbbatchsize", strprintf("Maximum database write batch size in bytes (default: %u)", nDefaultDbBatchSize), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::OPTIONS);
|
||||||
argsman.AddArg("-dbcache=<n>", strprintf("Maximum database cache size <n> MiB (minimum %d, default: %d). Make sure you have enough RAM. In addition, unused memory allocated to the mempool is shared with this cache (see -maxmempool).", MIN_DB_CACHE >> 20, DEFAULT_DB_CACHE >> 20), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
|
argsman.AddArg("-dbcache=<n>", strprintf("Maximum database cache size <n> MiB (minimum %d, default: %d). Make sure you have enough RAM. In addition, unused memory allocated to the mempool is shared with this cache (see -maxmempool).", MIN_DB_CACHE >> 20, DEFAULT_DB_CACHE >> 20), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
|
||||||
argsman.AddArg("-includeconf=<file>", "Specify additional configuration file, relative to the -datadir path (only useable from configuration file, not command line)", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
|
argsman.AddArg("-includeconf=<file>", "Specify additional configuration file, relative to the -datadir path (only useable from configuration file, not command line)", ArgsManager::ALLOW_ANY | ArgsManager::ALLOW_LIST, OptionsCategory::OPTIONS);
|
||||||
argsman.AddArg("-allowignoredconf", strprintf("For backwards compatibility, treat an unused %s file in the datadir as a warning, not an error.", BITCOIN_CONF_FILENAME), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
|
argsman.AddArg("-allowignoredconf", strprintf("For backwards compatibility, treat an unused %s file in the datadir as a warning, not an error.", BITCOIN_CONF_FILENAME), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
|
||||||
argsman.AddArg("-loadblock=<file>", "Imports blocks from external file on startup", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
|
argsman.AddArg("-loadblock=<file>", "Imports blocks from external file on startup", ArgsManager::ALLOW_ANY | ArgsManager::ALLOW_LIST, OptionsCategory::OPTIONS);
|
||||||
argsman.AddArg("-maxmempool=<n>", strprintf("Keep the transaction memory pool below <n> megabytes (default: %u)", DEFAULT_MAX_MEMPOOL_SIZE_MB), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
|
argsman.AddArg("-maxmempool=<n>", strprintf("Keep the transaction memory pool below <n> megabytes (default: %u)", DEFAULT_MAX_MEMPOOL_SIZE_MB), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
|
||||||
argsman.AddArg("-maxorphantx=<n>", strprintf("Keep at most <n> unconnectable transactions in memory (default: %u)", DEFAULT_MAX_ORPHAN_TRANSACTIONS), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
|
argsman.AddArg("-maxorphantx=<n>", strprintf("Keep at most <n> unconnectable transactions in memory (default: %u)", DEFAULT_MAX_ORPHAN_TRANSACTIONS), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
|
||||||
argsman.AddArg("-mempoolexpiry=<n>", strprintf("Do not keep transactions in the mempool longer than <n> hours (default: %u)", DEFAULT_MEMPOOL_EXPIRY_HOURS), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
|
argsman.AddArg("-mempoolexpiry=<n>", strprintf("Do not keep transactions in the mempool longer than <n> hours (default: %u)", DEFAULT_MEMPOOL_EXPIRY_HOURS), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
|
||||||
|
@ -513,24 +513,24 @@ void SetupServerArgs(ArgsManager& argsman, bool can_listen_ipc)
|
||||||
argsman.AddArg("-settings=<file>", strprintf("Specify path to dynamic settings data file. Can be disabled with -nosettings. File is written at runtime and not meant to be edited by users (use %s instead for custom settings). Relative paths will be prefixed by datadir location. (default: %s)", BITCOIN_CONF_FILENAME, BITCOIN_SETTINGS_FILENAME), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
|
argsman.AddArg("-settings=<file>", strprintf("Specify path to dynamic settings data file. Can be disabled with -nosettings. File is written at runtime and not meant to be edited by users (use %s instead for custom settings). Relative paths will be prefixed by datadir location. (default: %s)", BITCOIN_CONF_FILENAME, BITCOIN_SETTINGS_FILENAME), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
|
||||||
#if HAVE_SYSTEM
|
#if HAVE_SYSTEM
|
||||||
argsman.AddArg("-startupnotify=<cmd>", "Execute command on startup.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
|
argsman.AddArg("-startupnotify=<cmd>", "Execute command on startup.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
|
||||||
argsman.AddArg("-shutdownnotify=<cmd>", "Execute command immediately before beginning shutdown. The need for shutdown may be urgent, so be careful not to delay it long (if the command doesn't require interaction with the server, consider having it fork into the background).", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
|
argsman.AddArg("-shutdownnotify=<cmd>", "Execute command immediately before beginning shutdown. The need for shutdown may be urgent, so be careful not to delay it long (if the command doesn't require interaction with the server, consider having it fork into the background).", ArgsManager::ALLOW_ANY | ArgsManager::ALLOW_LIST, OptionsCategory::OPTIONS);
|
||||||
#endif
|
#endif
|
||||||
argsman.AddArg("-txindex", strprintf("Maintain a full transaction index, used by the getrawtransaction rpc call (default: %u)", DEFAULT_TXINDEX), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
|
argsman.AddArg("-txindex", strprintf("Maintain a full transaction index, used by the getrawtransaction rpc call (default: %u)", DEFAULT_TXINDEX), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
|
||||||
argsman.AddArg("-blockfilterindex=<type>",
|
argsman.AddArg("-blockfilterindex=<type>",
|
||||||
strprintf("Maintain an index of compact filters by block (default: %s, values: %s).", DEFAULT_BLOCKFILTERINDEX, ListBlockFilterTypes()) +
|
strprintf("Maintain an index of compact filters by block (default: %s, values: %s).", DEFAULT_BLOCKFILTERINDEX, ListBlockFilterTypes()) +
|
||||||
" If <type> is not supplied or if <type> = 1, indexes for all known types are enabled.",
|
" If <type> is not supplied or if <type> = 1, indexes for all known types are enabled.",
|
||||||
ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
|
ArgsManager::ALLOW_BOOL | ArgsManager::ALLOW_STRING | ArgsManager::ALLOW_LIST, OptionsCategory::OPTIONS);
|
||||||
|
|
||||||
argsman.AddArg("-addnode=<ip>", strprintf("Add a node to connect to and attempt to keep the connection open (see the addnode RPC help for more info). This option can be specified multiple times to add multiple nodes; connections are limited to %u at a time and are counted separately from the -maxconnections limit.", MAX_ADDNODE_CONNECTIONS), ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::CONNECTION);
|
argsman.AddArg("-addnode=<ip>", strprintf("Add a node to connect to and attempt to keep the connection open (see the addnode RPC help for more info). This option can be specified multiple times to add multiple nodes; connections are limited to %u at a time and are counted separately from the -maxconnections limit.", MAX_ADDNODE_CONNECTIONS), ArgsManager::ALLOW_ANY | ArgsManager::ALLOW_LIST | ArgsManager::NETWORK_ONLY, OptionsCategory::CONNECTION);
|
||||||
argsman.AddArg("-asmap=<file>", strprintf("Specify asn mapping used for bucketing of the peers (default: %s). Relative paths will be prefixed by the net-specific datadir location.", DEFAULT_ASMAP_FILENAME), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
|
argsman.AddArg("-asmap=<file>", strprintf("Specify asn mapping used for bucketing of the peers (default: %s). Relative paths will be prefixed by the net-specific datadir location.", DEFAULT_ASMAP_FILENAME), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
|
||||||
argsman.AddArg("-bantime=<n>", strprintf("Default duration (in seconds) of manually configured bans (default: %u)", DEFAULT_MISBEHAVING_BANTIME), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
|
argsman.AddArg("-bantime=<n>", strprintf("Default duration (in seconds) of manually configured bans (default: %u)", DEFAULT_MISBEHAVING_BANTIME), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
|
||||||
argsman.AddArg("-bind=<addr>[:<port>][=onion]", strprintf("Bind to given address and always listen on it (default: 0.0.0.0). Use [host]:port notation for IPv6. Append =onion to tag any incoming connections to that address and port as incoming Tor connections (default: 127.0.0.1:%u=onion, testnet3: 127.0.0.1:%u=onion, testnet4: 127.0.0.1:%u=onion, signet: 127.0.0.1:%u=onion, regtest: 127.0.0.1:%u=onion)", defaultChainParams->GetDefaultPort() + 1, testnetChainParams->GetDefaultPort() + 1, testnet4ChainParams->GetDefaultPort() + 1, signetChainParams->GetDefaultPort() + 1, regtestChainParams->GetDefaultPort() + 1), ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::CONNECTION);
|
argsman.AddArg("-bind=<addr>[:<port>][=onion]", strprintf("Bind to given address and always listen on it (default: 0.0.0.0). Use [host]:port notation for IPv6. Append =onion to tag any incoming connections to that address and port as incoming Tor connections (default: 127.0.0.1:%u=onion, testnet3: 127.0.0.1:%u=onion, testnet4: 127.0.0.1:%u=onion, signet: 127.0.0.1:%u=onion, regtest: 127.0.0.1:%u=onion)", defaultChainParams->GetDefaultPort() + 1, testnetChainParams->GetDefaultPort() + 1, testnet4ChainParams->GetDefaultPort() + 1, signetChainParams->GetDefaultPort() + 1, regtestChainParams->GetDefaultPort() + 1), ArgsManager::ALLOW_ANY | ArgsManager::ALLOW_LIST | ArgsManager::NETWORK_ONLY, OptionsCategory::CONNECTION);
|
||||||
argsman.AddArg("-cjdnsreachable", "If set, then this host is configured for CJDNS (connecting to fc00::/8 addresses would lead us to the CJDNS network, see doc/cjdns.md) (default: 0)", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
|
argsman.AddArg("-cjdnsreachable", "If set, then this host is configured for CJDNS (connecting to fc00::/8 addresses would lead us to the CJDNS network, see doc/cjdns.md) (default: 0)", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
|
||||||
argsman.AddArg("-connect=<ip>", "Connect only to the specified node; -noconnect disables automatic connections (the rules for this peer are the same as for -addnode). This option can be specified multiple times to connect to multiple nodes.", ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::CONNECTION);
|
argsman.AddArg("-connect=<ip>", "Connect only to the specified node; -noconnect disables automatic connections (the rules for this peer are the same as for -addnode). This option can be specified multiple times to connect to multiple nodes.", ArgsManager::ALLOW_ANY | ArgsManager::ALLOW_LIST | ArgsManager::NETWORK_ONLY, OptionsCategory::CONNECTION);
|
||||||
argsman.AddArg("-discover", "Discover own IP addresses (default: 1 when listening and no -externalip or -proxy)", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
|
argsman.AddArg("-discover", "Discover own IP addresses (default: 1 when listening and no -externalip or -proxy)", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
|
||||||
argsman.AddArg("-dns", strprintf("Allow DNS lookups for -addnode, -seednode and -connect (default: %u)", DEFAULT_NAME_LOOKUP), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
|
argsman.AddArg("-dns", strprintf("Allow DNS lookups for -addnode, -seednode and -connect (default: %u)", DEFAULT_NAME_LOOKUP), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
|
||||||
argsman.AddArg("-dnsseed", strprintf("Query for peer addresses via DNS lookup, if low on addresses (default: %u unless -connect used or -maxconnections=0)", DEFAULT_DNSSEED), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
|
argsman.AddArg("-dnsseed", strprintf("Query for peer addresses via DNS lookup, if low on addresses (default: %u unless -connect used or -maxconnections=0)", DEFAULT_DNSSEED), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
|
||||||
argsman.AddArg("-externalip=<ip>", "Specify your own public address", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
|
argsman.AddArg("-externalip=<ip>", "Specify your own public address", ArgsManager::ALLOW_ANY | ArgsManager::ALLOW_LIST, OptionsCategory::CONNECTION);
|
||||||
argsman.AddArg("-fixedseeds", strprintf("Allow fixed seeds if DNS seeds don't provide peers (default: %u)", DEFAULT_FIXEDSEEDS), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
|
argsman.AddArg("-fixedseeds", strprintf("Allow fixed seeds if DNS seeds don't provide peers (default: %u)", DEFAULT_FIXEDSEEDS), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
|
||||||
argsman.AddArg("-forcednsseed", strprintf("Always query for peer addresses via DNS lookup (default: %u)", DEFAULT_FORCEDNSSEED), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
|
argsman.AddArg("-forcednsseed", strprintf("Always query for peer addresses via DNS lookup (default: %u)", DEFAULT_FORCEDNSSEED), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
|
||||||
argsman.AddArg("-listen", strprintf("Accept connections from outside (default: %u if no -proxy, -connect or -maxconnections=0)", DEFAULT_LISTEN), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
|
argsman.AddArg("-listen", strprintf("Accept connections from outside (default: %u if no -proxy, -connect or -maxconnections=0)", DEFAULT_LISTEN), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
|
||||||
|
@ -546,7 +546,7 @@ void SetupServerArgs(ArgsManager& argsman, bool can_listen_ipc)
|
||||||
#endif
|
#endif
|
||||||
argsman.AddArg("-i2psam=<ip:port>", "I2P SAM proxy to reach I2P peers and accept I2P connections (default: none)", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
|
argsman.AddArg("-i2psam=<ip:port>", "I2P SAM proxy to reach I2P peers and accept I2P connections (default: none)", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
|
||||||
argsman.AddArg("-i2pacceptincoming", strprintf("Whether to accept inbound I2P connections (default: %i). Ignored if -i2psam is not set. Listening for inbound I2P connections is done through the SAM proxy, not by binding to a local address and port.", DEFAULT_I2P_ACCEPT_INCOMING), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
|
argsman.AddArg("-i2pacceptincoming", strprintf("Whether to accept inbound I2P connections (default: %i). Ignored if -i2psam is not set. Listening for inbound I2P connections is done through the SAM proxy, not by binding to a local address and port.", DEFAULT_I2P_ACCEPT_INCOMING), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
|
||||||
argsman.AddArg("-onlynet=<net>", "Make automatic outbound connections only to network <net> (" + Join(GetNetworkNames(), ", ") + "). Inbound and manual connections are not affected by this option. It can be specified multiple times to allow multiple networks.", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
|
argsman.AddArg("-onlynet=<net>", "Make automatic outbound connections only to network <net> (" + Join(GetNetworkNames(), ", ") + "). Inbound and manual connections are not affected by this option. It can be specified multiple times to allow multiple networks.", ArgsManager::ALLOW_ANY | ArgsManager::ALLOW_LIST, OptionsCategory::CONNECTION);
|
||||||
argsman.AddArg("-v2transport", strprintf("Support v2 transport (default: %u)", DEFAULT_V2_TRANSPORT), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
|
argsman.AddArg("-v2transport", strprintf("Support v2 transport (default: %u)", DEFAULT_V2_TRANSPORT), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
|
||||||
argsman.AddArg("-peerbloomfilters", strprintf("Support filtering of blocks and transaction with bloom filters (default: %u)", DEFAULT_PEERBLOOMFILTERS), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
|
argsman.AddArg("-peerbloomfilters", strprintf("Support filtering of blocks and transaction with bloom filters (default: %u)", DEFAULT_PEERBLOOMFILTERS), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
|
||||||
argsman.AddArg("-peerblockfilters", strprintf("Serve compact block filters to peers per BIP 157 (default: %u)", DEFAULT_PEERBLOCKFILTERS), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
|
argsman.AddArg("-peerblockfilters", strprintf("Serve compact block filters to peers per BIP 157 (default: %u)", DEFAULT_PEERBLOCKFILTERS), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
|
||||||
|
@ -558,7 +558,7 @@ void SetupServerArgs(ArgsManager& argsman, bool can_listen_ipc)
|
||||||
argsman.AddArg("-proxy=<ip:port>", "Connect through SOCKS5 proxy, set -noproxy to disable (default: disabled)", ArgsManager::ALLOW_ANY | ArgsManager::DISALLOW_ELISION, OptionsCategory::CONNECTION);
|
argsman.AddArg("-proxy=<ip:port>", "Connect through SOCKS5 proxy, set -noproxy to disable (default: disabled)", ArgsManager::ALLOW_ANY | ArgsManager::DISALLOW_ELISION, OptionsCategory::CONNECTION);
|
||||||
#endif
|
#endif
|
||||||
argsman.AddArg("-proxyrandomize", strprintf("Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)", DEFAULT_PROXYRANDOMIZE), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
|
argsman.AddArg("-proxyrandomize", strprintf("Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)", DEFAULT_PROXYRANDOMIZE), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
|
||||||
argsman.AddArg("-seednode=<ip>", "Connect to a node to retrieve peer addresses, and disconnect. This option can be specified multiple times to connect to multiple nodes. During startup, seednodes will be tried before dnsseeds.", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
|
argsman.AddArg("-seednode=<ip>", "Connect to a node to retrieve peer addresses, and disconnect. This option can be specified multiple times to connect to multiple nodes. During startup, seednodes will be tried before dnsseeds.", ArgsManager::ALLOW_ANY | ArgsManager::ALLOW_LIST, OptionsCategory::CONNECTION);
|
||||||
argsman.AddArg("-networkactive", "Enable all P2P network activity (default: 1). Can be changed by the setnetworkactive RPC command", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
|
argsman.AddArg("-networkactive", "Enable all P2P network activity (default: 1). Can be changed by the setnetworkactive RPC command", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
|
||||||
argsman.AddArg("-timeout=<n>", strprintf("Specify socket connection timeout in milliseconds. If an initial attempt to connect is unsuccessful after this amount of time, drop it (minimum: 1, default: %d)", DEFAULT_CONNECT_TIMEOUT), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
|
argsman.AddArg("-timeout=<n>", strprintf("Specify socket connection timeout in milliseconds. If an initial attempt to connect is unsuccessful after this amount of time, drop it (minimum: 1, default: %d)", DEFAULT_CONNECT_TIMEOUT), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
|
||||||
argsman.AddArg("-peertimeout=<n>", strprintf("Specify a p2p connection timeout delay in seconds. After connecting to a peer, wait this amount of time before considering disconnection based on inactivity (minimum: 1, default: %d)", DEFAULT_PEER_CONNECT_TIMEOUT), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CONNECTION);
|
argsman.AddArg("-peertimeout=<n>", strprintf("Specify a p2p connection timeout delay in seconds. After connecting to a peer, wait this amount of time before considering disconnection based on inactivity (minimum: 1, default: %d)", DEFAULT_PEER_CONNECT_TIMEOUT), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CONNECTION);
|
||||||
|
@ -569,22 +569,22 @@ void SetupServerArgs(ArgsManager& argsman, bool can_listen_ipc)
|
||||||
argsman.AddArg("-natpmp", strprintf("Use PCP or NAT-PMP to map the listening port (default: %u)", DEFAULT_NATPMP), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
|
argsman.AddArg("-natpmp", strprintf("Use PCP or NAT-PMP to map the listening port (default: %u)", DEFAULT_NATPMP), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
|
||||||
argsman.AddArg("-whitebind=<[permissions@]addr>", "Bind to the given address and add permission flags to the peers connecting to it. "
|
argsman.AddArg("-whitebind=<[permissions@]addr>", "Bind to the given address and add permission flags to the peers connecting to it. "
|
||||||
"Use [host]:port notation for IPv6. Allowed permissions: " + Join(NET_PERMISSIONS_DOC, ", ") + ". "
|
"Use [host]:port notation for IPv6. Allowed permissions: " + Join(NET_PERMISSIONS_DOC, ", ") + ". "
|
||||||
"Specify multiple permissions separated by commas (default: download,noban,mempool,relay). Can be specified multiple times.", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
|
"Specify multiple permissions separated by commas (default: download,noban,mempool,relay). Can be specified multiple times.", ArgsManager::ALLOW_ANY | ArgsManager::ALLOW_LIST, OptionsCategory::CONNECTION);
|
||||||
|
|
||||||
argsman.AddArg("-whitelist=<[permissions@]IP address or network>", "Add permission flags to the peers using the given IP address (e.g. 1.2.3.4) or "
|
argsman.AddArg("-whitelist=<[permissions@]IP address or network>", "Add permission flags to the peers using the given IP address (e.g. 1.2.3.4) or "
|
||||||
"CIDR-notated network (e.g. 1.2.3.0/24). Uses the same permissions as "
|
"CIDR-notated network (e.g. 1.2.3.0/24). Uses the same permissions as "
|
||||||
"-whitebind. "
|
"-whitebind. "
|
||||||
"Additional flags \"in\" and \"out\" control whether permissions apply to incoming connections and/or manual (default: incoming only). "
|
"Additional flags \"in\" and \"out\" control whether permissions apply to incoming connections and/or manual (default: incoming only). "
|
||||||
"Can be specified multiple times.", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
|
"Can be specified multiple times.", ArgsManager::ALLOW_ANY | ArgsManager::ALLOW_LIST, OptionsCategory::CONNECTION);
|
||||||
|
|
||||||
g_wallet_init_interface.AddWalletOptions(argsman);
|
g_wallet_init_interface.AddWalletOptions(argsman);
|
||||||
|
|
||||||
#ifdef ENABLE_ZMQ
|
#ifdef ENABLE_ZMQ
|
||||||
argsman.AddArg("-zmqpubhashblock=<address>", "Enable publish hash block in <address>", ArgsManager::ALLOW_ANY, OptionsCategory::ZMQ);
|
argsman.AddArg("-zmqpubhashblock=<address>", "Enable publish hash block in <address>", ArgsManager::ALLOW_ANY | ArgsManager::ALLOW_LIST, OptionsCategory::ZMQ);
|
||||||
argsman.AddArg("-zmqpubhashtx=<address>", "Enable publish hash transaction in <address>", ArgsManager::ALLOW_ANY, OptionsCategory::ZMQ);
|
argsman.AddArg("-zmqpubhashtx=<address>", "Enable publish hash transaction in <address>", ArgsManager::ALLOW_ANY | ArgsManager::ALLOW_LIST, OptionsCategory::ZMQ);
|
||||||
argsman.AddArg("-zmqpubrawblock=<address>", "Enable publish raw block in <address>", ArgsManager::ALLOW_ANY, OptionsCategory::ZMQ);
|
argsman.AddArg("-zmqpubrawblock=<address>", "Enable publish raw block in <address>", ArgsManager::ALLOW_ANY | ArgsManager::ALLOW_LIST, OptionsCategory::ZMQ);
|
||||||
argsman.AddArg("-zmqpubrawtx=<address>", "Enable publish raw transaction in <address>", ArgsManager::ALLOW_ANY, OptionsCategory::ZMQ);
|
argsman.AddArg("-zmqpubrawtx=<address>", "Enable publish raw transaction in <address>", ArgsManager::ALLOW_ANY | ArgsManager::ALLOW_LIST, OptionsCategory::ZMQ);
|
||||||
argsman.AddArg("-zmqpubsequence=<address>", "Enable publish hash block and tx sequence in <address>", ArgsManager::ALLOW_ANY, OptionsCategory::ZMQ);
|
argsman.AddArg("-zmqpubsequence=<address>", "Enable publish hash block and tx sequence in <address>", ArgsManager::ALLOW_ANY | ArgsManager::ALLOW_LIST, OptionsCategory::ZMQ);
|
||||||
argsman.AddArg("-zmqpubhashblockhwm=<n>", strprintf("Set publish hash block outbound message high water mark (default: %d)", CZMQAbstractNotifier::DEFAULT_ZMQ_SNDHWM), ArgsManager::ALLOW_ANY, OptionsCategory::ZMQ);
|
argsman.AddArg("-zmqpubhashblockhwm=<n>", strprintf("Set publish hash block outbound message high water mark (default: %d)", CZMQAbstractNotifier::DEFAULT_ZMQ_SNDHWM), ArgsManager::ALLOW_ANY, OptionsCategory::ZMQ);
|
||||||
argsman.AddArg("-zmqpubhashtxhwm=<n>", strprintf("Set publish hash transaction outbound message high water mark (default: %d)", CZMQAbstractNotifier::DEFAULT_ZMQ_SNDHWM), ArgsManager::ALLOW_ANY, OptionsCategory::ZMQ);
|
argsman.AddArg("-zmqpubhashtxhwm=<n>", strprintf("Set publish hash transaction outbound message high water mark (default: %d)", CZMQAbstractNotifier::DEFAULT_ZMQ_SNDHWM), ArgsManager::ALLOW_ANY, OptionsCategory::ZMQ);
|
||||||
argsman.AddArg("-zmqpubrawblockhwm=<n>", strprintf("Set publish raw block outbound message high water mark (default: %d)", CZMQAbstractNotifier::DEFAULT_ZMQ_SNDHWM), ArgsManager::ALLOW_ANY, OptionsCategory::ZMQ);
|
argsman.AddArg("-zmqpubrawblockhwm=<n>", strprintf("Set publish raw block outbound message high water mark (default: %d)", CZMQAbstractNotifier::DEFAULT_ZMQ_SNDHWM), ArgsManager::ALLOW_ANY, OptionsCategory::ZMQ);
|
||||||
|
@ -609,14 +609,14 @@ void SetupServerArgs(ArgsManager& argsman, bool can_listen_ipc)
|
||||||
argsman.AddArg("-checkaddrman=<n>", strprintf("Run addrman consistency checks every <n> operations. Use 0 to disable. (default: %u)", DEFAULT_ADDRMAN_CONSISTENCY_CHECKS), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
|
argsman.AddArg("-checkaddrman=<n>", strprintf("Run addrman consistency checks every <n> operations. Use 0 to disable. (default: %u)", DEFAULT_ADDRMAN_CONSISTENCY_CHECKS), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
|
||||||
argsman.AddArg("-checkmempool=<n>", strprintf("Run mempool consistency checks every <n> transactions. Use 0 to disable. (default: %u, regtest: %u)", defaultChainParams->DefaultConsistencyChecks(), regtestChainParams->DefaultConsistencyChecks()), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
|
argsman.AddArg("-checkmempool=<n>", strprintf("Run mempool consistency checks every <n> transactions. Use 0 to disable. (default: %u, regtest: %u)", defaultChainParams->DefaultConsistencyChecks(), regtestChainParams->DefaultConsistencyChecks()), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
|
||||||
argsman.AddArg("-checkpoints", strprintf("Enable rejection of any forks from the known historical chain until block %s (default: %u)", defaultChainParams->Checkpoints().GetHeight(), DEFAULT_CHECKPOINTS_ENABLED), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
|
argsman.AddArg("-checkpoints", strprintf("Enable rejection of any forks from the known historical chain until block %s (default: %u)", defaultChainParams->Checkpoints().GetHeight(), DEFAULT_CHECKPOINTS_ENABLED), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
|
||||||
argsman.AddArg("-deprecatedrpc=<method>", "Allows deprecated RPC method(s) to be used", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
|
argsman.AddArg("-deprecatedrpc=<method>", "Allows deprecated RPC method(s) to be used", ArgsManager::ALLOW_ANY | ArgsManager::ALLOW_LIST | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
|
||||||
argsman.AddArg("-stopafterblockimport", strprintf("Stop running after importing blocks from disk (default: %u)", DEFAULT_STOPAFTERBLOCKIMPORT), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
|
argsman.AddArg("-stopafterblockimport", strprintf("Stop running after importing blocks from disk (default: %u)", DEFAULT_STOPAFTERBLOCKIMPORT), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
|
||||||
argsman.AddArg("-stopatheight", strprintf("Stop running after reaching the given height in the main chain (default: %u)", DEFAULT_STOPATHEIGHT), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
|
argsman.AddArg("-stopatheight", strprintf("Stop running after reaching the given height in the main chain (default: %u)", DEFAULT_STOPATHEIGHT), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
|
||||||
argsman.AddArg("-limitancestorcount=<n>", strprintf("Do not accept transactions if number of in-mempool ancestors is <n> or more (default: %u)", DEFAULT_ANCESTOR_LIMIT), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
|
argsman.AddArg("-limitancestorcount=<n>", strprintf("Do not accept transactions if number of in-mempool ancestors is <n> or more (default: %u)", DEFAULT_ANCESTOR_LIMIT), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
|
||||||
argsman.AddArg("-limitancestorsize=<n>", strprintf("Do not accept transactions whose size with all in-mempool ancestors exceeds <n> kilobytes (default: %u)", DEFAULT_ANCESTOR_SIZE_LIMIT_KVB), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
|
argsman.AddArg("-limitancestorsize=<n>", strprintf("Do not accept transactions whose size with all in-mempool ancestors exceeds <n> kilobytes (default: %u)", DEFAULT_ANCESTOR_SIZE_LIMIT_KVB), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
|
||||||
argsman.AddArg("-limitdescendantcount=<n>", strprintf("Do not accept transactions if any ancestor would have <n> or more in-mempool descendants (default: %u)", DEFAULT_DESCENDANT_LIMIT), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
|
argsman.AddArg("-limitdescendantcount=<n>", strprintf("Do not accept transactions if any ancestor would have <n> or more in-mempool descendants (default: %u)", DEFAULT_DESCENDANT_LIMIT), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
|
||||||
argsman.AddArg("-limitdescendantsize=<n>", strprintf("Do not accept transactions if any ancestor would have more than <n> kilobytes of in-mempool descendants (default: %u).", DEFAULT_DESCENDANT_SIZE_LIMIT_KVB), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
|
argsman.AddArg("-limitdescendantsize=<n>", strprintf("Do not accept transactions if any ancestor would have more than <n> kilobytes of in-mempool descendants (default: %u).", DEFAULT_DESCENDANT_SIZE_LIMIT_KVB), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
|
||||||
argsman.AddArg("-test=<option>", "Pass a test-only option. Options include : " + Join(TEST_OPTIONS_DOC, ", ") + ".", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
|
argsman.AddArg("-test=<option>", "Pass a test-only option. Options include : " + Join(TEST_OPTIONS_DOC, ", ") + ".", ArgsManager::ALLOW_ANY | ArgsManager::ALLOW_LIST | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
|
||||||
argsman.AddArg("-capturemessages", "Capture all P2P messages to disk", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
|
argsman.AddArg("-capturemessages", "Capture all P2P messages to disk", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
|
||||||
argsman.AddArg("-mocktime=<n>", "Replace actual time with " + UNIX_EPOCH_TIME + " (default: 0)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
|
argsman.AddArg("-mocktime=<n>", "Replace actual time with " + UNIX_EPOCH_TIME + " (default: 0)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
|
||||||
argsman.AddArg("-maxsigcachesize=<n>", strprintf("Limit sum of signature cache and script execution cache sizes to <n> MiB (default: %u)", DEFAULT_VALIDATION_CACHE_BYTES >> 20), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
|
argsman.AddArg("-maxsigcachesize=<n>", strprintf("Limit sum of signature cache and script execution cache sizes to <n> MiB (default: %u)", DEFAULT_VALIDATION_CACHE_BYTES >> 20), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
|
||||||
|
@ -625,7 +625,7 @@ void SetupServerArgs(ArgsManager& argsman, bool can_listen_ipc)
|
||||||
Ticks<std::chrono::seconds>(DEFAULT_MAX_TIP_AGE)),
|
Ticks<std::chrono::seconds>(DEFAULT_MAX_TIP_AGE)),
|
||||||
ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
|
ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
|
||||||
argsman.AddArg("-printpriority", strprintf("Log transaction fee rate in %s/kvB when mining blocks (default: %u)", CURRENCY_UNIT, DEFAULT_PRINT_MODIFIED_FEE), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
|
argsman.AddArg("-printpriority", strprintf("Log transaction fee rate in %s/kvB when mining blocks (default: %u)", CURRENCY_UNIT, DEFAULT_PRINT_MODIFIED_FEE), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
|
||||||
argsman.AddArg("-uacomment=<cmt>", "Append comment to the user agent string", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
|
argsman.AddArg("-uacomment=<cmt>", "Append comment to the user agent string", ArgsManager::ALLOW_ANY | ArgsManager::ALLOW_LIST, OptionsCategory::DEBUG_TEST);
|
||||||
|
|
||||||
SetupChainParamsBaseOptions(argsman);
|
SetupChainParamsBaseOptions(argsman);
|
||||||
|
|
||||||
|
@ -654,9 +654,9 @@ void SetupServerArgs(ArgsManager& argsman, bool can_listen_ipc)
|
||||||
argsman.AddArg("-blockversion=<n>", "Override block version to test forking scenarios", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::BLOCK_CREATION);
|
argsman.AddArg("-blockversion=<n>", "Override block version to test forking scenarios", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::BLOCK_CREATION);
|
||||||
|
|
||||||
argsman.AddArg("-rest", strprintf("Accept public REST requests (default: %u)", DEFAULT_REST_ENABLE), ArgsManager::ALLOW_ANY, OptionsCategory::RPC);
|
argsman.AddArg("-rest", strprintf("Accept public REST requests (default: %u)", DEFAULT_REST_ENABLE), ArgsManager::ALLOW_ANY, OptionsCategory::RPC);
|
||||||
argsman.AddArg("-rpcallowip=<ip>", "Allow JSON-RPC connections from specified source. Valid values for <ip> are a single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0), a network/CIDR (e.g. 1.2.3.4/24), all ipv4 (0.0.0.0/0), or all ipv6 (::/0). This option can be specified multiple times", ArgsManager::ALLOW_ANY, OptionsCategory::RPC);
|
argsman.AddArg("-rpcallowip=<ip>", "Allow JSON-RPC connections from specified source. Valid values for <ip> are a single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0), a network/CIDR (e.g. 1.2.3.4/24), all ipv4 (0.0.0.0/0), or all ipv6 (::/0). This option can be specified multiple times", ArgsManager::ALLOW_ANY | ArgsManager::ALLOW_LIST, OptionsCategory::RPC);
|
||||||
argsman.AddArg("-rpcauth=<userpw>", "Username and HMAC-SHA-256 hashed password for JSON-RPC connections. The field <userpw> comes in the format: <USERNAME>:<SALT>$<HASH>. A canonical python script is included in share/rpcauth. The client then connects normally using the rpcuser=<USERNAME>/rpcpassword=<PASSWORD> pair of arguments. This option can be specified multiple times", ArgsManager::ALLOW_ANY | ArgsManager::SENSITIVE, OptionsCategory::RPC);
|
argsman.AddArg("-rpcauth=<userpw>", "Username and HMAC-SHA-256 hashed password for JSON-RPC connections. The field <userpw> comes in the format: <USERNAME>:<SALT>$<HASH>. A canonical python script is included in share/rpcauth. The client then connects normally using the rpcuser=<USERNAME>/rpcpassword=<PASSWORD> pair of arguments. This option can be specified multiple times", ArgsManager::ALLOW_ANY | ArgsManager::ALLOW_LIST | ArgsManager::SENSITIVE, OptionsCategory::RPC);
|
||||||
argsman.AddArg("-rpcbind=<addr>[:port]", "Bind to given address to listen for JSON-RPC connections. Do not expose the RPC server to untrusted networks such as the public internet! This option is ignored unless -rpcallowip is also passed. Port is optional and overrides -rpcport. Use [host]:port notation for IPv6. This option can be specified multiple times (default: 127.0.0.1 and ::1 i.e., localhost)", ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::RPC);
|
argsman.AddArg("-rpcbind=<addr>[:port]", "Bind to given address to listen for JSON-RPC connections. Do not expose the RPC server to untrusted networks such as the public internet! This option is ignored unless -rpcallowip is also passed. Port is optional and overrides -rpcport. Use [host]:port notation for IPv6. This option can be specified multiple times (default: 127.0.0.1 and ::1 i.e., localhost)", ArgsManager::ALLOW_ANY | ArgsManager::ALLOW_LIST | ArgsManager::NETWORK_ONLY, OptionsCategory::RPC);
|
||||||
argsman.AddArg("-rpcdoccheck", strprintf("Throw a non-fatal error at runtime if the documentation for an RPC is incorrect (default: %u)", DEFAULT_RPC_DOC_CHECK), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::RPC);
|
argsman.AddArg("-rpcdoccheck", strprintf("Throw a non-fatal error at runtime if the documentation for an RPC is incorrect (default: %u)", DEFAULT_RPC_DOC_CHECK), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::RPC);
|
||||||
argsman.AddArg("-rpccookiefile=<loc>", "Location of the auth cookie. Relative paths will be prefixed by a net-specific datadir location. (default: data dir)", ArgsManager::ALLOW_ANY, OptionsCategory::RPC);
|
argsman.AddArg("-rpccookiefile=<loc>", "Location of the auth cookie. Relative paths will be prefixed by a net-specific datadir location. (default: data dir)", ArgsManager::ALLOW_ANY, OptionsCategory::RPC);
|
||||||
argsman.AddArg("-rpccookieperms=<readable-by>", strprintf("Set permissions on the RPC auth cookie file so that it is readable by [owner|group|all] (default: owner [via umask 0077])"), ArgsManager::ALLOW_ANY, OptionsCategory::RPC);
|
argsman.AddArg("-rpccookieperms=<readable-by>", strprintf("Set permissions on the RPC auth cookie file so that it is readable by [owner|group|all] (default: owner [via umask 0077])"), ArgsManager::ALLOW_ANY, OptionsCategory::RPC);
|
||||||
|
@ -665,12 +665,12 @@ void SetupServerArgs(ArgsManager& argsman, bool can_listen_ipc)
|
||||||
argsman.AddArg("-rpcservertimeout=<n>", strprintf("Timeout during HTTP requests (default: %d)", DEFAULT_HTTP_SERVER_TIMEOUT), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::RPC);
|
argsman.AddArg("-rpcservertimeout=<n>", strprintf("Timeout during HTTP requests (default: %d)", DEFAULT_HTTP_SERVER_TIMEOUT), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::RPC);
|
||||||
argsman.AddArg("-rpcthreads=<n>", strprintf("Set the number of threads to service RPC calls (default: %d)", DEFAULT_HTTP_THREADS), ArgsManager::ALLOW_ANY, OptionsCategory::RPC);
|
argsman.AddArg("-rpcthreads=<n>", strprintf("Set the number of threads to service RPC calls (default: %d)", DEFAULT_HTTP_THREADS), ArgsManager::ALLOW_ANY, OptionsCategory::RPC);
|
||||||
argsman.AddArg("-rpcuser=<user>", "Username for JSON-RPC connections", ArgsManager::ALLOW_ANY | ArgsManager::SENSITIVE, OptionsCategory::RPC);
|
argsman.AddArg("-rpcuser=<user>", "Username for JSON-RPC connections", ArgsManager::ALLOW_ANY | ArgsManager::SENSITIVE, OptionsCategory::RPC);
|
||||||
argsman.AddArg("-rpcwhitelist=<whitelist>", "Set a whitelist to filter incoming RPC calls for a specific user. The field <whitelist> comes in the format: <USERNAME>:<rpc 1>,<rpc 2>,...,<rpc n>. If multiple whitelists are set for a given user, they are set-intersected. See -rpcwhitelistdefault documentation for information on default whitelist behavior.", ArgsManager::ALLOW_ANY, OptionsCategory::RPC);
|
argsman.AddArg("-rpcwhitelist=<whitelist>", "Set a whitelist to filter incoming RPC calls for a specific user. The field <whitelist> comes in the format: <USERNAME>:<rpc 1>,<rpc 2>,...,<rpc n>. If multiple whitelists are set for a given user, they are set-intersected. See -rpcwhitelistdefault documentation for information on default whitelist behavior.", ArgsManager::ALLOW_ANY | ArgsManager::ALLOW_LIST, OptionsCategory::RPC);
|
||||||
argsman.AddArg("-rpcwhitelistdefault", "Sets default behavior for rpc whitelisting. Unless rpcwhitelistdefault is set to 0, if any -rpcwhitelist is set, the rpc server acts as if all rpc users are subject to empty-unless-otherwise-specified whitelists. If rpcwhitelistdefault is set to 1 and no -rpcwhitelist is set, rpc server acts as if all rpc users are subject to empty whitelists.", ArgsManager::ALLOW_ANY, OptionsCategory::RPC);
|
argsman.AddArg("-rpcwhitelistdefault", "Sets default behavior for rpc whitelisting. Unless rpcwhitelistdefault is set to 0, if any -rpcwhitelist is set, the rpc server acts as if all rpc users are subject to empty-unless-otherwise-specified whitelists. If rpcwhitelistdefault is set to 1 and no -rpcwhitelist is set, rpc server acts as if all rpc users are subject to empty whitelists.", ArgsManager::ALLOW_ANY, OptionsCategory::RPC);
|
||||||
argsman.AddArg("-rpcworkqueue=<n>", strprintf("Set the maximum depth of the work queue to service RPC calls (default: %d)", DEFAULT_HTTP_WORKQUEUE), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::RPC);
|
argsman.AddArg("-rpcworkqueue=<n>", strprintf("Set the maximum depth of the work queue to service RPC calls (default: %d)", DEFAULT_HTTP_WORKQUEUE), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::RPC);
|
||||||
argsman.AddArg("-server", "Accept command line and JSON-RPC commands", ArgsManager::ALLOW_ANY, OptionsCategory::RPC);
|
argsman.AddArg("-server", "Accept command line and JSON-RPC commands", ArgsManager::ALLOW_ANY, OptionsCategory::RPC);
|
||||||
if (can_listen_ipc) {
|
if (can_listen_ipc) {
|
||||||
argsman.AddArg("-ipcbind=<address>", "Bind to Unix socket address and listen for incoming connections. Valid address values are \"unix\" to listen on the default path, <datadir>/node.sock, or \"unix:/custom/path\" to specify a custom path. Can be specified multiple times to listen on multiple paths. Default behavior is not to listen on any path. If relative paths are specified, they are interpreted relative to the network data directory. If paths include any parent directory components and the parent directories do not exist, they will be created.", ArgsManager::ALLOW_ANY, OptionsCategory::IPC);
|
argsman.AddArg("-ipcbind=<address>", "Bind to Unix socket address and listen for incoming connections. Valid address values are \"unix\" to listen on the default path, <datadir>/node.sock, or \"unix:/custom/path\" to specify a custom path. Can be specified multiple times to listen on multiple paths. Default behavior is not to listen on any path. If relative paths are specified, they are interpreted relative to the network data directory. If paths include any parent directory components and the parent directories do not exist, they will be created.", ArgsManager::ALLOW_ANY | ArgsManager::ALLOW_LIST, OptionsCategory::IPC);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if HAVE_DECL_FORK
|
#if HAVE_DECL_FORK
|
||||||
|
@ -936,12 +936,13 @@ bool AppInitParameterInteraction(const ArgsManager& args)
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse and validate enabled filter types
|
// parse and validate enabled filter types
|
||||||
std::string blockfilterindex_value = args.GetArg("-blockfilterindex", DEFAULT_BLOCKFILTERINDEX);
|
for (const auto& value : args.GetSettingsList("-blockfilterindex")) {
|
||||||
if (blockfilterindex_value == "" || blockfilterindex_value == "1") {
|
if (value.isTrue() || value.get_str() == "1") {
|
||||||
g_enabled_filter_types = AllBlockFilterTypes();
|
g_enabled_filter_types = AllBlockFilterTypes();
|
||||||
} else if (blockfilterindex_value != "0") {
|
} else if (value.get_str() == "0") {
|
||||||
const std::vector<std::string> names = args.GetArgs("-blockfilterindex");
|
g_enabled_filter_types.clear();
|
||||||
for (const auto& name : names) {
|
} else {
|
||||||
|
const std::string& name = value.get_str();
|
||||||
BlockFilterType filter_type;
|
BlockFilterType filter_type;
|
||||||
if (!BlockFilterTypeByName(name, filter_type)) {
|
if (!BlockFilterTypeByName(name, filter_type)) {
|
||||||
return InitError(strprintf(_("Unknown -blockfilterindex value %s."), name));
|
return InitError(strprintf(_("Unknown -blockfilterindex value %s."), name));
|
||||||
|
@ -1200,7 +1201,14 @@ bool CheckHostPortOptions(const ArgsManager& args) {
|
||||||
{"-zmqpubrawtx", true},
|
{"-zmqpubrawtx", true},
|
||||||
{"-zmqpubsequence", true},
|
{"-zmqpubsequence", true},
|
||||||
}) {
|
}) {
|
||||||
for (const std::string& socket_addr : args.GetArgs(arg)) {
|
std::vector<std::string> addrs;
|
||||||
|
std::optional<unsigned int> flags = args.GetArgFlags(arg);
|
||||||
|
if (!flags || *flags & ArgsManager::ALLOW_LIST) {
|
||||||
|
addrs = args.GetArgs(arg);
|
||||||
|
} else if (args.IsArgSet(arg) && !args.IsArgNegated(arg)) {
|
||||||
|
addrs.emplace_back(*args.GetArg(arg));
|
||||||
|
}
|
||||||
|
for (const std::string& socket_addr : addrs) {
|
||||||
std::string host_out;
|
std::string host_out;
|
||||||
uint16_t port_out{0};
|
uint16_t port_out{0};
|
||||||
if (!SplitHostPort(socket_addr, port_out, host_out)) {
|
if (!SplitHostPort(socket_addr, port_out, host_out)) {
|
||||||
|
|
|
@ -29,10 +29,10 @@ void AddLoggingArgs(ArgsManager& argsman)
|
||||||
argsman.AddArg("-debuglogfile=<file>", strprintf("Specify location of debug log file (default: %s). Relative paths will be prefixed by a net-specific datadir location. Pass -nodebuglogfile to disable writing the log to a file.", DEFAULT_DEBUGLOGFILE), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
|
argsman.AddArg("-debuglogfile=<file>", strprintf("Specify location of debug log file (default: %s). Relative paths will be prefixed by a net-specific datadir location. Pass -nodebuglogfile to disable writing the log to a file.", DEFAULT_DEBUGLOGFILE), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
|
||||||
argsman.AddArg("-debug=<category>", "Output debug and trace logging (default: -nodebug, supplying <category> is optional). "
|
argsman.AddArg("-debug=<category>", "Output debug and trace logging (default: -nodebug, supplying <category> is optional). "
|
||||||
"If <category> is not supplied or if <category> is 1 or \"all\", output all debug logging. If <category> is 0 or \"none\", any other categories are ignored. Other valid values for <category> are: " + LogInstance().LogCategoriesString() + ". This option can be specified multiple times to output multiple categories.",
|
"If <category> is not supplied or if <category> is 1 or \"all\", output all debug logging. If <category> is 0 or \"none\", any other categories are ignored. Other valid values for <category> are: " + LogInstance().LogCategoriesString() + ". This option can be specified multiple times to output multiple categories.",
|
||||||
ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
|
ArgsManager::ALLOW_ANY | ArgsManager::ALLOW_LIST, OptionsCategory::DEBUG_TEST);
|
||||||
argsman.AddArg("-debugexclude=<category>", "Exclude debug and trace logging for a category. Can be used in conjunction with -debug=1 to output debug and trace logging for all categories except the specified category. This option can be specified multiple times to exclude multiple categories. This takes priority over \"-debug\"", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
|
argsman.AddArg("-debugexclude=<category>", "Exclude debug and trace logging for a category. Can be used in conjunction with -debug=1 to output debug and trace logging for all categories except the specified category. This option can be specified multiple times to exclude multiple categories. This takes priority over \"-debug\"", ArgsManager::ALLOW_ANY | ArgsManager::ALLOW_LIST, OptionsCategory::DEBUG_TEST);
|
||||||
argsman.AddArg("-logips", strprintf("Include IP addresses in debug output (default: %u)", DEFAULT_LOGIPS), ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
|
argsman.AddArg("-logips", strprintf("Include IP addresses in debug output (default: %u)", DEFAULT_LOGIPS), ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
|
||||||
argsman.AddArg("-loglevel=<level>|<category>:<level>", strprintf("Set the global or per-category severity level for logging categories enabled with the -debug configuration option or the logging RPC. Possible values are %s (default=%s). The following levels are always logged: error, warning, info. If <category>:<level> is supplied, the setting will override the global one and may be specified multiple times to set multiple category-specific levels. <category> can be: %s.", LogInstance().LogLevelsString(), LogInstance().LogLevelToStr(BCLog::DEFAULT_LOG_LEVEL), LogInstance().LogCategoriesString()), ArgsManager::DISALLOW_NEGATION | ArgsManager::DISALLOW_ELISION | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
|
argsman.AddArg("-loglevel=<level>|<category>:<level>", strprintf("Set the global or per-category severity level for logging categories enabled with the -debug configuration option or the logging RPC. Possible values are %s (default=%s). The following levels are always logged: error, warning, info. If <category>:<level> is supplied, the setting will override the global one and may be specified multiple times to set multiple category-specific levels. <category> can be: %s.", LogInstance().LogLevelsString(), LogInstance().LogLevelToStr(BCLog::DEFAULT_LOG_LEVEL), LogInstance().LogCategoriesString()), ArgsManager::ALLOW_LIST | ArgsManager::DISALLOW_NEGATION | ArgsManager::DISALLOW_ELISION | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
|
||||||
argsman.AddArg("-logtimestamps", strprintf("Prepend debug output with timestamp (default: %u)", DEFAULT_LOGTIMESTAMPS), ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
|
argsman.AddArg("-logtimestamps", strprintf("Prepend debug output with timestamp (default: %u)", DEFAULT_LOGTIMESTAMPS), ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
|
||||||
argsman.AddArg("-logthreadnames", strprintf("Prepend debug output with name of the originating thread (default: %u)", DEFAULT_LOGTHREADNAMES), ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
|
argsman.AddArg("-logthreadnames", strprintf("Prepend debug output with name of the originating thread (default: %u)", DEFAULT_LOGTHREADNAMES), ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
|
||||||
argsman.AddArg("-logsourcelocations", strprintf("Prepend debug output with name of the originating source location (source file, line number and function name) (default: %u)", DEFAULT_LOGSOURCELOCATIONS), ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
|
argsman.AddArg("-logsourcelocations", strprintf("Prepend debug output with name of the originating source location (source file, line number and function name) (default: %u)", DEFAULT_LOGSOURCELOCATIONS), ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
|
||||||
|
|
|
@ -24,6 +24,384 @@ using util::ToString;
|
||||||
|
|
||||||
BOOST_FIXTURE_TEST_SUITE(argsman_tests, BasicTestingSetup)
|
BOOST_FIXTURE_TEST_SUITE(argsman_tests, BasicTestingSetup)
|
||||||
|
|
||||||
|
//! Example code showing how to declare and parse options using ArgsManager flags.
|
||||||
|
namespace example_options {
|
||||||
|
struct Address {
|
||||||
|
std::string host;
|
||||||
|
uint16_t port;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RescanOptions {
|
||||||
|
std::optional<int> start_height;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Options {
|
||||||
|
//! Whether to use UPnP to map the listening port.
|
||||||
|
//! Example of a boolean option defaulting to false.
|
||||||
|
bool enable_upnp{false};
|
||||||
|
|
||||||
|
//! Whether to listen for RPC commands.
|
||||||
|
//! Example of a boolean option defaulting to true.
|
||||||
|
bool enable_rpc_server{true};
|
||||||
|
|
||||||
|
//! Whether to look for peers with DNS lookup.
|
||||||
|
//! Example of a boolean option without a default value. (If unspecified,
|
||||||
|
//! default behavior depends on other options.)
|
||||||
|
std::optional<bool> enable_dns_seed;
|
||||||
|
|
||||||
|
//! Amount of time to ban peers
|
||||||
|
//! Example of a simple integer setting.
|
||||||
|
std::chrono::seconds bantime{86400};
|
||||||
|
|
||||||
|
//! Equivalent bytes per sigop.
|
||||||
|
//! Example of a where negation should be disallowed.
|
||||||
|
int bytes_per_sigop{20};
|
||||||
|
|
||||||
|
//! Hash of block to assume valid and skip script verification.
|
||||||
|
//! Example of a simple string option.
|
||||||
|
std::optional<uint256> assumevalid;
|
||||||
|
|
||||||
|
//! Path to log file
|
||||||
|
//! Example of a simple string option with a default value.
|
||||||
|
fs::path log_file{"debug.log"};
|
||||||
|
|
||||||
|
//! Chain name.
|
||||||
|
//! Example of a simple string option that canoot be negated
|
||||||
|
ChainType chain{ChainType::MAIN};
|
||||||
|
|
||||||
|
//! Whether rescan wallets starting from an optional height.
|
||||||
|
//! Example of an imperative integer setting that uses ALLOW_BOOL flag.
|
||||||
|
std::optional<RescanOptions> wallet_rescan;
|
||||||
|
|
||||||
|
//! Whether to bind to an IPC socket. False to not bind, true to bind to the
|
||||||
|
//! default path, and string to bind to the specified path.
|
||||||
|
//! Example of an imperative string setting that uses ALLOW_BOOL flag.
|
||||||
|
std::variant<bool, std::string> ipc_bind{false};
|
||||||
|
|
||||||
|
//! Paths of block files to load before starting.
|
||||||
|
//! Example of a simple string list setting.
|
||||||
|
std::vector<fs::path> load_block;
|
||||||
|
|
||||||
|
//! Addresses to listen on.
|
||||||
|
//! Example of a list setting where negating the setting is different than
|
||||||
|
//! not specifying it.
|
||||||
|
std::optional<std::vector<Address>> listen_addresses;
|
||||||
|
};
|
||||||
|
|
||||||
|
void RegisterArgs(ArgsManager& args)
|
||||||
|
{
|
||||||
|
args.AddArg("-upnp", "", ArgsManager::ALLOW_BOOL, {});
|
||||||
|
args.AddArg("-rpcserver", "", ArgsManager::ALLOW_BOOL, {});
|
||||||
|
args.AddArg("-dnsseed", "", ArgsManager::ALLOW_BOOL, {});
|
||||||
|
args.AddArg("-bantime", "", ArgsManager::ALLOW_INT, {});
|
||||||
|
args.AddArg("-bytespersigop", "", ArgsManager::ALLOW_INT | ArgsManager::DISALLOW_NEGATION, {});
|
||||||
|
args.AddArg("-assumevalid", "", ArgsManager::ALLOW_STRING, {});
|
||||||
|
args.AddArg("-logfile", "", ArgsManager::ALLOW_STRING, {});
|
||||||
|
args.AddArg("-chain", "", ArgsManager::ALLOW_STRING | ArgsManager::DISALLOW_NEGATION, {});
|
||||||
|
args.AddArg("-rescan", "", ArgsManager::ALLOW_INT | ArgsManager::ALLOW_BOOL, {});
|
||||||
|
args.AddArg("-ipcbind", "", ArgsManager::ALLOW_STRING | ArgsManager::ALLOW_BOOL, {});
|
||||||
|
args.AddArg("-loadblock", "", ArgsManager::ALLOW_STRING | ArgsManager::ALLOW_LIST, {});
|
||||||
|
args.AddArg("-listen", "", ArgsManager::ALLOW_STRING | ArgsManager::ALLOW_LIST, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReadOptions(const ArgsManager& args, Options& options)
|
||||||
|
{
|
||||||
|
if (auto value = args.GetBoolArg("-upnp")) options.enable_upnp = *value;
|
||||||
|
|
||||||
|
if (auto value = args.GetBoolArg("-rpcserver")) options.enable_rpc_server = *value;
|
||||||
|
|
||||||
|
if (auto value = args.GetBoolArg("-dnsseed")) options.enable_dns_seed = *value;
|
||||||
|
|
||||||
|
if (auto value = args.GetIntArg("-bantime")) {
|
||||||
|
if (*value < 0) throw std::runtime_error(strprintf("-bantime value %i is negative", *value));
|
||||||
|
options.bantime = std::chrono::seconds{*value};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto value = args.GetIntArg("-bytespersigop")) {
|
||||||
|
if (*value < 1) throw std::runtime_error(strprintf("-bytespersigop value %i is less than 1", *value));
|
||||||
|
options.bytes_per_sigop = *value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto value = args.GetArg("-assumevalid"); value && !value->empty()) {
|
||||||
|
if (auto hash{uint256::FromHex(*value)}) {
|
||||||
|
options.assumevalid = *hash;
|
||||||
|
} else {
|
||||||
|
throw std::runtime_error(strprintf("-assumevalid value '%s' is not a valid hash", *value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto value = args.GetArg("-logfile")) {
|
||||||
|
options.log_file = fs::PathFromString(*value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto value = args.GetArg("-chain")) {
|
||||||
|
if (auto chain_type{ChainTypeFromString(*value)}) {
|
||||||
|
options.chain = *chain_type;
|
||||||
|
} else {
|
||||||
|
throw std::runtime_error(strprintf("Invalid chain type '%s'", *value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto value{args.GetBoolArg("-rescan")}) {
|
||||||
|
// If -rescan was passed with no height, enable wallet rescan with
|
||||||
|
// default options. If -norescan was passed, do nothing.
|
||||||
|
if (*value) options.wallet_rescan.emplace();
|
||||||
|
} else if (auto value = args.GetIntArg("-rescan")) {
|
||||||
|
// If -rescan=<height> command was passed enable wallet rescan from the
|
||||||
|
// specified height.
|
||||||
|
options.wallet_rescan = RescanOptions{.start_height=*value};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto value{args.GetBoolArg("-ipcbind")}) {
|
||||||
|
// If -ipcbind was passed with no address, set ipc_bind = true, or if
|
||||||
|
// -noipcbind was passed, set ipc_bind = false.
|
||||||
|
options.ipc_bind = *value;
|
||||||
|
} else if (auto value = args.GetArg("-ipcbind")) {
|
||||||
|
// If -ipcbind=<address> was passed, set ipc_bind = <address>
|
||||||
|
options.ipc_bind = *value;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const std::string& value : args.GetArgs("-loadblock")) {
|
||||||
|
if (value.empty()) throw std::runtime_error(strprintf("-loadblock value '%s' is not a valid file path", value));
|
||||||
|
options.load_block.push_back(fs::PathFromString(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.IsArgNegated("-listen")) {
|
||||||
|
// If -nolisten was passed, disable listening by assigning an empty list
|
||||||
|
// of listening addresses.
|
||||||
|
options.listen_addresses.emplace();
|
||||||
|
} else if (auto addresses{args.GetArgs("-listen")}; !addresses.empty()) {
|
||||||
|
// If -listen=<addresses> options were passed, explicitly add these as
|
||||||
|
// listening addresses, otherwise leave listening option unset to enable
|
||||||
|
// default listening behavior.
|
||||||
|
options.listen_addresses.emplace();
|
||||||
|
for (const std::string& value : addresses) {
|
||||||
|
Address addr{"", 8333};
|
||||||
|
if (!SplitHostPort(value, addr.port, addr.host) || addr.host.empty()) {
|
||||||
|
throw std::runtime_error(strprintf("-listen address '%s' is not a valid host[:port]", value));
|
||||||
|
}
|
||||||
|
options.listen_addresses->emplace_back(std::move(addr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Return Options::ipc_bind as a human readable string for easier testing.
|
||||||
|
std::string IpcBindStr(const Options& options)
|
||||||
|
{
|
||||||
|
if (auto address{std::get_if<std::string>(&options.ipc_bind)}) {
|
||||||
|
return *address;
|
||||||
|
} else if (auto enabled{std::get_if<bool>(&options.ipc_bind)}; enabled && *enabled) {
|
||||||
|
// Default address in this example when -ipcbind is specified without an
|
||||||
|
// address is "node.sock".
|
||||||
|
return "node.sock";
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Return Options::load_block as a human readable string for easier testing.
|
||||||
|
std::string LoadBlockStr(const Options& options)
|
||||||
|
{
|
||||||
|
std::string ret;
|
||||||
|
for (const auto& block : options.load_block) {
|
||||||
|
if (!ret.empty()) ret += " ";
|
||||||
|
ret += fs::PathToString(block);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Return Options::listen_addresses as a human readable string for easier
|
||||||
|
//! testing.
|
||||||
|
std::string ListenStr(const Options& options)
|
||||||
|
{
|
||||||
|
if (!options.listen_addresses) {
|
||||||
|
// Default listening behavior in this example is just to listen on port
|
||||||
|
// 8333. In reality, it could be arbitrarily complicated and depend on
|
||||||
|
// other settings.
|
||||||
|
return "0.0.0.0:8333";
|
||||||
|
} else {
|
||||||
|
std::string ret;
|
||||||
|
for (const auto& addr : *options.listen_addresses) {
|
||||||
|
if (!ret.empty()) ret += " ";
|
||||||
|
ret += strprintf("%s:%d", addr.host, addr.port);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct TestSetup : public BasicTestingSetup
|
||||||
|
{
|
||||||
|
Options ParseOptions(const std::vector<std::string>& opts)
|
||||||
|
{
|
||||||
|
ArgsManager args;
|
||||||
|
RegisterArgs(args);
|
||||||
|
std::vector<const char*> argv{"ignored"};
|
||||||
|
for (const auto& opt : opts) {
|
||||||
|
argv.push_back(opt.c_str());
|
||||||
|
}
|
||||||
|
std::string error;
|
||||||
|
if (!args.ParseParameters(argv.size(), argv.data(), error)) {
|
||||||
|
throw std::runtime_error(error);
|
||||||
|
}
|
||||||
|
BOOST_CHECK_EQUAL(error, "");
|
||||||
|
Options options;
|
||||||
|
ReadOptions(args, options);
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace example_options
|
||||||
|
|
||||||
|
BOOST_FIXTURE_TEST_CASE(ExampleOptions, example_options::TestSetup)
|
||||||
|
{
|
||||||
|
// Check default upnp value is false
|
||||||
|
BOOST_CHECK_EQUAL(ParseOptions({}).enable_upnp, false);
|
||||||
|
// Check passing -upnp makes it true.
|
||||||
|
BOOST_CHECK_EQUAL(ParseOptions({"-upnp"}).enable_upnp, true);
|
||||||
|
// Check passing -upnp=1 makes it true.
|
||||||
|
BOOST_CHECK_EQUAL(ParseOptions({"-upnp=1"}).enable_upnp, true);
|
||||||
|
// Check adding -upnp= sets it back to default.
|
||||||
|
BOOST_CHECK_EQUAL(ParseOptions({"-upnp=1", "-upnp="}).enable_upnp, false);
|
||||||
|
// Check passing invalid value.
|
||||||
|
BOOST_CHECK_EXCEPTION(ParseOptions({"-upnp=yes"}), std::exception, HasReason{"Cannot set -upnp value to 'yes'. It must be set to 0 or 1."});
|
||||||
|
|
||||||
|
// Check default rpcserver value is true.
|
||||||
|
BOOST_CHECK_EQUAL(ParseOptions({}).enable_rpc_server, true);
|
||||||
|
// Check passing -norpcserver makes it false.
|
||||||
|
BOOST_CHECK_EQUAL(ParseOptions({"-norpcserver"}).enable_rpc_server, false);
|
||||||
|
// Check passing -rpcserver=0 makes it false.
|
||||||
|
BOOST_CHECK_EQUAL(ParseOptions({"-rpcserver=0"}).enable_rpc_server, false);
|
||||||
|
// Check adding -rpcserver= sets it back to default.
|
||||||
|
BOOST_CHECK_EQUAL(ParseOptions({"-rpcserver=0", "-rpcserver="}).enable_rpc_server, true);
|
||||||
|
// Check passing invalid value.
|
||||||
|
BOOST_CHECK_EXCEPTION(ParseOptions({"-rpcserver=yes"}), std::exception, HasReason{"Cannot set -rpcserver value to 'yes'. It must be set to 0 or 1."});
|
||||||
|
|
||||||
|
// Check default dnsseed value is unset.
|
||||||
|
BOOST_CHECK_EQUAL(ParseOptions({}).enable_dns_seed, std::nullopt);
|
||||||
|
// Check passing -dnsseed makes it true.
|
||||||
|
BOOST_CHECK_EQUAL(ParseOptions({"-dnsseed"}).enable_dns_seed, true);
|
||||||
|
// Check passing -dnsseed=1 makes it true.
|
||||||
|
BOOST_CHECK_EQUAL(ParseOptions({"-dnsseed=1"}).enable_dns_seed, true);
|
||||||
|
// Check passing -nodnsseed makes it false.
|
||||||
|
BOOST_CHECK_EQUAL(ParseOptions({"-nodnsseed"}).enable_dns_seed, false);
|
||||||
|
// Check passing -dnsseed=0 makes it false.
|
||||||
|
BOOST_CHECK_EQUAL(ParseOptions({"-dnsseed=0"}).enable_dns_seed, false);
|
||||||
|
// Check adding -dnsseed= sets it back to default.
|
||||||
|
BOOST_CHECK_EQUAL(ParseOptions({"-dnsseed=1", "-dnsseed="}).enable_dns_seed, std::nullopt);
|
||||||
|
// Check passing invalid value.
|
||||||
|
BOOST_CHECK_EXCEPTION(ParseOptions({"-dnsseed=yes"}), std::exception, HasReason{"Cannot set -dnsseed value to 'yes'. It must be set to 0 or 1."});
|
||||||
|
|
||||||
|
// Check default bantime value is unset.
|
||||||
|
BOOST_CHECK_EQUAL(ParseOptions({}).bantime.count(), 86400);
|
||||||
|
// Check passing -bantime=3600 overrides it.
|
||||||
|
BOOST_CHECK_EQUAL(ParseOptions({"-bantime=3600"}).bantime.count(), 3600);
|
||||||
|
// Check passing -nobantime makes it 0.
|
||||||
|
BOOST_CHECK_EQUAL(ParseOptions({"-nobantime"}).bantime.count(), 0);
|
||||||
|
// Check passing -bantime=0 makes it 0.
|
||||||
|
BOOST_CHECK_EQUAL(ParseOptions({"-bantime=0"}).bantime.count(), 0);
|
||||||
|
// Check adding -bantime= sets it back to default.
|
||||||
|
BOOST_CHECK_EQUAL(ParseOptions({"-bantime=3600", "-bantime="}).bantime.count(), 86400);
|
||||||
|
// Check passing invalid values.
|
||||||
|
BOOST_CHECK_EXCEPTION(ParseOptions({"-bantime"}), std::exception, HasReason{"Cannot set -bantime with no value. Please specify value with -bantime=value. It must be set to an integer."});
|
||||||
|
BOOST_CHECK_EXCEPTION(ParseOptions({"-bantime=abc"}), std::exception, HasReason{"Cannot set -bantime value to 'abc'. It must be set to an integer."});
|
||||||
|
BOOST_CHECK_EXCEPTION(ParseOptions({"-bantime=-1000"}), std::exception, HasReason{"-bantime value -1000 is negative"});
|
||||||
|
|
||||||
|
// Check default bytespersigop value.
|
||||||
|
BOOST_CHECK_EQUAL(ParseOptions({}).bytes_per_sigop, 20);
|
||||||
|
// Check passing -bytespersigop=30 overrides it.
|
||||||
|
BOOST_CHECK_EQUAL(ParseOptions({"-bytespersigop=30"}).bytes_per_sigop, 30);
|
||||||
|
// Check adding -bytespersigop= sets it back to default.
|
||||||
|
BOOST_CHECK_EQUAL(ParseOptions({"-bytespersigop=30", "-bytespersigop="}).bytes_per_sigop, 20);
|
||||||
|
// Check passing invalid values.
|
||||||
|
BOOST_CHECK_EXCEPTION(ParseOptions({"-bytespersigop"}), std::exception, HasReason{"Cannot set -bytespersigop with no value. Please specify value with -bytespersigop=value. It must be set to an integer."});
|
||||||
|
BOOST_CHECK_EXCEPTION(ParseOptions({"-nobytespersigop"}), std::exception, HasReason{"Negating of -bytespersigop is meaningless and therefore forbidden"});
|
||||||
|
BOOST_CHECK_EXCEPTION(ParseOptions({"-bytespersigop=0"}), std::exception, HasReason{"-bytespersigop value 0 is less than 1"});
|
||||||
|
BOOST_CHECK_EXCEPTION(ParseOptions({"-bytespersigop=abc"}), std::exception, HasReason{"Cannot set -bytespersigop value to 'abc'. It must be set to an integer."});
|
||||||
|
|
||||||
|
// Check default assumevalid value is unset.
|
||||||
|
BOOST_CHECK_EQUAL(ParseOptions({}).assumevalid, std::nullopt);
|
||||||
|
// Check passing -assumevalid=<hash> makes it set that hash.
|
||||||
|
BOOST_CHECK_EQUAL(ParseOptions({"-assumevalid=0000111122223333444455556666777788889999aaaabbbbccccddddeeeeffff"}).assumevalid, uint256{"0000111122223333444455556666777788889999aaaabbbbccccddddeeeeffff"});
|
||||||
|
// Check passing -noassumevalid makes it not assumevalid.
|
||||||
|
BOOST_CHECK_EQUAL(ParseOptions({"-noassumevalid"}).assumevalid, std::nullopt);
|
||||||
|
// Check adding -assumevalid= sets it back to default.
|
||||||
|
BOOST_CHECK_EQUAL(ParseOptions({"-assumevalid=0000111122223333444455556666777788889999aaaabbbbccccddddeeeeffff", "-assumevalid="}).assumevalid, std::nullopt);
|
||||||
|
// Check passing invalid values.
|
||||||
|
BOOST_CHECK_EXCEPTION(ParseOptions({"-assumevalid"}), std::exception, HasReason{"Cannot set -assumevalid with no value. Please specify value with -assumevalid=value. It must be set to a string."});
|
||||||
|
BOOST_CHECK_EXCEPTION(ParseOptions({"-assumevalid=1"}), std::exception, HasReason{"-assumevalid value '1' is not a valid hash"});
|
||||||
|
|
||||||
|
// Check default logfile value.
|
||||||
|
BOOST_CHECK_EQUAL(ParseOptions({}).log_file, fs::path{"debug.log"});
|
||||||
|
// Check passing -logfile=custom.log overrides it.
|
||||||
|
BOOST_CHECK_EQUAL(ParseOptions({"-logfile=custom.log"}).log_file, fs::path{"custom.log"});
|
||||||
|
// Check passing -nologfile makes it disables logging.
|
||||||
|
BOOST_CHECK_EQUAL(ParseOptions({"-nologfile"}).log_file, fs::path{});
|
||||||
|
// Check adding -logfile= sets it back to default.
|
||||||
|
BOOST_CHECK_EQUAL(ParseOptions({"-logfile=custom.log", "-logfile="}).log_file, fs::path{"debug.log"});
|
||||||
|
BOOST_CHECK_EQUAL(ParseOptions({"-nologfile", "-logfile="}).log_file, fs::path{"debug.log"});
|
||||||
|
// Check passing invalid values.
|
||||||
|
BOOST_CHECK_EXCEPTION(ParseOptions({"-logfile"}), std::exception, HasReason{"Cannot set -logfile with no value. Please specify value with -logfile=value. It must be set to a string."});
|
||||||
|
|
||||||
|
// Check default chain value.
|
||||||
|
BOOST_CHECK_EQUAL(ParseOptions({}).chain, ChainType::MAIN);
|
||||||
|
// Check passing -chain=regtest overrides it.
|
||||||
|
BOOST_CHECK_EQUAL(ParseOptions({"-chain=regtest"}).chain, ChainType::REGTEST);
|
||||||
|
// Check adding -chain= sets it back to default.
|
||||||
|
BOOST_CHECK_EQUAL(ParseOptions({"-chain=regtest", "-chain="}).chain, ChainType::MAIN);
|
||||||
|
// Check passing invalid values.
|
||||||
|
BOOST_CHECK_EXCEPTION(ParseOptions({"-chain"}), std::exception, HasReason{"Cannot set -chain with no value. Please specify value with -chain=value. It must be set to a string."});
|
||||||
|
BOOST_CHECK_EXCEPTION(ParseOptions({"-chain=abc"}), std::exception, HasReason{"Invalid chain type 'abc'"});
|
||||||
|
BOOST_CHECK_EXCEPTION(ParseOptions({"-nochain"}), std::exception, HasReason{"Negating of -chain is meaningless and therefore forbidden"});
|
||||||
|
|
||||||
|
// Check default rescan value is unset.
|
||||||
|
BOOST_CHECK(!ParseOptions({}).wallet_rescan);
|
||||||
|
// Check passing -rescan makes it rescan from default height
|
||||||
|
BOOST_CHECK_EQUAL(ParseOptions({"-rescan"}).wallet_rescan.value().start_height, std::nullopt);
|
||||||
|
// Check passing -rescan=500000 makes it scan from specified height.
|
||||||
|
BOOST_CHECK_EQUAL(ParseOptions({"-rescan=500000"}).wallet_rescan.value().start_height, 500000);
|
||||||
|
// Check passing -norescan makes it not rescan.
|
||||||
|
BOOST_CHECK(!ParseOptions({"-norescan"}).wallet_rescan);
|
||||||
|
// Check passing -rescan=0 does not simply set the bool but treats it as a height.
|
||||||
|
BOOST_CHECK_EQUAL(ParseOptions({"-rescan=0"}).wallet_rescan.value().start_height, 0);
|
||||||
|
// Check passing -rescan=1 does not simply set the bool but treats it as a height.
|
||||||
|
BOOST_CHECK_EQUAL(ParseOptions({"-rescan=1"}).wallet_rescan.value().start_height, 1);
|
||||||
|
// Check adding -rescan= sets it back to default.
|
||||||
|
BOOST_CHECK(!ParseOptions({"-rescan=500000", "-rescan="}).wallet_rescan);
|
||||||
|
// Check passing invalid value.
|
||||||
|
BOOST_CHECK_EXCEPTION(ParseOptions({"-rescan=yes"}), std::exception, HasReason{"Cannot set -rescan value to 'yes'. It must be set to an integer."});
|
||||||
|
|
||||||
|
// Check default ipcbind value is disabled.
|
||||||
|
BOOST_CHECK_EQUAL(IpcBindStr(ParseOptions({})), "");
|
||||||
|
// Check passing -ipcbind enables it at default address.
|
||||||
|
BOOST_CHECK_EQUAL(IpcBindStr(ParseOptions({"-ipcbind"})), "node.sock");
|
||||||
|
// Check passing -noipcbind makes it disabled.
|
||||||
|
BOOST_CHECK_EQUAL(IpcBindStr(ParseOptions({"-noipcbind"})), "");
|
||||||
|
// Check passing -ipcbind=address sets an address.
|
||||||
|
BOOST_CHECK_EQUAL(IpcBindStr(ParseOptions({"-ipcbind=address"})), "address");
|
||||||
|
// Check adding -ipcbind= sets it back to default.
|
||||||
|
BOOST_CHECK_EQUAL(IpcBindStr(ParseOptions({"-ipcbind=address", "-ipcbind="})), "");
|
||||||
|
|
||||||
|
// Check default loadblock value is empty.
|
||||||
|
BOOST_CHECK_EQUAL(LoadBlockStr(ParseOptions({})), "");
|
||||||
|
// Check passing -loadblock can set multiple values.
|
||||||
|
BOOST_CHECK_EQUAL(LoadBlockStr(ParseOptions({"-loadblock=a", "-loadblock=b"})), "a b");
|
||||||
|
// Check passing -noloadblock clears previous values.
|
||||||
|
BOOST_CHECK_EQUAL(LoadBlockStr(ParseOptions({"-loadblock=a", "-noloadblock", "-loadblock=b", "-loadblock=c"})), "b c");
|
||||||
|
// Check passing invalid values.
|
||||||
|
BOOST_CHECK_EXCEPTION(ParseOptions({"-loadblock"}), std::exception, HasReason{"Cannot set -loadblock with no value. Please specify value with -loadblock=value. It must be set to a string."});
|
||||||
|
BOOST_CHECK_EXCEPTION(ParseOptions({"-loadblock="}), std::exception, HasReason{"-loadblock value '' is not a valid file path"});
|
||||||
|
|
||||||
|
// Check default listen value.
|
||||||
|
BOOST_CHECK_EQUAL(ListenStr(ParseOptions({})), "0.0.0.0:8333");
|
||||||
|
// Check passing -listen can set multiple values.
|
||||||
|
BOOST_CHECK_EQUAL(ListenStr(ParseOptions({"-listen=a", "-listen=b"})), "a:8333 b:8333");
|
||||||
|
// Check passing -nolisten clears previous values.
|
||||||
|
BOOST_CHECK_EQUAL(ListenStr(ParseOptions({"-listen=a", "-nolisten", "-listen=b", "-listen=c"})), "b:8333 c:8333");
|
||||||
|
// Check final -nolisten disables listening.
|
||||||
|
BOOST_CHECK_EQUAL(ListenStr(ParseOptions({"-listen=a", "-nolisten"})), "");
|
||||||
|
// Check passing invalid values.
|
||||||
|
BOOST_CHECK_EXCEPTION(ParseOptions({"-listen"}), std::exception, HasReason{"Cannot set -listen with no value. Please specify value with -listen=value. It must be set to a string."});
|
||||||
|
BOOST_CHECK_EXCEPTION(ParseOptions({"-listen="}), std::exception, HasReason{"-listen address '' is not a valid host[:port]"});
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(util_datadir)
|
BOOST_AUTO_TEST_CASE(util_datadir)
|
||||||
{
|
{
|
||||||
// Use local args variable instead of m_args to avoid making assumptions about test setup
|
// Use local args variable instead of m_args to avoid making assumptions about test setup
|
||||||
|
@ -74,6 +452,49 @@ struct TestArgsManager : public ArgsManager
|
||||||
AddArg(arg.first, "", arg.second, OptionsCategory::OPTIONS);
|
AddArg(arg.first, "", arg.second, OptionsCategory::OPTIONS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//! Return registered argument information.
|
||||||
|
Arg* FindArg(const std::string& name)
|
||||||
|
{
|
||||||
|
LOCK(cs_args);
|
||||||
|
for (auto& category : m_available_args) {
|
||||||
|
if (Arg* arg = common::FindKey(category.second, name)) {
|
||||||
|
return arg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
//! Look up current registered argument flags so they can be modified, and
|
||||||
|
//! restore them on destruction.
|
||||||
|
struct TestFlags {
|
||||||
|
TestFlags(TestArgsManager& test, const std::string& name) : arg(test.FindArg(name)) {}
|
||||||
|
~TestFlags() { if (arg) arg->m_flags = prev_flags; }
|
||||||
|
Arg* arg;
|
||||||
|
unsigned int prev_flags = arg ? arg->m_flags : 0;
|
||||||
|
};
|
||||||
|
//! Call GetArgs(), temporarily enabling ALLOW_LIST so call can succeed.
|
||||||
|
//! This is called by old tests written before ALLOW_LIST was enforced.
|
||||||
|
std::vector<std::string> TestArgList(const std::string& name)
|
||||||
|
{
|
||||||
|
TestFlags test(*this, name);
|
||||||
|
if (test.arg) test.arg->m_flags |= ALLOW_LIST;
|
||||||
|
return GetArgs(name);
|
||||||
|
}
|
||||||
|
//! Call GetArg(), temporarily disabling ALLOW_LIST so call can succeed.
|
||||||
|
//! This is called by old tests written before ALLOW_LIST was enforced.
|
||||||
|
std::string TestArgString(const std::string& name, const std::string& default_value)
|
||||||
|
{
|
||||||
|
TestFlags test(*this, name);
|
||||||
|
if (test.arg) test.arg->m_flags &= ~ALLOW_LIST;
|
||||||
|
return GetArg(name, default_value);
|
||||||
|
}
|
||||||
|
//! Call GetBoolArg(), temporarily disabling ALLOW_LIST so call can succeed.
|
||||||
|
//! This is called by old tests written before ALLOW_LIST was enforced.
|
||||||
|
bool TestArgBool(const std::string& name, bool default_value)
|
||||||
|
{
|
||||||
|
TestFlags test(*this, name);
|
||||||
|
if (test.arg) test.arg->m_flags &= ~ALLOW_LIST;
|
||||||
|
return GetBoolArg(name, default_value);
|
||||||
|
}
|
||||||
using ArgsManager::GetSetting;
|
using ArgsManager::GetSetting;
|
||||||
using ArgsManager::GetSettingsList;
|
using ArgsManager::GetSettingsList;
|
||||||
using ArgsManager::ReadConfigStream;
|
using ArgsManager::ReadConfigStream;
|
||||||
|
@ -127,7 +548,7 @@ public:
|
||||||
|
|
||||||
if (expect.error) {
|
if (expect.error) {
|
||||||
BOOST_CHECK(!success);
|
BOOST_CHECK(!success);
|
||||||
BOOST_CHECK_NE(error.find(expect.error), std::string::npos);
|
BOOST_CHECK_EQUAL(error, expect.error);
|
||||||
} else {
|
} else {
|
||||||
BOOST_CHECK(success);
|
BOOST_CHECK(success);
|
||||||
BOOST_CHECK_EQUAL(error, "");
|
BOOST_CHECK_EQUAL(error, "");
|
||||||
|
@ -137,16 +558,26 @@ public:
|
||||||
BOOST_CHECK_EQUAL(test.GetArg("-value", "zzzzz"), "zzzzz");
|
BOOST_CHECK_EQUAL(test.GetArg("-value", "zzzzz"), "zzzzz");
|
||||||
} else if (expect.string_value) {
|
} else if (expect.string_value) {
|
||||||
BOOST_CHECK_EQUAL(test.GetArg("-value", "zzzzz"), expect.string_value);
|
BOOST_CHECK_EQUAL(test.GetArg("-value", "zzzzz"), expect.string_value);
|
||||||
} else {
|
} else if (success) {
|
||||||
BOOST_CHECK(!success);
|
// Extra check to ensure complete test coverage. Assert that if
|
||||||
|
// caller did not call Expect::DefaultString() or Expect::String(),
|
||||||
|
// then this test case must be one where ParseParameters() fails, or
|
||||||
|
// one where GetArg() throws logic_error because ALLOW_STRING is not
|
||||||
|
// specified.
|
||||||
|
BOOST_CHECK_THROW(test.GetArg("-value", "zzzzz"), std::logic_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (expect.default_int) {
|
if (expect.default_int) {
|
||||||
BOOST_CHECK_EQUAL(test.GetIntArg("-value", 99999), 99999);
|
BOOST_CHECK_EQUAL(test.GetIntArg("-value", 99999), 99999);
|
||||||
} else if (expect.int_value) {
|
} else if (expect.int_value) {
|
||||||
BOOST_CHECK_EQUAL(test.GetIntArg("-value", 99999), *expect.int_value);
|
BOOST_CHECK_EQUAL(test.GetIntArg("-value", 99999), *expect.int_value);
|
||||||
} else {
|
} else if (success) {
|
||||||
BOOST_CHECK(!success);
|
// Extra check to ensure complete test coverage. Assert that if
|
||||||
|
// caller did not call Expect::DefaultInt() or Expect::Int(), then
|
||||||
|
// this test case must be one where ParseParameters() fails, or one
|
||||||
|
// where GetArg() throws logic_error because ALLOW_INT is not
|
||||||
|
// specified.
|
||||||
|
BOOST_CHECK_THROW(test.GetIntArg("-value", 99999), std::logic_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (expect.default_bool) {
|
if (expect.default_bool) {
|
||||||
|
@ -155,15 +586,21 @@ public:
|
||||||
} else if (expect.bool_value) {
|
} else if (expect.bool_value) {
|
||||||
BOOST_CHECK_EQUAL(test.GetBoolArg("-value", false), *expect.bool_value);
|
BOOST_CHECK_EQUAL(test.GetBoolArg("-value", false), *expect.bool_value);
|
||||||
BOOST_CHECK_EQUAL(test.GetBoolArg("-value", true), *expect.bool_value);
|
BOOST_CHECK_EQUAL(test.GetBoolArg("-value", true), *expect.bool_value);
|
||||||
} else {
|
} else if (success) {
|
||||||
BOOST_CHECK(!success);
|
// Extra check to ensure complete test coverage. Assert that if
|
||||||
|
// caller did not call Expect::DefaultBool() or Expect::Bool(), then
|
||||||
|
// this test case must be one where ParseParameters() fails, or one
|
||||||
|
// where GetArg() throws logic_error because ALLOW_BOOL is not
|
||||||
|
// specified.
|
||||||
|
BOOST_CHECK_THROW(test.GetBoolArg("-value", false), std::logic_error);
|
||||||
|
BOOST_CHECK_THROW(test.GetBoolArg("-value", true), std::logic_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (expect.list_value) {
|
if (expect.list_value) {
|
||||||
auto l = test.GetArgs("-value");
|
auto l = test.GetArgs("-value");
|
||||||
BOOST_CHECK_EQUAL_COLLECTIONS(l.begin(), l.end(), expect.list_value->begin(), expect.list_value->end());
|
BOOST_CHECK_EQUAL_COLLECTIONS(l.begin(), l.end(), expect.list_value->begin(), expect.list_value->end());
|
||||||
} else {
|
} else if (success) {
|
||||||
BOOST_CHECK(!success);
|
BOOST_CHECK_THROW(test.GetArgs("-value"), std::logic_error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -172,19 +609,163 @@ BOOST_FIXTURE_TEST_CASE(util_CheckValue, CheckValueTest)
|
||||||
{
|
{
|
||||||
using M = ArgsManager;
|
using M = ArgsManager;
|
||||||
|
|
||||||
CheckValue(M::ALLOW_ANY, nullptr, Expect{{}}.DefaultString().DefaultInt().DefaultBool().List({}));
|
CheckValue(M::ALLOW_ANY, nullptr, Expect{{}}.DefaultString().DefaultInt().DefaultBool());
|
||||||
CheckValue(M::ALLOW_ANY, "-novalue", Expect{false}.String("0").Int(0).Bool(false).List({}));
|
CheckValue(M::ALLOW_ANY, "-novalue", Expect{false}.String("0").Int(0).Bool(false));
|
||||||
CheckValue(M::ALLOW_ANY, "-novalue=", Expect{false}.String("0").Int(0).Bool(false).List({}));
|
CheckValue(M::ALLOW_ANY, "-novalue=", Expect{false}.String("0").Int(0).Bool(false));
|
||||||
CheckValue(M::ALLOW_ANY, "-novalue=0", Expect{true}.String("1").Int(1).Bool(true).List({"1"}));
|
CheckValue(M::ALLOW_ANY, "-novalue=0", Expect{true}.String("1").Int(1).Bool(true));
|
||||||
CheckValue(M::ALLOW_ANY, "-novalue=1", Expect{false}.String("0").Int(0).Bool(false).List({}));
|
CheckValue(M::ALLOW_ANY, "-novalue=1", Expect{false}.String("0").Int(0).Bool(false));
|
||||||
CheckValue(M::ALLOW_ANY, "-novalue=2", Expect{false}.String("0").Int(0).Bool(false).List({}));
|
CheckValue(M::ALLOW_ANY, "-novalue=2", Expect{false}.String("0").Int(0).Bool(false));
|
||||||
CheckValue(M::ALLOW_ANY, "-novalue=abc", Expect{true}.String("1").Int(1).Bool(true).List({"1"}));
|
CheckValue(M::ALLOW_ANY, "-novalue=abc", Expect{true}.String("1").Int(1).Bool(true));
|
||||||
CheckValue(M::ALLOW_ANY, "-value", Expect{""}.String("").Int(0).Bool(true).List({""}));
|
CheckValue(M::ALLOW_ANY, "-value", Expect{""}.String("").Int(0).Bool(true));
|
||||||
CheckValue(M::ALLOW_ANY, "-value=", Expect{""}.String("").Int(0).Bool(true).List({""}));
|
CheckValue(M::ALLOW_ANY, "-value=", Expect{""}.String("").Int(0).Bool(true));
|
||||||
CheckValue(M::ALLOW_ANY, "-value=0", Expect{"0"}.String("0").Int(0).Bool(false).List({"0"}));
|
CheckValue(M::ALLOW_ANY, "-value=0", Expect{"0"}.String("0").Int(0).Bool(false));
|
||||||
CheckValue(M::ALLOW_ANY, "-value=1", Expect{"1"}.String("1").Int(1).Bool(true).List({"1"}));
|
CheckValue(M::ALLOW_ANY, "-value=1", Expect{"1"}.String("1").Int(1).Bool(true));
|
||||||
CheckValue(M::ALLOW_ANY, "-value=2", Expect{"2"}.String("2").Int(2).Bool(true).List({"2"}));
|
CheckValue(M::ALLOW_ANY, "-value=2", Expect{"2"}.String("2").Int(2).Bool(true));
|
||||||
CheckValue(M::ALLOW_ANY, "-value=abc", Expect{"abc"}.String("abc").Int(0).Bool(false).List({"abc"}));
|
CheckValue(M::ALLOW_ANY, "-value=abc", Expect{"abc"}.String("abc").Int(0).Bool(false));
|
||||||
|
|
||||||
|
CheckValue(M::ALLOW_ANY | M::ALLOW_LIST, nullptr, Expect{{}}.List({}));
|
||||||
|
CheckValue(M::ALLOW_ANY | M::ALLOW_LIST, "-novalue", Expect{false}.List({}));
|
||||||
|
CheckValue(M::ALLOW_ANY | M::ALLOW_LIST, "-novalue=", Expect{false}.List({}));
|
||||||
|
CheckValue(M::ALLOW_ANY | M::ALLOW_LIST, "-novalue=0", Expect{true}.List({"1"}));
|
||||||
|
CheckValue(M::ALLOW_ANY | M::ALLOW_LIST, "-novalue=1", Expect{false}.List({}));
|
||||||
|
CheckValue(M::ALLOW_ANY | M::ALLOW_LIST, "-novalue=2", Expect{false}.List({}));
|
||||||
|
CheckValue(M::ALLOW_ANY | M::ALLOW_LIST, "-novalue=abc", Expect{true}.List({"1"}));
|
||||||
|
CheckValue(M::ALLOW_ANY | M::ALLOW_LIST, "-value", Expect{""}.List({""}));
|
||||||
|
CheckValue(M::ALLOW_ANY | M::ALLOW_LIST, "-value=", Expect{""}.List({""}));
|
||||||
|
CheckValue(M::ALLOW_ANY | M::ALLOW_LIST, "-value=0", Expect{"0"}.List({"0"}));
|
||||||
|
CheckValue(M::ALLOW_ANY | M::ALLOW_LIST, "-value=1", Expect{"1"}.List({"1"}));
|
||||||
|
CheckValue(M::ALLOW_ANY | M::ALLOW_LIST, "-value=2", Expect{"2"}.List({"2"}));
|
||||||
|
CheckValue(M::ALLOW_ANY | M::ALLOW_LIST, "-value=abc", Expect{"abc"}.List({"abc"}));
|
||||||
|
|
||||||
|
CheckValue(M::ALLOW_BOOL, nullptr, Expect{{}}.DefaultBool());
|
||||||
|
CheckValue(M::ALLOW_BOOL, "-novalue", Expect{false}.Bool(false));
|
||||||
|
CheckValue(M::ALLOW_BOOL, "-novalue=", Expect{{}}.Error("Cannot negate -value at the same time as setting a value ('')."));
|
||||||
|
CheckValue(M::ALLOW_BOOL, "-novalue=0", Expect{{}}.Error("Cannot negate -value at the same time as setting a value ('0')."));
|
||||||
|
CheckValue(M::ALLOW_BOOL, "-novalue=1", Expect{false}.Bool(false));
|
||||||
|
CheckValue(M::ALLOW_BOOL, "-novalue=2", Expect{{}}.Error("Cannot negate -value at the same time as setting a value ('2')."));
|
||||||
|
CheckValue(M::ALLOW_BOOL, "-novalue=abc", Expect{{}}.Error("Cannot negate -value at the same time as setting a value ('abc')."));
|
||||||
|
CheckValue(M::ALLOW_BOOL, "-value", Expect{true}.Bool(true));
|
||||||
|
CheckValue(M::ALLOW_BOOL, "-value=", Expect{""}.DefaultBool());
|
||||||
|
CheckValue(M::ALLOW_BOOL, "-value=0", Expect{false}.Bool(false));
|
||||||
|
CheckValue(M::ALLOW_BOOL, "-value=1", Expect{true}.Bool(true));
|
||||||
|
CheckValue(M::ALLOW_BOOL, "-value=2", Expect{{}}.Error("Cannot set -value value to '2'. It must be set to 0 or 1."));
|
||||||
|
CheckValue(M::ALLOW_BOOL, "-value=abc", Expect{{}}.Error("Cannot set -value value to 'abc'. It must be set to 0 or 1."));
|
||||||
|
|
||||||
|
CheckValue(M::ALLOW_INT, nullptr, Expect{{}}.DefaultInt());
|
||||||
|
CheckValue(M::ALLOW_INT, "-novalue", Expect{false}.Int(0));
|
||||||
|
CheckValue(M::ALLOW_INT, "-novalue=", Expect{{}}.Error("Cannot negate -value at the same time as setting a value ('')."));
|
||||||
|
CheckValue(M::ALLOW_INT, "-novalue=0", Expect{{}}.Error("Cannot negate -value at the same time as setting a value ('0')."));
|
||||||
|
CheckValue(M::ALLOW_INT, "-novalue=1", Expect{false}.Int(0));
|
||||||
|
CheckValue(M::ALLOW_INT, "-novalue=2", Expect{{}}.Error("Cannot negate -value at the same time as setting a value ('2')."));
|
||||||
|
CheckValue(M::ALLOW_INT, "-novalue=abc", Expect{{}}.Error("Cannot negate -value at the same time as setting a value ('abc')."));
|
||||||
|
CheckValue(M::ALLOW_INT, "-value", Expect{{}}.Error("Cannot set -value with no value. Please specify value with -value=value. It must be set to an integer."));
|
||||||
|
CheckValue(M::ALLOW_INT, "-value=", Expect{""}.DefaultInt());
|
||||||
|
CheckValue(M::ALLOW_INT, "-value=0", Expect{0}.Int(0));
|
||||||
|
CheckValue(M::ALLOW_INT, "-value=1", Expect{1}.Int(1));
|
||||||
|
CheckValue(M::ALLOW_INT, "-value=2", Expect{2}.Int(2));
|
||||||
|
CheckValue(M::ALLOW_INT, "-value=abc", Expect{{}}.Error("Cannot set -value value to 'abc'. It must be set to an integer."));
|
||||||
|
|
||||||
|
CheckValue(M::ALLOW_STRING, nullptr, Expect{{}}.DefaultString());
|
||||||
|
CheckValue(M::ALLOW_STRING, "-novalue", Expect{false}.String(""));
|
||||||
|
CheckValue(M::ALLOW_STRING, "-novalue=", Expect{{}}.Error("Cannot negate -value at the same time as setting a value ('')."));
|
||||||
|
CheckValue(M::ALLOW_STRING, "-novalue=0", Expect{{}}.Error("Cannot negate -value at the same time as setting a value ('0')."));
|
||||||
|
CheckValue(M::ALLOW_STRING, "-novalue=1", Expect{false}.String(""));
|
||||||
|
CheckValue(M::ALLOW_STRING, "-novalue=2", Expect{{}}.Error("Cannot negate -value at the same time as setting a value ('2')."));
|
||||||
|
CheckValue(M::ALLOW_STRING, "-novalue=abc", Expect{{}}.Error("Cannot negate -value at the same time as setting a value ('abc')."));
|
||||||
|
CheckValue(M::ALLOW_STRING, "-value", Expect{{}}.Error("Cannot set -value with no value. Please specify value with -value=value. It must be set to a string."));
|
||||||
|
CheckValue(M::ALLOW_STRING, "-value=", Expect{""}.DefaultString());
|
||||||
|
CheckValue(M::ALLOW_STRING, "-value=0", Expect{"0"}.String("0"));
|
||||||
|
CheckValue(M::ALLOW_STRING, "-value=1", Expect{"1"}.String("1"));
|
||||||
|
CheckValue(M::ALLOW_STRING, "-value=2", Expect{"2"}.String("2"));
|
||||||
|
CheckValue(M::ALLOW_STRING, "-value=abc", Expect{"abc"}.String("abc"));
|
||||||
|
|
||||||
|
CheckValue(M::ALLOW_INT | M::ALLOW_BOOL, nullptr, Expect{{}}.DefaultInt().DefaultBool());
|
||||||
|
CheckValue(M::ALLOW_INT | M::ALLOW_BOOL, "-novalue", Expect{false}.Int(0).Bool(false));
|
||||||
|
CheckValue(M::ALLOW_INT | M::ALLOW_BOOL, "-novalue=", Expect{{}}.Error("Cannot negate -value at the same time as setting a value ('')."));
|
||||||
|
CheckValue(M::ALLOW_INT | M::ALLOW_BOOL, "-novalue=0", Expect{{}}.Error("Cannot negate -value at the same time as setting a value ('0')."));
|
||||||
|
CheckValue(M::ALLOW_INT | M::ALLOW_BOOL, "-novalue=1", Expect{false}.Int(0).Bool(false));
|
||||||
|
CheckValue(M::ALLOW_INT | M::ALLOW_BOOL, "-novalue=2", Expect{{}}.Error("Cannot negate -value at the same time as setting a value ('2')."));
|
||||||
|
CheckValue(M::ALLOW_INT | M::ALLOW_BOOL, "-novalue=abc", Expect{{}}.Error("Cannot negate -value at the same time as setting a value ('abc')."));
|
||||||
|
CheckValue(M::ALLOW_INT | M::ALLOW_BOOL, "-value", Expect{true}.Int(1).Bool(true));
|
||||||
|
CheckValue(M::ALLOW_INT | M::ALLOW_BOOL, "-value=", Expect{""}.DefaultInt().DefaultBool());
|
||||||
|
CheckValue(M::ALLOW_INT | M::ALLOW_BOOL, "-value=0", Expect{0}.Int(0).DefaultBool());
|
||||||
|
CheckValue(M::ALLOW_INT | M::ALLOW_BOOL, "-value=1", Expect{1}.Int(1).DefaultBool());
|
||||||
|
CheckValue(M::ALLOW_INT | M::ALLOW_BOOL, "-value=2", Expect{2}.Int(2).DefaultBool());
|
||||||
|
CheckValue(M::ALLOW_INT | M::ALLOW_BOOL, "-value=abc", Expect{{}}.Error("Cannot set -value value to 'abc'. It must be set to an integer."));
|
||||||
|
|
||||||
|
CheckValue(M::ALLOW_STRING | M::ALLOW_BOOL, nullptr, Expect{{}}.DefaultString().DefaultBool());
|
||||||
|
CheckValue(M::ALLOW_STRING | M::ALLOW_BOOL, "-novalue", Expect{false}.String("").Bool(false));
|
||||||
|
CheckValue(M::ALLOW_STRING | M::ALLOW_BOOL, "-novalue=", Expect{{}}.Error("Cannot negate -value at the same time as setting a value ('')."));
|
||||||
|
CheckValue(M::ALLOW_STRING | M::ALLOW_BOOL, "-novalue=0", Expect{{}}.Error("Cannot negate -value at the same time as setting a value ('0')."));
|
||||||
|
CheckValue(M::ALLOW_STRING | M::ALLOW_BOOL, "-novalue=1", Expect{false}.String("").Bool(false));
|
||||||
|
CheckValue(M::ALLOW_STRING | M::ALLOW_BOOL, "-novalue=2", Expect{{}}.Error("Cannot negate -value at the same time as setting a value ('2')."));
|
||||||
|
CheckValue(M::ALLOW_STRING | M::ALLOW_BOOL, "-novalue=abc", Expect{{}}.Error("Cannot negate -value at the same time as setting a value ('abc')."));
|
||||||
|
CheckValue(M::ALLOW_STRING | M::ALLOW_BOOL, "-value", Expect{true}.DefaultString().Bool(true));
|
||||||
|
CheckValue(M::ALLOW_STRING | M::ALLOW_BOOL, "-value=", Expect{""}.DefaultString().DefaultBool());
|
||||||
|
CheckValue(M::ALLOW_STRING | M::ALLOW_BOOL, "-value=0", Expect{"0"}.String("0").DefaultBool());
|
||||||
|
CheckValue(M::ALLOW_STRING | M::ALLOW_BOOL, "-value=1", Expect{"1"}.String("1").DefaultBool());
|
||||||
|
CheckValue(M::ALLOW_STRING | M::ALLOW_BOOL, "-value=2", Expect{"2"}.String("2").DefaultBool());
|
||||||
|
CheckValue(M::ALLOW_STRING | M::ALLOW_BOOL, "-value=abc", Expect{"abc"}.String("abc").DefaultBool());
|
||||||
|
|
||||||
|
CheckValue(M::ALLOW_STRING | M::ALLOW_LIST, nullptr, Expect{{}}.List({}));
|
||||||
|
CheckValue(M::ALLOW_STRING | M::ALLOW_LIST, "-novalue", Expect{false}.List({}));
|
||||||
|
CheckValue(M::ALLOW_STRING | M::ALLOW_LIST, "-novalue=", Expect{{}}.Error("Cannot negate -value at the same time as setting a value ('')."));
|
||||||
|
CheckValue(M::ALLOW_STRING | M::ALLOW_LIST, "-novalue=0", Expect{{}}.Error("Cannot negate -value at the same time as setting a value ('0')."));
|
||||||
|
CheckValue(M::ALLOW_STRING | M::ALLOW_LIST, "-novalue=1", Expect{false}.List({}));
|
||||||
|
CheckValue(M::ALLOW_STRING | M::ALLOW_LIST, "-novalue=2", Expect{{}}.Error("Cannot negate -value at the same time as setting a value ('2')."));
|
||||||
|
CheckValue(M::ALLOW_STRING | M::ALLOW_LIST, "-novalue=abc", Expect{{}}.Error("Cannot negate -value at the same time as setting a value ('abc')."));
|
||||||
|
CheckValue(M::ALLOW_STRING | M::ALLOW_LIST, "-value", Expect{{}}.Error("Cannot set -value with no value. Please specify value with -value=value. It must be set to a string."));
|
||||||
|
CheckValue(M::ALLOW_STRING | M::ALLOW_LIST, "-value=", Expect{""}.List({""}));
|
||||||
|
CheckValue(M::ALLOW_STRING | M::ALLOW_LIST, "-value=0", Expect{"0"}.List({"0"}));
|
||||||
|
CheckValue(M::ALLOW_STRING | M::ALLOW_LIST, "-value=1", Expect{"1"}.List({"1"}));
|
||||||
|
CheckValue(M::ALLOW_STRING | M::ALLOW_LIST, "-value=2", Expect{"2"}.List({"2"}));
|
||||||
|
CheckValue(M::ALLOW_STRING | M::ALLOW_LIST, "-value=abc", Expect{"abc"}.List({"abc"}));
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_FIXTURE_TEST_CASE(util_CheckBoolStringsNotSpecial, CheckValueTest)
|
||||||
|
{
|
||||||
|
// Check that "true" and "false" strings are rejected for ALLOW_BOOL
|
||||||
|
// arguments. We might want to change this behavior in the future and
|
||||||
|
// interpret strings like "true" as true, and strings like "false" as false.
|
||||||
|
// But because it would be confusing to interpret "true" as true for
|
||||||
|
// ALLOW_BOOL arguments but false for ALLOW_ANY arguments (because
|
||||||
|
// atoi("true")==0), for now it is safer to just disallow strings like
|
||||||
|
// "true" and "false" for ALLOW_BOOL arguments as long as there are still
|
||||||
|
// other boolean arguments interpreted with ALLOW_ANY.
|
||||||
|
using M = ArgsManager;
|
||||||
|
CheckValue(M::ALLOW_BOOL, "-value=true", Expect{{}}.Error("Cannot set -value value to 'true'. It must be set to 0 or 1."));
|
||||||
|
CheckValue(M::ALLOW_BOOL, "-value=false", Expect{{}}.Error("Cannot set -value value to 'false'. It must be set to 0 or 1."));
|
||||||
|
|
||||||
|
// Similarly, check "true" and "false" are not treated specially when
|
||||||
|
// ALLOW_BOOL is combined with ALLOW_INT and ALLOW_STRING. (The only
|
||||||
|
// difference ALLOW_BOOL makes for int and string arguments is that it
|
||||||
|
// enables "-foo" syntax with no equal sign assigning explicit int or string
|
||||||
|
// values. This is useful for arguments like "-upgradewallet" or "-listen"
|
||||||
|
// that primarily toggle features on and off, but also accept optional int
|
||||||
|
// or string values to influence behavior.)
|
||||||
|
CheckValue(M::ALLOW_INT | M::ALLOW_BOOL, "-value=true", Expect{{}}.Error("Cannot set -value value to 'true'. It must be set to an integer."));
|
||||||
|
CheckValue(M::ALLOW_INT | M::ALLOW_BOOL, "-value=false", Expect{{}}.Error("Cannot set -value value to 'false'. It must be set to an integer."));
|
||||||
|
CheckValue(M::ALLOW_STRING | M::ALLOW_BOOL, "-value=true", Expect{"true"}.String("true").DefaultBool());
|
||||||
|
CheckValue(M::ALLOW_STRING | M::ALLOW_BOOL, "-value=false", Expect{"false"}.String("false").DefaultBool());
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(util_CheckSingleValue)
|
||||||
|
{
|
||||||
|
TestArgsManager test;
|
||||||
|
test.SetupArgs({{"-single", ArgsManager::ALLOW_ANY}});
|
||||||
|
std::istringstream stream("single=1\nsingle=2\n");
|
||||||
|
std::string error;
|
||||||
|
BOOST_CHECK(!test.ReadConfigStream(stream, "file.conf", error));
|
||||||
|
BOOST_CHECK_EQUAL(error, "Multiple values specified for -single in same section of config file.");
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(util_CheckBadFlagCombinations)
|
||||||
|
{
|
||||||
|
TestArgsManager test;
|
||||||
|
using M = ArgsManager;
|
||||||
|
BOOST_CHECK_THROW(test.AddArg("-arg1", "name", M::ALLOW_BOOL | M::ALLOW_ANY, OptionsCategory::OPTIONS), std::logic_error);
|
||||||
|
BOOST_CHECK_THROW(test.AddArg("-arg2", "name", M::ALLOW_BOOL | M::DISALLOW_ELISION, OptionsCategory::OPTIONS), std::logic_error);
|
||||||
|
BOOST_CHECK_THROW(test.AddArg("-arg3", "name", M::ALLOW_INT | M::ALLOW_STRING, OptionsCategory::OPTIONS), std::logic_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct NoIncludeConfTest {
|
struct NoIncludeConfTest {
|
||||||
|
@ -211,7 +792,7 @@ BOOST_AUTO_TEST_CASE(util_ParseParameters)
|
||||||
TestArgsManager testArgs;
|
TestArgsManager testArgs;
|
||||||
const auto a = std::make_pair("-a", ArgsManager::ALLOW_ANY);
|
const auto a = std::make_pair("-a", ArgsManager::ALLOW_ANY);
|
||||||
const auto b = std::make_pair("-b", ArgsManager::ALLOW_ANY);
|
const auto b = std::make_pair("-b", ArgsManager::ALLOW_ANY);
|
||||||
const auto ccc = std::make_pair("-ccc", ArgsManager::ALLOW_ANY);
|
const auto ccc = std::make_pair("-ccc", ArgsManager::ALLOW_ANY | ArgsManager::ALLOW_LIST);
|
||||||
const auto d = std::make_pair("-d", ArgsManager::ALLOW_ANY);
|
const auto d = std::make_pair("-d", ArgsManager::ALLOW_ANY);
|
||||||
|
|
||||||
const char *argv_test[] = {"-ignored", "-a", "-b", "-ccc=argument", "-ccc=multiple", "f", "-d=e"};
|
const char *argv_test[] = {"-ignored", "-a", "-b", "-ccc=argument", "-ccc=multiple", "f", "-d=e"};
|
||||||
|
@ -365,7 +946,7 @@ BOOST_AUTO_TEST_CASE(util_GetBoolArgEdgeCases)
|
||||||
TestArgsManager testArgs;
|
TestArgsManager testArgs;
|
||||||
|
|
||||||
// Params test
|
// Params test
|
||||||
const auto foo = std::make_pair("-foo", ArgsManager::ALLOW_ANY);
|
const auto foo = std::make_pair("-foo", ArgsManager::ALLOW_ANY | ArgsManager::ALLOW_LIST);
|
||||||
const auto bar = std::make_pair("-bar", ArgsManager::ALLOW_ANY);
|
const auto bar = std::make_pair("-bar", ArgsManager::ALLOW_ANY);
|
||||||
const char *argv_test[] = {"ignored", "-nofoo", "-foo", "-nobar=0"};
|
const char *argv_test[] = {"ignored", "-nofoo", "-foo", "-nobar=0"};
|
||||||
testArgs.SetupArgs({foo, bar});
|
testArgs.SetupArgs({foo, bar});
|
||||||
|
@ -374,7 +955,7 @@ BOOST_AUTO_TEST_CASE(util_GetBoolArgEdgeCases)
|
||||||
|
|
||||||
// This was passed twice, second one overrides the negative setting.
|
// This was passed twice, second one overrides the negative setting.
|
||||||
BOOST_CHECK(!testArgs.IsArgNegated("-foo"));
|
BOOST_CHECK(!testArgs.IsArgNegated("-foo"));
|
||||||
BOOST_CHECK(testArgs.GetArg("-foo", "xxx") == "");
|
BOOST_CHECK(testArgs.TestArgString("-foo", "xxx") == "");
|
||||||
|
|
||||||
// A double negative is a positive, and not marked as negated.
|
// A double negative is a positive, and not marked as negated.
|
||||||
BOOST_CHECK(!testArgs.IsArgNegated("-bar"));
|
BOOST_CHECK(!testArgs.IsArgNegated("-bar"));
|
||||||
|
@ -388,7 +969,7 @@ BOOST_AUTO_TEST_CASE(util_GetBoolArgEdgeCases)
|
||||||
// This was passed twice, second one overrides the negative setting,
|
// This was passed twice, second one overrides the negative setting,
|
||||||
// and the value.
|
// and the value.
|
||||||
BOOST_CHECK(!testArgs.IsArgNegated("-foo"));
|
BOOST_CHECK(!testArgs.IsArgNegated("-foo"));
|
||||||
BOOST_CHECK(testArgs.GetArg("-foo", "xxx") == "1");
|
BOOST_CHECK(testArgs.TestArgString("-foo", "xxx") == "1");
|
||||||
|
|
||||||
// A double negative is a positive, and does not count as negated.
|
// A double negative is a positive, and does not count as negated.
|
||||||
BOOST_CHECK(!testArgs.IsArgNegated("-bar"));
|
BOOST_CHECK(!testArgs.IsArgNegated("-bar"));
|
||||||
|
@ -402,14 +983,14 @@ BOOST_AUTO_TEST_CASE(util_GetBoolArgEdgeCases)
|
||||||
|
|
||||||
// Command line overrides, but doesn't erase old setting
|
// Command line overrides, but doesn't erase old setting
|
||||||
BOOST_CHECK(testArgs.IsArgNegated("-foo"));
|
BOOST_CHECK(testArgs.IsArgNegated("-foo"));
|
||||||
BOOST_CHECK(testArgs.GetArg("-foo", "xxx") == "0");
|
BOOST_CHECK(testArgs.TestArgString("-foo", "xxx") == "0");
|
||||||
BOOST_CHECK(testArgs.GetArgs("-foo").size() == 0);
|
BOOST_CHECK(testArgs.GetArgs("-foo").size() == 0);
|
||||||
|
|
||||||
// Command line overrides, but doesn't erase old setting
|
// Command line overrides, but doesn't erase old setting
|
||||||
BOOST_CHECK(!testArgs.IsArgNegated("-bar"));
|
BOOST_CHECK(!testArgs.IsArgNegated("-bar"));
|
||||||
BOOST_CHECK(testArgs.GetArg("-bar", "xxx") == "");
|
BOOST_CHECK(testArgs.GetArg("-bar", "xxx") == "");
|
||||||
BOOST_CHECK(testArgs.GetArgs("-bar").size() == 1
|
BOOST_CHECK(testArgs.TestArgList("-bar").size() == 1
|
||||||
&& testArgs.GetArgs("-bar").front() == "");
|
&& testArgs.TestArgList("-bar").front() == "");
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(util_ReadConfigStream)
|
BOOST_AUTO_TEST_CASE(util_ReadConfigStream)
|
||||||
|
@ -440,13 +1021,13 @@ BOOST_AUTO_TEST_CASE(util_ReadConfigStream)
|
||||||
LOCK(test_args.cs_args);
|
LOCK(test_args.cs_args);
|
||||||
const auto a = std::make_pair("-a", ArgsManager::ALLOW_ANY);
|
const auto a = std::make_pair("-a", ArgsManager::ALLOW_ANY);
|
||||||
const auto b = std::make_pair("-b", ArgsManager::ALLOW_ANY);
|
const auto b = std::make_pair("-b", ArgsManager::ALLOW_ANY);
|
||||||
const auto ccc = std::make_pair("-ccc", ArgsManager::ALLOW_ANY);
|
const auto ccc = std::make_pair("-ccc", ArgsManager::ALLOW_ANY | ArgsManager::ALLOW_LIST);
|
||||||
const auto d = std::make_pair("-d", ArgsManager::ALLOW_ANY);
|
const auto d = std::make_pair("-d", ArgsManager::ALLOW_ANY);
|
||||||
const auto e = std::make_pair("-e", ArgsManager::ALLOW_ANY);
|
const auto e = std::make_pair("-e", ArgsManager::ALLOW_ANY);
|
||||||
const auto fff = std::make_pair("-fff", ArgsManager::ALLOW_ANY);
|
const auto fff = std::make_pair("-fff", ArgsManager::ALLOW_ANY);
|
||||||
const auto ggg = std::make_pair("-ggg", ArgsManager::ALLOW_ANY);
|
const auto ggg = std::make_pair("-ggg", ArgsManager::ALLOW_ANY);
|
||||||
const auto h = std::make_pair("-h", ArgsManager::ALLOW_ANY);
|
const auto h = std::make_pair("-h", ArgsManager::ALLOW_ANY | ArgsManager::ALLOW_LIST);
|
||||||
const auto i = std::make_pair("-i", ArgsManager::ALLOW_ANY);
|
const auto i = std::make_pair("-i", ArgsManager::ALLOW_ANY | ArgsManager::ALLOW_LIST);
|
||||||
const auto iii = std::make_pair("-iii", ArgsManager::ALLOW_ANY);
|
const auto iii = std::make_pair("-iii", ArgsManager::ALLOW_ANY);
|
||||||
test_args.SetupArgs({a, b, ccc, d, e, fff, ggg, h, i, iii});
|
test_args.SetupArgs({a, b, ccc, d, e, fff, ggg, h, i, iii});
|
||||||
|
|
||||||
|
@ -486,46 +1067,46 @@ BOOST_AUTO_TEST_CASE(util_ReadConfigStream)
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(test_args.GetArg("-a", "xxx"), "");
|
BOOST_CHECK_EQUAL(test_args.GetArg("-a", "xxx"), "");
|
||||||
BOOST_CHECK_EQUAL(test_args.GetArg("-b", "xxx"), "1");
|
BOOST_CHECK_EQUAL(test_args.GetArg("-b", "xxx"), "1");
|
||||||
BOOST_CHECK_EQUAL(test_args.GetArg("-ccc", "xxx"), "argument");
|
BOOST_CHECK_EQUAL(test_args.TestArgString("-ccc", "xxx"), "argument");
|
||||||
BOOST_CHECK_EQUAL(test_args.GetArg("-d", "xxx"), "e");
|
BOOST_CHECK_EQUAL(test_args.GetArg("-d", "xxx"), "e");
|
||||||
BOOST_CHECK_EQUAL(test_args.GetArg("-fff", "xxx"), "0");
|
BOOST_CHECK_EQUAL(test_args.GetArg("-fff", "xxx"), "0");
|
||||||
BOOST_CHECK_EQUAL(test_args.GetArg("-ggg", "xxx"), "1");
|
BOOST_CHECK_EQUAL(test_args.GetArg("-ggg", "xxx"), "1");
|
||||||
BOOST_CHECK_EQUAL(test_args.GetArg("-h", "xxx"), "0");
|
BOOST_CHECK_EQUAL(test_args.TestArgString("-h", "xxx"), "0");
|
||||||
BOOST_CHECK_EQUAL(test_args.GetArg("-i", "xxx"), "1");
|
BOOST_CHECK_EQUAL(test_args.TestArgString("-i", "xxx"), "1");
|
||||||
BOOST_CHECK_EQUAL(test_args.GetArg("-zzz", "xxx"), "xxx");
|
BOOST_CHECK_EQUAL(test_args.GetArg("-zzz", "xxx"), "xxx");
|
||||||
BOOST_CHECK_EQUAL(test_args.GetArg("-iii", "xxx"), "xxx");
|
BOOST_CHECK_EQUAL(test_args.GetArg("-iii", "xxx"), "xxx");
|
||||||
|
|
||||||
for (const bool def : {false, true}) {
|
for (const bool def : {false, true}) {
|
||||||
BOOST_CHECK(test_args.GetBoolArg("-a", def));
|
BOOST_CHECK(test_args.GetBoolArg("-a", def));
|
||||||
BOOST_CHECK(test_args.GetBoolArg("-b", def));
|
BOOST_CHECK(test_args.GetBoolArg("-b", def));
|
||||||
BOOST_CHECK(!test_args.GetBoolArg("-ccc", def));
|
BOOST_CHECK(!test_args.TestArgBool("-ccc", def));
|
||||||
BOOST_CHECK(!test_args.GetBoolArg("-d", def));
|
BOOST_CHECK(!test_args.GetBoolArg("-d", def));
|
||||||
BOOST_CHECK(!test_args.GetBoolArg("-fff", def));
|
BOOST_CHECK(!test_args.GetBoolArg("-fff", def));
|
||||||
BOOST_CHECK(test_args.GetBoolArg("-ggg", def));
|
BOOST_CHECK(test_args.GetBoolArg("-ggg", def));
|
||||||
BOOST_CHECK(!test_args.GetBoolArg("-h", def));
|
BOOST_CHECK(!test_args.TestArgBool("-h", def));
|
||||||
BOOST_CHECK(test_args.GetBoolArg("-i", def));
|
BOOST_CHECK(test_args.TestArgBool("-i", def));
|
||||||
BOOST_CHECK(test_args.GetBoolArg("-zzz", def) == def);
|
BOOST_CHECK(test_args.GetBoolArg("-zzz", def) == def);
|
||||||
BOOST_CHECK(test_args.GetBoolArg("-iii", def) == def);
|
BOOST_CHECK(test_args.GetBoolArg("-iii", def) == def);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_CHECK(test_args.GetArgs("-a").size() == 1
|
BOOST_CHECK(test_args.TestArgList("-a").size() == 1
|
||||||
&& test_args.GetArgs("-a").front() == "");
|
&& test_args.TestArgList("-a").front() == "");
|
||||||
BOOST_CHECK(test_args.GetArgs("-b").size() == 1
|
BOOST_CHECK(test_args.TestArgList("-b").size() == 1
|
||||||
&& test_args.GetArgs("-b").front() == "1");
|
&& test_args.TestArgList("-b").front() == "1");
|
||||||
BOOST_CHECK(test_args.GetArgs("-ccc").size() == 2
|
BOOST_CHECK(test_args.GetArgs("-ccc").size() == 2
|
||||||
&& test_args.GetArgs("-ccc").front() == "argument"
|
&& test_args.GetArgs("-ccc").front() == "argument"
|
||||||
&& test_args.GetArgs("-ccc").back() == "multiple");
|
&& test_args.GetArgs("-ccc").back() == "multiple");
|
||||||
BOOST_CHECK(test_args.GetArgs("-fff").size() == 0);
|
BOOST_CHECK(test_args.TestArgList("-fff").size() == 0);
|
||||||
BOOST_CHECK(test_args.GetArgs("-nofff").size() == 0);
|
BOOST_CHECK(test_args.TestArgList("-nofff").size() == 0);
|
||||||
BOOST_CHECK(test_args.GetArgs("-ggg").size() == 1
|
BOOST_CHECK(test_args.TestArgList("-ggg").size() == 1
|
||||||
&& test_args.GetArgs("-ggg").front() == "1");
|
&& test_args.TestArgList("-ggg").front() == "1");
|
||||||
BOOST_CHECK(test_args.GetArgs("-noggg").size() == 0);
|
BOOST_CHECK(test_args.TestArgList("-noggg").size() == 0);
|
||||||
BOOST_CHECK(test_args.GetArgs("-h").size() == 0);
|
BOOST_CHECK(test_args.GetArgs("-h").size() == 0);
|
||||||
BOOST_CHECK(test_args.GetArgs("-noh").size() == 0);
|
BOOST_CHECK(test_args.GetArgs("-noh").size() == 0);
|
||||||
BOOST_CHECK(test_args.GetArgs("-i").size() == 1
|
BOOST_CHECK(test_args.GetArgs("-i").size() == 1
|
||||||
&& test_args.GetArgs("-i").front() == "1");
|
&& test_args.GetArgs("-i").front() == "1");
|
||||||
BOOST_CHECK(test_args.GetArgs("-noi").size() == 0);
|
BOOST_CHECK(test_args.GetArgs("-noi").size() == 0);
|
||||||
BOOST_CHECK(test_args.GetArgs("-zzz").size() == 0);
|
BOOST_CHECK(test_args.TestArgList("-zzz").size() == 0);
|
||||||
|
|
||||||
BOOST_CHECK(!test_args.IsArgNegated("-a"));
|
BOOST_CHECK(!test_args.IsArgNegated("-a"));
|
||||||
BOOST_CHECK(!test_args.IsArgNegated("-b"));
|
BOOST_CHECK(!test_args.IsArgNegated("-b"));
|
||||||
|
@ -550,9 +1131,9 @@ BOOST_AUTO_TEST_CASE(util_ReadConfigStream)
|
||||||
// d is overridden
|
// d is overridden
|
||||||
BOOST_CHECK(test_args.GetArg("-d", "xxx") == "eee");
|
BOOST_CHECK(test_args.GetArg("-d", "xxx") == "eee");
|
||||||
// section-specific setting
|
// section-specific setting
|
||||||
BOOST_CHECK(test_args.GetArg("-h", "xxx") == "1");
|
BOOST_CHECK(test_args.TestArgString("-h", "xxx") == "1");
|
||||||
// section takes priority for multiple values
|
// section takes priority for multiple values
|
||||||
BOOST_CHECK(test_args.GetArg("-ccc", "xxx") == "extend1");
|
BOOST_CHECK(test_args.TestArgString("-ccc", "xxx") == "extend1");
|
||||||
// check multiple values works
|
// check multiple values works
|
||||||
const std::vector<std::string> sec1_ccc_expected = {"extend1","extend2","argument","multiple"};
|
const std::vector<std::string> sec1_ccc_expected = {"extend1","extend2","argument","multiple"};
|
||||||
const auto& sec1_ccc_res = test_args.GetArgs("-ccc");
|
const auto& sec1_ccc_res = test_args.GetArgs("-ccc");
|
||||||
|
@ -567,11 +1148,11 @@ BOOST_AUTO_TEST_CASE(util_ReadConfigStream)
|
||||||
BOOST_CHECK(test_args.GetArg("-fff", "xxx") == "0");
|
BOOST_CHECK(test_args.GetArg("-fff", "xxx") == "0");
|
||||||
BOOST_CHECK(test_args.GetArg("-ggg", "xxx") == "1");
|
BOOST_CHECK(test_args.GetArg("-ggg", "xxx") == "1");
|
||||||
BOOST_CHECK(test_args.GetArg("-zzz", "xxx") == "xxx");
|
BOOST_CHECK(test_args.GetArg("-zzz", "xxx") == "xxx");
|
||||||
BOOST_CHECK(test_args.GetArg("-h", "xxx") == "0");
|
BOOST_CHECK(test_args.TestArgString("-h", "xxx") == "0");
|
||||||
// section-specific setting
|
// section-specific setting
|
||||||
BOOST_CHECK(test_args.GetArg("-iii", "xxx") == "2");
|
BOOST_CHECK(test_args.GetArg("-iii", "xxx") == "2");
|
||||||
// section takes priority for multiple values
|
// section takes priority for multiple values
|
||||||
BOOST_CHECK(test_args.GetArg("-ccc", "xxx") == "extend3");
|
BOOST_CHECK(test_args.TestArgString("-ccc", "xxx") == "extend3");
|
||||||
// check multiple values works
|
// check multiple values works
|
||||||
const std::vector<std::string> sec2_ccc_expected = {"extend3","argument","multiple"};
|
const std::vector<std::string> sec2_ccc_expected = {"extend3","argument","multiple"};
|
||||||
const auto& sec2_ccc_res = test_args.GetArgs("-ccc");
|
const auto& sec2_ccc_res = test_args.GetArgs("-ccc");
|
||||||
|
@ -586,19 +1167,19 @@ BOOST_AUTO_TEST_CASE(util_ReadConfigStream)
|
||||||
test_args.SelectConfigNetwork(ChainTypeToString(ChainType::MAIN));
|
test_args.SelectConfigNetwork(ChainTypeToString(ChainType::MAIN));
|
||||||
BOOST_CHECK(test_args.GetArg("-d", "xxx") == "e");
|
BOOST_CHECK(test_args.GetArg("-d", "xxx") == "e");
|
||||||
BOOST_CHECK(test_args.GetArgs("-ccc").size() == 2);
|
BOOST_CHECK(test_args.GetArgs("-ccc").size() == 2);
|
||||||
BOOST_CHECK(test_args.GetArg("-h", "xxx") == "0");
|
BOOST_CHECK(test_args.TestArgString("-h", "xxx") == "0");
|
||||||
|
|
||||||
test_args.SelectConfigNetwork("sec1");
|
test_args.SelectConfigNetwork("sec1");
|
||||||
BOOST_CHECK(test_args.GetArg("-d", "xxx") == "eee");
|
BOOST_CHECK(test_args.GetArg("-d", "xxx") == "eee");
|
||||||
BOOST_CHECK(test_args.GetArgs("-d").size() == 1);
|
BOOST_CHECK(test_args.TestArgList("-d").size() == 1);
|
||||||
BOOST_CHECK(test_args.GetArgs("-ccc").size() == 2);
|
BOOST_CHECK(test_args.GetArgs("-ccc").size() == 2);
|
||||||
BOOST_CHECK(test_args.GetArg("-h", "xxx") == "1");
|
BOOST_CHECK(test_args.TestArgString("-h", "xxx") == "1");
|
||||||
|
|
||||||
test_args.SelectConfigNetwork("sec2");
|
test_args.SelectConfigNetwork("sec2");
|
||||||
BOOST_CHECK(test_args.GetArg("-d", "xxx") == "xxx");
|
BOOST_CHECK(test_args.GetArg("-d", "xxx") == "xxx");
|
||||||
BOOST_CHECK(test_args.GetArgs("-d").size() == 0);
|
BOOST_CHECK(test_args.TestArgList("-d").size() == 0);
|
||||||
BOOST_CHECK(test_args.GetArgs("-ccc").size() == 1);
|
BOOST_CHECK(test_args.GetArgs("-ccc").size() == 1);
|
||||||
BOOST_CHECK(test_args.GetArg("-h", "xxx") == "0");
|
BOOST_CHECK(test_args.TestArgString("-h", "xxx") == "0");
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(util_GetArg)
|
BOOST_AUTO_TEST_CASE(util_GetArg)
|
||||||
|
@ -819,17 +1400,23 @@ BOOST_FIXTURE_TEST_CASE(util_ArgsMerge, ArgsMergeTestingSetup)
|
||||||
|
|
||||||
ForEachMergeSetup([&](const ActionList& arg_actions, const ActionList& conf_actions, bool soft_set, bool force_set,
|
ForEachMergeSetup([&](const ActionList& arg_actions, const ActionList& conf_actions, bool soft_set, bool force_set,
|
||||||
const std::string& section, const std::string& network, bool net_specific) {
|
const std::string& section, const std::string& network, bool net_specific) {
|
||||||
TestArgsManager parser;
|
TestArgsManager parser, single_parser;
|
||||||
LOCK(parser.cs_args);
|
LOCK(parser.cs_args);
|
||||||
|
LOCK(single_parser.cs_args);
|
||||||
|
|
||||||
std::string desc = "net=";
|
std::string desc = "net=";
|
||||||
desc += network;
|
desc += network;
|
||||||
parser.m_network = network;
|
parser.m_network = network;
|
||||||
|
single_parser.m_network = network;
|
||||||
|
|
||||||
const std::string& name = net_specific ? "wallet" : "server";
|
const std::string& name = net_specific ? "wallet" : "server";
|
||||||
const std::string key = "-" + name;
|
const std::string key = "-" + name;
|
||||||
parser.AddArg(key, name, ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
|
parser.AddArg(key, name, ArgsManager::ALLOW_ANY | ArgsManager::ALLOW_LIST, OptionsCategory::OPTIONS);
|
||||||
if (net_specific) parser.SetNetworkOnlyArg(key);
|
single_parser.AddArg(key, name, ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
|
||||||
|
if (net_specific) {
|
||||||
|
parser.SetNetworkOnlyArg(key);
|
||||||
|
single_parser.SetNetworkOnlyArg(key);
|
||||||
|
}
|
||||||
|
|
||||||
auto args = GetValues(arg_actions, section, name, "a");
|
auto args = GetValues(arg_actions, section, name, "a");
|
||||||
std::vector<const char*> argv = {"ignored"};
|
std::vector<const char*> argv = {"ignored"};
|
||||||
|
@ -842,6 +1429,8 @@ BOOST_FIXTURE_TEST_CASE(util_ArgsMerge, ArgsMergeTestingSetup)
|
||||||
std::string error;
|
std::string error;
|
||||||
BOOST_CHECK(parser.ParseParameters(argv.size(), argv.data(), error));
|
BOOST_CHECK(parser.ParseParameters(argv.size(), argv.data(), error));
|
||||||
BOOST_CHECK_EQUAL(error, "");
|
BOOST_CHECK_EQUAL(error, "");
|
||||||
|
BOOST_CHECK(single_parser.ParseParameters(argv.size(), argv.data(), error));
|
||||||
|
BOOST_CHECK_EQUAL(error, "");
|
||||||
|
|
||||||
std::string conf;
|
std::string conf;
|
||||||
for (auto& conf_val : GetValues(conf_actions, section, name, "c")) {
|
for (auto& conf_val : GetValues(conf_actions, section, name, "c")) {
|
||||||
|
@ -853,17 +1442,27 @@ BOOST_FIXTURE_TEST_CASE(util_ArgsMerge, ArgsMergeTestingSetup)
|
||||||
std::istringstream conf_stream(conf);
|
std::istringstream conf_stream(conf);
|
||||||
BOOST_CHECK(parser.ReadConfigStream(conf_stream, "filepath", error));
|
BOOST_CHECK(parser.ReadConfigStream(conf_stream, "filepath", error));
|
||||||
BOOST_CHECK_EQUAL(error, "");
|
BOOST_CHECK_EQUAL(error, "");
|
||||||
|
std::istringstream single_conf_stream(conf);
|
||||||
|
if (single_parser.ReadConfigStream(single_conf_stream, "filepath", error)) {
|
||||||
|
BOOST_CHECK_EQUAL(error, "");
|
||||||
|
} else {
|
||||||
|
BOOST_CHECK(!error.empty());
|
||||||
|
}
|
||||||
|
|
||||||
if (soft_set) {
|
if (soft_set) {
|
||||||
desc += " soft";
|
desc += " soft";
|
||||||
parser.SoftSetArg(key, "soft1");
|
parser.SoftSetArg(key, "soft1");
|
||||||
parser.SoftSetArg(key, "soft2");
|
parser.SoftSetArg(key, "soft2");
|
||||||
|
single_parser.SoftSetArg(key, "soft1");
|
||||||
|
single_parser.SoftSetArg(key, "soft2");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (force_set) {
|
if (force_set) {
|
||||||
desc += " force";
|
desc += " force";
|
||||||
parser.ForceSetArg(key, "force1");
|
parser.ForceSetArg(key, "force1");
|
||||||
parser.ForceSetArg(key, "force2");
|
parser.ForceSetArg(key, "force2");
|
||||||
|
single_parser.ForceSetArg(key, "force1");
|
||||||
|
single_parser.ForceSetArg(key, "force2");
|
||||||
}
|
}
|
||||||
|
|
||||||
desc += " || ";
|
desc += " || ";
|
||||||
|
@ -871,14 +1470,32 @@ BOOST_FIXTURE_TEST_CASE(util_ArgsMerge, ArgsMergeTestingSetup)
|
||||||
if (!parser.IsArgSet(key)) {
|
if (!parser.IsArgSet(key)) {
|
||||||
desc += "unset";
|
desc += "unset";
|
||||||
BOOST_CHECK(!parser.IsArgNegated(key));
|
BOOST_CHECK(!parser.IsArgNegated(key));
|
||||||
BOOST_CHECK_EQUAL(parser.GetArg(key, "default"), "default");
|
|
||||||
BOOST_CHECK(parser.GetArgs(key).empty());
|
BOOST_CHECK(parser.GetArgs(key).empty());
|
||||||
|
if (error.empty()) {
|
||||||
|
BOOST_CHECK(!single_parser.IsArgSet(key));
|
||||||
|
BOOST_CHECK(!single_parser.IsArgNegated(key));
|
||||||
|
BOOST_CHECK_EQUAL(single_parser.GetArg(key, "default"), "default");
|
||||||
|
} else {
|
||||||
|
desc += " / ";
|
||||||
|
desc += error;
|
||||||
|
}
|
||||||
} else if (parser.IsArgNegated(key)) {
|
} else if (parser.IsArgNegated(key)) {
|
||||||
desc += "negated";
|
desc += "negated";
|
||||||
BOOST_CHECK_EQUAL(parser.GetArg(key, "default"), "0");
|
|
||||||
BOOST_CHECK(parser.GetArgs(key).empty());
|
BOOST_CHECK(parser.GetArgs(key).empty());
|
||||||
|
if (error.empty()) {
|
||||||
|
BOOST_CHECK(single_parser.IsArgSet(key));
|
||||||
|
BOOST_CHECK(single_parser.IsArgNegated(key));
|
||||||
|
BOOST_CHECK_EQUAL(single_parser.GetArg(key, "default"), "0");
|
||||||
|
} else {
|
||||||
|
desc += " / ";
|
||||||
|
desc += error;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
desc += parser.GetArg(key, "default");
|
if (error.empty()) {
|
||||||
|
desc += single_parser.GetArg(key, "default");
|
||||||
|
} else {
|
||||||
|
desc += error;
|
||||||
|
}
|
||||||
desc += " |";
|
desc += " |";
|
||||||
for (const auto& arg : parser.GetArgs(key)) {
|
for (const auto& arg : parser.GetArgs(key)) {
|
||||||
desc += " ";
|
desc += " ";
|
||||||
|
@ -921,7 +1538,7 @@ BOOST_FIXTURE_TEST_CASE(util_ArgsMerge, ArgsMergeTestingSetup)
|
||||||
// Results file is formatted like:
|
// Results file is formatted like:
|
||||||
//
|
//
|
||||||
// <input> || <IsArgSet/IsArgNegated/GetArg output> | <GetArgs output> | <GetUnsuitable output>
|
// <input> || <IsArgSet/IsArgNegated/GetArg output> | <GetArgs output> | <GetUnsuitable output>
|
||||||
BOOST_CHECK_EQUAL(out_sha_hex, "f1ee5ab094cc43d16a6086fa7f2c10389e0f99902616b31bbf29189972ad1473");
|
BOOST_CHECK_EQUAL(out_sha_hex, "28b16f794dc598d39c3bc558cb8ed3b7bfbdb442ea118684627b520c8be9ec75");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Similar test as above, but for ArgsManager::GetChainTypeString function.
|
// Similar test as above, but for ArgsManager::GetChainTypeString function.
|
||||||
|
@ -955,8 +1572,8 @@ BOOST_FIXTURE_TEST_CASE(util_ChainMerge, ChainMergeTestingSetup)
|
||||||
ForEachMergeSetup([&](const ActionList& arg_actions, const ActionList& conf_actions) {
|
ForEachMergeSetup([&](const ActionList& arg_actions, const ActionList& conf_actions) {
|
||||||
TestArgsManager parser;
|
TestArgsManager parser;
|
||||||
LOCK(parser.cs_args);
|
LOCK(parser.cs_args);
|
||||||
parser.AddArg("-regtest", "regtest", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
|
parser.AddArg("-regtest", "regtest", ArgsManager::ALLOW_ANY | ArgsManager::ALLOW_LIST, OptionsCategory::OPTIONS);
|
||||||
parser.AddArg("-testnet", "testnet", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
|
parser.AddArg("-testnet", "testnet", ArgsManager::ALLOW_ANY | ArgsManager::ALLOW_LIST, OptionsCategory::OPTIONS);
|
||||||
|
|
||||||
auto arg = [](Action action) { return action == ENABLE_TEST ? "-testnet=1" :
|
auto arg = [](Action action) { return action == ENABLE_TEST ? "-testnet=1" :
|
||||||
action == DISABLE_TEST ? "-testnet=0" :
|
action == DISABLE_TEST ? "-testnet=0" :
|
||||||
|
|
|
@ -46,7 +46,12 @@ FUZZ_TARGET(system, .init = initialize_system)
|
||||||
[&] {
|
[&] {
|
||||||
auto str_arg = fuzzed_data_provider.ConsumeRandomLengthString(16);
|
auto str_arg = fuzzed_data_provider.ConsumeRandomLengthString(16);
|
||||||
auto str_value = fuzzed_data_provider.ConsumeRandomLengthString(16);
|
auto str_value = fuzzed_data_provider.ConsumeRandomLengthString(16);
|
||||||
args_manager.SoftSetArg(str_arg, str_value);
|
// Avoid Can't call SoftSetArg on arg registered with flags 0x8d8d8d00 (requires 0x2, disallows 0x10)
|
||||||
|
try {
|
||||||
|
args_manager.SoftSetArg(str_arg, str_value);
|
||||||
|
} catch (const std::logic_error& e) {
|
||||||
|
if (std::string_view(e.what()).find("Can't call ForceSetArg on arg") == std::string_view::npos) throw;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
[&] {
|
[&] {
|
||||||
auto str_arg = fuzzed_data_provider.ConsumeRandomLengthString(16);
|
auto str_arg = fuzzed_data_provider.ConsumeRandomLengthString(16);
|
||||||
|
@ -56,7 +61,12 @@ FUZZ_TARGET(system, .init = initialize_system)
|
||||||
[&] {
|
[&] {
|
||||||
auto str_arg = fuzzed_data_provider.ConsumeRandomLengthString(16);
|
auto str_arg = fuzzed_data_provider.ConsumeRandomLengthString(16);
|
||||||
auto f_value = fuzzed_data_provider.ConsumeBool();
|
auto f_value = fuzzed_data_provider.ConsumeBool();
|
||||||
args_manager.SoftSetBoolArg(str_arg, f_value);
|
// Avoid Can't call SoftSetBoolArg on arg registered with flags 0x8d8d8d00 (requires 0x2, disallows 0x10)
|
||||||
|
try {
|
||||||
|
args_manager.SoftSetBoolArg(str_arg, f_value);
|
||||||
|
} catch (const std::logic_error& e) {
|
||||||
|
if (std::string_view(e.what()).find("Can't call SoftSetBoolArg on arg") == std::string_view::npos) throw;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
[&] {
|
[&] {
|
||||||
const OptionsCategory options_category = fuzzed_data_provider.PickValueInArray<OptionsCategory>({OptionsCategory::OPTIONS, OptionsCategory::CONNECTION, OptionsCategory::WALLET, OptionsCategory::WALLET_DEBUG_TEST, OptionsCategory::ZMQ, OptionsCategory::DEBUG_TEST, OptionsCategory::CHAINPARAMS, OptionsCategory::NODE_RELAY, OptionsCategory::BLOCK_CREATION, OptionsCategory::RPC, OptionsCategory::GUI, OptionsCategory::COMMANDS, OptionsCategory::REGISTER_COMMANDS, OptionsCategory::CLI_COMMANDS, OptionsCategory::IPC, OptionsCategory::HIDDEN});
|
const OptionsCategory options_category = fuzzed_data_provider.PickValueInArray<OptionsCategory>({OptionsCategory::OPTIONS, OptionsCategory::CONNECTION, OptionsCategory::WALLET, OptionsCategory::WALLET_DEBUG_TEST, OptionsCategory::ZMQ, OptionsCategory::DEBUG_TEST, OptionsCategory::CHAINPARAMS, OptionsCategory::NODE_RELAY, OptionsCategory::BLOCK_CREATION, OptionsCategory::RPC, OptionsCategory::GUI, OptionsCategory::COMMANDS, OptionsCategory::REGISTER_COMMANDS, OptionsCategory::CLI_COMMANDS, OptionsCategory::IPC, OptionsCategory::HIDDEN});
|
||||||
|
@ -68,6 +78,10 @@ FUZZ_TARGET(system, .init = initialize_system)
|
||||||
}
|
}
|
||||||
auto help = fuzzed_data_provider.ConsumeRandomLengthString(16);
|
auto help = fuzzed_data_provider.ConsumeRandomLengthString(16);
|
||||||
auto flags = fuzzed_data_provider.ConsumeIntegral<unsigned int>() & ~ArgsManager::COMMAND;
|
auto flags = fuzzed_data_provider.ConsumeIntegral<unsigned int>() & ~ArgsManager::COMMAND;
|
||||||
|
// Avoid hitting "ALLOW_INT flag is incompatible with ALLOW_STRING", etc exceptions
|
||||||
|
if (flags & ArgsManager::ALLOW_ANY) flags &= ~(ArgsManager::ALLOW_BOOL | ArgsManager::ALLOW_INT | ArgsManager::ALLOW_STRING);
|
||||||
|
if (flags & ArgsManager::ALLOW_BOOL) flags &= ~ArgsManager::DISALLOW_ELISION;
|
||||||
|
if (flags & ArgsManager::ALLOW_STRING) flags &= ~ArgsManager::ALLOW_INT;
|
||||||
args_manager.AddArg(argument_name, help, flags, options_category);
|
args_manager.AddArg(argument_name, help, flags, options_category);
|
||||||
},
|
},
|
||||||
[&] {
|
[&] {
|
||||||
|
@ -110,11 +124,27 @@ FUZZ_TARGET(system, .init = initialize_system)
|
||||||
const int64_t i64 = fuzzed_data_provider.ConsumeIntegral<int64_t>();
|
const int64_t i64 = fuzzed_data_provider.ConsumeIntegral<int64_t>();
|
||||||
const bool b = fuzzed_data_provider.ConsumeBool();
|
const bool b = fuzzed_data_provider.ConsumeBool();
|
||||||
|
|
||||||
(void)args_manager.GetIntArg(s1, i64);
|
try {
|
||||||
(void)args_manager.GetArg(s1, s2);
|
(void)args_manager.GetIntArg(s1, i64);
|
||||||
|
} catch (const std::logic_error& e) {
|
||||||
|
if (std::string_view(e.what()).find("Can't call GetIntArg on arg") == std::string_view::npos) throw;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
(void)args_manager.GetArg(s1, s2);
|
||||||
|
} catch (const std::logic_error& e) {
|
||||||
|
if (std::string_view(e.what()).find("Can't call GetArg on arg") == std::string_view::npos) throw;
|
||||||
|
}
|
||||||
(void)args_manager.GetArgFlags(s1);
|
(void)args_manager.GetArgFlags(s1);
|
||||||
(void)args_manager.GetArgs(s1);
|
try {
|
||||||
(void)args_manager.GetBoolArg(s1, b);
|
(void)args_manager.GetArgs(s1);
|
||||||
|
} catch (const std::logic_error& e) {
|
||||||
|
if (std::string_view(e.what()).find("Can't call GetArgs on arg") == std::string_view::npos) throw;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
(void)args_manager.GetBoolArg(s1, b);
|
||||||
|
} catch (const std::logic_error& e) {
|
||||||
|
if (std::string_view(e.what()).find("Can't call GetBoolArg on arg") == std::string_view::npos) throw;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
(void)args_manager.GetChainTypeString();
|
(void)args_manager.GetChainTypeString();
|
||||||
} catch (const std::runtime_error&) {
|
} catch (const std::runtime_error&) {
|
||||||
|
|
|
@ -52,9 +52,11 @@ void SetupArgs(ArgsManager& local_args, const std::vector<std::pair<std::string,
|
||||||
// functions. The GetSetting method can always be used instead of GetArg
|
// functions. The GetSetting method can always be used instead of GetArg
|
||||||
// methods to retrieve original values, and there's not always an objective
|
// methods to retrieve original values, and there's not always an objective
|
||||||
// answer to what GetArg behavior is best in every case. This test makes sure
|
// answer to what GetArg behavior is best in every case. This test makes sure
|
||||||
// there's test coverage for whatever the current behavior is, so it's not
|
// there's test coverage for the current behavior with ALLOW_ANY flag, so
|
||||||
// broken or changed unintentionally.
|
// it's not broken or changed unintentionally. Additional test cases with
|
||||||
BOOST_AUTO_TEST_CASE(setting_args)
|
// flags other than ALLOW_ANY can be found in the setting_arg_allow_types
|
||||||
|
// test below.
|
||||||
|
BOOST_AUTO_TEST_CASE(setting_args_allow_any)
|
||||||
{
|
{
|
||||||
ArgsManager args;
|
ArgsManager args;
|
||||||
SetupArgs(args, {{"-foo", ArgsManager::ALLOW_ANY}});
|
SetupArgs(args, {{"-foo", ArgsManager::ALLOW_ANY}});
|
||||||
|
@ -157,6 +159,62 @@ BOOST_AUTO_TEST_CASE(setting_args)
|
||||||
BOOST_CHECK_EQUAL(args.GetBoolArg("foo", false), false);
|
BOOST_CHECK_EQUAL(args.GetBoolArg("foo", false), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test behavior of GetArg functions with a settings.json file when
|
||||||
|
// ALLOW_BOOL and ALLOW_INT flags are specified, in contrast to
|
||||||
|
// setting_args_allow_any test above, which tests legacy behavior with the
|
||||||
|
// ALLOW_ANY flag.
|
||||||
|
//
|
||||||
|
// Currently, the ReadSettingsFile() function ignores type flags and just copies
|
||||||
|
// JSON values in the file directly into the Settings::rw_settings map without
|
||||||
|
// converting the values to types specified by the flags, or returning errors if
|
||||||
|
// the values were invalid and couldn't be converted. In the future it would be
|
||||||
|
// nice to improve ReadSettingsFile() to use the flags so the parsing could be
|
||||||
|
// more robust and return errors if problems were detected. This test could be
|
||||||
|
// extended in that case.
|
||||||
|
BOOST_AUTO_TEST_CASE(setting_args_allow_types)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
ArgsManager args;
|
||||||
|
args.LockSettings([&](common::Settings& settings) {
|
||||||
|
settings.rw_settings["boolarg1"] = true;
|
||||||
|
settings.rw_settings["boolarg2"] = false;
|
||||||
|
});
|
||||||
|
args.ForceSetArg("-datadir", fs::PathToString(m_path_root));
|
||||||
|
BOOST_CHECK(args.WriteSettingsFile());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
ArgsManager args;
|
||||||
|
args.ForceSetArg("-datadir", fs::PathToString(m_path_root));
|
||||||
|
BOOST_CHECK(args.ReadSettingsFile());
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(args.GetSetting("-boolarg1").write(), "true");
|
||||||
|
BOOST_CHECK_EQUAL(args.GetSetting("-boolarg2").write(), "false");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
ArgsManager args;
|
||||||
|
args.AddArg("-boolarg1", "", ArgsManager::ALLOW_BOOL, OptionsCategory::OPTIONS);
|
||||||
|
args.AddArg("-boolarg2", "", ArgsManager::ALLOW_BOOL, OptionsCategory::OPTIONS);
|
||||||
|
args.ForceSetArg("-datadir", fs::PathToString(m_path_root));
|
||||||
|
BOOST_CHECK(args.ReadSettingsFile());
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(args.GetBoolArg("-boolarg1").value(), true);
|
||||||
|
BOOST_CHECK_EQUAL(args.GetBoolArg("-boolarg2").value(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
ArgsManager args;
|
||||||
|
args.AddArg("-boolarg1", "", ArgsManager::ALLOW_INT, OptionsCategory::OPTIONS);
|
||||||
|
args.AddArg("-boolarg2", "", ArgsManager::ALLOW_INT, OptionsCategory::OPTIONS);
|
||||||
|
args.ForceSetArg("-datadir", fs::PathToString(m_path_root));
|
||||||
|
BOOST_CHECK(args.ReadSettingsFile());
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(args.GetIntArg("-boolarg1").value(), 1);
|
||||||
|
BOOST_CHECK_EQUAL(args.GetIntArg("-boolarg2").value(), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(boolarg)
|
BOOST_AUTO_TEST_CASE(boolarg)
|
||||||
{
|
{
|
||||||
ArgsManager local_args;
|
ArgsManager local_args;
|
||||||
|
|
|
@ -221,7 +221,7 @@ BOOST_FIXTURE_TEST_CASE(logging_Conf, LogSetup)
|
||||||
{
|
{
|
||||||
ResetLogger();
|
ResetLogger();
|
||||||
ArgsManager args;
|
ArgsManager args;
|
||||||
args.AddArg("-loglevel", "...", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
|
args.AddArg("-loglevel", "...", ArgsManager::ALLOW_ANY | ArgsManager::ALLOW_LIST, OptionsCategory::DEBUG_TEST);
|
||||||
const char* argv_test[] = {"bitcoind", "-loglevel=debug"};
|
const char* argv_test[] = {"bitcoind", "-loglevel=debug"};
|
||||||
std::string err;
|
std::string err;
|
||||||
BOOST_REQUIRE(args.ParseParameters(2, argv_test, err));
|
BOOST_REQUIRE(args.ParseParameters(2, argv_test, err));
|
||||||
|
@ -235,7 +235,7 @@ BOOST_FIXTURE_TEST_CASE(logging_Conf, LogSetup)
|
||||||
{
|
{
|
||||||
ResetLogger();
|
ResetLogger();
|
||||||
ArgsManager args;
|
ArgsManager args;
|
||||||
args.AddArg("-loglevel", "...", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
|
args.AddArg("-loglevel", "...", ArgsManager::ALLOW_ANY | ArgsManager::ALLOW_LIST, OptionsCategory::DEBUG_TEST);
|
||||||
const char* argv_test[] = {"bitcoind", "-loglevel=net:trace"};
|
const char* argv_test[] = {"bitcoind", "-loglevel=net:trace"};
|
||||||
std::string err;
|
std::string err;
|
||||||
BOOST_REQUIRE(args.ParseParameters(2, argv_test, err));
|
BOOST_REQUIRE(args.ParseParameters(2, argv_test, err));
|
||||||
|
@ -254,7 +254,7 @@ BOOST_FIXTURE_TEST_CASE(logging_Conf, LogSetup)
|
||||||
{
|
{
|
||||||
ResetLogger();
|
ResetLogger();
|
||||||
ArgsManager args;
|
ArgsManager args;
|
||||||
args.AddArg("-loglevel", "...", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
|
args.AddArg("-loglevel", "...", ArgsManager::ALLOW_ANY | ArgsManager::ALLOW_LIST, OptionsCategory::DEBUG_TEST);
|
||||||
const char* argv_test[] = {"bitcoind", "-loglevel=debug", "-loglevel=net:trace", "-loglevel=http:info"};
|
const char* argv_test[] = {"bitcoind", "-loglevel=debug", "-loglevel=net:trace", "-loglevel=http:info"};
|
||||||
std::string err;
|
std::string err;
|
||||||
BOOST_REQUIRE(args.ParseParameters(4, argv_test, err));
|
BOOST_REQUIRE(args.ParseParameters(4, argv_test, err));
|
||||||
|
|
|
@ -286,6 +286,10 @@ inline std::ostream& operator<<(std::ostream& os, const std::optional<T>& v)
|
||||||
return v ? os << *v
|
return v ? os << *v
|
||||||
: os << "std::nullopt";
|
: os << "std::nullopt";
|
||||||
}
|
}
|
||||||
|
inline std::ostream& operator<<(std::ostream& os, const std::nullopt_t)
|
||||||
|
{
|
||||||
|
return os << "std::nullopt";
|
||||||
|
}
|
||||||
} // namespace std
|
} // namespace std
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& os, const arith_uint256& num);
|
std::ostream& operator<<(std::ostream& os, const arith_uint256& num);
|
||||||
|
|
|
@ -73,7 +73,7 @@ void WalletInit::AddWalletOptions(ArgsManager& argsman) const
|
||||||
#endif
|
#endif
|
||||||
argsman.AddArg("-spendzeroconfchange", strprintf("Spend unconfirmed change when sending transactions (default: %u)", DEFAULT_SPEND_ZEROCONF_CHANGE), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
|
argsman.AddArg("-spendzeroconfchange", strprintf("Spend unconfirmed change when sending transactions (default: %u)", DEFAULT_SPEND_ZEROCONF_CHANGE), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
|
||||||
argsman.AddArg("-txconfirmtarget=<n>", strprintf("If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u)", DEFAULT_TX_CONFIRM_TARGET), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
|
argsman.AddArg("-txconfirmtarget=<n>", strprintf("If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u)", DEFAULT_TX_CONFIRM_TARGET), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
|
||||||
argsman.AddArg("-wallet=<path>", "Specify wallet path to load at startup. Can be used multiple times to load multiple wallets. Path is to a directory containing wallet data and log files. If the path is not absolute, it is interpreted relative to <walletdir>. This only loads existing wallets and does not create new ones. For backwards compatibility this also accepts names of existing top-level data files in <walletdir>.", ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::WALLET);
|
argsman.AddArg("-wallet=<path>", "Specify wallet path to load at startup. Can be used multiple times to load multiple wallets. Path is to a directory containing wallet data and log files. If the path is not absolute, it is interpreted relative to <walletdir>. This only loads existing wallets and does not create new ones. For backwards compatibility this also accepts names of existing top-level data files in <walletdir>.", ArgsManager::ALLOW_ANY | ArgsManager::ALLOW_LIST | ArgsManager::NETWORK_ONLY, OptionsCategory::WALLET);
|
||||||
argsman.AddArg("-walletbroadcast", strprintf("Make the wallet broadcast transactions (default: %u)", DEFAULT_WALLETBROADCAST), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
|
argsman.AddArg("-walletbroadcast", strprintf("Make the wallet broadcast transactions (default: %u)", DEFAULT_WALLETBROADCAST), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
|
||||||
argsman.AddArg("-walletdir=<dir>", "Specify directory to hold wallets (default: <datadir>/wallets if it exists, otherwise <datadir>)", ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::WALLET);
|
argsman.AddArg("-walletdir=<dir>", "Specify directory to hold wallets (default: <datadir>/wallets if it exists, otherwise <datadir>)", ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::WALLET);
|
||||||
#if HAVE_SYSTEM
|
#if HAVE_SYSTEM
|
||||||
|
|
|
@ -216,7 +216,7 @@ class ConfArgsTest(BitcoinTestFramework):
|
||||||
|
|
||||||
def test_invalid_command_line_options(self):
|
def test_invalid_command_line_options(self):
|
||||||
self.nodes[0].assert_start_raises_init_error(
|
self.nodes[0].assert_start_raises_init_error(
|
||||||
expected_msg='Error: Error parsing command line arguments: Can not set -proxy with no value. Please specify value with -proxy=value.',
|
expected_msg='Error: Error parsing command line arguments: Cannot set -proxy with no value. Please specify value with -proxy=value.',
|
||||||
extra_args=['-proxy'],
|
extra_args=['-proxy'],
|
||||||
)
|
)
|
||||||
# Provide a value different from 1 to the -wallet negated option
|
# Provide a value different from 1 to the -wallet negated option
|
||||||
|
|
|
@ -14,11 +14,12 @@ from subprocess import check_output
|
||||||
import re
|
import re
|
||||||
|
|
||||||
FOLDER_GREP = 'src'
|
FOLDER_GREP = 'src'
|
||||||
FOLDER_TEST = 'src/test/'
|
EXCLUDE_PATHS = ['src/test/', 'src/common/args.h']
|
||||||
|
EXCLUDE_ARGS = ' '.join(f"':(exclude){path}'" for path in EXCLUDE_PATHS)
|
||||||
REGEX_ARG = r'\b(?:GetArg|GetArgs|GetBoolArg|GetIntArg|GetPathArg|IsArgSet|get_net)\("(-[^"]+)"'
|
REGEX_ARG = r'\b(?:GetArg|GetArgs|GetBoolArg|GetIntArg|GetPathArg|IsArgSet|get_net)\("(-[^"]+)"'
|
||||||
REGEX_DOC = r'AddArg\("(-[^"=]+?)(?:=|")'
|
REGEX_DOC = r'AddArg\("(-[^"=]+?)(?:=|")'
|
||||||
CMD_ROOT_DIR = '$(git rev-parse --show-toplevel)/{}'.format(FOLDER_GREP)
|
CMD_ROOT_DIR = '$(git rev-parse --show-toplevel)/{}'.format(FOLDER_GREP)
|
||||||
CMD_GREP_ARGS = r"git grep --perl-regexp '{}' -- {} ':(exclude){}'".format(REGEX_ARG, CMD_ROOT_DIR, FOLDER_TEST)
|
CMD_GREP_ARGS = f"git grep --perl-regexp '{REGEX_ARG}' -- {CMD_ROOT_DIR} {EXCLUDE_ARGS}"
|
||||||
CMD_GREP_WALLET_ARGS = r"git grep --function-context 'void WalletInit::AddWalletOptions' -- {} | grep AddArg".format(CMD_ROOT_DIR)
|
CMD_GREP_WALLET_ARGS = r"git grep --function-context 'void WalletInit::AddWalletOptions' -- {} | grep AddArg".format(CMD_ROOT_DIR)
|
||||||
CMD_GREP_WALLET_HIDDEN_ARGS = r"git grep --function-context 'void DummyWalletInit::AddWalletOptions' -- {}".format(CMD_ROOT_DIR)
|
CMD_GREP_WALLET_HIDDEN_ARGS = r"git grep --function-context 'void DummyWalletInit::AddWalletOptions' -- {}".format(CMD_ROOT_DIR)
|
||||||
CMD_GREP_DOCS = r"git grep --perl-regexp '{}' {}".format(REGEX_DOC, CMD_ROOT_DIR)
|
CMD_GREP_DOCS = r"git grep --perl-regexp '{}' {}".format(REGEX_DOC, CMD_ROOT_DIR)
|
||||||
|
|
Loading…
Add table
Reference in a new issue