diff --git a/src/interfaces/node.h b/src/interfaces/node.h --- a/src/interfaces/node.h +++ b/src/interfaces/node.h @@ -5,12 +5,12 @@ #ifndef BITCOIN_INTERFACES_NODE_H #define BITCOIN_INTERFACES_NODE_H -#include -#include // For CConnman::NumConnections -#include // For banmap_t -#include // For Network - +#include // For Amount +#include // For CConnman::NumConnections +#include // For banmap_t +#include // For Network #include // For SecureString +#include // For util::SettingsValue #include #include @@ -83,6 +83,23 @@ //! Return whether shutdown was requested. virtual bool shutdownRequested() = 0; + //! Return whether a particular setting in /settings.json is or + //! would be ignored because it is also specified in the command line. + virtual bool isSettingIgnored(const std::string &name) = 0; + + //! Return setting value from /settings.json or bitcoin.conf. + virtual util::SettingsValue + getPersistentSetting(const std::string &name) = 0; + + //! Update a setting in /settings.json. + virtual void updateRwSetting(const std::string &name, + const util::SettingsValue &value) = 0; + + //! Force a setting value to be applied, overriding any other configuration + //! source, but not being persisted. + virtual void forceSetting(const std::string &name, + const util::SettingsValue &value) = 0; + //! Map port. virtual void mapPort(bool use_upnp, bool use_natpmp) = 0; diff --git a/src/interfaces/node.cpp b/src/interfaces/node.cpp --- a/src/interfaces/node.cpp +++ b/src/interfaces/node.cpp @@ -86,6 +86,41 @@ } } bool shutdownRequested() override { return ShutdownRequested(); } + bool isSettingIgnored(const std::string &name) override { + bool ignored = false; + gArgs.LockSettings([&](util::Settings &settings) { + if (auto *options = + util::FindKey(settings.command_line_options, name)) { + ignored = !options->empty(); + } + }); + return ignored; + } + util::SettingsValue + getPersistentSetting(const std::string &name) override { + return gArgs.GetPersistentSetting(name); + } + void updateRwSetting(const std::string &name, + const util::SettingsValue &value) override { + gArgs.LockSettings([&](util::Settings &settings) { + if (value.isNull()) { + settings.rw_settings.erase(name); + } else { + settings.rw_settings[name] = value; + } + }); + gArgs.WriteSettingsFile(); + } + void forceSetting(const std::string &name, + const util::SettingsValue &value) override { + gArgs.LockSettings([&](util::Settings &settings) { + if (value.isNull()) { + settings.forced_settings.erase(name); + } else { + settings.forced_settings[name] = value; + } + }); + } void mapPort(bool use_upnp, bool use_natpmp) override { StartMapPort(use_upnp, use_natpmp); } diff --git a/src/test/settings_tests.cpp b/src/test/settings_tests.cpp --- a/src/test/settings_tests.cpp +++ b/src/test/settings_tests.cpp @@ -110,7 +110,7 @@ const std::string &single_val, const std::string &list_val) { util::SettingsValue single_value = - GetSetting(settings, "section", "name", false, false); + GetSetting(settings, "section", "name", false, false, false); util::SettingsValue list_value(util::SettingsValue::VARR); for (const auto &item : GetSettingsList(settings, "section", "name", false)) { @@ -145,13 +145,15 @@ BOOST_AUTO_TEST_CASE(NullOverride) { util::Settings settings; settings.command_line_options["name"].push_back("value"); - BOOST_CHECK_EQUAL( - R"("value")", - GetSetting(settings, "section", "name", false, false).write().c_str()); + BOOST_CHECK_EQUAL(R"("value")", GetSetting(settings, "section", "name", + false, false, false) + .write() + .c_str()); settings.forced_settings["name"] = {}; BOOST_CHECK_EQUAL( - R"(null)", - GetSetting(settings, "section", "name", false, false).write().c_str()); + R"(null)", GetSetting(settings, "section", "name", false, false, false) + .write() + .c_str()); } // Test different ways settings can be merged, and verify results. This test can @@ -242,7 +244,7 @@ desc += " || "; desc += GetSetting(settings, network, name, ignore_default_section_config, - /* get_chain_name= */ false) + /*ignore_nonpersistent=*/false, /*get_chain_name=*/false) .write(); desc += " |"; for (const auto &s : GetSettingsList(settings, network, name, diff --git a/src/util/settings.h b/src/util/settings.h --- a/src/util/settings.h +++ b/src/util/settings.h @@ -57,12 +57,17 @@ //! @param ignore_default_section_config - ignore values in the default section //! of the config file (part before any //! [section] keywords) +//! @param ignore_nonpersistent - ignore non-persistent settings values (forced +//! settings values and values specified on the +//! command line). Only return settings in the +//! read-only config and read-write settings +//! files. //! @param get_chain_name - enable special backwards compatible behavior //! for GetChainName SettingsValue GetSetting(const Settings &settings, const std::string §ion, const std::string &name, bool ignore_default_section_config, - bool get_chain_name); + bool ignore_nonpersistent, bool get_chain_name); //! Get combined setting value similar to GetSetting(), except if setting was //! specified multiple times, return a list of all the values specified. diff --git a/src/util/settings.cpp b/src/util/settings.cpp --- a/src/util/settings.cpp +++ b/src/util/settings.cpp @@ -136,7 +136,7 @@ SettingsValue GetSetting(const Settings &settings, const std::string §ion, const std::string &name, bool ignore_default_section_config, - bool get_chain_name) { + bool ignore_nonpersistent, bool get_chain_name) { SettingsValue result; // Done merging any more settings sources. bool done = false; @@ -178,6 +178,12 @@ return; } + // Ignore nonpersistent settings if requested. + if (ignore_nonpersistent && + (source == Source::COMMAND_LINE || source == Source::FORCED)) { + return; + } + // Skip negated command line settings. if (skip_negated_command_line && span.last_negated()) { return; diff --git a/src/util/system.h b/src/util/system.h --- a/src/util/system.h +++ b/src/util/system.h @@ -140,6 +140,10 @@ int m_line; }; +std::string SettingToString(const util::SettingsValue &, const std::string &); +int64_t SettingToInt(const util::SettingsValue &, int64_t); +bool SettingToBool(const util::SettingsValue &, bool); + class ArgsManager { public: enum Flags { @@ -407,6 +411,12 @@ */ bool WriteSettingsFile(std::vector *errors = nullptr) const; + /** + * Get current setting from config file or read/write settings file, + * ignoring nonpersistent command line or forced settings values. + */ + util::SettingsValue GetPersistentSetting(const std::string &name) const; + /** * Access settings with lock held. */ diff --git a/src/util/system.cpp b/src/util/system.cpp --- a/src/util/system.cpp +++ b/src/util/system.cpp @@ -577,6 +577,14 @@ return true; } +util::SettingsValue +ArgsManager::GetPersistentSetting(const std::string &name) const { + LOCK(cs_args); + return util::GetSetting( + m_settings, m_network, name, !UseDefaultSection("-" + name), + /*ignore_nonpersistent=*/true, /*get_chain_name=*/false); +} + bool ArgsManager::IsArgNegated(const std::string &strArg) const { return GetSetting(strArg).isFalse(); } @@ -584,6 +592,11 @@ std::string ArgsManager::GetArg(const std::string &strArg, const std::string &strDefault) const { const util::SettingsValue value = GetSetting(strArg); + return SettingToString(value, strDefault); +} + +std::string SettingToString(const util::SettingsValue &value, + const std::string &strDefault) { return value.isNull() ? strDefault : value.isFalse() ? "0" : value.isTrue() ? "1" @@ -593,6 +606,10 @@ int64_t ArgsManager::GetIntArg(const std::string &strArg, int64_t nDefault) const { const util::SettingsValue value = GetSetting(strArg); + return SettingToInt(value, nDefault); +} + +int64_t SettingToInt(const util::SettingsValue &value, int64_t nDefault) { return value.isNull() ? nDefault : value.isFalse() ? 0 : value.isTrue() ? 1 @@ -602,6 +619,10 @@ bool ArgsManager::GetBoolArg(const std::string &strArg, bool fDefault) const { const util::SettingsValue value = GetSetting(strArg); + return SettingToBool(value, fDefault); +} + +bool SettingToBool(const util::SettingsValue &value, bool fDefault) { return value.isNull() ? fDefault : value.isBool() ? value.get_bool() : InterpretBool(value.get_str()); @@ -1047,6 +1068,7 @@ util::SettingsValue value = util::GetSetting(m_settings, /* section= */ "", SettingName(arg), /* ignore_default_section_config= */ false, + /*ignore_nonpersistent=*/false, /* get_chain_name= */ true); return value.isNull() ? false : value.isBool() ? value.get_bool() @@ -1079,6 +1101,7 @@ LOCK(cs_args); return util::GetSetting(m_settings, m_network, SettingName(arg), !UseDefaultSection(arg), + /*ignore_nonpersistent=*/false, /* get_chain_name= */ false); }