2626#include < QStringList>
2727#include < QVariant>
2828
29+ #include < univalue.h>
30+
2931const char *DEFAULT_GUI_PROXY_HOST = " 127.0.0.1" ;
3032
3133static const QString GetDefaultProxyAddress ();
3234
33- OptionsModel::OptionsModel (interfaces::Node& node, QObject *parent, bool resetSettings) :
35+ /* * Map GUI option ID to node setting name. */
36+ static const char * SettingName (OptionsModel::OptionID option)
37+ {
38+ switch (option) {
39+ case OptionsModel::DatabaseCache: return " dbcache" ;
40+ default : throw std::logic_error (strprintf (" GUI option %i has no corresponding node setting." , option));
41+ }
42+ }
43+
44+ /* * Call node.updateRwSetting() with Bitcoin 22.x workaround. */
45+ static void UpdateRwSetting (interfaces::Node& node, OptionsModel::OptionID option, const util::SettingsValue& value)
46+ {
47+ if (value.isNum () && option == OptionsModel::DatabaseCache) {
48+ // Write certain old settings as strings, even though they are numbers,
49+ // because Bitcoin 22.x releases try to read these specific settings as
50+ // strings in addOverriddenOption() calls at startup, triggering
51+ // uncaught exceptions in UniValue::get_str(). These errors were fixed
52+ // in later releases by https://github.com/bitcoin/bitcoin/pull/24498.
53+ // If new numeric settings are added, they can be written as numbers
54+ // instead of strings, because bitcoin 22.x will not try to read these.
55+ node.updateRwSetting (SettingName (option), value.getValStr ());
56+ } else {
57+ node.updateRwSetting (SettingName (option), value);
58+ }
59+ }
60+
61+ OptionsModel::OptionsModel (interfaces::Node& node, QObject *parent) :
3462 QAbstractListModel(parent), m_node{node}
3563{
36- Init (resetSettings);
3764}
3865
3966void OptionsModel::addOverriddenOption (const std::string &option)
@@ -42,11 +69,8 @@ void OptionsModel::addOverriddenOption(const std::string &option)
4269}
4370
4471// Writes all missing QSettings with their default values
45- void OptionsModel::Init (bool resetSettings )
72+ bool OptionsModel::Init (bilingual_str& error )
4673{
47- if (resetSettings)
48- Reset ();
49-
5074 checkAndMigrate ();
5175
5276 QSettings settings;
@@ -98,7 +122,20 @@ void OptionsModel::Init(bool resetSettings)
98122
99123 // These are shared with the core or have a command-line parameter
100124 // and we want command-line parameters to overwrite the GUI settings.
101- //
125+ for (OptionID option : {DatabaseCache}) {
126+ std::string setting = SettingName (option);
127+ if (node ().isSettingIgnored (setting)) addOverriddenOption (" -" + setting);
128+ try {
129+ getOption (option);
130+ } catch (const std::exception& e) {
131+ // This handles exceptions thrown by univalue that can happen if
132+ // settings in settings.json don't have the expected types.
133+ error.original = strprintf (" Could not read setting \" %s\" , %s." , setting, e.what ());
134+ error.translated = tr (" Could not read setting \" %1\" , %2." ).arg (QString::fromStdString (setting), e.what ()).toStdString ();
135+ return false ;
136+ }
137+ }
138+
102139 // If setting doesn't exist create it with defaults.
103140 //
104141 // If gArgs.SoftSetArg() or gArgs.SoftSetBoolArg() return false we were overridden
@@ -111,11 +148,6 @@ void OptionsModel::Init(bool resetSettings)
111148 settings.setValue (" nPruneSize" , DEFAULT_PRUNE_TARGET_GB);
112149 SetPruneEnabled (settings.value (" bPrune" ).toBool ());
113150
114- if (!settings.contains (" nDatabaseCache" ))
115- settings.setValue (" nDatabaseCache" , (qint64)nDefaultDbCache);
116- if (!gArgs .SoftSetArg (" -dbcache" , settings.value (" nDatabaseCache" ).toString ().toStdString ()))
117- addOverriddenOption (" -dbcache" );
118-
119151 if (!settings.contains (" nThreadsScriptVerif" ))
120152 settings.setValue (" nThreadsScriptVerif" , DEFAULT_SCRIPTCHECK_THREADS);
121153 if (!gArgs .SoftSetArg (" -par" , settings.value (" nThreadsScriptVerif" ).toString ().toStdString ()))
@@ -222,6 +254,8 @@ void OptionsModel::Init(bool resetSettings)
222254 }
223255 m_use_embedded_monospaced_font = settings.value (" UseEmbeddedMonospacedFont" ).toBool ();
224256 Q_EMIT useEmbeddedMonospacedFontChanged (m_use_embedded_monospaced_font);
257+
258+ return true ;
225259}
226260
227261/* * Helper function to copy contents from one QSettings to another.
@@ -356,6 +390,8 @@ bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, in
356390
357391QVariant OptionsModel::getOption (OptionID option) const
358392{
393+ auto setting = [&]{ return node ().getPersistentSetting (SettingName (option)); };
394+
359395 QSettings settings;
360396 switch (option) {
361397 case StartAtStartup:
@@ -420,7 +456,7 @@ QVariant OptionsModel::getOption(OptionID option) const
420456 case PruneSize:
421457 return settings.value (" nPruneSize" );
422458 case DatabaseCache:
423- return settings. value ( " nDatabaseCache " );
459+ return qlonglong ( SettingToInt ( setting (), nDefaultDbCache) );
424460 case ThreadsScriptVerif:
425461 return settings.value (" nThreadsScriptVerif" );
426462 case Listen:
@@ -434,6 +470,9 @@ QVariant OptionsModel::getOption(OptionID option) const
434470
435471bool OptionsModel::setOption (OptionID option, const QVariant& value)
436472{
473+ auto changed = [&] { return value.isValid () && value != getOption (option); };
474+ auto update = [&](const util::SettingsValue& value) { return UpdateRwSetting (node (), option, value); };
475+
437476 bool successful = true ; /* set to false on parse error */
438477 QSettings settings;
439478
@@ -574,8 +613,8 @@ bool OptionsModel::setOption(OptionID option, const QVariant& value)
574613 }
575614 break ;
576615 case DatabaseCache:
577- if (settings. value ( " nDatabaseCache " ) != value ) {
578- settings. setValue ( " nDatabaseCache " , value);
616+ if (changed () ) {
617+ update ( static_cast < int64_t >( value. toLongLong ()) );
579618 setRestartRequired (true );
580619 }
581620 break ;
@@ -654,4 +693,16 @@ void OptionsModel::checkAndMigrate()
654693 if (settings.contains (" addrSeparateProxyTor" ) && settings.value (" addrSeparateProxyTor" ).toString ().endsWith (" %2" )) {
655694 settings.setValue (" addrSeparateProxyTor" , GetDefaultProxyAddress ());
656695 }
696+
697+ // Migrate and delete legacy GUI settings that have now moved to <datadir>/settings.json.
698+ auto migrate_setting = [&](OptionID option, const QString& qt_name) {
699+ if (!settings.contains (qt_name)) return ;
700+ QVariant value = settings.value (qt_name);
701+ if (node ().getPersistentSetting (SettingName (option)).isNull ()) {
702+ setOption (option, value);
703+ }
704+ settings.remove (qt_name);
705+ };
706+
707+ migrate_setting (DatabaseCache, " nDatabaseCache" );
657708}
0 commit comments