diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index a7003c95ab7..bd6a1f5ecaa 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -344,7 +344,7 @@ void BitcoinApplication::parameterSetup() void BitcoinApplication::InitPruneSetting(int64_t prune_MiB) { - optionsModel->SetPruneTargetGB(PruneMiBtoGB(prune_MiB), true); + optionsModel->SetPruneTargetGB(PruneMiBtoGB(prune_MiB)); } void BitcoinApplication::requestInitialize() diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index 238727e6697..39e79a2a53a 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -45,6 +45,8 @@ static const char* SettingName(OptionsModel::OptionID option) case OptionsModel::MapPortNatpmp: return "natpmp"; case OptionsModel::Listen: return "listen"; case OptionsModel::Server: return "server"; + case OptionsModel::PruneSize: return "prune"; + case OptionsModel::Prune: return "prune"; case OptionsModel::ProxyIP: return "proxy"; case OptionsModel::ProxyPort: return "proxy"; case OptionsModel::ProxyUse: return "proxy"; @@ -60,7 +62,9 @@ static void UpdateRwSetting(interfaces::Node& node, OptionsModel::OptionID optio { if (value.isNum() && (option == OptionsModel::DatabaseCache || - option == OptionsModel::ThreadsScriptVerif)) { + option == OptionsModel::ThreadsScriptVerif || + option == OptionsModel::Prune || + option == OptionsModel::PruneSize)) { // Write certain old settings as strings, even though they are numbers, // because Bitcoin 22.x releases try to read these specific settings as // strings in addOverriddenOption() calls at startup, triggering @@ -74,6 +78,36 @@ static void UpdateRwSetting(interfaces::Node& node, OptionsModel::OptionID optio } } +//! Convert enabled/size values to bitcoin -prune setting. +static util::SettingsValue PruneSetting(bool prune_enabled, int prune_size_gb) +{ + assert(!prune_enabled || prune_size_gb >= 1); // PruneSizeGB and ParsePruneSizeGB never return less + return prune_enabled ? PruneGBtoMiB(prune_size_gb) : 0; +} + +//! Get pruning enabled value to show in GUI from bitcoin -prune setting. +static bool PruneEnabled(const util::SettingsValue& prune_setting) +{ + // -prune=1 setting is manual pruning mode, so disabled for purposes of the gui + return SettingToInt(prune_setting, 0) > 1; +} + +//! Get pruning size value to show in GUI from bitcoin -prune setting. If +//! pruning is not enabled, just show default recommended pruning size (2GB). +static int PruneSizeGB(const util::SettingsValue& prune_setting) +{ + int value = SettingToInt(prune_setting, 0); + return value > 1 ? PruneMiBtoGB(value) : DEFAULT_PRUNE_TARGET_GB; +} + +//! Parse pruning size value provided by user in GUI or loaded from QSettings +//! (windows registry key or qt .conf file). Smallest value that the GUI can +//! display is 1 GB, so round up if anything less is parsed. +static int ParsePruneSizeGB(const QVariant& prune_size) +{ + return std::max(1, prune_size.toInt()); +} + struct ProxySetting { bool is_set; QString ip; @@ -96,6 +130,7 @@ void OptionsModel::addOverriddenOption(const std::string &option) bool OptionsModel::Init(bilingual_str& error) { // Initialize display settings from stored settings. + m_prune_size_gb = PruneSizeGB(node().getPersistentSetting("prune")); ProxySetting proxy = ParseProxyString(SettingToString(node().getPersistentSetting("proxy"), GetDefaultProxyAddress().toStdString())); m_proxy_ip = proxy.ip; m_proxy_port = proxy.port; @@ -155,7 +190,7 @@ bool OptionsModel::Init(bilingual_str& error) // These are shared with the core or have a command-line parameter // and we want command-line parameters to overwrite the GUI settings. for (OptionID option : {DatabaseCache, ThreadsScriptVerif, SpendZeroConfChange, ExternalSignerPath, MapPortUPnP, - MapPortNatpmp, Listen, Server, ProxyUse, ProxyUseTor}) { + MapPortNatpmp, Listen, Server, Prune, ProxyUse, ProxyUseTor}) { std::string setting = SettingName(option); if (node().isSettingIgnored(setting)) addOverriddenOption("-" + setting); try { @@ -175,11 +210,6 @@ bool OptionsModel::Init(bilingual_str& error) // by command-line and show this in the UI. // Main - if (!settings.contains("bPrune")) - settings.setValue("bPrune", false); - if (!settings.contains("nPruneSize")) - settings.setValue("nPruneSize", DEFAULT_PRUNE_TARGET_GB); - SetPruneEnabled(settings.value("bPrune").toBool()); if (!settings.contains("strDataDir")) settings.setValue("strDataDir", GUIUtil::getDefaultDataDirectory()); @@ -288,29 +318,27 @@ static const QString GetDefaultProxyAddress() return QString("%1:%2").arg(DEFAULT_GUI_PROXY_HOST).arg(DEFAULT_GUI_PROXY_PORT); } -void OptionsModel::SetPruneEnabled(bool prune, bool force) +void OptionsModel::SetPruneTargetGB(int prune_target_gb) { - QSettings settings; - settings.setValue("bPrune", prune); - const int64_t prune_target_mib = PruneGBtoMiB(settings.value("nPruneSize").toInt()); - std::string prune_val = prune ? ToString(prune_target_mib) : "0"; - if (force) { - gArgs.ForceSetArg("-prune", prune_val); - return; - } - if (!gArgs.SoftSetArg("-prune", prune_val)) { - addOverriddenOption("-prune"); - } -} - -void OptionsModel::SetPruneTargetGB(int prune_target_gb, bool force) -{ - const bool prune = prune_target_gb > 0; - if (prune) { - QSettings settings; - settings.setValue("nPruneSize", prune_target_gb); + const util::SettingsValue cur_value = node().getPersistentSetting("prune"); + const util::SettingsValue new_value = PruneSetting(prune_target_gb > 0, prune_target_gb); + + m_prune_size_gb = prune_target_gb; + + // Force setting to take effect. It is still safe to change the value at + // this point because this function is only called after the intro screen is + // shown, before the node starts. + node().forceSetting("prune", new_value); + + // Update settings.json if value configured in intro screen is different + // from saved value. Avoid writing settings.json if bitcoin.conf value + // doesn't need to be overridden. + if (PruneEnabled(cur_value) != PruneEnabled(new_value) || + PruneSizeGB(cur_value) != PruneSizeGB(new_value)) { + // Call UpdateRwSetting() instead of setOption() to avoid setting + // RestartRequired flag + UpdateRwSetting(node(), Prune, new_value); } - SetPruneEnabled(prune, force); } // read QSettings values and return them @@ -401,9 +429,9 @@ QVariant OptionsModel::getOption(OptionID option) const case EnablePSBTControls: return settings.value("enable_psbt_controls"); case Prune: - return settings.value("bPrune"); + return PruneEnabled(setting()); case PruneSize: - return settings.value("nPruneSize"); + return m_prune_size_gb; case DatabaseCache: return qlonglong(SettingToInt(setting(), nDefaultDbCache)); case ThreadsScriptVerif: @@ -556,15 +584,18 @@ bool OptionsModel::setOption(OptionID option, const QVariant& value) settings.setValue("enable_psbt_controls", m_enable_psbt_controls); break; case Prune: - if (settings.value("bPrune") != value) { - settings.setValue("bPrune", value); + if (changed()) { + update(PruneSetting(value.toBool(), m_prune_size_gb)); setRestartRequired(true); } break; case PruneSize: - if (settings.value("nPruneSize") != value) { - settings.setValue("nPruneSize", value); - setRestartRequired(true); + if (changed()) { + m_prune_size_gb = ParsePruneSizeGB(value); + if (getOption(Prune).toBool()) { + update(PruneSetting(true, m_prune_size_gb)); + setRestartRequired(true); + } } break; case DatabaseCache: @@ -674,6 +705,8 @@ void OptionsModel::checkAndMigrate() migrate_setting(MapPortNatpmp, "fUseNatpmp"); migrate_setting(Listen, "fListen"); migrate_setting(Server, "server"); + migrate_setting(PruneSize, "nPruneSize"); + migrate_setting(Prune, "bPrune"); migrate_setting(ProxyIP, "addrProxy"); migrate_setting(ProxyUse, "fUseProxy"); migrate_setting(ProxyIPTor, "addrSeparateProxyTor"); diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h index ca07a268e8e..42b89c50293 100644 --- a/src/qt/optionsmodel.h +++ b/src/qt/optionsmodel.h @@ -99,8 +99,7 @@ class OptionsModel : public QAbstractListModel const QString& getOverriddenByCommandLine() { return strOverriddenByCommandLine; } /* Explicit setters */ - void SetPruneEnabled(bool prune, bool force = false); - void SetPruneTargetGB(int prune_target_gb, bool force = false); + void SetPruneTargetGB(int prune_target_gb); /* Restart flag helper */ void setRestartRequired(bool fRequired); @@ -125,6 +124,7 @@ class OptionsModel : public QAbstractListModel //! In-memory settings for display. These are stored persistently by the //! bitcoin node but it's also nice to store them in memory to prevent them //! getting cleared when enable/disable toggles are used in the GUI. + int m_prune_size_gb; QString m_proxy_ip; QString m_proxy_port; QString m_onion_ip; diff --git a/src/qt/test/optiontests.cpp b/src/qt/test/optiontests.cpp index 443c9f2a93b..3bd0af19ada 100644 --- a/src/qt/test/optiontests.cpp +++ b/src/qt/test/optiontests.cpp @@ -36,6 +36,8 @@ void OptionTests::migrateSettings() settings.setValue("nThreadsScriptVerif", 12); settings.setValue("fUseUPnP", false); settings.setValue("fListen", false); + settings.setValue("bPrune", true); + settings.setValue("nPruneSize", 3); settings.setValue("fUseProxy", true); settings.setValue("addrProxy", "proxy:123"); settings.setValue("fUseSeparateProxyTor", true); @@ -50,6 +52,8 @@ void OptionTests::migrateSettings() QVERIFY(!settings.contains("nThreadsScriptVerif")); QVERIFY(!settings.contains("fUseUPnP")); QVERIFY(!settings.contains("fListen")); + QVERIFY(!settings.contains("bPrune")); + QVERIFY(!settings.contains("nPruneSize")); QVERIFY(!settings.contains("fUseProxy")); QVERIFY(!settings.contains("addrProxy")); QVERIFY(!settings.contains("fUseSeparateProxyTor")); @@ -61,7 +65,8 @@ void OptionTests::migrateSettings() " \"listen\": false,\n" " \"onion\": \"onion:234\",\n" " \"par\": \"12\",\n" - " \"proxy\": \"proxy:123\"\n" + " \"proxy\": \"proxy:123\",\n" + " \"prune\": \"2861\"\n" "}\n"); }