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