Bitcoin ABC 0.32.6
P2P Digital Currency
optionsmodel.cpp
Go to the documentation of this file.
1// Copyright (c) 2011-2016 The Bitcoin Core developers
2// Distributed under the MIT software license, see the accompanying
3// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5#if defined(HAVE_CONFIG_H)
6#include <config/bitcoin-config.h>
7#endif
8
9#include <qt/optionsmodel.h>
10
11#include <clientversion.h>
12#include <common/args.h>
13#include <interfaces/node.h>
14#include <mapport.h>
15#include <net.h>
16#include <netbase.h>
17#include <node/caches.h>
18#include <qt/bitcoinunits.h>
19#include <qt/guiconstants.h>
20#include <qt/guiutil.h>
21#include <util/string.h>
22#include <validation.h> // For DEFAULT_SCRIPTCHECK_THREADS
23
24#include <QDebug> // needed by qInfo()
25#ifdef ENABLE_BIP70
26#include <QNetworkProxy>
27#endif
28#include <QSettings>
29#include <QStringList>
30
31const char *DEFAULT_GUI_PROXY_HOST = "127.0.0.1";
32
33static QString GetDefaultProxyAddress();
34
35OptionsModel::OptionsModel(QObject *parent, bool resetSettings)
36 : QAbstractListModel(parent) {
37 Init(resetSettings);
38}
39
40void OptionsModel::addOverriddenOption(const std::string &option) {
42 QString::fromStdString(option) + "=" +
43 QString::fromStdString(gArgs.GetArg(option, "")) + " ";
44}
45
46// Writes all missing QSettings with their default values
47void OptionsModel::Init(bool resetSettings) {
48 if (resetSettings) {
49 Reset();
50 }
51
53
54 QSettings settings;
55
56 // Ensure restart flag is unset on client startup
57 setRestartRequired(false);
58
59 // These are Qt-only settings:
60
61 // Window
62 if (!settings.contains("fHideTrayIcon")) {
63 settings.setValue("fHideTrayIcon", false);
64 }
65 fHideTrayIcon = settings.value("fHideTrayIcon").toBool();
67
68 if (!settings.contains("fMinimizeToTray")) {
69 settings.setValue("fMinimizeToTray", false);
70 }
72 settings.value("fMinimizeToTray").toBool() && !fHideTrayIcon;
73
74 if (!settings.contains("fMinimizeOnClose")) {
75 settings.setValue("fMinimizeOnClose", false);
76 }
77 fMinimizeOnClose = settings.value("fMinimizeOnClose").toBool();
78
79 // Display
80 if (!settings.contains("nDisplayUnit")) {
81 settings.setValue("nDisplayUnit", BitcoinUnits::base);
82 }
83 nDisplayUnit = settings.value("nDisplayUnit").toInt();
84
85 if (!settings.contains("strThirdPartyTxUrls")) {
86 settings.setValue("strThirdPartyTxUrls", "");
87 }
88 strThirdPartyTxUrls = settings.value("strThirdPartyTxUrls", "").toString();
89
90 if (!settings.contains("fCoinControlFeatures")) {
91 settings.setValue("fCoinControlFeatures", false);
92 }
94 settings.value("fCoinControlFeatures", false).toBool();
95
96 // These are shared with the core or have a command-line parameter
97 // and we want command-line parameters to overwrite the GUI settings.
98 //
99 // If setting doesn't exist create it with defaults.
100 //
101 // If gArgs.SoftSetArg() or gArgs.SoftSetBoolArg() return false we were
102 // overridden
103 // by command-line and show this in the UI.
104
105 // Main
106 if (!settings.contains("bPrune")) {
107 settings.setValue("bPrune", false);
108 }
109 if (!settings.contains("nPruneSize")) {
110 settings.setValue("nPruneSize", DEFAULT_PRUNE_TARGET_GB);
111 }
112 SetPruneEnabled(settings.value("bPrune").toBool());
113
114 if (!settings.contains("nDatabaseCache")) {
115 settings.setValue("nDatabaseCache", (qint64)DEFAULT_DB_CACHE >> 20);
116 }
117 if (!gArgs.SoftSetArg(
118 "-dbcache",
119 settings.value("nDatabaseCache").toString().toStdString())) {
120 addOverriddenOption("-dbcache");
121 }
122
123 if (!settings.contains("nThreadsScriptVerif")) {
124 settings.setValue("nThreadsScriptVerif", DEFAULT_SCRIPTCHECK_THREADS);
125 }
126 if (!gArgs.SoftSetArg(
127 "-par",
128 settings.value("nThreadsScriptVerif").toString().toStdString())) {
129 addOverriddenOption("-par");
130 }
131
132 if (!settings.contains("strDataDir")) {
133 settings.setValue("strDataDir", GUIUtil::getDefaultDataDirectory());
134 }
135
136// Wallet
137#ifdef ENABLE_WALLET
138 if (!settings.contains("bSpendZeroConfChange")) {
139 settings.setValue("bSpendZeroConfChange", true);
140 }
142 "-spendzeroconfchange",
143 settings.value("bSpendZeroConfChange").toBool())) {
144 addOverriddenOption("-spendzeroconfchange");
145 }
146#endif
147
148 // Network
149 if (!settings.contains("fUseUPnP")) {
150 settings.setValue("fUseUPnP", DEFAULT_UPNP);
151 }
152 if (!gArgs.SoftSetBoolArg("-upnp", settings.value("fUseUPnP").toBool())) {
153 addOverriddenOption("-upnp");
154 }
155
156 if (!settings.contains("fUseNatpmp")) {
157 settings.setValue("fUseNatpmp", DEFAULT_NATPMP);
158 }
159 if (!gArgs.SoftSetBoolArg("-natpmp",
160 settings.value("fUseNatpmp").toBool())) {
161 addOverriddenOption("-natpmp");
162 }
163
164 if (!settings.contains("fListen")) {
165 settings.setValue("fListen", DEFAULT_LISTEN);
166 }
167 if (!gArgs.SoftSetBoolArg("-listen", settings.value("fListen").toBool())) {
168 addOverriddenOption("-listen");
169 }
170
171 if (!settings.contains("fUseProxy")) {
172 settings.setValue("fUseProxy", false);
173 }
174 if (!settings.contains("addrProxy")) {
175 settings.setValue("addrProxy", GetDefaultProxyAddress());
176 }
177 // Only try to set -proxy, if user has enabled fUseProxy
178 if (settings.value("fUseProxy").toBool() &&
180 "-proxy", settings.value("addrProxy").toString().toStdString())) {
181 addOverriddenOption("-proxy");
182 } else if (!settings.value("fUseProxy").toBool() &&
183 !gArgs.GetArg("-proxy", "").empty()) {
184 addOverriddenOption("-proxy");
185 }
186
187 if (!settings.contains("fUseSeparateProxyTor")) {
188 settings.setValue("fUseSeparateProxyTor", false);
189 }
190 if (!settings.contains("addrSeparateProxyTor")) {
191 settings.setValue("addrSeparateProxyTor", GetDefaultProxyAddress());
192 }
193 // Only try to set -onion, if user has enabled fUseSeparateProxyTor
194 if (settings.value("fUseSeparateProxyTor").toBool() &&
196 "-onion",
197 settings.value("addrSeparateProxyTor").toString().toStdString())) {
198 addOverriddenOption("-onion");
199 } else if (!settings.value("fUseSeparateProxyTor").toBool() &&
200 !gArgs.GetArg("-onion", "").empty()) {
201 addOverriddenOption("-onion");
202 }
203
204 // Display
205 if (!settings.contains("language")) {
206 settings.setValue("language", "");
207 }
208 if (!gArgs.SoftSetArg(
209 "-lang", settings.value("language").toString().toStdString())) {
210 addOverriddenOption("-lang");
211 }
212
213 language = settings.value("language").toString();
214}
215
220static void CopySettings(QSettings &dst, const QSettings &src) {
221 for (const QString &key : src.allKeys()) {
222 dst.setValue(key, src.value(key));
223 }
224}
225
227static void BackupSettings(const fs::path &filename, const QSettings &src) {
228 qInfo() << "Backing up GUI settings to"
229 << GUIUtil::boostPathToQString(filename);
230 QSettings dst(GUIUtil::boostPathToQString(filename), QSettings::IniFormat);
231 dst.clear();
232 CopySettings(dst, src);
233}
234
236 QSettings settings;
237
238 // Backup old settings to chain-specific datadir for troubleshooting
239 BackupSettings(gArgs.GetDataDirNet() / "guisettings.ini.bak", settings);
240
241 // Save the strDataDir setting
242 QString dataDir = GUIUtil::getDefaultDataDirectory();
243 dataDir = settings.value("strDataDir", dataDir).toString();
244
245 // Remove all entries from our QSettings object
246 settings.clear();
247
248 // Set strDataDir
249 settings.setValue("strDataDir", dataDir);
250
251 // Set that this was reset
252 settings.setValue("fReset", true);
253
254 // default setting for OptionsModel::StartAtStartup - disabled
257 }
258}
259
260int OptionsModel::rowCount(const QModelIndex &parent) const {
261 return OptionIDRowCount;
262}
263
265 bool is_set;
266 QString ip;
267 QString port;
268};
269
270static ProxySetting GetProxySetting(QSettings &settings, const QString &name) {
271 static const ProxySetting default_val = {
273 QString("%1").arg(DEFAULT_GUI_PROXY_PORT)};
274 // Handle the case that the setting is not set at all
275 if (!settings.contains(name)) {
276 return default_val;
277 }
278 // contains IP at index 0 and port at index 1
279 QStringList ip_port =
280 GUIUtil::splitSkipEmptyParts(settings.value(name).toString(), ":");
281 if (ip_port.size() == 2) {
282 return {true, ip_port.at(0), ip_port.at(1)};
283 } else { // Invalid: return default
284 return default_val;
285 }
286}
287
288static void SetProxySetting(QSettings &settings, const QString &name,
289 const ProxySetting &ip_port) {
290 settings.setValue(name, ip_port.ip + ":" + ip_port.port);
291}
292
293static QString GetDefaultProxyAddress() {
294 return QString("%1:%2")
297}
298
299void OptionsModel::SetPruneEnabled(bool prune, bool force) {
300 QSettings settings;
301 settings.setValue("bPrune", prune);
302 const int64_t prune_target_mib =
303 PruneGBtoMiB(settings.value("nPruneSize").toInt());
304 std::string prune_val = prune ? ToString(prune_target_mib) : "0";
305 if (force) {
306 gArgs.ForceSetArg("-prune", prune_val);
307 return;
308 }
309 if (!gArgs.SoftSetArg("-prune", prune_val)) {
310 addOverriddenOption("-prune");
311 }
312}
313
314void OptionsModel::SetPruneTargetGB(int prune_target_gb, bool force) {
315 const bool prune = prune_target_gb > 0;
316 if (prune) {
317 QSettings settings;
318 settings.setValue("nPruneSize", prune_target_gb);
319 }
320 SetPruneEnabled(prune, force);
321}
322
323// read QSettings values and return them
324QVariant OptionsModel::data(const QModelIndex &index, int role) const {
325 if (role == Qt::EditRole) {
326 QSettings settings;
327 switch (index.row()) {
328 case StartAtStartup:
330 case HideTrayIcon:
331 return fHideTrayIcon;
332 case MinimizeToTray:
333 return fMinimizeToTray;
334 case MapPortUPnP:
335#ifdef USE_UPNP
336 return settings.value("fUseUPnP");
337#else
338 return false;
339#endif // USE_UPNP
340 case MapPortNatpmp:
341#ifdef USE_NATPMP
342 return settings.value("fUseNatpmp");
343#else
344 return false;
345#endif // USE_NATPMP
346 case MinimizeOnClose:
347 return fMinimizeOnClose;
348
349 // default proxy
350 case ProxyUse:
351 return settings.value("fUseProxy", false);
352 case ProxyIP:
353 return GetProxySetting(settings, "addrProxy").ip;
354 case ProxyPort:
355 return GetProxySetting(settings, "addrProxy").port;
356
357 // separate Tor proxy
358 case ProxyUseTor:
359 return settings.value("fUseSeparateProxyTor", false);
360 case ProxyIPTor:
361 return GetProxySetting(settings, "addrSeparateProxyTor").ip;
362 case ProxyPortTor:
363 return GetProxySetting(settings, "addrSeparateProxyTor").port;
364
365#ifdef ENABLE_WALLET
367 return settings.value("bSpendZeroConfChange");
368#endif
369 case DisplayUnit:
370 return nDisplayUnit;
371 case ThirdPartyTxUrls:
372 return strThirdPartyTxUrls;
373 case Language:
374 return settings.value("language");
377 case Prune:
378 return settings.value("bPrune");
379 case PruneSize:
380 return settings.value("nPruneSize");
381 case DatabaseCache:
382 return settings.value("nDatabaseCache");
384 return settings.value("nThreadsScriptVerif");
385 case Listen:
386 return settings.value("fListen");
387 default:
388 return QVariant();
389 }
390 }
391 return QVariant();
392}
393
394// write QSettings values
395bool OptionsModel::setData(const QModelIndex &index, const QVariant &value,
396 int role) {
397 bool successful = true; /* set to false on parse error */
398 if (role == Qt::EditRole) {
399 QSettings settings;
400 switch (index.row()) {
401 case StartAtStartup:
402 successful = GUIUtil::SetStartOnSystemStartup(value.toBool());
403 break;
404 case HideTrayIcon:
405 fHideTrayIcon = value.toBool();
406 settings.setValue("fHideTrayIcon", fHideTrayIcon);
408 break;
409 case MinimizeToTray:
410 fMinimizeToTray = value.toBool();
411 settings.setValue("fMinimizeToTray", fMinimizeToTray);
412 break;
413 case MapPortUPnP: // core option - can be changed on-the-fly
414 settings.setValue("fUseUPnP", value.toBool());
415 break;
416 case MapPortNatpmp: // core option - can be changed on-the-fly
417 settings.setValue("fUseNatpmp", value.toBool());
418 break;
419 case MinimizeOnClose:
420 fMinimizeOnClose = value.toBool();
421 settings.setValue("fMinimizeOnClose", fMinimizeOnClose);
422 break;
423
424 // default proxy
425 case ProxyUse:
426 if (settings.value("fUseProxy") != value) {
427 settings.setValue("fUseProxy", value.toBool());
428 setRestartRequired(true);
429 }
430 break;
431 case ProxyIP: {
432 auto ip_port = GetProxySetting(settings, "addrProxy");
433 if (!ip_port.is_set || ip_port.ip != value.toString()) {
434 ip_port.ip = value.toString();
435 SetProxySetting(settings, "addrProxy", ip_port);
436 setRestartRequired(true);
437 }
438 } break;
439 case ProxyPort: {
440 auto ip_port = GetProxySetting(settings, "addrProxy");
441 if (!ip_port.is_set || ip_port.port != value.toString()) {
442 ip_port.port = value.toString();
443 SetProxySetting(settings, "addrProxy", ip_port);
444 setRestartRequired(true);
445 }
446 } break;
447
448 // separate Tor proxy
449 case ProxyUseTor:
450 if (settings.value("fUseSeparateProxyTor") != value) {
451 settings.setValue("fUseSeparateProxyTor", value.toBool());
452 setRestartRequired(true);
453 }
454 break;
455 case ProxyIPTor: {
456 auto ip_port =
457 GetProxySetting(settings, "addrSeparateProxyTor");
458 if (!ip_port.is_set || ip_port.ip != value.toString()) {
459 ip_port.ip = value.toString();
460 SetProxySetting(settings, "addrSeparateProxyTor", ip_port);
461 setRestartRequired(true);
462 }
463 } break;
464 case ProxyPortTor: {
465 auto ip_port =
466 GetProxySetting(settings, "addrSeparateProxyTor");
467 if (!ip_port.is_set || ip_port.port != value.toString()) {
468 ip_port.port = value.toString();
469 SetProxySetting(settings, "addrSeparateProxyTor", ip_port);
470 setRestartRequired(true);
471 }
472 } break;
473
474#ifdef ENABLE_WALLET
476 if (settings.value("bSpendZeroConfChange") != value) {
477 settings.setValue("bSpendZeroConfChange", value);
478 setRestartRequired(true);
479 }
480 break;
481#endif
482 case DisplayUnit:
483 setDisplayUnit(value);
484 break;
485 case ThirdPartyTxUrls:
486 if (strThirdPartyTxUrls != value.toString()) {
487 strThirdPartyTxUrls = value.toString();
488 settings.setValue("strThirdPartyTxUrls",
490 setRestartRequired(true);
491 }
492 break;
493 case Language:
494 if (settings.value("language") != value) {
495 settings.setValue("language", value);
496 setRestartRequired(true);
497 }
498 break;
500 fCoinControlFeatures = value.toBool();
501 settings.setValue("fCoinControlFeatures", fCoinControlFeatures);
503 break;
504 case Prune:
505 if (settings.value("bPrune") != value) {
506 settings.setValue("bPrune", value);
507 setRestartRequired(true);
508 }
509 break;
510 case PruneSize:
511 if (settings.value("nPruneSize") != value) {
512 settings.setValue("nPruneSize", value);
513 setRestartRequired(true);
514 }
515 break;
516 case DatabaseCache:
517 if (settings.value("nDatabaseCache") != value) {
518 settings.setValue("nDatabaseCache", value);
519 setRestartRequired(true);
520 }
521 break;
523 if (settings.value("nThreadsScriptVerif") != value) {
524 settings.setValue("nThreadsScriptVerif", value);
525 setRestartRequired(true);
526 }
527 break;
528 case Listen:
529 if (settings.value("fListen") != value) {
530 settings.setValue("fListen", value);
531 setRestartRequired(true);
532 }
533 break;
534 default:
535 break;
536 }
537 }
538
539 Q_EMIT dataChanged(index, index);
540
541 return successful;
542}
543
546void OptionsModel::setDisplayUnit(const QVariant &value) {
547 if (!value.isNull()) {
548 QSettings settings;
549 nDisplayUnit = value.toInt();
550 settings.setValue("nDisplayUnit", nDisplayUnit);
552 }
553}
554
555#ifdef ENABLE_BIP70
556bool OptionsModel::getProxySettings(QNetworkProxy &proxy) const {
557 // Directly query current base proxy, because
558 // GUI settings can be overridden with -proxy.
559 proxyType curProxy;
560 if (node().getProxy(NET_IPV4, curProxy)) {
561 proxy.setType(QNetworkProxy::Socks5Proxy);
562 proxy.setHostName(QString::fromStdString(curProxy.proxy.ToStringIP()));
563 proxy.setPort(curProxy.proxy.GetPort());
564
565 return true;
566 } else {
567 proxy.setType(QNetworkProxy::NoProxy);
568 }
569
570 return false;
571}
572#endif
573
575 QSettings settings;
576 return settings.setValue("fRestartRequired", fRequired);
577}
578
580 QSettings settings;
581 return settings.value("fRestartRequired", false).toBool();
582}
583
585 // Migration of default values
586 // Check if the QSettings container was already loaded with this client
587 // version
588 QSettings settings;
589 static const char strSettingsVersionKey[] = "nSettingsVersion";
590 int settingsVersion = settings.contains(strSettingsVersionKey)
591 ? settings.value(strSettingsVersionKey).toInt()
592 : 0;
593 if (settingsVersion < CLIENT_VERSION) {
594 // -dbcache was bumped from 100 to 300 in 0.13
595 // see https://github.com/bitcoin/bitcoin/pull/8273
596 // force people to upgrade to the new value if they are using 100MB
597 if (settingsVersion < 130000 && settings.contains("nDatabaseCache") &&
598 settings.value("nDatabaseCache").toLongLong() == 100) {
599 settings.setValue("nDatabaseCache", (qint64)DEFAULT_DB_CACHE >> 20);
600 }
601
602 settings.setValue(strSettingsVersionKey, CLIENT_VERSION);
603 }
604
605 // Overwrite the 'addrProxy' setting in case it has been set to an illegal
606 // default value (see issue #12623; PR #12650).
607 if (settings.contains("addrProxy") &&
608 settings.value("addrProxy").toString().endsWith("%2")) {
609 settings.setValue("addrProxy", GetDefaultProxyAddress());
610 }
611
612 // Overwrite the 'addrSeparateProxyTor' setting in case it has been set to
613 // an illegal default value (see issue #12623; PR #12650).
614 if (settings.contains("addrSeparateProxyTor") &&
615 settings.value("addrSeparateProxyTor").toString().endsWith("%2")) {
616 settings.setValue("addrSeparateProxyTor", GetDefaultProxyAddress());
617 }
618}
ArgsManager gArgs
Definition: args.cpp:40
void ForceSetArg(const std::string &strArg, const std::string &strValue)
Definition: args.cpp:566
fs::path GetDataDirNet() const
Get data directory path with appended network identifier.
Definition: args.h:239
bool SoftSetArg(const std::string &strArg, const std::string &strValue)
Set an argument if it doesn't already have a value.
Definition: args.cpp:548
std::string GetArg(const std::string &strArg, const std::string &strDefault) const
Return string argument or default value.
Definition: args.cpp:463
bool SoftSetBoolArg(const std::string &strArg, bool fValue)
Set a boolean argument if it doesn't already have a value.
Definition: args.cpp:558
std::string ToStringIP() const
Definition: netaddress.cpp:623
uint16_t GetPort() const
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
QString strOverriddenByCommandLine
Definition: optionsmodel.h:133
bool getProxySettings(QNetworkProxy &proxy) const
bool isRestartRequired() const
void Init(bool resetSettings=false)
bool fCoinControlFeatures
Definition: optionsmodel.h:131
interfaces::Node & node() const
Definition: optionsmodel.h:113
void setDisplayUnit(const QVariant &value)
Updates current unit in memory, settings and emits displayUnitChanged(newUnit) signal.
void coinControlFeaturesChanged(bool)
QString strThirdPartyTxUrls
Definition: optionsmodel.h:130
OptionsModel(QObject *parent=nullptr, bool resetSettings=false)
int rowCount(const QModelIndex &parent=QModelIndex()) const override
void SetPruneTargetGB(int prune_target_gb, bool force=false)
void SetPruneEnabled(bool prune, bool force=false)
void displayUnitChanged(int unit)
bool fHideTrayIcon
Definition: optionsmodel.h:125
bool fMinimizeToTray
Definition: optionsmodel.h:126
bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole) override
void checkAndMigrate()
QString language
Definition: optionsmodel.h:128
void addOverriddenOption(const std::string &option)
bool fMinimizeOnClose
Definition: optionsmodel.h:127
void setRestartRequired(bool fRequired)
void hideTrayIconChanged(bool)
Path class wrapper to block calls to the fs::path(std::string) implicit constructor and the fs::path:...
Definition: fs.h:30
CService proxy
Definition: netbase.h:60
static constexpr int CLIENT_VERSION
bitcoind-res.rc includes this file, but it cannot cope with real c++ code.
Definition: clientversion.h:38
static constexpr int DEFAULT_PRUNE_TARGET_GB
Definition: guiconstants.h:56
static constexpr bool DEFAULT_NATPMP
Definition: mapport.h:17
static constexpr bool DEFAULT_UPNP
Definition: mapport.h:11
QString getDefaultDataDirectory()
Determine default data directory for operating system.
Definition: guiutil.cpp:295
QString boostPathToQString(const fs::path &path)
Convert OS specific boost path to QString through UTF-8.
Definition: guiutil.cpp:791
bool SetStartOnSystemStartup(bool fAutoStart)
Definition: guiutil.cpp:776
bool GetStartOnSystemStartup()
Definition: guiutil.cpp:773
QStringList splitSkipEmptyParts(const QString &s, const QString &separator)
Definition: guiutil.cpp:451
static const bool DEFAULT_LISTEN
-listen default
Definition: net.h:87
@ NET_IPV4
IPv4.
Definition: netaddress.h:43
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 QString GetDefaultProxyAddress()
static ProxySetting GetProxySetting(QSettings &settings, const QString &name)
static void SetProxySetting(QSettings &settings, const QString &name, const ProxySetting &ip_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 int64_t PruneGBtoMiB(int gb)
Convert displayed prune target GB to configured MiB.
Definition: optionsmodel.h:38
static constexpr uint16_t DEFAULT_GUI_PROXY_PORT
Definition: optionsmodel.h:24
const char * name
Definition: rest.cpp:46
std::string ToString(const T &t)
Locale-independent version of std::to_string.
Definition: string.h:108
static const int DEFAULT_SCRIPTCHECK_THREADS
-par default (number of script-checking threads, 0 = auto)
Definition: validation.h:91