Bitcoin Core  26.1.0
P2P Digital Currency
optionsmodel.cpp
Go to the documentation of this file.
1 // Copyright (c) 2011-2022 The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 
5 #if defined(HAVE_CONFIG_H)
7 #endif
8 
9 #include <qt/optionsmodel.h>
10 
11 #include <qt/bitcoinunits.h>
12 #include <qt/guiconstants.h>
13 #include <qt/guiutil.h>
14 
15 #include <common/args.h>
16 #include <interfaces/node.h>
17 #include <mapport.h>
18 #include <net.h>
19 #include <netbase.h>
20 #include <txdb.h> // for -dbcache defaults
21 #include <util/string.h>
22 #include <validation.h> // For DEFAULT_SCRIPTCHECK_THREADS
23 #include <wallet/wallet.h> // For DEFAULT_SPEND_ZEROCONF_CHANGE
24 
25 #include <QDebug>
26 #include <QLatin1Char>
27 #include <QSettings>
28 #include <QStringList>
29 #include <QVariant>
30 
31 #include <univalue.h>
32 
33 const char *DEFAULT_GUI_PROXY_HOST = "127.0.0.1";
34 
35 static QString GetDefaultProxyAddress();
36 
38 static const char* SettingName(OptionsModel::OptionID option)
39 {
40  switch (option) {
41  case OptionsModel::DatabaseCache: return "dbcache";
42  case OptionsModel::ThreadsScriptVerif: return "par";
43  case OptionsModel::SpendZeroConfChange: return "spendzeroconfchange";
44  case OptionsModel::ExternalSignerPath: return "signer";
45  case OptionsModel::MapPortUPnP: return "upnp";
46  case OptionsModel::MapPortNatpmp: return "natpmp";
47  case OptionsModel::Listen: return "listen";
48  case OptionsModel::Server: return "server";
49  case OptionsModel::PruneSize: return "prune";
50  case OptionsModel::Prune: return "prune";
51  case OptionsModel::ProxyIP: return "proxy";
52  case OptionsModel::ProxyPort: return "proxy";
53  case OptionsModel::ProxyUse: return "proxy";
54  case OptionsModel::ProxyIPTor: return "onion";
55  case OptionsModel::ProxyPortTor: return "onion";
56  case OptionsModel::ProxyUseTor: return "onion";
57  case OptionsModel::Language: return "lang";
58  default: throw std::logic_error(strprintf("GUI option %i has no corresponding node setting.", option));
59  }
60 }
61 
63 static void UpdateRwSetting(interfaces::Node& node, OptionsModel::OptionID option, const std::string& suffix, const common::SettingsValue& value)
64 {
65  if (value.isNum() &&
66  (option == OptionsModel::DatabaseCache ||
68  option == OptionsModel::Prune ||
69  option == OptionsModel::PruneSize)) {
70  // Write certain old settings as strings, even though they are numbers,
71  // because Bitcoin 22.x releases try to read these specific settings as
72  // strings in addOverriddenOption() calls at startup, triggering
73  // uncaught exceptions in UniValue::get_str(). These errors were fixed
74  // in later releases by https://github.com/bitcoin/bitcoin/pull/24498.
75  // If new numeric settings are added, they can be written as numbers
76  // instead of strings, because bitcoin 22.x will not try to read these.
77  node.updateRwSetting(SettingName(option) + suffix, value.getValStr());
78  } else {
79  node.updateRwSetting(SettingName(option) + suffix, value);
80  }
81 }
82 
84 static common::SettingsValue PruneSetting(bool prune_enabled, int prune_size_gb)
85 {
86  assert(!prune_enabled || prune_size_gb >= 1); // PruneSizeGB and ParsePruneSizeGB never return less
87  return prune_enabled ? PruneGBtoMiB(prune_size_gb) : 0;
88 }
89 
91 static bool PruneEnabled(const common::SettingsValue& prune_setting)
92 {
93  // -prune=1 setting is manual pruning mode, so disabled for purposes of the gui
94  return SettingToInt(prune_setting, 0) > 1;
95 }
96 
99 static int PruneSizeGB(const common::SettingsValue& prune_setting)
100 {
101  int value = SettingToInt(prune_setting, 0);
102  return value > 1 ? PruneMiBtoGB(value) : DEFAULT_PRUNE_TARGET_GB;
103 }
104 
108 static int ParsePruneSizeGB(const QVariant& prune_size)
109 {
110  return std::max(1, prune_size.toInt());
111 }
112 
113 struct ProxySetting {
114  bool is_set;
115  QString ip;
116  QString port;
117 };
118 static ProxySetting ParseProxyString(const std::string& proxy);
119 static std::string ProxyString(bool is_set, QString ip, QString port);
120 
122  QAbstractListModel(parent), m_node{node}
123 {
124 }
125 
126 void OptionsModel::addOverriddenOption(const std::string &option)
127 {
128  strOverriddenByCommandLine += QString::fromStdString(option) + "=" + QString::fromStdString(gArgs.GetArg(option, "")) + " ";
129 }
130 
131 // Writes all missing QSettings with their default values
133 {
134  // Initialize display settings from stored settings.
135  language = QString::fromStdString(SettingToString(node().getPersistentSetting("lang"), ""));
136 
137  checkAndMigrate();
138 
139  QSettings settings;
140 
141  // Ensure restart flag is unset on client startup
142  setRestartRequired(false);
143 
144  // These are Qt-only settings:
145 
146  // Window
147  if (!settings.contains("fHideTrayIcon")) {
148  settings.setValue("fHideTrayIcon", false);
149  }
150  m_show_tray_icon = !settings.value("fHideTrayIcon").toBool();
152 
153  if (!settings.contains("fMinimizeToTray"))
154  settings.setValue("fMinimizeToTray", false);
155  fMinimizeToTray = settings.value("fMinimizeToTray").toBool() && m_show_tray_icon;
156 
157  if (!settings.contains("fMinimizeOnClose"))
158  settings.setValue("fMinimizeOnClose", false);
159  fMinimizeOnClose = settings.value("fMinimizeOnClose").toBool();
160 
161  // Display
162  if (!settings.contains("DisplayBitcoinUnit")) {
163  settings.setValue("DisplayBitcoinUnit", QVariant::fromValue(BitcoinUnit::BTC));
164  }
165  QVariant unit = settings.value("DisplayBitcoinUnit");
166  if (unit.canConvert<BitcoinUnit>()) {
167  m_display_bitcoin_unit = unit.value<BitcoinUnit>();
168  } else {
170  settings.setValue("DisplayBitcoinUnit", QVariant::fromValue(m_display_bitcoin_unit));
171  }
172 
173  if (!settings.contains("strThirdPartyTxUrls"))
174  settings.setValue("strThirdPartyTxUrls", "");
175  strThirdPartyTxUrls = settings.value("strThirdPartyTxUrls", "").toString();
176 
177  if (!settings.contains("fCoinControlFeatures"))
178  settings.setValue("fCoinControlFeatures", false);
179  fCoinControlFeatures = settings.value("fCoinControlFeatures", false).toBool();
180 
181  if (!settings.contains("enable_psbt_controls")) {
182  settings.setValue("enable_psbt_controls", false);
183  }
184  m_enable_psbt_controls = settings.value("enable_psbt_controls", false).toBool();
185 
186  // These are shared with the core or have a command-line parameter
187  // and we want command-line parameters to overwrite the GUI settings.
190  std::string setting = SettingName(option);
191  if (node().isSettingIgnored(setting)) addOverriddenOption("-" + setting);
192  try {
193  getOption(option);
194  } catch (const std::exception& e) {
195  // This handles exceptions thrown by univalue that can happen if
196  // settings in settings.json don't have the expected types.
197  error.original = strprintf("Could not read setting \"%s\", %s.", setting, e.what());
198  error.translated = tr("Could not read setting \"%1\", %2.").arg(QString::fromStdString(setting), e.what()).toStdString();
199  return false;
200  }
201  }
202 
203  // If setting doesn't exist create it with defaults.
204 
205  // Main
206  if (!settings.contains("strDataDir"))
207  settings.setValue("strDataDir", GUIUtil::getDefaultDataDirectory());
208 
209  // Wallet
210 #ifdef ENABLE_WALLET
211  if (!settings.contains("SubFeeFromAmount")) {
212  settings.setValue("SubFeeFromAmount", false);
213  }
214  m_sub_fee_from_amount = settings.value("SubFeeFromAmount", false).toBool();
215 #endif
216 
217  // Display
218  if (!settings.contains("UseEmbeddedMonospacedFont")) {
219  settings.setValue("UseEmbeddedMonospacedFont", "true");
220  }
221  m_use_embedded_monospaced_font = settings.value("UseEmbeddedMonospacedFont").toBool();
223 
224  m_mask_values = settings.value("mask_values", false).toBool();
225 
226  return true;
227 }
228 
232 static void CopySettings(QSettings& dst, const QSettings& src)
233 {
234  for (const QString& key : src.allKeys()) {
235  dst.setValue(key, src.value(key));
236  }
237 }
238 
240 static void BackupSettings(const fs::path& filename, const QSettings& src)
241 {
242  qInfo() << "Backing up GUI settings to" << GUIUtil::PathToQString(filename);
243  QSettings dst(GUIUtil::PathToQString(filename), QSettings::IniFormat);
244  dst.clear();
245  CopySettings(dst, src);
246 }
247 
249 {
250  // Backup and reset settings.json
251  node().resetSettings();
252 
253  QSettings settings;
254 
255  // Backup old settings to chain-specific datadir for troubleshooting
256  BackupSettings(gArgs.GetDataDirNet() / "guisettings.ini.bak", settings);
257 
258  // Save the strDataDir setting
259  QString dataDir = GUIUtil::getDefaultDataDirectory();
260  dataDir = settings.value("strDataDir", dataDir).toString();
261 
262  // Remove all entries from our QSettings object
263  settings.clear();
264 
265  // Set strDataDir
266  settings.setValue("strDataDir", dataDir);
267 
268  // Set that this was reset
269  settings.setValue("fReset", true);
270 
271  // default setting for OptionsModel::StartAtStartup - disabled
274 }
275 
276 int OptionsModel::rowCount(const QModelIndex & parent) const
277 {
278  return OptionIDRowCount;
279 }
280 
281 static ProxySetting ParseProxyString(const QString& proxy)
282 {
283  static const ProxySetting default_val = {false, DEFAULT_GUI_PROXY_HOST, QString("%1").arg(DEFAULT_GUI_PROXY_PORT)};
284  // Handle the case that the setting is not set at all
285  if (proxy.isEmpty()) {
286  return default_val;
287  }
288  // contains IP at index 0 and port at index 1
289  QStringList ip_port = GUIUtil::SplitSkipEmptyParts(proxy, ":");
290  if (ip_port.size() == 2) {
291  return {true, ip_port.at(0), ip_port.at(1)};
292  } else { // Invalid: return default
293  return default_val;
294  }
295 }
296 
297 static ProxySetting ParseProxyString(const std::string& proxy)
298 {
299  return ParseProxyString(QString::fromStdString(proxy));
300 }
301 
302 static std::string ProxyString(bool is_set, QString ip, QString port)
303 {
304  return is_set ? QString(ip + ":" + port).toStdString() : "";
305 }
306 
307 static QString GetDefaultProxyAddress()
308 {
309  return QString("%1:%2").arg(DEFAULT_GUI_PROXY_HOST).arg(DEFAULT_GUI_PROXY_PORT);
310 }
311 
312 void OptionsModel::SetPruneTargetGB(int prune_target_gb)
313 {
314  const common::SettingsValue cur_value = node().getPersistentSetting("prune");
315  const common::SettingsValue new_value = PruneSetting(prune_target_gb > 0, prune_target_gb);
316 
317  // Force setting to take effect. It is still safe to change the value at
318  // this point because this function is only called after the intro screen is
319  // shown, before the node starts.
320  node().forceSetting("prune", new_value);
321 
322  // Update settings.json if value configured in intro screen is different
323  // from saved value. Avoid writing settings.json if bitcoin.conf value
324  // doesn't need to be overridden.
325  if (PruneEnabled(cur_value) != PruneEnabled(new_value) ||
326  PruneSizeGB(cur_value) != PruneSizeGB(new_value)) {
327  // Call UpdateRwSetting() instead of setOption() to avoid setting
328  // RestartRequired flag
329  UpdateRwSetting(node(), Prune, "", new_value);
330  }
331 
332  // Keep previous pruning size, if pruning was disabled.
333  if (PruneEnabled(cur_value)) {
334  UpdateRwSetting(node(), Prune, "-prev", PruneEnabled(new_value) ? common::SettingsValue{} : cur_value);
335  }
336 }
337 
338 // read QSettings values and return them
339 QVariant OptionsModel::data(const QModelIndex & index, int role) const
340 {
341  if(role == Qt::EditRole)
342  {
343  return getOption(OptionID(index.row()));
344  }
345  return QVariant();
346 }
347 
348 // write QSettings values
349 bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, int role)
350 {
351  bool successful = true; /* set to false on parse error */
352  if(role == Qt::EditRole)
353  {
354  successful = setOption(OptionID(index.row()), value);
355  }
356 
357  Q_EMIT dataChanged(index, index);
358 
359  return successful;
360 }
361 
362 QVariant OptionsModel::getOption(OptionID option, const std::string& suffix) const
363 {
364  auto setting = [&]{ return node().getPersistentSetting(SettingName(option) + suffix); };
365 
366  QSettings settings;
367  switch (option) {
368  case StartAtStartup:
370  case ShowTrayIcon:
371  return m_show_tray_icon;
372  case MinimizeToTray:
373  return fMinimizeToTray;
374  case MapPortUPnP:
375 #ifdef USE_UPNP
376  return SettingToBool(setting(), DEFAULT_UPNP);
377 #else
378  return false;
379 #endif // USE_UPNP
380  case MapPortNatpmp:
381 #ifdef USE_NATPMP
382  return SettingToBool(setting(), DEFAULT_NATPMP);
383 #else
384  return false;
385 #endif // USE_NATPMP
386  case MinimizeOnClose:
387  return fMinimizeOnClose;
388 
389  // default proxy
390  case ProxyUse:
391  case ProxyUseTor:
392  return ParseProxyString(SettingToString(setting(), "")).is_set;
393  case ProxyIP:
394  case ProxyIPTor: {
395  ProxySetting proxy = ParseProxyString(SettingToString(setting(), ""));
396  if (proxy.is_set) {
397  return proxy.ip;
398  } else if (suffix.empty()) {
399  return getOption(option, "-prev");
400  } else {
401  return ParseProxyString(GetDefaultProxyAddress().toStdString()).ip;
402  }
403  }
404  case ProxyPort:
405  case ProxyPortTor: {
406  ProxySetting proxy = ParseProxyString(SettingToString(setting(), ""));
407  if (proxy.is_set) {
408  return proxy.port;
409  } else if (suffix.empty()) {
410  return getOption(option, "-prev");
411  } else {
412  return ParseProxyString(GetDefaultProxyAddress().toStdString()).port;
413  }
414  }
415 
416 #ifdef ENABLE_WALLET
417  case SpendZeroConfChange:
419  case ExternalSignerPath:
420  return QString::fromStdString(SettingToString(setting(), ""));
421  case SubFeeFromAmount:
422  return m_sub_fee_from_amount;
423 #endif
424  case DisplayUnit:
425  return QVariant::fromValue(m_display_bitcoin_unit);
426  case ThirdPartyTxUrls:
427  return strThirdPartyTxUrls;
428  case Language:
429  return QString::fromStdString(SettingToString(setting(), ""));
432  case CoinControlFeatures:
433  return fCoinControlFeatures;
434  case EnablePSBTControls:
435  return settings.value("enable_psbt_controls");
436  case Prune:
437  return PruneEnabled(setting());
438  case PruneSize:
439  return PruneEnabled(setting()) ? PruneSizeGB(setting()) :
440  suffix.empty() ? getOption(option, "-prev") :
442  case DatabaseCache:
443  return qlonglong(SettingToInt(setting(), nDefaultDbCache));
444  case ThreadsScriptVerif:
445  return qlonglong(SettingToInt(setting(), DEFAULT_SCRIPTCHECK_THREADS));
446  case Listen:
447  return SettingToBool(setting(), DEFAULT_LISTEN);
448  case Server:
449  return SettingToBool(setting(), false);
450  case MaskValues:
451  return m_mask_values;
452  default:
453  return QVariant();
454  }
455 }
456 
457 bool OptionsModel::setOption(OptionID option, const QVariant& value, const std::string& suffix)
458 {
459  auto changed = [&] { return value.isValid() && value != getOption(option, suffix); };
460  auto update = [&](const common::SettingsValue& value) { return UpdateRwSetting(node(), option, suffix, value); };
461 
462  bool successful = true; /* set to false on parse error */
463  QSettings settings;
464 
465  switch (option) {
466  case StartAtStartup:
467  successful = GUIUtil::SetStartOnSystemStartup(value.toBool());
468  break;
469  case ShowTrayIcon:
470  m_show_tray_icon = value.toBool();
471  settings.setValue("fHideTrayIcon", !m_show_tray_icon);
473  break;
474  case MinimizeToTray:
475  fMinimizeToTray = value.toBool();
476  settings.setValue("fMinimizeToTray", fMinimizeToTray);
477  break;
478  case MapPortUPnP: // core option - can be changed on-the-fly
479  if (changed()) {
480  update(value.toBool());
481  node().mapPort(value.toBool(), getOption(MapPortNatpmp).toBool());
482  }
483  break;
484  case MapPortNatpmp: // core option - can be changed on-the-fly
485  if (changed()) {
486  update(value.toBool());
487  node().mapPort(getOption(MapPortUPnP).toBool(), value.toBool());
488  }
489  break;
490  case MinimizeOnClose:
491  fMinimizeOnClose = value.toBool();
492  settings.setValue("fMinimizeOnClose", fMinimizeOnClose);
493  break;
494 
495  // default proxy
496  case ProxyUse:
497  if (changed()) {
498  if (suffix.empty() && !value.toBool()) setOption(option, true, "-prev");
499  update(ProxyString(value.toBool(), getOption(ProxyIP).toString(), getOption(ProxyPort).toString()));
500  if (suffix.empty() && value.toBool()) UpdateRwSetting(node(), option, "-prev", {});
501  if (suffix.empty()) setRestartRequired(true);
502  }
503  break;
504  case ProxyIP:
505  if (changed()) {
506  if (suffix.empty() && !getOption(ProxyUse).toBool()) {
507  setOption(option, value, "-prev");
508  } else {
509  update(ProxyString(true, value.toString(), getOption(ProxyPort).toString()));
510  }
511  if (suffix.empty() && getOption(ProxyUse).toBool()) setRestartRequired(true);
512  }
513  break;
514  case ProxyPort:
515  if (changed()) {
516  if (suffix.empty() && !getOption(ProxyUse).toBool()) {
517  setOption(option, value, "-prev");
518  } else {
519  update(ProxyString(true, getOption(ProxyIP).toString(), value.toString()));
520  }
521  if (suffix.empty() && getOption(ProxyUse).toBool()) setRestartRequired(true);
522  }
523  break;
524 
525  // separate Tor proxy
526  case ProxyUseTor:
527  if (changed()) {
528  if (suffix.empty() && !value.toBool()) setOption(option, true, "-prev");
529  update(ProxyString(value.toBool(), getOption(ProxyIPTor).toString(), getOption(ProxyPortTor).toString()));
530  if (suffix.empty() && value.toBool()) UpdateRwSetting(node(), option, "-prev", {});
531  if (suffix.empty()) setRestartRequired(true);
532  }
533  break;
534  case ProxyIPTor:
535  if (changed()) {
536  if (suffix.empty() && !getOption(ProxyUseTor).toBool()) {
537  setOption(option, value, "-prev");
538  } else {
539  update(ProxyString(true, value.toString(), getOption(ProxyPortTor).toString()));
540  }
541  if (suffix.empty() && getOption(ProxyUseTor).toBool()) setRestartRequired(true);
542  }
543  break;
544  case ProxyPortTor:
545  if (changed()) {
546  if (suffix.empty() && !getOption(ProxyUseTor).toBool()) {
547  setOption(option, value, "-prev");
548  } else {
549  update(ProxyString(true, getOption(ProxyIPTor).toString(), value.toString()));
550  }
551  if (suffix.empty() && getOption(ProxyUseTor).toBool()) setRestartRequired(true);
552  }
553  break;
554 
555 #ifdef ENABLE_WALLET
556  case SpendZeroConfChange:
557  if (changed()) {
558  update(value.toBool());
559  setRestartRequired(true);
560  }
561  break;
562  case ExternalSignerPath:
563  if (changed()) {
564  update(value.toString().toStdString());
565  setRestartRequired(true);
566  }
567  break;
568  case SubFeeFromAmount:
569  m_sub_fee_from_amount = value.toBool();
570  settings.setValue("SubFeeFromAmount", m_sub_fee_from_amount);
571  break;
572 #endif
573  case DisplayUnit:
574  setDisplayUnit(value);
575  break;
576  case ThirdPartyTxUrls:
577  if (strThirdPartyTxUrls != value.toString()) {
578  strThirdPartyTxUrls = value.toString();
579  settings.setValue("strThirdPartyTxUrls", strThirdPartyTxUrls);
580  setRestartRequired(true);
581  }
582  break;
583  case Language:
584  if (changed()) {
585  update(value.toString().toStdString());
586  setRestartRequired(true);
587  }
588  break;
590  m_use_embedded_monospaced_font = value.toBool();
591  settings.setValue("UseEmbeddedMonospacedFont", m_use_embedded_monospaced_font);
593  break;
594  case CoinControlFeatures:
595  fCoinControlFeatures = value.toBool();
596  settings.setValue("fCoinControlFeatures", fCoinControlFeatures);
598  break;
599  case EnablePSBTControls:
600  m_enable_psbt_controls = value.toBool();
601  settings.setValue("enable_psbt_controls", m_enable_psbt_controls);
602  break;
603  case Prune:
604  if (changed()) {
605  if (suffix.empty() && !value.toBool()) setOption(option, true, "-prev");
606  update(PruneSetting(value.toBool(), getOption(PruneSize).toInt()));
607  if (suffix.empty() && value.toBool()) UpdateRwSetting(node(), option, "-prev", {});
608  if (suffix.empty()) setRestartRequired(true);
609  }
610  break;
611  case PruneSize:
612  if (changed()) {
613  if (suffix.empty() && !getOption(Prune).toBool()) {
614  setOption(option, value, "-prev");
615  } else {
616  update(PruneSetting(true, ParsePruneSizeGB(value)));
617  }
618  if (suffix.empty() && getOption(Prune).toBool()) setRestartRequired(true);
619  }
620  break;
621  case DatabaseCache:
622  if (changed()) {
623  update(static_cast<int64_t>(value.toLongLong()));
624  setRestartRequired(true);
625  }
626  break;
627  case ThreadsScriptVerif:
628  if (changed()) {
629  update(static_cast<int64_t>(value.toLongLong()));
630  setRestartRequired(true);
631  }
632  break;
633  case Listen:
634  case Server:
635  if (changed()) {
636  update(value.toBool());
637  setRestartRequired(true);
638  }
639  break;
640  case MaskValues:
641  m_mask_values = value.toBool();
642  settings.setValue("mask_values", m_mask_values);
643  break;
644  default:
645  break;
646  }
647 
648  return successful;
649 }
650 
651 void OptionsModel::setDisplayUnit(const QVariant& new_unit)
652 {
653  if (new_unit.isNull() || new_unit.value<BitcoinUnit>() == m_display_bitcoin_unit) return;
654  m_display_bitcoin_unit = new_unit.value<BitcoinUnit>();
655  QSettings settings;
656  settings.setValue("DisplayBitcoinUnit", QVariant::fromValue(m_display_bitcoin_unit));
658 }
659 
661 {
662  QSettings settings;
663  return settings.setValue("fRestartRequired", fRequired);
664 }
665 
667 {
668  QSettings settings;
669  return settings.value("fRestartRequired", false).toBool();
670 }
671 
673 {
674  return gArgs.GetArg("-signer", "") != "";
675 }
676 
678 {
679  // Migration of default values
680  // Check if the QSettings container was already loaded with this client version
681  QSettings settings;
682  static const char strSettingsVersionKey[] = "nSettingsVersion";
683  int settingsVersion = settings.contains(strSettingsVersionKey) ? settings.value(strSettingsVersionKey).toInt() : 0;
684  if (settingsVersion < CLIENT_VERSION)
685  {
686  // -dbcache was bumped from 100 to 300 in 0.13
687  // see https://github.com/bitcoin/bitcoin/pull/8273
688  // force people to upgrade to the new value if they are using 100MB
689  if (settingsVersion < 130000 && settings.contains("nDatabaseCache") && settings.value("nDatabaseCache").toLongLong() == 100)
690  settings.setValue("nDatabaseCache", (qint64)nDefaultDbCache);
691 
692  settings.setValue(strSettingsVersionKey, CLIENT_VERSION);
693  }
694 
695  // Overwrite the 'addrProxy' setting in case it has been set to an illegal
696  // default value (see issue #12623; PR #12650).
697  if (settings.contains("addrProxy") && settings.value("addrProxy").toString().endsWith("%2")) {
698  settings.setValue("addrProxy", GetDefaultProxyAddress());
699  }
700 
701  // Overwrite the 'addrSeparateProxyTor' setting in case it has been set to an illegal
702  // default value (see issue #12623; PR #12650).
703  if (settings.contains("addrSeparateProxyTor") && settings.value("addrSeparateProxyTor").toString().endsWith("%2")) {
704  settings.setValue("addrSeparateProxyTor", GetDefaultProxyAddress());
705  }
706 
707  // Migrate and delete legacy GUI settings that have now moved to <datadir>/settings.json.
708  auto migrate_setting = [&](OptionID option, const QString& qt_name) {
709  if (!settings.contains(qt_name)) return;
710  QVariant value = settings.value(qt_name);
711  if (node().getPersistentSetting(SettingName(option)).isNull()) {
712  if (option == ProxyIP) {
713  ProxySetting parsed = ParseProxyString(value.toString());
714  setOption(ProxyIP, parsed.ip);
715  setOption(ProxyPort, parsed.port);
716  } else if (option == ProxyIPTor) {
717  ProxySetting parsed = ParseProxyString(value.toString());
718  setOption(ProxyIPTor, parsed.ip);
719  setOption(ProxyPortTor, parsed.port);
720  } else {
721  setOption(option, value);
722  }
723  }
724  settings.remove(qt_name);
725  };
726 
727  migrate_setting(DatabaseCache, "nDatabaseCache");
728  migrate_setting(ThreadsScriptVerif, "nThreadsScriptVerif");
729 #ifdef ENABLE_WALLET
730  migrate_setting(SpendZeroConfChange, "bSpendZeroConfChange");
731  migrate_setting(ExternalSignerPath, "external_signer_path");
732 #endif
733  migrate_setting(MapPortUPnP, "fUseUPnP");
734  migrate_setting(MapPortNatpmp, "fUseNatpmp");
735  migrate_setting(Listen, "fListen");
736  migrate_setting(Server, "server");
737  migrate_setting(PruneSize, "nPruneSize");
738  migrate_setting(Prune, "bPrune");
739  migrate_setting(ProxyIP, "addrProxy");
740  migrate_setting(ProxyUse, "fUseProxy");
741  migrate_setting(ProxyIPTor, "addrSeparateProxyTor");
742  migrate_setting(ProxyUseTor, "fUseSeparateProxyTor");
743  migrate_setting(Language, "language");
744 
745  // In case migrating QSettings caused any settings value to change, rerun
746  // parameter interaction code to update other settings. This is particularly
747  // important for the -listen setting, which should cause -listenonion, -upnp,
748  // and other settings to default to false if it was set to false.
749  // (https://github.com/bitcoin-core/gui/issues/567).
751 }
virtual common::SettingsValue getPersistentSetting(const std::string &name)=0
Return setting value from <datadir>/settings.json or bitcoin.conf.
static std::string ProxyString(bool is_set, QString ip, QString port)
static const int DEFAULT_SCRIPTCHECK_THREADS
-par default (number of script-checking threads, 0 = auto)
Definition: validation.h:71
static void UpdateRwSetting(interfaces::Node &node, OptionsModel::OptionID option, const std::string &suffix, const common::SettingsValue &value)
Call node.updateRwSetting() with Bitcoin 22.x workaround.
static const char * SettingName(OptionsModel::OptionID option)
Map GUI option ID to node setting name.
virtual void resetSettings()=0
Clear all settings in <datadir>/settings.json and store a backup of previous settings in <datadir>/se...
Unit
Bitcoin units.
Definition: bitcoinunits.h:42
static constexpr int DEFAULT_PRUNE_TARGET_GB
Definition: guiconstants.h:60
static void BackupSettings(const fs::path &filename, const QSettings &src)
Back up a QSettings to an ini-formatted file.
void addOverriddenOption(const std::string &option)
assert(!tx.IsCoinBase())
Bilingual messages:
Definition: translation.h:18
node::NodeContext m_node
Definition: bitcoin-gui.cpp:37
bool m_mask_values
Definition: optionsmodel.h:127
bool hasSigner()
Whether -signer was set or not.
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1162
static common::SettingsValue PruneSetting(bool prune_enabled, int prune_size_gb)
Convert enabled/size values to bitcoin -prune setting.
static int ParsePruneSizeGB(const QVariant &prune_size)
Parse pruning size value provided by user in GUI or loaded from QSettings (windows registry key or qt...
static void CopySettings(QSettings &dst, const QSettings &src)
Helper function to copy contents from one QSettings to another.
bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole) override
static const bool DEFAULT_LISTEN
-listen default
Definition: net.h:79
void SetPruneTargetGB(int prune_target_gb)
QString language
Definition: optionsmodel.h:120
BitcoinUnit m_display_bitcoin_unit
Definition: optionsmodel.h:121
bool GetStartOnSystemStartup()
Definition: guiutil.cpp:651
void coinControlFeaturesChanged(bool)
bool isNum() const
Definition: univalue.h:83
void useEmbeddedMonospacedFontChanged(bool)
static int64_t PruneGBtoMiB(int gb)
Convert displayed prune target GB to configured MiB.
Definition: optionsmodel.h:32
const std::string & getValStr() const
Definition: univalue.h:67
bool fMinimizeOnClose
Definition: optionsmodel.h:119
static int PruneSizeGB(const common::SettingsValue &prune_setting)
Get pruning size value to show in GUI from bitcoin -prune setting.
bool Init(bilingual_str &error)
bool isRestartRequired() const
static const bool DEFAULT_SPEND_ZEROCONF_CHANGE
Default for -spendzeroconfchange.
Definition: wallet.h:127
interfaces::Node & node() const
Definition: optionsmodel.h:112
static constexpr bool DEFAULT_UPNP
Definition: mapport.h:8
bool setOption(OptionID option, const QVariant &value, const std::string &suffix="")
int rowCount(const QModelIndex &parent=QModelIndex()) const override
void displayUnitChanged(BitcoinUnit unit)
std::optional< std::string > SettingToString(const common::SettingsValue &value)
Definition: args.cpp:467
bool fMinimizeToTray
Definition: optionsmodel.h:118
QVariant getOption(OptionID option, const std::string &suffix="") const
std::optional< bool > SettingToBool(const common::SettingsValue &value)
Definition: args.cpp:517
static bool PruneEnabled(const common::SettingsValue &prune_setting)
Get pruning enabled value to show in GUI from bitcoin -prune setting.
const char * DEFAULT_GUI_PROXY_HOST
static const int64_t nDefaultDbCache
-dbcache default (MiB)
Definition: txdb.h:25
static CService ip(uint32_t i)
static int PruneMiBtoGB(int64_t mib)
Convert configured prune target MiB to displayed GB.
Definition: optionsmodel.h:27
bool m_show_tray_icon
Definition: optionsmodel.h:117
bool fCoinControlFeatures
Definition: optionsmodel.h:124
bool m_enable_psbt_controls
Definition: optionsmodel.h:126
Definition: init.h:25
static constexpr uint16_t DEFAULT_GUI_PROXY_PORT
Definition: optionsmodel.h:22
ArgsManager gArgs
Definition: args.cpp:42
void checkAndMigrate()
virtual void initParameterInteraction()=0
Init parameter interaction.
QStringList SplitSkipEmptyParts(const QString &string, const SeparatorType &separator)
Splits the string into substrings wherever separator occurs, and returns the list of those strings...
Definition: guiutil.h:363
static constexpr bool DEFAULT_NATPMP
Definition: mapport.h:10
bool m_use_embedded_monospaced_font
Definition: optionsmodel.h:123
void setRestartRequired(bool fRequired)
bool error(const char *fmt, const Args &... args)
Definition: logging.h:262
QString strThirdPartyTxUrls
Definition: optionsmodel.h:122
std::string GetArg(const std::string &strArg, const std::string &strDefault) const
Return string argument or default value.
Definition: args.cpp:456
static ProxySetting ParseProxyString(const std::string &proxy)
bool m_sub_fee_from_amount
Definition: optionsmodel.h:125
bool SetStartOnSystemStartup(bool fAutoStart)
Definition: guiutil.cpp:652
std::optional< int64_t > SettingToInt(const common::SettingsValue &value)
Definition: args.cpp:492
OptionsModel(interfaces::Node &node, QObject *parent=nullptr)
virtual void forceSetting(const std::string &name, const common::SettingsValue &value)=0
Force a setting value to be applied, overriding any other configuration source, but not being persist...
static QString GetDefaultProxyAddress()
QString getDefaultDataDirectory()
Determine default data directory for operating system.
Definition: guiutil.cpp:292
Path class wrapper to block calls to the fs::path(std::string) implicit constructor and the fs::path:...
Definition: fs.h:30
static const int CLIENT_VERSION
bitcoind-res.rc includes this file, but it cannot cope with real c++ code.
Definition: clientversion.h:33
virtual void mapPort(bool use_upnp, bool use_natpmp)=0
Map port.
Top-level interface for a bitcoin node (bitcoind process).
Definition: node.h:69
void setDisplayUnit(const QVariant &new_unit)
Updates current unit in memory, settings and emits displayUnitChanged(new_unit) signal.
QString PathToQString(const fs::path &path)
Convert OS specific boost path to QString through UTF-8.
Definition: guiutil.cpp:670
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
QString strOverriddenByCommandLine
Definition: optionsmodel.h:130
const fs::path & GetDataDirNet() const
Get data directory path with appended network identifier.
Definition: args.h:231
void showTrayIconChanged(bool)