From 6e7e9e3d34467f9b0b61d3a91becc892ec7f5e6b Mon Sep 17 00:00:00 2001 From: Anthony Towns Date: Wed, 23 Aug 2023 15:12:36 +1000 Subject: [PATCH 1/6] config: separate base and non-base chainparams config options --- src/chainparams.cpp | 9 +++++++++ src/chainparams.h | 5 +++++ src/chainparamsbase.cpp | 4 ---- src/init.cpp | 1 + 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 539578085b5a..75ae98ebf6b3 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -21,6 +21,15 @@ #include #include +void SetupChainParamsOptions(ArgsManager& argsman) +{ + 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("-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("-signetchallenge", "Blocks must satisfy the given script to be considered valid (only for signet networks; defaults to the global default signet test network challenge)", ArgsManager::ALLOW_ANY | ArgsManager::DISALLOW_NEGATION, OptionsCategory::CHAINPARAMS); + argsman.AddArg("-signetseednode", "Specify a seed node for the signet network, in the hostname[:port] format, e.g. sig.net:1234 (may be used multiple times to specify multiple seed nodes; defaults to the global default signet test network seed node(s))", ArgsManager::ALLOW_ANY | ArgsManager::DISALLOW_NEGATION, OptionsCategory::CHAINPARAMS); +} + + void ReadSigNetArgs(const ArgsManager& args, CChainParams::SigNetOptions& options) { if (args.IsArgSet("-signetseednode")) { diff --git a/src/chainparams.h b/src/chainparams.h index 4743e022dbbb..6c2f9bfb3bb4 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -12,6 +12,11 @@ class ArgsManager; +/** + * Setup configuration options + */ +void SetupChainParamsOptions(ArgsManager& argsman); + /** * Creates and returns a std::unique_ptr of the chosen chain. */ diff --git a/src/chainparamsbase.cpp b/src/chainparamsbase.cpp index 8cbf9e85e0ca..9bd4aac9ec9d 100644 --- a/src/chainparamsbase.cpp +++ b/src/chainparamsbase.cpp @@ -16,12 +16,8 @@ void SetupChainParamsBaseOptions(ArgsManager& argsman) argsman.AddArg("-chain=", "Use the chain (default: main). Allowed values: main, test, signet, regtest", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS); argsman.AddArg("-regtest", "Enter regression test mode, which uses a special chain in which blocks can be solved instantly. " "This is intended for regression testing tools and app development. Equivalent to -chain=regtest.", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CHAINPARAMS); - argsman.AddArg("-testactivationheight=name@height.", "Set the activation height of 'name' (segwit, bip34, dersig, cltv, csv). (regtest-only)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); argsman.AddArg("-testnet", "Use the test chain. Equivalent to -chain=test.", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS); - argsman.AddArg("-vbparams=deployment:start:end[:min_activation_height]", "Use given start/end times and min_activation_height for specified version bits deployment (regtest-only)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CHAINPARAMS); argsman.AddArg("-signet", "Use the signet chain. Equivalent to -chain=signet. Note that the network is defined by the -signetchallenge parameter", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS); - argsman.AddArg("-signetchallenge", "Blocks must satisfy the given script to be considered valid (only for signet networks; defaults to the global default signet test network challenge)", ArgsManager::ALLOW_ANY | ArgsManager::DISALLOW_NEGATION, OptionsCategory::CHAINPARAMS); - argsman.AddArg("-signetseednode", "Specify a seed node for the signet network, in the hostname[:port] format, e.g. sig.net:1234 (may be used multiple times to specify multiple seed nodes; defaults to the global default signet test network seed node(s))", ArgsManager::ALLOW_ANY | ArgsManager::DISALLOW_NEGATION, OptionsCategory::CHAINPARAMS); } static std::unique_ptr globalChainBaseParams; diff --git a/src/init.cpp b/src/init.cpp index 864c2e278b18..9e8c49ba9fe3 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -584,6 +584,7 @@ void SetupServerArgs(ArgsManager& argsman) argsman.AddArg("-uacomment=", "Append comment to the user agent string", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); SetupChainParamsBaseOptions(argsman); + SetupChainParamsOptions(argsman); argsman.AddArg("-acceptnonstdtxn", strprintf("Relay and mine \"non-standard\" transactions (%sdefault: %u)", "testnet/regtest only; ", !testnetChainParams->RequireStandard()), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::NODE_RELAY); argsman.AddArg("-incrementalrelayfee=", strprintf("Fee rate (in %s/kvB) used to define cost of relay, used for mempool limiting and replacement policy. (default: %s)", CURRENCY_UNIT, FormatMoney(DEFAULT_INCREMENTAL_RELAY_FEE)), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::NODE_RELAY); From 059861c0080dcbb5eb9817a3a1a47ce95aece3af Mon Sep 17 00:00:00 2001 From: Anthony Towns Date: Wed, 23 Aug 2023 18:30:51 +1000 Subject: [PATCH 2/6] chainparams: move -fastprune definition into chainparams.cpp --- src/chainparams.cpp | 1 + src/init.cpp | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 75ae98ebf6b3..9b7ae003e2a5 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -23,6 +23,7 @@ void SetupChainParamsOptions(ArgsManager& argsman) { + argsman.AddArg("-fastprune", "Use smaller block files and lower minimum prune height for testing purposes", 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::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); 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("-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); diff --git a/src/init.cpp b/src/init.cpp index 9e8c49ba9fe3..459f3c857bb5 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -436,7 +436,6 @@ void SetupServerArgs(ArgsManager& argsman) #endif argsman.AddArg("-assumevalid=", strprintf("If this block is in the chain assume that it and its ancestors are valid and potentially skip their script verification (0 to verify all, default: %s, testnet: %s, signet: %s)", defaultChainParams->GetConsensus().defaultAssumeValid.GetHex(), testnetChainParams->GetConsensus().defaultAssumeValid.GetHex(), signetChainParams->GetConsensus().defaultAssumeValid.GetHex()), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsman.AddArg("-blocksdir=", "Specify directory to hold blocks subdirectory for *.dat files (default: )", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - argsman.AddArg("-fastprune", "Use smaller block files and lower minimum prune height for testing purposes", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); #if HAVE_SYSTEM argsman.AddArg("-blocknotify=", "Execute command when the best block changes (%s in cmd is replaced by block hash)", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); #endif From 28ddd97e567a9ef7aacccc9441469fb6a30b1e01 Mon Sep 17 00:00:00 2001 From: Anthony Towns Date: Wed, 23 Aug 2023 18:32:19 +1000 Subject: [PATCH 3/6] chainparams: put -vbparams in DEBUG_TEST category --- src/chainparams.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 9b7ae003e2a5..81d2a10b9cac 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -25,7 +25,7 @@ void SetupChainParamsOptions(ArgsManager& argsman) { argsman.AddArg("-fastprune", "Use smaller block files and lower minimum prune height for testing purposes", 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::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); - 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::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); argsman.AddArg("-signetchallenge", "Blocks must satisfy the given script to be considered valid (only for signet networks; defaults to the global default signet test network challenge)", ArgsManager::ALLOW_ANY | ArgsManager::DISALLOW_NEGATION, OptionsCategory::CHAINPARAMS); argsman.AddArg("-signetseednode", "Specify a seed node for the signet network, in the hostname[:port] format, e.g. sig.net:1234 (may be used multiple times to specify multiple seed nodes; defaults to the global default signet test network seed node(s))", ArgsManager::ALLOW_ANY | ArgsManager::DISALLOW_NEGATION, OptionsCategory::CHAINPARAMS); } From 7cb67a694e82c52b71ec86d23cb574465f9aad22 Mon Sep 17 00:00:00 2001 From: Anthony Towns Date: Wed, 23 Aug 2023 15:48:36 +1000 Subject: [PATCH 4/6] args: add ArgsRegister --- src/Makefile.am | 1 + src/common/args.cpp | 22 ++++++ src/common/args.h | 20 +++++ src/common/argsregister.h | 151 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 194 insertions(+) create mode 100644 src/common/argsregister.h diff --git a/src/Makefile.am b/src/Makefile.am index feed4a0061cd..743e0101c3cc 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -136,6 +136,7 @@ BITCOIN_CORE_H = \ clientversion.h \ coins.h \ common/args.h \ + common/argsregister.h \ common/bloom.h \ common/init.h \ common/run_command.h \ diff --git a/src/common/args.cpp b/src/common/args.cpp index 643838399fc5..f043294e070c 100644 --- a/src/common/args.cpp +++ b/src/common/args.cpp @@ -489,6 +489,28 @@ std::optional ArgsManager::GetIntArg(const std::string& strArg) const return SettingToInt(value); } +template<> +std::optional ArgsManager::Get(const std::string& arg) const +{ + return GetArg(arg); +} + +template<> +std::optional ArgsManager::Get(const std::string& arg) const +{ + return GetBoolArg(arg); +} + +template<> +std::optional> ArgsManager::Get>(const std::string& arg) const +{ + std::optional> result{GetArgs(arg)}; + if (result.has_value() && result.value().empty()) { + result.reset(); + } + return result; +} + std::optional SettingToInt(const common::SettingsValue& value) { if (value.isNull()) return std::nullopt; diff --git a/src/common/args.h b/src/common/args.h index ae3ed02bc7df..e7ccce22c5a5 100644 --- a/src/common/args.h +++ b/src/common/args.h @@ -260,6 +260,15 @@ class ArgsManager */ bool IsArgNegated(const std::string& strArg) const; + /** + * Return typed argument if present + * + * @param arg Argument to get (e.g. "-foo") + * @return command-line argument or nullopt + */ + template + std::optional Get(const std::string& arg) const; + /** * Return string argument or default value * @@ -343,6 +352,17 @@ class ArgsManager */ void AddArg(const std::string& name, const std::string& help, unsigned int flags, const OptionsCategory& cat); + /** + * Add typed argument + */ + template + void AddTypedArg(const std::string& name, const std::string& help, unsigned int flags, const OptionsCategory& cat) + { + // able to asssociate type information with argument directly in future, + // eg specialise AddTypedArg> to call AddArg(name, help, flags|ALLOW_LIST, cat). + AddArg(name, help, flags, cat); + } + /** * Add subcommand */ diff --git a/src/common/argsregister.h b/src/common/argsregister.h new file mode 100644 index 000000000000..80d67dcd75fc --- /dev/null +++ b/src/common/argsregister.h @@ -0,0 +1,151 @@ +// Copyright (c) 2023 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_COMMON_ARGSREGISTER_H +#define BITCOIN_COMMON_ARGSREGISTER_H + +#include + +#include + +/** Typesafe args registration. */ + +/** Example usage: + +constexpr bool DEFAULT_FOO_A{true}; + +struct FooOpts { + bool a{DEFAULT_FOO_A}; + std::optional b; + std::vector c; + Custom d; +}; + +class FooRegister +{ +public: + using T = CChainParams::SigNetOptions; + + static inline void GetD(Custom& d, const std::string& arg_d); + + template + static inline void Register(Op& op) + { + return C::Do(op, + C::Defn(&T::a, "-fooa", "", + "Description of option A", + ArgsManager::ALLOW_ANY | ArgsManager::DISALLOW_NEGATION, + OptionsCategory::DEBUG_TEST), + C::Defn(&T::b, "-foob", "=bar", + "Description of option B", + ArgsManager::ALLOW_ANY, + OptionsCategory::DEBUG_TEST), + C::Defn(&T::c, "-foob", "=bar", + "Description of option B", + ArgsManager::ALLOW_ANY, + OptionsCategory::DEBUG_TEST), + C::Defn(&T::d, "-foob", "=bar", GetD, + "Description of option B", + ArgsManager::ALLOW_ANY, + OptionsCategory::DEBUG_TEST) + ); + } +}; + +void SetupFooOptions(ArgsManager& argsman) +{ + ArgsRegister::Register(argsman); +} + +void ReadFooArgs(const ArgsManager& args, FooOpts& options) +{ + ArgsRegister::Update(args, options); +} + +**/ + +template +class ArgsRegister +{ +public: + using STRUCT = typename REG::T; + + static inline void Register(ArgsManager& args) + { + auto l = [&](const auto& sd) { + using AT = typename std::remove_reference_t::ArgType; + args.AddTypedArg(sd.name+sd.params, sd.desc, sd.flags, sd.cat); + }; + (REG::template Register<_Do>)(l); + } + + static inline void Update(const ArgsManager& args, STRUCT& options) + { + auto l = [&](const auto& sd) { + using AT = typename std::remove_reference_t::ArgType; + auto arg = args.Get(sd.name); + if (arg.has_value()) { + sd.cvt(options.*(sd.field), arg.value()); + } + }; + (REG::template Register<_Do>)(l); + } + +private: + template + struct ArgDefn + { + using FieldType = FT; + using ArgType = AT; + + void (&cvt)(FieldType&, const ArgType&); + FieldType STRUCT::* field; + std::string name; + std::string params; // "=blah" or "" + std::string desc; + unsigned int flags; + OptionsCategory cat; + }; + + class _Do + { + private: + template + static inline void Do(Op& op) { } + + template + static inline void set_directly(T& dst, const T& src) { dst = src; } + + template + static inline void set_optional(std::optional& dst, const T& src) { dst = src; } + + public: + template + static inline ArgDefn, T> Defn(std::optional STRUCT::* field, const std::string& name, const std::string& params, const std::string& desc, Ts... ts) + { + return { set_optional, field, name, params, desc, ts... }; + } + + template + static inline ArgDefn Defn(T STRUCT::* field, const std::string& name, const std::string& params, const std::string& desc, Ts... ts) + { + return { set_directly, field, name, params, desc, ts... }; + } + + template + static inline ArgDefn Defn(FT STRUCT::* field, const std::string& name, const std::string& params, void(&cvt)(FT&,const AT&), const std::string& desc, Ts... ts) + { + return { cvt, field, name, params, desc, ts... }; + } + + template + static inline void Do(Op& op, const ArgDefn& sd, Ts... ts) + { + op(sd); + Do(op, ts...); + } + }; +}; + +#endif // BITCOIN_COMMON_ARGSREGISTER_H From 26372df4b853a37ab599a0a0e485721fc8a35842 Mon Sep 17 00:00:00 2001 From: Anthony Towns Date: Wed, 23 Aug 2023 18:18:07 +1000 Subject: [PATCH 5/6] chainparams: convert signet params to ArgsRegister --- src/chainparams.cpp | 57 ++++++++++++++++++++++++++++++++------------- 1 file changed, 41 insertions(+), 16 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 81d2a10b9cac..879bf571b2fc 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -21,32 +22,56 @@ #include #include + +namespace { +class SigNetArgsRegister +{ +public: + using T = CChainParams::SigNetOptions; + + static inline void GetChallenge(std::optional>& challenge, const std::vector& arg_challenges) + { + if (arg_challenges.size() != 1) { + throw std::runtime_error("-signetchallenge cannot be multiple values."); + } + + const auto val{TryParseHex(arg_challenges[0])}; + if (!val) { + throw std::runtime_error(strprintf("-signetchallenge must be hex, not '%s'.", arg_challenges[0])); + } + challenge.emplace(*val); + } + + template + static inline void Register(Op& op) + { + return C::Do(op, + C::Defn(&T::challenge, "-signetchallenge", "", GetChallenge, + "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), + C::Defn(&T::seeds, "-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) + ); + } +}; +} // anon namespace + void SetupChainParamsOptions(ArgsManager& argsman) { argsman.AddArg("-fastprune", "Use smaller block files and lower minimum prune height for testing purposes", 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::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); 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::DEBUG_TEST); - argsman.AddArg("-signetchallenge", "Blocks must satisfy the given script to be considered valid (only for signet networks; defaults to the global default signet test network challenge)", ArgsManager::ALLOW_ANY | ArgsManager::DISALLOW_NEGATION, OptionsCategory::CHAINPARAMS); - argsman.AddArg("-signetseednode", "Specify a seed node for the signet network, in the hostname[:port] format, e.g. sig.net:1234 (may be used multiple times to specify multiple seed nodes; defaults to the global default signet test network seed node(s))", ArgsManager::ALLOW_ANY | ArgsManager::DISALLOW_NEGATION, OptionsCategory::CHAINPARAMS); + + ArgsRegister::Register(argsman); } void ReadSigNetArgs(const ArgsManager& args, CChainParams::SigNetOptions& options) { - if (args.IsArgSet("-signetseednode")) { - options.seeds.emplace(args.GetArgs("-signetseednode")); - } - if (args.IsArgSet("-signetchallenge")) { - const auto signet_challenge = args.GetArgs("-signetchallenge"); - if (signet_challenge.size() != 1) { - throw std::runtime_error("-signetchallenge cannot be multiple values."); - } - const auto val{TryParseHex(signet_challenge[0])}; - if (!val) { - throw std::runtime_error(strprintf("-signetchallenge must be hex, not '%s'.", signet_challenge[0])); - } - options.challenge.emplace(*val); - } + ArgsRegister::Update(args, options); } void ReadRegTestArgs(const ArgsManager& args, CChainParams::RegTestOptions& options) From dddfbead90fc7b121b3a6870d546e9881eb5278a Mon Sep 17 00:00:00 2001 From: Anthony Towns Date: Wed, 23 Aug 2023 18:51:05 +1000 Subject: [PATCH 6/6] chainparams: convert regtest params to ArgsRegister --- src/chainparams.cpp | 148 ++++++++++++++++++++++++++------------------ 1 file changed, 88 insertions(+), 60 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 879bf571b2fc..75f02c7ed648 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -57,14 +57,97 @@ class SigNetArgsRegister ); } }; + +class RegTestArgsRegister +{ +public: + using T = CChainParams::RegTestOptions; + + + static inline void GetActivationHeights(std::unordered_map& activation_heights, const std::vector& args) + { + for (const std::string& arg : args) { + const auto found{arg.find('@')}; + if (found == std::string::npos) { + throw std::runtime_error(strprintf("Invalid format (%s) for -testactivationheight=name@height.", arg)); + } + + const auto value{arg.substr(found + 1)}; + int32_t height; + if (!ParseInt32(value, &height) || height < 0 || height >= std::numeric_limits::max()) { + throw std::runtime_error(strprintf("Invalid height value (%s) for -testactivationheight=name@height.", arg)); + } + + const auto deployment_name{arg.substr(0, found)}; + if (const auto buried_deployment = GetBuriedDeployment(deployment_name)) { + activation_heights[*buried_deployment] = height; + } else { + throw std::runtime_error(strprintf("Invalid name (%s) for -testactivationheight=name@height.", arg)); + } + } + } + + static inline void GetVBParams(std::unordered_map& version_bits_parameters, const std::vector& args) + { + for (const std::string& deployment : args) { + std::vector vDeploymentParams = SplitString(deployment, ':'); + if (vDeploymentParams.size() < 3 || 4 < vDeploymentParams.size()) { + throw std::runtime_error("Version bits parameters malformed, expecting deployment:start:end[:min_activation_height]"); + } + CChainParams::VersionBitsParameters vbparams{}; + if (!ParseInt64(vDeploymentParams[1], &vbparams.start_time)) { + throw std::runtime_error(strprintf("Invalid nStartTime (%s)", vDeploymentParams[1])); + } + if (!ParseInt64(vDeploymentParams[2], &vbparams.timeout)) { + throw std::runtime_error(strprintf("Invalid nTimeout (%s)", vDeploymentParams[2])); + } + if (vDeploymentParams.size() >= 4) { + if (!ParseInt32(vDeploymentParams[3], &vbparams.min_activation_height)) { + throw std::runtime_error(strprintf("Invalid min_activation_height (%s)", vDeploymentParams[3])); + } + } else { + vbparams.min_activation_height = 0; + } + bool found = false; + for (int j=0; j < (int)Consensus::MAX_VERSION_BITS_DEPLOYMENTS; ++j) { + if (vDeploymentParams[0] == VersionBitsDeploymentInfo[j].name) { + version_bits_parameters[Consensus::DeploymentPos(j)] = vbparams; + found = true; + LogPrintf("Setting version bits activation parameters for %s to start=%ld, timeout=%ld, min_activation_height=%d\n", vDeploymentParams[0], vbparams.start_time, vbparams.timeout, vbparams.min_activation_height); + break; + } + } + if (!found) { + throw std::runtime_error(strprintf("Invalid deployment (%s)", vDeploymentParams[0])); + } + } + } + + template + static inline void Register(Op& op) + { + return C::Do(op, + C::Defn(&T::version_bits_parameters, "-vbparams", "=deployment:start:end[:min_activation_height]", GetVBParams, + "Use given start/end times and min_activation_height for specified version bits deployment (regtest-only)", + ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, + OptionsCategory::DEBUG_TEST), + C::Defn(&T::activation_heights, "-testactivationheight", "=name@height.", GetActivationHeights, + "Set the activation height of 'name' (segwit, bip34, dersig, cltv, csv). (regtest-only)", + ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, + OptionsCategory::DEBUG_TEST), + C::Defn(&T::fastprune, "-fastprune", "", + "Use smaller block files and lower minimum prune height for testing purposes", + ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, + OptionsCategory::DEBUG_TEST) + ); + } +}; + } // anon namespace void SetupChainParamsOptions(ArgsManager& argsman) { - argsman.AddArg("-fastprune", "Use smaller block files and lower minimum prune height for testing purposes", 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::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); - 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::DEBUG_TEST); - + ArgsRegister::Register(argsman); ArgsRegister::Register(argsman); } @@ -76,62 +159,7 @@ void ReadSigNetArgs(const ArgsManager& args, CChainParams::SigNetOptions& option void ReadRegTestArgs(const ArgsManager& args, CChainParams::RegTestOptions& options) { - if (auto value = args.GetBoolArg("-fastprune")) options.fastprune = *value; - - for (const std::string& arg : args.GetArgs("-testactivationheight")) { - const auto found{arg.find('@')}; - if (found == std::string::npos) { - throw std::runtime_error(strprintf("Invalid format (%s) for -testactivationheight=name@height.", arg)); - } - - const auto value{arg.substr(found + 1)}; - int32_t height; - if (!ParseInt32(value, &height) || height < 0 || height >= std::numeric_limits::max()) { - throw std::runtime_error(strprintf("Invalid height value (%s) for -testactivationheight=name@height.", arg)); - } - - const auto deployment_name{arg.substr(0, found)}; - if (const auto buried_deployment = GetBuriedDeployment(deployment_name)) { - options.activation_heights[*buried_deployment] = height; - } else { - throw std::runtime_error(strprintf("Invalid name (%s) for -testactivationheight=name@height.", arg)); - } - } - - if (!args.IsArgSet("-vbparams")) return; - - for (const std::string& strDeployment : args.GetArgs("-vbparams")) { - std::vector vDeploymentParams = SplitString(strDeployment, ':'); - if (vDeploymentParams.size() < 3 || 4 < vDeploymentParams.size()) { - throw std::runtime_error("Version bits parameters malformed, expecting deployment:start:end[:min_activation_height]"); - } - CChainParams::VersionBitsParameters vbparams{}; - if (!ParseInt64(vDeploymentParams[1], &vbparams.start_time)) { - throw std::runtime_error(strprintf("Invalid nStartTime (%s)", vDeploymentParams[1])); - } - if (!ParseInt64(vDeploymentParams[2], &vbparams.timeout)) { - throw std::runtime_error(strprintf("Invalid nTimeout (%s)", vDeploymentParams[2])); - } - if (vDeploymentParams.size() >= 4) { - if (!ParseInt32(vDeploymentParams[3], &vbparams.min_activation_height)) { - throw std::runtime_error(strprintf("Invalid min_activation_height (%s)", vDeploymentParams[3])); - } - } else { - vbparams.min_activation_height = 0; - } - bool found = false; - for (int j=0; j < (int)Consensus::MAX_VERSION_BITS_DEPLOYMENTS; ++j) { - if (vDeploymentParams[0] == VersionBitsDeploymentInfo[j].name) { - options.version_bits_parameters[Consensus::DeploymentPos(j)] = vbparams; - found = true; - LogPrintf("Setting version bits activation parameters for %s to start=%ld, timeout=%ld, min_activation_height=%d\n", vDeploymentParams[0], vbparams.start_time, vbparams.timeout, vbparams.min_activation_height); - break; - } - } - if (!found) { - throw std::runtime_error(strprintf("Invalid deployment (%s)", vDeploymentParams[0])); - } - } + ArgsRegister::Update(args, options); } static std::unique_ptr globalChainParams;