diff --git a/doc/release-notes.md b/doc/release-notes.md --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -25,4 +25,7 @@ [test] mempoolsize=200 [regtest] - mempoolsize=50 \ No newline at end of file + mempoolsize=50 + The `addnode=`, `connect=`, `port=`, `bind=`, `rpcport=`, `rpcbind=` + and `wallet=` options will only apply to mainnet when specified in the + configuration file, unless a network is specified. \ No newline at end of file diff --git a/src/init.cpp b/src/init.cpp --- a/src/init.cpp +++ b/src/init.cpp @@ -1262,6 +1262,11 @@ __func__); } } + + // Warn if network-specific options (-addnode, -connect, etc) are + // specified in default section of config file, but not overridden + // on the command line or in this network's section of the config file. + gArgs.WarnForSectionOnlyArgs(); } static std::string ResolveErrMsg(const char *const optname, diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -170,6 +170,7 @@ } struct TestArgsManager : public ArgsManager { + TestArgsManager() { m_network_only_args.clear(); } std::map> &GetOverrideArgs() { return m_override_args; } @@ -184,6 +185,10 @@ } ReadConfigStream(streamConfig); } + void SetNetworkOnlyArg(const std::string arg) { + LOCK(cs_args); + m_network_only_args.insert(arg); + } }; BOOST_AUTO_TEST_CASE(util_ParseParameters) { @@ -317,6 +322,7 @@ "\n" "[sec1]\n" "ccc=extend2\n" + "d=eee\n" "h=1\n" "[sec2]\n" "ccc=extend3\n" @@ -326,10 +332,10 @@ test_args.ReadConfigString(str_config); // expectation: a, b, ccc, d, fff, ggg, h, i end up in map - // so do sec1.ccc, sec1.h, sec2.ccc, sec2.iii + // so do sec1.ccc, sec1.d, sec1.h, sec2.ccc, sec2.iii BOOST_CHECK(test_args.GetOverrideArgs().empty()); - BOOST_CHECK(test_args.GetConfigArgs().size() == 12); + BOOST_CHECK(test_args.GetConfigArgs().size() == 13); BOOST_CHECK(test_args.GetConfigArgs().count("-a") && test_args.GetConfigArgs().count("-b") && @@ -411,11 +417,12 @@ // same as original BOOST_CHECK(test_args.GetArg("-a", "xxx") == "" && test_args.GetArg("-b", "xxx") == "1" && - test_args.GetArg("-d", "xxx") == "e" && test_args.GetArg("-fff", "xxx") == "0" && test_args.GetArg("-ggg", "xxx") == "1" && test_args.GetArg("-zzz", "xxx") == "xxx" && test_args.GetArg("-iii", "xxx") == "xxx"); + // d is overridden + BOOST_CHECK(test_args.GetArg("-d", "xxx") == "eee"); // section-specific setting BOOST_CHECK(test_args.GetArg("-h", "xxx") == "1"); // section takes priority for multiple values @@ -449,6 +456,29 @@ BOOST_CHECK_EQUAL_COLLECTIONS(sec2_ccc_res.begin(), sec2_ccc_res.end(), sec2_ccc_expected.begin(), sec2_ccc_expected.end()); + + // Test section only options + + test_args.SetNetworkOnlyArg("-d"); + test_args.SetNetworkOnlyArg("-ccc"); + test_args.SetNetworkOnlyArg("-h"); + + test_args.SelectConfigNetwork(CBaseChainParams::MAIN); + BOOST_CHECK(test_args.GetArg("-d", "xxx") == "e"); + BOOST_CHECK(test_args.GetArgs("-ccc").size() == 2); + BOOST_CHECK(test_args.GetArg("-h", "xxx") == "0"); + + test_args.SelectConfigNetwork("sec1"); + BOOST_CHECK(test_args.GetArg("-d", "xxx") == "eee"); + BOOST_CHECK(test_args.GetArgs("-d").size() == 1); + BOOST_CHECK(test_args.GetArgs("-ccc").size() == 2); + BOOST_CHECK(test_args.GetArg("-h", "xxx") == "1"); + + test_args.SelectConfigNetwork("sec2"); + BOOST_CHECK(test_args.GetArg("-d", "xxx") == "xxx"); + BOOST_CHECK(test_args.GetArgs("-d").size() == 0); + BOOST_CHECK(test_args.GetArgs("-ccc").size() == 1); + BOOST_CHECK(test_args.GetArg("-h", "xxx") == "0"); } BOOST_AUTO_TEST_CASE(util_GetArg) { diff --git a/src/util.h b/src/util.h --- a/src/util.h +++ b/src/util.h @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -101,9 +102,13 @@ std::map> m_override_args; std::map> m_config_args; std::string m_network; + std::set m_network_only_args; + void ReadConfigStream(std::istream &stream); public: + ArgsManager(); + /** * Select the network in use */ @@ -112,6 +117,13 @@ void ParseParameters(int argc, const char *const argv[]); void ReadConfigFile(const std::string &confPath); + /** + * Log warnings for options in m_section_only_args when they are specified + * in the default section but not overridden on the command line or in a + * network-specific section in the config file. + */ + void WarnForSectionOnlyArgs(); + /** * Return a vector of strings of the given argument * diff --git a/src/util.cpp b/src/util.cpp --- a/src/util.cpp +++ b/src/util.cpp @@ -173,6 +173,14 @@ public: typedef std::map> MapArgs; + /** Determine whether to use config settings in the default section, + * See also comments around ArgsManager::ArgsManager() below. */ + static inline bool UseDefaultSection(const ArgsManager &am, + const std::string &arg) { + return (am.m_network == CBaseChainParams::MAIN || + am.m_network_only_args.count(arg) == 0); + } + /** Convert regular argument into the network-specific setting */ static inline std::string NetworkArg(const ArgsManager &am, const std::string &arg) { @@ -238,9 +246,11 @@ } } - found_result = GetArgHelper(am.m_config_args, arg); - if (found_result.first) { - return found_result; + if (UseDefaultSection(am, arg)) { + found_result = GetArgHelper(am.m_config_args, arg); + if (found_result.first) { + return found_result; + } } return found_result; @@ -292,6 +302,59 @@ return false; } +ArgsManager::ArgsManager() + : /* These options would cause cross-contamination if values for mainnet + * were used while running on regtest/testnet (or vice-versa). + * Setting them as section_only_args ensures that sharing a config file + * between mainnet and regtest/testnet won't cause problems due to these + * parameters by accident. */ + m_network_only_args{ + "-addnode", "-connect", "-port", "-bind", + "-rpcport", "-rpcbind", "-wallet", + } { + // nothing to do +} + +void ArgsManager::WarnForSectionOnlyArgs() { + // if there's no section selected, don't worry + if (m_network.empty()) { + return; + } + + // if it's okay to use the default section for this network, don't worry + if (m_network == CBaseChainParams::MAIN) { + return; + } + + for (const auto &arg : m_network_only_args) { + std::pair found_result; + + // if this option is overridden it's fine + found_result = ArgsManagerHelper::GetArgHelper(m_override_args, arg); + if (found_result.first) { + continue; + } + + // if there's a network-specific value for this option, it's fine + found_result = ArgsManagerHelper::GetArgHelper( + m_config_args, ArgsManagerHelper::NetworkArg(*this, arg)); + if (found_result.first) { + continue; + } + + // if there isn't a default value for this option, it's fine + found_result = ArgsManagerHelper::GetArgHelper(m_config_args, arg); + if (!found_result.first) { + continue; + } + + // otherwise, issue a warning + LogPrintf("Warning: Config setting for %s only applied on %s network " + "when in [%s] section.\n", + arg, m_network, m_network); + } +} + void ArgsManager::SelectConfigNetwork(const std::string &network) { m_network = network; } @@ -341,13 +404,18 @@ } LOCK(cs_args); + ArgsManagerHelper::AddArgs(result, m_override_args, strArg); if (!m_network.empty()) { ArgsManagerHelper::AddArgs( result, m_config_args, ArgsManagerHelper::NetworkArg(*this, strArg)); } - ArgsManagerHelper::AddArgs(result, m_config_args, strArg); + + if (ArgsManagerHelper::UseDefaultSection(*this, strArg)) { + ArgsManagerHelper::AddArgs(result, m_config_args, strArg); + } + return result; }