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