Bitcoin ABC 0.32.4
P2P Digital Currency
bitcoin.cpp
Go to the documentation of this file.
1// Copyright (c) 2011-2019 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 <qt/bitcoin.h>
6
7#include <chainparams.h>
8#include <common/args.h>
9#include <common/init.h>
10#include <config.h>
11#include <httprpc.h>
12#include <init.h>
13#include <interfaces/handler.h>
14#include <interfaces/node.h>
15#include <node/context.h>
16#include <node/ui_interface.h>
17#include <noui.h>
18#include <qt/bitcoingui.h>
19#include <qt/clientmodel.h>
20#include <qt/guiconstants.h>
21#include <qt/guiutil.h>
22#include <qt/intro.h>
23#include <qt/networkstyle.h>
24#include <qt/optionsmodel.h>
25#include <qt/platformstyle.h>
26#include <qt/splashscreen.h>
27#include <qt/utilitydialog.h>
29#include <rpc/server.h>
30#include <uint256.h>
31#include <util/exception.h>
32#include <util/string.h>
33#include <util/threadnames.h>
34#include <util/translation.h>
35#include <validation.h>
36
37#ifdef ENABLE_WALLET
38#include <qt/paymentserver.h>
39#include <qt/walletcontroller.h>
40#include <qt/walletmodel.h>
41#endif // ENABLE_WALLET
42
43#include <QDebug>
44#include <QLibraryInfo>
45#include <QLocale>
46#include <QMessageBox>
47#include <QSettings>
48#include <QThread>
49#include <QTimer>
50#include <QTranslator>
51#include <QWindow>
52
53#include <boost/signals2/connection.hpp>
54
55#include <any>
56
57#if defined(QT_STATICPLUGIN)
58#include <QtPlugin>
59#if defined(QT_QPA_PLATFORM_XCB)
60Q_IMPORT_PLUGIN(QXcbIntegrationPlugin);
61#elif defined(QT_QPA_PLATFORM_WINDOWS)
62Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin);
63#elif defined(QT_QPA_PLATFORM_COCOA)
64Q_IMPORT_PLUGIN(QCocoaIntegrationPlugin);
65Q_IMPORT_PLUGIN(QMacStylePlugin);
66#endif
67#endif
68
69// Declare meta types used for QMetaObject::invokeMethod
70Q_DECLARE_METATYPE(bool *)
71Q_DECLARE_METATYPE(Amount)
72Q_DECLARE_METATYPE(HTTPRPCRequestProcessor *)
73Q_DECLARE_METATYPE(RPCServer *)
74Q_DECLARE_METATYPE(SynchronizationState)
75Q_DECLARE_METATYPE(SyncType)
76Q_DECLARE_METATYPE(uint256)
77
78// Config is non-copyable so we can only register pointers to it
79Q_DECLARE_METATYPE(Config *)
80
82
83static void RegisterMetaTypes() {
84 // Register meta types used for QMetaObject::invokeMethod and
85 // Qt::QueuedConnection
86 qRegisterMetaType<bool *>();
87 qRegisterMetaType<SynchronizationState>();
88 qRegisterMetaType<SyncType>();
89#ifdef ENABLE_WALLET
90 qRegisterMetaType<WalletModel *>();
91#endif
92 qRegisterMetaType<Amount>();
93 // Register typedefs (see
94 // http://qt-project.org/doc/qt-5/qmetatype.html#qRegisterMetaType)
95 qRegisterMetaType<size_t>("size_t");
96
97 qRegisterMetaType<std::function<void()>>("std::function<void()>");
98 qRegisterMetaType<QMessageBox::Icon>("QMessageBox::Icon");
99 qRegisterMetaType<interfaces::BlockAndHeaderTipInfo>(
100 "interfaces::BlockAndHeaderTipInfo");
101
102 // Need to register any types Qt doesn't know about if you intend
103 // to use them with the signal/slot mechanism Qt provides. Even pointers.
104 // Note that class Config is noncopyable and so we can't register a
105 // non-pointer version of it with Qt, because Qt expects to be able to
106 // copy-construct non-pointers to objects for invoking slots
107 // behind-the-scenes in the 'Queued' connection case.
108 qRegisterMetaType<Config *>();
109 qRegisterMetaType<RPCServer *>();
110 qRegisterMetaType<HTTPRPCRequestProcessor *>();
111
112 // TODO: apply core-gui#623 if we ever backport core-gui#556
113}
114
115static QString GetLangTerritory() {
116 QSettings settings;
117 // Get desired locale (e.g. "de_DE")
118 // 1) System default language
119 QString lang_territory = QLocale::system().name();
120 // 2) Language from QSettings
121 QString lang_territory_qsettings =
122 settings.value("language", "").toString();
123 if (!lang_territory_qsettings.isEmpty()) {
124 lang_territory = lang_territory_qsettings;
125 }
126 // 3) -lang command line argument
127 lang_territory = QString::fromStdString(
128 gArgs.GetArg("-lang", lang_territory.toStdString()));
129 return lang_territory;
130}
131
133static void initTranslations(QTranslator &qtTranslatorBase,
134 QTranslator &qtTranslator,
135 QTranslator &translatorBase,
136 QTranslator &translator) {
137 // Remove old translators
138 QApplication::removeTranslator(&qtTranslatorBase);
139 QApplication::removeTranslator(&qtTranslator);
140 QApplication::removeTranslator(&translatorBase);
141 QApplication::removeTranslator(&translator);
142
143 // Get desired locale (e.g. "de_DE")
144 // 1) System default language
145 QString lang_territory = GetLangTerritory();
146
147 // Convert to "de" only by truncating "_DE"
148 QString lang = lang_territory;
149 lang.truncate(lang_territory.lastIndexOf('_'));
150
151 // Load language files for configured locale:
152 // - First load the translator for the base language, without territory
153 // - Then load the more specific locale translator
154
155#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
156 const QString translation_path{
157 QLibraryInfo::location(QLibraryInfo::TranslationsPath)};
158#else
159 const QString translation_path{
160 QLibraryInfo::path(QLibraryInfo::TranslationsPath)};
161#endif
162 // Load e.g. qt_de.qm
163 if (qtTranslatorBase.load("qt_" + lang, translation_path)) {
164 QApplication::installTranslator(&qtTranslatorBase);
165 }
166
167 // Load e.g. qt_de_DE.qm
168 if (qtTranslator.load("qt_" + lang_territory, translation_path)) {
169 QApplication::installTranslator(&qtTranslator);
170 }
171
172 // Load e.g. bitcoin_de.qm (shortcut "de" needs to be defined in
173 // bitcoin.qrc)
174 if (translatorBase.load(lang, ":/translations/")) {
175 QApplication::installTranslator(&translatorBase);
176 }
177
178 // Load e.g. bitcoin_de_DE.qm (shortcut "de_DE" needs to be defined in
179 // bitcoin.qrc)
180 if (translator.load(lang_territory, ":/translations/")) {
181 QApplication::installTranslator(&translator);
182 }
183}
184
185static bool ErrorSettingsRead(const bilingual_str &error,
186 const std::vector<std::string> &details) {
187 QMessageBox messagebox(
188 QMessageBox::Critical, PACKAGE_NAME,
189 QString::fromStdString(strprintf("%s.", error.translated)),
190 QMessageBox::Reset | QMessageBox::Abort);
191 // Explanatory text shown on startup when the settings file cannot
192 // be read. Prompts user to make a choice between resetting or aborting.
193 messagebox.setInformativeText(
194 QObject::tr("Do you want to reset settings to default values, or to "
195 "abort without making changes?"));
196 messagebox.setDetailedText(
197 QString::fromStdString(MakeUnorderedList(details)));
198 messagebox.setTextFormat(Qt::PlainText);
199 messagebox.setDefaultButton(QMessageBox::Reset);
200 switch (messagebox.exec()) {
201 case QMessageBox::Reset:
202 return false;
203 case QMessageBox::Abort:
204 return true;
205 default:
206 assert(false);
207 }
208}
209
210static void ErrorSettingsWrite(const bilingual_str &error,
211 const std::vector<std::string> &details) {
212 QMessageBox messagebox(
213 QMessageBox::Critical, PACKAGE_NAME,
214 QString::fromStdString(strprintf("%s.", error.translated)),
215 QMessageBox::Ok);
216 // Explanatory text shown on startup when the settings file could
217 // not be written. Prompts user to check that we have the ability to
218 // write to the file. Explains that the user has the option of running
219 // without a settings file.
220 messagebox.setInformativeText(
221 QObject::tr("A fatal error occurred. Check that settings file is "
222 "writable, or try running with -nosettings."));
223 messagebox.setDetailedText(
224 QString::fromStdString(MakeUnorderedList(details)));
225 messagebox.setTextFormat(Qt::PlainText);
226 messagebox.setDefaultButton(QMessageBox::Ok);
227 messagebox.exec();
228}
229
230/* qDebug() message handler --> debug.log */
231void DebugMessageHandler(QtMsgType type, const QMessageLogContext &context,
232 const QString &msg) {
233 Q_UNUSED(context);
234 if (type == QtDebugMsg) {
235 LogPrint(BCLog::QT, "GUI: %s\n", msg.toStdString());
236 } else {
237 LogPrintf("GUI: %s\n", msg.toStdString());
238 }
239}
240
242
243void BitcoinABC::handleRunawayException(const std::exception *e) {
244 PrintExceptionContinue(e, "Runaway exception");
245 Q_EMIT runawayException(
246 QString::fromStdString(m_node.getWarnings().translated));
247}
248
249void BitcoinABC::initialize(Config *config, RPCServer *rpcServer,
250 HTTPRPCRequestProcessor *httpRPCRequestProcessor) {
251 try {
252 util::ThreadRename("qt-init");
253 qDebug() << __func__ << ": Running initialization in thread";
255 bool rv = m_node.appInitMain(*config, *rpcServer,
256 *httpRPCRequestProcessor, &tip_info);
257 Q_EMIT initializeResult(rv, tip_info);
258 } catch (const std::exception &e) {
260 } catch (...) {
261 handleRunawayException(nullptr);
262 }
263}
264
266 try {
267 qDebug() << __func__ << ": Running Shutdown in thread";
269 qDebug() << __func__ << ": Shutdown finished";
270 Q_EMIT shutdownResult();
271 } catch (const std::exception &e) {
273 } catch (...) {
274 handleRunawayException(nullptr);
275 }
276}
277
278static int qt_argc = 1;
279static const char *qt_argv = "bitcoin-qt";
280
282 : QApplication(qt_argc, const_cast<char **>(&qt_argv)), coreThread(nullptr),
283 optionsModel(nullptr), clientModel(nullptr), window(nullptr),
284 pollShutdownTimer(nullptr), platformStyle(nullptr) {
285 // Qt runs setlocale(LC_ALL, "") on initialization.
287 setQuitOnLastWindowClosed(false);
288}
289
291 // UI per-platform customization
292 // This must be done inside the BitcoinApplication constructor, or after it,
293 // because PlatformStyle::instantiate requires a QApplication.
294 std::string platformName;
295 platformName = gArgs.GetArg("-uiplatform", BitcoinGUI::DEFAULT_UIPLATFORM);
297 PlatformStyle::instantiate(QString::fromStdString(platformName));
298 // Fall back to "other" if specified name not found.
299 if (!platformStyle) {
301 }
303}
304
306 if (coreThread) {
307 qDebug() << __func__ << ": Stopping thread";
308 coreThread->quit();
309 coreThread->wait();
310 qDebug() << __func__ << ": Stopped thread";
311 }
312
313 delete window;
314 window = nullptr;
315 delete platformStyle;
316 platformStyle = nullptr;
317}
318
319#ifdef ENABLE_WALLET
320void BitcoinApplication::createPaymentServer() {
321 paymentServer = new PaymentServer(this);
322}
323#endif
324
326 optionsModel = new OptionsModel(this, resetSettings);
327}
328
330 const NetworkStyle *networkStyle) {
331 window =
332 new BitcoinGUI(node(), config, platformStyle, networkStyle, nullptr);
333 connect(window, &BitcoinGUI::quitRequested, this,
335
336 pollShutdownTimer = new QTimer(window);
337 connect(pollShutdownTimer, &QTimer::timeout, [this] {
338 if (!QApplication::activeModalWidget()) {
340 }
341 });
342}
343
346 m_splash = new SplashScreen(networkStyle);
347 // We don't hold a direct pointer to the splash screen after creation, but
348 // the splash screen will take care of deleting itself when finish()
349 // happens.
350 m_splash->show();
356 &QWidget::close);
357}
358
360 assert(!m_node);
361 m_node = &node;
362 if (optionsModel) {
364 }
365 if (m_splash) {
367 }
368}
369
371 return node().baseInitialize(config);
372}
373
375 if (coreThread) {
376 return;
377 }
378 coreThread = new QThread(this);
379 BitcoinABC *executor = new BitcoinABC(node());
380 executor->moveToThread(coreThread);
381
382 /* communication to and from thread */
383 connect(executor, &BitcoinABC::initializeResult, this,
385 connect(executor, &BitcoinABC::shutdownResult, this,
386 [] { QCoreApplication::exit(0); });
387 connect(executor, &BitcoinABC::runawayException, this,
389
390 // Note on how Qt works: it tries to directly invoke methods if the signal
391 // is emitted on the same thread that the target object 'lives' on.
392 // But if the target object 'lives' on another thread (executor here does)
393 // the SLOT will be invoked asynchronously at a later time in the thread
394 // of the target object. So.. we pass a pointer around. If you pass
395 // a reference around (even if it's non-const) you'll get Qt generating
396 // code to copy-construct the parameter in question (Q_DECLARE_METATYPE
397 // and qRegisterMetaType generate this code). For the Config class,
398 // which is noncopyable, we can't do this. So.. we have to pass
399 // pointers to Config around. Make sure Config &/Config * isn't a
400 // temporary (eg it lives somewhere aside from the stack) or this will
401 // crash because initialize() gets executed in another thread at some
402 // unspecified time (after) requestedInitialize() is emitted!
403 connect(this, &BitcoinApplication::requestedInitialize, executor,
405
406 connect(this, &BitcoinApplication::requestedShutdown, executor,
408 /* make sure executor object is deleted in its own thread */
409 connect(coreThread, &QThread::finished, executor, &QObject::deleteLater);
410
411 coreThread->start();
412}
413
415 // Default printtoconsole to false for the GUI. GUI programs should not
416 // print to the console unnecessarily.
417 gArgs.SoftSetBoolArg("-printtoconsole", false);
418
421}
422
424 // If prune is set, intentionally override existing prune size with
425 // the default size since this is called when choosing a new datadir.
427}
428
430 Config &config, RPCServer &rpcServer,
431 HTTPRPCRequestProcessor &httpRPCRequestProcessor) {
432 qDebug() << __func__ << ": Requesting initialize";
433 startThread();
434 // IMPORTANT: config must NOT be a reference to a temporary because below
435 // signal may be connected to a slot that will be executed as a queued
436 // connection in another thread!
437 Q_EMIT requestedInitialize(&config, &rpcServer, &httpRPCRequestProcessor);
438}
439
441 for (const auto w : QGuiApplication::topLevelWindows()) {
442 w->hide();
443 }
444
445 // Show a simple window indicating shutdown status. Do this first as some of
446 // the steps may take some time below, for example the RPC console may still
447 // be executing a command.
449
450 qDebug() << __func__ << ": Requesting shutdown";
451 startThread();
452
453 // Must disconnect node signals otherwise current thread can deadlock since
454 // no event loop is running.
456 // Request node shutdown, which can interrupt long operations, like
457 // rescanning a wallet.
459 // Prior to unsetting the client model, stop listening backend signals
460 if (clientModel) {
461 clientModel->stop();
462 }
463
464 // Unsetting the client model can cause the current thread to wait for node
465 // to complete an operation, like wait for a RPC execution to complete.
466 window->setClientModel(nullptr);
467 pollShutdownTimer->stop();
468
469#ifdef ENABLE_WALLET
470 // Delete wallet controller here manually, instead of relying on Qt object
471 // tracking (https://doc.qt.io/qt-5/objecttrees.html). This makes sure
472 // walletmodel m_handle_* notification handlers are deleted before wallets
473 // are unloaded, which can simplify wallet implementations. It also avoids
474 // these notifications having to be handled while GUI objects are being
475 // destroyed, making GUI code less fragile as well.
476 delete m_wallet_controller;
477 m_wallet_controller = nullptr;
478#endif // ENABLE_WALLET
479
480 delete clientModel;
481 clientModel = nullptr;
482
483 // Request shutdown from core thread
484 Q_EMIT requestedShutdown();
485}
486
488 bool success, interfaces::BlockAndHeaderTipInfo tip_info) {
489 qDebug() << __func__ << ": Initialization result: " << success;
490 if (!success) {
491 // Make sure splash screen doesn't stick around during shutdown.
492 Q_EMIT splashFinished();
494 return;
495 }
496 // Log this only after AppInitMain finishes, as then logging setup is
497 // guaranteed complete.
498 qInfo() << "Platform customization:" << platformStyle->getName();
500 window->setClientModel(clientModel, &tip_info);
501#ifdef ENABLE_WALLET
503 m_wallet_controller =
505 window->setWalletController(m_wallet_controller);
506 if (paymentServer) {
507 paymentServer->setOptionsModel(optionsModel);
508#ifdef ENABLE_BIP70
509 PaymentServer::LoadRootCAs();
510 connect(m_wallet_controller, &WalletController::coinsSent,
511 paymentServer, &PaymentServer::fetchPaymentACK);
512#endif
513 }
514 }
515#endif // ENABLE_WALLET
516
517 // If -min option passed, start window minimized(iconified)
518 // or minimized to tray
519 if (!gArgs.GetBoolArg("-min", false)) {
520 window->show();
522 window->hasTrayIcon()) {
523 // do nothing as the window is managed by the tray icon
524 } else {
525 window->showMinimized();
526 }
527 Q_EMIT splashFinished();
528 Q_EMIT windowShown(window);
529
530#ifdef ENABLE_WALLET
531 // Now that initialization/startup is done, process any command-line
532 // bitcoincash: URIs or payment requests:
533 if (paymentServer) {
534 connect(paymentServer, &PaymentServer::receivedPaymentRequest, window,
535 &BitcoinGUI::handlePaymentRequest);
536 connect(window, &BitcoinGUI::receivedURI, paymentServer,
538 connect(paymentServer, &PaymentServer::message,
539 [this](const QString &title, const QString &message,
540 unsigned int style) {
541 window->message(title, message, style);
542 });
543 QTimer::singleShot(100, paymentServer, &PaymentServer::uiReady);
544 }
545#endif
546
547 pollShutdownTimer->start(200);
548}
549
550void BitcoinApplication::handleRunawayException(const QString &message) {
551 QMessageBox::critical(
552 nullptr, "Runaway exception",
553 BitcoinGUI::tr("A fatal error occurred. %1 can no longer continue "
554 "safely and will quit.")
555 .arg(PACKAGE_NAME) +
556 QString("<br><br>") + message);
557 ::exit(EXIT_FAILURE);
558}
559
561 if (!window) {
562 return 0;
563 }
564
565 return window->winId();
566}
567
569 if (e->type() == QEvent::Quit) {
571 return true;
572 }
573
574 return QApplication::event(e);
575}
576
577static void SetupUIArgs(ArgsManager &argsman) {
578#if defined(ENABLE_WALLET) && defined(ENABLE_BIP70)
579 argsman.AddArg(
580 "-allowselfsignedrootcertificates",
581 strprintf("Allow self signed root certificates (default: %d)",
584#endif
585 argsman.AddArg("-choosedatadir",
586 strprintf("Choose data directory on startup (default: %d)",
589 argsman.AddArg(
590 "-lang=<lang>",
591 "Set language, for example \"de_DE\" (default: system locale)",
593 argsman.AddArg("-min", "Start minimized", ArgsManager::ALLOW_ANY,
595 argsman.AddArg(
596 "-rootcertificates=<file>",
597 "Set SSL root certificates for payment request (default: -system-)",
599 argsman.AddArg("-splash",
600 strprintf("Show splash screen on startup (default: %d)",
603 argsman.AddArg("-resetguisettings", "Reset all settings changed in the GUI",
605 argsman.AddArg("-uiplatform",
606 strprintf("Select platform to customize UI for (one of "
607 "windows, macosx, other; default: %s)",
611}
612
613int GuiMain(int argc, char *argv[]) {
614#ifdef WIN32
615 common::WinCmdLineArgs winArgs;
616 std::tie(argc, argv) = winArgs.get();
617#endif
620
621 NodeContext node_context;
622 std::unique_ptr<interfaces::Node> node =
623 interfaces::MakeNode(&node_context);
624
625 // Subscribe to global signals from core
626 boost::signals2::scoped_connection handler_message_box =
627 ::uiInterface.ThreadSafeMessageBox_connect(noui_ThreadSafeMessageBox);
628 boost::signals2::scoped_connection handler_question =
629 ::uiInterface.ThreadSafeQuestion_connect(noui_ThreadSafeQuestion);
630 boost::signals2::scoped_connection handler_init_message =
631 ::uiInterface.InitMessage_connect(noui_InitMessage);
632
633 // Do not refer to data directory yet, this can be overridden by
634 // Intro::pickDataDirectory
635
638 Q_INIT_RESOURCE(bitcoin);
639 Q_INIT_RESOURCE(bitcoin_locale);
640
641#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
642 // Generate high-dpi pixmaps
643 QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
644 QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
645#endif
646
648
651 // Command-line options take precedence:
652 SetupServerArgs(node_context);
654 std::string error;
655 if (!gArgs.ParseParameters(argc, argv, error)) {
657 Untranslated("Error parsing command line arguments: %s"), error));
658 // Create a message box, because the gui has neither been created nor
659 // has subscribed to core signals
660 QMessageBox::critical(
661 nullptr, PACKAGE_NAME,
662 // message can not be translated because translations have not been
663 // initialized
664 QString::fromStdString("Error parsing command line arguments: %1.")
665 .arg(QString::fromStdString(error)));
666 return EXIT_FAILURE;
667 }
668
669 // Now that the QApplication is setup and we have parsed our parameters, we
670 // can set the platform style
671 app.setupPlatformStyle();
672
674 // must be set before OptionsModel is initialized or translations are
675 // loaded, as it is used to locate QSettings.
676 QApplication::setOrganizationName(QAPP_ORG_NAME);
677 QApplication::setOrganizationDomain(QAPP_ORG_DOMAIN);
678 QApplication::setApplicationName(QAPP_APP_NAME_DEFAULT);
679
682 QTranslator qtTranslatorBase, qtTranslator, translatorBase, translator;
683 initTranslations(qtTranslatorBase, qtTranslator, translatorBase,
684 translator);
685
686 // Show help message immediately after parsing command-line options (for
687 // "-lang") and setting locale, but before showing splash screen.
688 if (HelpRequested(gArgs) || gArgs.IsArgSet("-version")) {
689 HelpMessageDialog help(nullptr, gArgs.IsArgSet("-version"));
690 help.showOrPrint();
691 return EXIT_SUCCESS;
692 }
693
694 // Install global event filter that makes sure that long tooltips can be
695 // word-wrapped
696 app.installEventFilter(
698
701 bool did_show_intro = false;
702 // Intro dialog prune check box
703 bool prune = false;
704 // Gracefully exit if the user cancels
705 if (!Intro::showIfNeeded(did_show_intro, prune)) {
706 return EXIT_SUCCESS;
707 }
708
711 // - Do not call gArgs.GetDataDirNet() before this step finishes
712 // - Do not call Params() before this step
713 // - QSettings() will use the new application name after this, resulting in
714 // network-specific settings
715 // - Needs to be done before createOptionsModel
716 if (auto err = common::InitConfig(gArgs, ErrorSettingsRead)) {
717 InitError(err->message, err->details);
718 if (err->status == common::ConfigStatus::FAILED_WRITE) {
719 // Show a custom error message to provide more information in the
720 // case of a datadir write error.
721 ErrorSettingsWrite(err->message, err->details);
722 } else if (err->status != common::ConfigStatus::ABORTED) {
723 // Show a generic message in other cases, and no additional error
724 // message in the case of a read error if the user decided to abort.
725 QMessageBox::critical(
726 nullptr, PACKAGE_NAME,
727 QObject::tr("Error: %1")
728 .arg(QString::fromStdString(err->message.translated)));
729 }
730 return EXIT_FAILURE;
731 }
732#ifdef ENABLE_WALLET
733 // Parse URIs on command line -- this can affect Params()
735#endif
736
737 QScopedPointer<const NetworkStyle> networkStyle(
738 NetworkStyle::instantiate(Params().GetChainType()));
739 assert(!networkStyle.isNull());
740 // Allow for separate UI settings for testnets
741 QApplication::setApplicationName(networkStyle->getAppName());
742 // Re-initialize translations after changing application name (language in
743 // network-specific settings can be different)
744 initTranslations(qtTranslatorBase, qtTranslator, translatorBase,
745 translator);
746
747#ifdef ENABLE_WALLET
749 // - Do this early as we don't want to bother initializing if we are just
750 // calling IPC
751 // - Do this *after* setting up the data directory, as the data directory
752 // hash is used in the name
753 // of the server.
754 // - Do this after creating app and setting up translations, so errors are
755 // translated properly.
757 exit(EXIT_SUCCESS);
758 }
759
760 // Start up the payment server early, too, so impatient users that click on
761 // bitcoincash: links repeatedly have their payment requests routed to this
762 // process:
764 app.createPaymentServer();
765 }
766#endif // ENABLE_WALLET
767
769 // Install global event filter that makes sure that out-of-focus labels do
770 // not contain text cursor.
771 app.installEventFilter(new GUIUtil::LabelOutOfFocusEventFilter(&app));
772#if defined(Q_OS_WIN)
773 // Install global event filter for processing Windows session related
774 // Windows messages (WM_QUERYENDSESSION and WM_ENDSESSION)
775 qApp->installNativeEventFilter(new WinShutdownMonitor());
776#endif
777 // Install qDebug() message handler to route to debug.log
778 qInstallMessageHandler(DebugMessageHandler);
779 // Allow parameter interaction before we create the options model
780 app.parameterSetup();
782 // Load GUI settings from QSettings
783 app.createOptionsModel(gArgs.GetBoolArg("-resetguisettings", false));
784
785 if (did_show_intro) {
786 // Store intro dialog settings other than datadir (network specific)
787 app.InitializePruneSetting(prune);
788 }
789
790 // Get global config
791 Config &config = const_cast<Config &>(GetConfig());
792
793 if (gArgs.GetBoolArg("-splash", DEFAULT_SPLASHSCREEN) &&
794 !gArgs.GetBoolArg("-min", false)) {
795 app.createSplashScreen(networkStyle.data());
796 }
797
798 app.setNode(*node);
799
800 RPCServer rpcServer;
801 std::any context{&node_context};
802 HTTPRPCRequestProcessor httpRPCRequestProcessor(config, rpcServer, context);
803
804 try {
805 app.createWindow(config, networkStyle.data());
806 // Perform base initialization before spinning up
807 // initialization/shutdown thread. This is acceptable because this
808 // function only contains steps that are quick to execute, so the GUI
809 // thread won't be held up.
810 if (!app.baseInitialize(config)) {
811 // A dialog with detailed error will have been shown by InitError()
812 return EXIT_FAILURE;
813 }
814 app.requestInitialize(config, rpcServer, httpRPCRequestProcessor);
815#if defined(Q_OS_WIN)
816 WinShutdownMonitor::registerShutdownBlockReason(
817 QObject::tr("%1 didn't yet exit safely...").arg(PACKAGE_NAME),
818 (HWND)app.getMainWinId());
819#endif
820 app.exec();
821 } catch (const std::exception &e) {
822 PrintExceptionContinue(&e, "Runaway exception");
824 QString::fromStdString(app.node().getWarnings().translated));
825 } catch (...) {
826 PrintExceptionContinue(nullptr, "Runaway exception");
828 QString::fromStdString(app.node().getWarnings().translated));
829 }
830 return app.node().getExitStatus();
831}
bool HelpRequested(const ArgsManager &args)
Definition: args.cpp:701
ArgsManager gArgs
Definition: args.cpp:40
const CChainParams & Params()
Return the currently selected parameters.
Definition: chainparams.cpp:21
@ ALLOW_ANY
disable validation
Definition: args.h:114
@ DEBUG_ONLY
Definition: args.h:128
bool ParseParameters(int argc, const char *const argv[], std::string &error)
Definition: args.cpp:211
bool IsArgSet(const std::string &strArg) const
Return true if the given argument has been manually set.
Definition: args.cpp:372
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
bool GetBoolArg(const std::string &strArg, bool fDefault) const
Return boolean argument or default value.
Definition: args.cpp:525
void AddArg(const std::string &name, const std::string &help, unsigned int flags, const OptionsCategory &cat)
Add argument.
Definition: args.cpp:589
Class encapsulating Bitcoin ABC startup and shutdown.
Definition: bitcoin.h:36
interfaces::Node & m_node
Definition: bitcoin.h:56
void initializeResult(bool success, interfaces::BlockAndHeaderTipInfo tip_info)
void handleRunawayException(const std::exception *e)
Pass fatal exception message to UI thread.
Definition: bitcoin.cpp:243
void shutdown()
Definition: bitcoin.cpp:265
void runawayException(const QString &message)
void shutdownResult()
BitcoinABC(interfaces::Node &node)
Definition: bitcoin.cpp:241
void initialize(Config *config, RPCServer *rpcServer, HTTPRPCRequestProcessor *httpRPCRequestProcessor)
Definition: bitcoin.cpp:249
Main Bitcoin application object.
Definition: bitcoin.h:60
void createWindow(const Config &, const NetworkStyle *networkStyle)
Create main window.
Definition: bitcoin.cpp:329
ClientModel * clientModel
Definition: bitcoin.h:122
bool baseInitialize(Config &config)
Basic initialization, before starting initialization/shutdown thread.
Definition: bitcoin.cpp:370
void createSplashScreen(const NetworkStyle *networkStyle)
Create splash screen.
Definition: bitcoin.cpp:344
void requestShutdown()
Request core shutdown.
Definition: bitcoin.cpp:440
SplashScreen * m_splash
Definition: bitcoin.h:131
void windowShown(BitcoinGUI *window)
void initializeResult(bool success, interfaces::BlockAndHeaderTipInfo tip_info)
Definition: bitcoin.cpp:487
QThread * coreThread
Definition: bitcoin.h:120
void setNode(interfaces::Node &node)
Definition: bitcoin.cpp:359
interfaces::Node & node() const
Definition: bitcoin.h:94
QTimer * pollShutdownTimer
Definition: bitcoin.h:124
BitcoinGUI * window
Definition: bitcoin.h:123
void InitializePruneSetting(bool prune)
Initialize prune setting.
Definition: bitcoin.cpp:423
interfaces::Node * m_node
Definition: bitcoin.h:132
const PlatformStyle * platformStyle
Definition: bitcoin.h:129
void parameterSetup()
parameter interaction/setup based on rules
Definition: bitcoin.cpp:414
void handleRunawayException(const QString &message)
Handle runaway exceptions.
Definition: bitcoin.cpp:550
OptionsModel * optionsModel
Definition: bitcoin.h:121
bool event(QEvent *e) override
Definition: bitcoin.cpp:568
void createOptionsModel(bool resetSettings)
Create options model.
Definition: bitcoin.cpp:325
void requestInitialize(Config &config, RPCServer &rpcServer, HTTPRPCRequestProcessor &httpRPCRequestProcessor)
Request core initialization.
Definition: bitcoin.cpp:429
void setupPlatformStyle()
Setup platform style.
Definition: bitcoin.cpp:290
void requestedInitialize(Config *config, RPCServer *rpcServer, HTTPRPCRequestProcessor *httpRPCRequestProcessor)
std::unique_ptr< QWidget > shutdownWindow
Definition: bitcoin.h:130
WId getMainWinId() const
Get window identifier of QMainWindow (BitcoinGUI)
Definition: bitcoin.cpp:560
Bitcoin GUI main class.
Definition: bitcoingui.h:68
static const std::string DEFAULT_UIPLATFORM
Definition: bitcoingui.h:72
void setClientModel(ClientModel *clientModel=nullptr, interfaces::BlockAndHeaderTipInfo *tip_info=nullptr)
Set the client model.
Definition: bitcoingui.cpp:637
void receivedURI(const QString &uri)
Signal raised when a URI was entered or dragged to the GUI.
void unsubscribeFromCoreSignals()
Disconnect core signals from GUI client.
bool hasTrayIcon() const
Get the tray icon status.
Definition: bitcoingui.h:113
void detectShutdown()
called by a timer to check if ShutdownRequested() has been set
void message(const QString &title, QString message, unsigned int style, bool *ret=nullptr, const QString &detailed_message=QString())
Notify the user of an event from the core network or transaction handling code.
void quitRequested()
Model for Bitcoin network client.
Definition: clientmodel.h:43
OptionsModel * getOptionsModel()
Definition: config.h:19
Qt event filter that intercepts QEvent::FocusOut events for QLabel objects, and resets their ‘textInt...
Definition: guiutil.h:218
Qt event filter that intercepts ToolTipChange events, and replaces the tooltip with a rich text repre...
Definition: guiutil.h:198
"Help message" dialog box
Definition: utilitydialog.h:20
static bool showIfNeeded(bool &did_show_intro, bool &prune)
Determine data directory.
Definition: intro.cpp:180
static const NetworkStyle * instantiate(const ChainType networkId)
Get style associated with provided BIP70 network id, or 0 if not known.
Interface from Qt to configuration data structure for Bitcoin client.
Definition: optionsmodel.h:48
void SetPruneTargetGB(int prune_target_gb, bool force=false)
bool getMinimizeToTray() const
Definition: optionsmodel.h:95
void setNode(interfaces::Node &node)
Definition: optionsmodel.h:117
static bool ipcSendCommandLine()
void message(const QString &title, const QString &message, unsigned int style)
static void ipcParseCommandLine(int argc, char *argv[])
void receivedPaymentRequest(SendCoinsRecipient)
void handleURIOrFile(const QString &s)
const QString & getName() const
Definition: platformstyle.h:18
static const PlatformStyle * instantiate(const QString &platformId)
Get style associated with provided platform name, or 0 if not known.
Class for registering and managing all RPC calls.
Definition: server.h:40
static QWidget * showShutdownWindow(QMainWindow *window)
Class for the splashscreen with information of the running client.
Definition: splashscreen.h:26
void finish()
Hide the splash screen window and schedule the splash screen object for deletion.
void handleLoadWallet()
Handle wallet load notifications.
void setNode(interfaces::Node &node)
Controller between interfaces::Node, WalletModel instances and the GUI.
void coinsSent(interfaces::Wallet &wallet, SendCoinsRecipient recipient, QByteArray transaction)
static bool isWalletEnabled()
Top-level interface for a bitcoin node (bitcoind process).
Definition: node.h:59
virtual bilingual_str getWarnings()=0
Get warnings.
virtual void appShutdown()=0
Stop node.
virtual bool appInitMain(Config &config, RPCServer &rpcServer, HTTPRPCRequestProcessor &httpRPCRequestProcessor, interfaces::BlockAndHeaderTipInfo *tip_info=nullptr)=0
Start node.
virtual void startShutdown()=0
Start shutdown.
virtual int getExitStatus()=0
Get exit status.
virtual bool baseInitialize(Config &config)=0
Initialize app dependencies.
256-bit opaque blob.
Definition: uint256.h:129
SyncType
Definition: clientmodel.h:40
const Config & GetConfig()
Definition: config.cpp:40
void PrintExceptionContinue(const std::exception *pex, std::string_view thread_name)
Definition: exception.cpp:38
static constexpr int DEFAULT_PRUNE_TARGET_GB
Definition: guiconstants.h:56
static const int TOOLTIP_WRAP_THRESHOLD
Definition: guiconstants.h:41
#define QAPP_ORG_NAME
Definition: guiconstants.h:46
static const bool DEFAULT_SPLASHSCREEN
Definition: guiconstants.h:22
#define QAPP_APP_NAME_DEFAULT
Definition: guiconstants.h:48
#define QAPP_ORG_DOMAIN
Definition: guiconstants.h:47
void InitLogging(const ArgsManager &args)
Initialize global loggers.
Definition: init.cpp:1761
void SetupServerArgs(NodeContext &node)
Register all arguments with the ArgsManager.
Definition: init.cpp:425
void InitParameterInteraction(ArgsManager &args)
Parameter interaction: change current parameters depending on various rules.
Definition: init.cpp:1627
static const bool DEFAULT_CHOOSE_DATADIR
Definition: intro.h:12
#define LogPrint(category,...)
Definition: logging.h:452
#define LogPrintf(...)
Definition: logging.h:424
@ QT
Definition: logging.h:88
void LogQtInfo()
Writes to debug.log short info about the used Qt and the host system.
Definition: guiutil.cpp:970
std::optional< ConfigError > InitConfig(ArgsManager &args, SettingsAbortFn settings_abort_fn)
Read config files, and create datadir and settings.json if they don't exist.
Definition: init.cpp:19
@ ABORTED
Aborted by user.
@ FAILED_WRITE
Failed to write settings.json.
std::unique_ptr< Node > MakeNode(node::NodeContext *context)
Return implementation of Node interface.
Definition: interfaces.cpp:829
Definition: init.h:31
void ThreadSetInternalName(std::string &&)
Set the internal (in-memory) name of the current thread only.
Definition: threadnames.cpp:53
void ThreadRename(std::string &&)
Rename a thread both in terms of an internal (in-memory) name as well as its system thread name.
Definition: threadnames.cpp:48
NodeContext & m_node
Definition: interfaces.cpp:822
bool noui_ThreadSafeQuestion(const bilingual_str &, const std::string &message, const std::string &caption, unsigned int style)
Non-GUI handler, which logs and prints questions.
Definition: noui.cpp:48
void noui_InitMessage(const std::string &message)
Non-GUI handler, which only logs a message.
Definition: noui.cpp:55
bool noui_ThreadSafeMessageBox(const bilingual_str &message, const std::string &caption, unsigned int style)
Non-GUI handler, which logs and prints messages.
Definition: noui.cpp:20
static const bool DEFAULT_SELFSIGNED_ROOTCERTS
static bool ErrorSettingsRead(const bilingual_str &error, const std::vector< std::string > &details)
Definition: bitcoin.cpp:185
static void RegisterMetaTypes()
Definition: bitcoin.cpp:83
static int qt_argc
Definition: bitcoin.cpp:278
static QString GetLangTerritory()
Definition: bitcoin.cpp:115
int GuiMain(int argc, char *argv[])
Definition: bitcoin.cpp:613
static void ErrorSettingsWrite(const bilingual_str &error, const std::vector< std::string > &details)
Definition: bitcoin.cpp:210
static void SetupUIArgs(ArgsManager &argsman)
Definition: bitcoin.cpp:577
static const char * qt_argv
Definition: bitcoin.cpp:279
static void initTranslations(QTranslator &qtTranslatorBase, QTranslator &qtTranslator, QTranslator &translatorBase, QTranslator &translator)
Set up translations.
Definition: bitcoin.cpp:133
void DebugMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg)
Definition: bitcoin.cpp:231
static RPCHelpMan help()
Definition: server.cpp:183
std::string MakeUnorderedList(const std::vector< std::string > &items)
Create an unordered multi-line list of items.
Definition: string.h:90
Definition: amount.h:19
Bilingual messages:
Definition: translation.h:17
std::string translated
Definition: translation.h:19
Block and header tip information.
Definition: node.h:50
NodeContext struct containing references to chain state and connection state.
Definition: context.h:48
void SetupEnvironment()
Definition: system.cpp:71
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1202
bilingual_str Untranslated(std::string original)
Mark a bilingual_str as untranslated.
Definition: translation.h:36
CClientUIInterface uiInterface
bool InitError(const bilingual_str &str)
Show error message.
assert(!tx.IsCoinBase())
SynchronizationState
Current sync state passed to tip changed callbacks.
Definition: validation.h:119