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