Bitcoin Core  27.99.0
P2P Digital Currency
bitcoin.cpp
Go to the documentation of this file.
1 // Copyright (c) 2011-2022 The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 
5 #if defined(HAVE_CONFIG_H)
7 #endif
8 
9 #include <qt/bitcoin.h>
10 
11 #include <chainparams.h>
12 #include <common/args.h>
13 #include <common/init.h>
14 #include <common/system.h>
15 #include <init.h>
16 #include <interfaces/handler.h>
17 #include <interfaces/init.h>
18 #include <interfaces/node.h>
19 #include <logging.h>
20 #include <node/context.h>
21 #include <node/interface_ui.h>
22 #include <noui.h>
23 #include <qt/bitcoingui.h>
24 #include <qt/clientmodel.h>
25 #include <qt/guiconstants.h>
26 #include <qt/guiutil.h>
27 #include <qt/initexecutor.h>
28 #include <qt/intro.h>
29 #include <qt/networkstyle.h>
30 #include <qt/optionsmodel.h>
31 #include <qt/platformstyle.h>
32 #include <qt/splashscreen.h>
33 #include <qt/utilitydialog.h>
34 #include <qt/winshutdownmonitor.h>
35 #include <uint256.h>
36 #include <util/exception.h>
37 #include <util/string.h>
38 #include <util/threadnames.h>
39 #include <util/translation.h>
40 #include <validation.h>
41 
42 #ifdef ENABLE_WALLET
43 #include <qt/paymentserver.h>
44 #include <qt/walletcontroller.h>
45 #include <qt/walletmodel.h>
46 #include <wallet/types.h>
47 #endif // ENABLE_WALLET
48 
49 #include <boost/signals2/connection.hpp>
50 #include <chrono>
51 #include <memory>
52 
53 #include <QApplication>
54 #include <QDebug>
55 #include <QLatin1String>
56 #include <QLibraryInfo>
57 #include <QLocale>
58 #include <QMessageBox>
59 #include <QSettings>
60 #include <QThread>
61 #include <QTimer>
62 #include <QTranslator>
63 #include <QWindow>
64 
65 #if defined(QT_STATICPLUGIN)
66 #include <QtPlugin>
67 #if defined(QT_QPA_PLATFORM_XCB)
68 Q_IMPORT_PLUGIN(QXcbIntegrationPlugin);
69 #elif defined(QT_QPA_PLATFORM_WINDOWS)
70 Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin);
71 Q_IMPORT_PLUGIN(QWindowsVistaStylePlugin);
72 #elif defined(QT_QPA_PLATFORM_COCOA)
73 Q_IMPORT_PLUGIN(QCocoaIntegrationPlugin);
74 Q_IMPORT_PLUGIN(QMacStylePlugin);
75 #elif defined(QT_QPA_PLATFORM_ANDROID)
76 Q_IMPORT_PLUGIN(QAndroidPlatformIntegrationPlugin)
77 #endif
78 #endif
79 
80 // Declare meta types used for QMetaObject::invokeMethod
81 Q_DECLARE_METATYPE(bool*)
82 Q_DECLARE_METATYPE(CAmount)
83 Q_DECLARE_METATYPE(SynchronizationState)
84 Q_DECLARE_METATYPE(SyncType)
85 Q_DECLARE_METATYPE(uint256)
86 #ifdef ENABLE_WALLET
87 Q_DECLARE_METATYPE(wallet::AddressPurpose)
88 #endif // ENABLE_WALLET
89 
90 static void RegisterMetaTypes()
91 {
92  // Register meta types used for QMetaObject::invokeMethod and Qt::QueuedConnection
93  qRegisterMetaType<bool*>();
94  qRegisterMetaType<SynchronizationState>();
95  qRegisterMetaType<SyncType>();
96  #ifdef ENABLE_WALLET
97  qRegisterMetaType<WalletModel*>();
98  qRegisterMetaType<wallet::AddressPurpose>();
99  #endif // ENABLE_WALLET
100  // Register typedefs (see https://doc.qt.io/qt-5/qmetatype.html#qRegisterMetaType)
101  // IMPORTANT: if CAmount is no longer a typedef use the normal variant above (see https://doc.qt.io/qt-5/qmetatype.html#qRegisterMetaType-1)
102  qRegisterMetaType<CAmount>("CAmount");
103  qRegisterMetaType<size_t>("size_t");
104 
105  qRegisterMetaType<std::function<void()>>("std::function<void()>");
106  qRegisterMetaType<QMessageBox::Icon>("QMessageBox::Icon");
107  qRegisterMetaType<interfaces::BlockAndHeaderTipInfo>("interfaces::BlockAndHeaderTipInfo");
108 
109 #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
110  qRegisterMetaTypeStreamOperators<BitcoinUnit>("BitcoinUnit");
111 #else
112  qRegisterMetaType<BitcoinUnit>("BitcoinUnit");
113 #endif
114 }
115 
116 static QString GetLangTerritory()
117 {
118  QSettings settings;
119  // Get desired locale (e.g. "de_DE")
120  // 1) System default language
121  QString lang_territory = QLocale::system().name();
122  // 2) Language from QSettings
123  QString lang_territory_qsettings = settings.value("language", "").toString();
124  if(!lang_territory_qsettings.isEmpty())
125  lang_territory = lang_territory_qsettings;
126  // 3) -lang command line argument
127  lang_territory = QString::fromStdString(gArgs.GetArg("-lang", lang_territory.toStdString()));
128  return lang_territory;
129 }
130 
132 static void initTranslations(QTranslator &qtTranslatorBase, QTranslator &qtTranslator, QTranslator &translatorBase, QTranslator &translator)
133 {
134  // Remove old translators
135  QApplication::removeTranslator(&qtTranslatorBase);
136  QApplication::removeTranslator(&qtTranslator);
137  QApplication::removeTranslator(&translatorBase);
138  QApplication::removeTranslator(&translator);
139 
140  // Get desired locale (e.g. "de_DE")
141  // 1) System default language
142  QString lang_territory = GetLangTerritory();
143 
144  // Convert to "de" only by truncating "_DE"
145  QString lang = lang_territory;
146  lang.truncate(lang_territory.lastIndexOf('_'));
147 
148  // Load language files for configured locale:
149  // - First load the translator for the base language, without territory
150  // - Then load the more specific locale translator
151 
152 #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
153  const QString translation_path{QLibraryInfo::location(QLibraryInfo::TranslationsPath)};
154 #else
155  const QString translation_path{QLibraryInfo::path(QLibraryInfo::TranslationsPath)};
156 #endif
157  // Load e.g. qt_de.qm
158  if (qtTranslatorBase.load("qt_" + lang, translation_path)) {
159  QApplication::installTranslator(&qtTranslatorBase);
160  }
161 
162  // Load e.g. qt_de_DE.qm
163  if (qtTranslator.load("qt_" + lang_territory, translation_path)) {
164  QApplication::installTranslator(&qtTranslator);
165  }
166 
167  // Load e.g. bitcoin_de.qm (shortcut "de" needs to be defined in bitcoin.qrc)
168  if (translatorBase.load(lang, ":/translations/")) {
169  QApplication::installTranslator(&translatorBase);
170  }
171 
172  // Load e.g. bitcoin_de_DE.qm (shortcut "de_DE" needs to be defined in bitcoin.qrc)
173  if (translator.load(lang_territory, ":/translations/")) {
174  QApplication::installTranslator(&translator);
175  }
176 }
177 
178 static bool ErrorSettingsRead(const bilingual_str& error, const std::vector<std::string>& details)
179 {
180  QMessageBox messagebox(QMessageBox::Critical, PACKAGE_NAME, QString::fromStdString(strprintf("%s.", error.translated)), QMessageBox::Reset | QMessageBox::Abort);
181  /*: Explanatory text shown on startup when the settings file cannot be read.
182  Prompts user to make a choice between resetting or aborting. */
183  messagebox.setInformativeText(QObject::tr("Do you want to reset settings to default values, or to abort without making changes?"));
184  messagebox.setDetailedText(QString::fromStdString(MakeUnorderedList(details)));
185  messagebox.setTextFormat(Qt::PlainText);
186  messagebox.setDefaultButton(QMessageBox::Reset);
187  switch (messagebox.exec()) {
188  case QMessageBox::Reset:
189  return false;
190  case QMessageBox::Abort:
191  return true;
192  default:
193  assert(false);
194  }
195 }
196 
197 static void ErrorSettingsWrite(const bilingual_str& error, const std::vector<std::string>& details)
198 {
199  QMessageBox messagebox(QMessageBox::Critical, PACKAGE_NAME, QString::fromStdString(strprintf("%s.", error.translated)), QMessageBox::Ok);
200  /*: Explanatory text shown on startup when the settings file could not be written.
201  Prompts user to check that we have the ability to write to the file.
202  Explains that the user has the option of running without a settings file.*/
203  messagebox.setInformativeText(QObject::tr("A fatal error occurred. Check that settings file is writable, or try running with -nosettings."));
204  messagebox.setDetailedText(QString::fromStdString(MakeUnorderedList(details)));
205  messagebox.setTextFormat(Qt::PlainText);
206  messagebox.setDefaultButton(QMessageBox::Ok);
207  messagebox.exec();
208 }
209 
210 /* qDebug() message handler --> debug.log */
211 void DebugMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString &msg)
212 {
213  Q_UNUSED(context);
214  if (type == QtDebugMsg) {
215  LogPrint(BCLog::QT, "GUI: %s\n", msg.toStdString());
216  } else {
217  LogPrintf("GUI: %s\n", msg.toStdString());
218  }
219 }
220 
221 static int qt_argc = 1;
222 static const char* qt_argv = "bitcoin-qt";
223 
225  : QApplication(qt_argc, const_cast<char**>(&qt_argv))
226 {
227  // Qt runs setlocale(LC_ALL, "") on initialization.
229  setQuitOnLastWindowClosed(false);
230 }
231 
233 {
234  // UI per-platform customization
235  // This must be done inside the BitcoinApplication constructor, or after it, because
236  // PlatformStyle::instantiate requires a QApplication
237  std::string platformName;
238  platformName = gArgs.GetArg("-uiplatform", BitcoinGUI::DEFAULT_UIPLATFORM);
239  platformStyle = PlatformStyle::instantiate(QString::fromStdString(platformName));
240  if (!platformStyle) // Fall back to "other" if specified name not found
243 }
244 
246 {
247  m_executor.reset();
248 
249  delete window;
250  window = nullptr;
251  delete platformStyle;
252  platformStyle = nullptr;
253 }
254 
255 #ifdef ENABLE_WALLET
256 void BitcoinApplication::createPaymentServer()
257 {
258  paymentServer = new PaymentServer(this);
259 }
260 #endif
261 
263 {
264  optionsModel = new OptionsModel(node(), this);
265  if (resetSettings) {
266  optionsModel->Reset();
267  }
268  bilingual_str error;
269  if (!optionsModel->Init(error)) {
270  fs::path settings_path;
271  if (gArgs.GetSettingsPath(&settings_path)) {
272  error += Untranslated("\n");
273  std::string quoted_path = strprintf("%s", fs::quoted(fs::PathToString(settings_path)));
274  error.original += strprintf("Settings file %s might be corrupt or invalid.", quoted_path);
275  error.translated += tr("Settings file %1 might be corrupt or invalid.").arg(QString::fromStdString(quoted_path)).toStdString();
276  }
277  InitError(error);
278  QMessageBox::critical(nullptr, PACKAGE_NAME, QString::fromStdString(error.translated));
279  return false;
280  }
281  return true;
282 }
283 
285 {
286  window = new BitcoinGUI(node(), platformStyle, networkStyle, nullptr);
288 
289  pollShutdownTimer = new QTimer(window);
290  connect(pollShutdownTimer, &QTimer::timeout, [this]{
291  if (!QApplication::activeModalWidget()) {
293  }
294  });
295 }
296 
298 {
299  assert(!m_splash);
300  m_splash = new SplashScreen(networkStyle);
301  m_splash->show();
302 }
303 
305 {
306  assert(!m_node);
307  m_node = init.makeNode();
309 }
310 
312 {
313  return node().baseInitialize();
314 }
315 
317 {
318  assert(!m_executor);
319  m_executor.emplace(node());
320 
321  /* communication to and from thread */
323  connect(&m_executor.value(), &InitExecutor::shutdownResult, this, [] {
324  QCoreApplication::exit(0);
325  });
329 }
330 
332 {
333  // Default printtoconsole to false for the GUI. GUI programs should not
334  // print to the console unnecessarily.
335  gArgs.SoftSetBoolArg("-printtoconsole", false);
336 
339 }
340 
342 {
344 }
345 
347 {
348  qDebug() << __func__ << ": Requesting initialize";
349  startThread();
350  Q_EMIT requestedInitialize();
351 }
352 
354 {
355  for (const auto w : QGuiApplication::topLevelWindows()) {
356  w->hide();
357  }
358 
359  delete m_splash;
360  m_splash = nullptr;
361 
362  // Show a simple window indicating shutdown status
363  // Do this first as some of the steps may take some time below,
364  // for example the RPC console may still be executing a command.
366 
367  qDebug() << __func__ << ": Requesting shutdown";
368 
369  // Must disconnect node signals otherwise current thread can deadlock since
370  // no event loop is running.
372  // Request node shutdown, which can interrupt long operations, like
373  // rescanning a wallet.
374  node().startShutdown();
375  // Prior to unsetting the client model, stop listening backend signals
376  if (clientModel) {
377  clientModel->stop();
378  }
379 
380  // Unsetting the client model can cause the current thread to wait for node
381  // to complete an operation, like wait for a RPC execution to complete.
382  window->setClientModel(nullptr);
383  pollShutdownTimer->stop();
384 
385 #ifdef ENABLE_WALLET
386  // Delete wallet controller here manually, instead of relying on Qt object
387  // tracking (https://doc.qt.io/qt-5/objecttrees.html). This makes sure
388  // walletmodel m_handle_* notification handlers are deleted before wallets
389  // are unloaded, which can simplify wallet implementations. It also avoids
390  // these notifications having to be handled while GUI objects are being
391  // destroyed, making GUI code less fragile as well.
392  delete m_wallet_controller;
393  m_wallet_controller = nullptr;
394 #endif // ENABLE_WALLET
395 
396  delete clientModel;
397  clientModel = nullptr;
398 
399  // Request shutdown from core thread
400  Q_EMIT requestedShutdown();
401 }
402 
404 {
405  qDebug() << __func__ << ": Initialization result: " << success;
406 
407  if (success) {
408  delete m_splash;
409  m_splash = nullptr;
410 
411  // Log this only after AppInitMain finishes, as then logging setup is guaranteed complete
412  qInfo() << "Platform customization:" << platformStyle->getName();
414  window->setClientModel(clientModel, &tip_info);
415 
416  // If '-min' option passed, start window minimized (iconified) or minimized to tray
417  bool start_minimized = gArgs.GetBoolArg("-min", false);
418 #ifdef ENABLE_WALLET
420  m_wallet_controller = new WalletController(*clientModel, platformStyle, this);
421  window->setWalletController(m_wallet_controller, /*show_loading_minimized=*/start_minimized);
422  if (paymentServer) {
423  paymentServer->setOptionsModel(optionsModel);
424  }
425  }
426 #endif // ENABLE_WALLET
427 
428  // Show or minimize window
429  if (!start_minimized) {
430  window->show();
432  // do nothing as the window is managed by the tray icon
433  } else {
434  window->showMinimized();
435  }
436  Q_EMIT windowShown(window);
437 
438 #ifdef ENABLE_WALLET
439  // Now that initialization/startup is done, process any command-line
440  // bitcoin: URIs or payment requests:
441  if (paymentServer) {
442  connect(paymentServer, &PaymentServer::receivedPaymentRequest, window, &BitcoinGUI::handlePaymentRequest);
444  connect(paymentServer, &PaymentServer::message, [this](const QString& title, const QString& message, unsigned int style) {
445  window->message(title, message, style);
446  });
447  QTimer::singleShot(100ms, paymentServer, &PaymentServer::uiReady);
448  }
449 #endif
451  } else {
452  requestShutdown();
453  }
454 }
455 
456 void BitcoinApplication::handleRunawayException(const QString &message)
457 {
458  QMessageBox::critical(
459  nullptr, tr("Runaway exception"),
460  tr("A fatal error occurred. %1 can no longer continue safely and will quit.").arg(PACKAGE_NAME) +
461  QLatin1String("<br><br>") + GUIUtil::MakeHtmlLink(message, PACKAGE_BUGREPORT));
462  ::exit(EXIT_FAILURE);
463 }
464 
466 {
467  assert(QThread::currentThread() == thread());
468  QMessageBox::warning(
469  nullptr, tr("Internal error"),
470  tr("An internal error occurred. %1 will attempt to continue safely. This is "
471  "an unexpected bug which can be reported as described below.").arg(PACKAGE_NAME) +
472  QLatin1String("<br><br>") + GUIUtil::MakeHtmlLink(message, PACKAGE_BUGREPORT));
473 }
474 
476 {
477  if (!window)
478  return 0;
479 
480  return window->winId();
481 }
482 
484 {
485  if (e->type() == QEvent::Quit) {
486  requestShutdown();
487  return true;
488  }
489 
490  return QApplication::event(e);
491 }
492 
493 static void SetupUIArgs(ArgsManager& argsman)
494 {
495  argsman.AddArg("-choosedatadir", strprintf("Choose data directory on startup (default: %u)", DEFAULT_CHOOSE_DATADIR), ArgsManager::ALLOW_ANY, OptionsCategory::GUI);
496  argsman.AddArg("-lang=<lang>", "Set language, for example \"de_DE\" (default: system locale)", ArgsManager::ALLOW_ANY, OptionsCategory::GUI);
497  argsman.AddArg("-min", "Start minimized", ArgsManager::ALLOW_ANY, OptionsCategory::GUI);
498  argsman.AddArg("-resetguisettings", "Reset all settings changed in the GUI", ArgsManager::ALLOW_ANY, OptionsCategory::GUI);
499  argsman.AddArg("-splash", strprintf("Show splash screen on startup (default: %u)", DEFAULT_SPLASHSCREEN), ArgsManager::ALLOW_ANY, OptionsCategory::GUI);
500  argsman.AddArg("-uiplatform", strprintf("Select platform to customize UI for (one of windows, macosx, other; default: %s)", BitcoinGUI::DEFAULT_UIPLATFORM), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::GUI);
501 }
502 
503 int GuiMain(int argc, char* argv[])
504 {
505 #ifdef WIN32
506  common::WinCmdLineArgs winArgs;
507  std::tie(argc, argv) = winArgs.get();
508 #endif
509 
510  std::unique_ptr<interfaces::Init> init = interfaces::MakeGuiInit(argc, argv);
511 
514 
515  // Subscribe to global signals from core
516  boost::signals2::scoped_connection handler_message_box = ::uiInterface.ThreadSafeMessageBox_connect(noui_ThreadSafeMessageBox);
517  boost::signals2::scoped_connection handler_question = ::uiInterface.ThreadSafeQuestion_connect(noui_ThreadSafeQuestion);
518  boost::signals2::scoped_connection handler_init_message = ::uiInterface.InitMessage_connect(noui_InitMessage);
519 
520  // Do not refer to data directory yet, this can be overridden by Intro::pickDataDirectory
521 
523  Q_INIT_RESOURCE(bitcoin);
524  Q_INIT_RESOURCE(bitcoin_locale);
525 
526 #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
527  // Generate high-dpi pixmaps
528  QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
529  QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
530 #endif
531 
532 #if defined(QT_QPA_PLATFORM_ANDROID)
533  QApplication::setAttribute(Qt::AA_DontUseNativeMenuBar);
534  QApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings);
535  QApplication::setAttribute(Qt::AA_DontUseNativeDialogs);
536 #endif
537 
538  BitcoinApplication app;
539  GUIUtil::LoadFont(QStringLiteral(":/fonts/monospace"));
540 
542  // Command-line options take precedence:
545  std::string error;
546  if (!gArgs.ParseParameters(argc, argv, error)) {
547  InitError(strprintf(Untranslated("Error parsing command line arguments: %s"), error));
548  // Create a message box, because the gui has neither been created nor has subscribed to core signals
549  QMessageBox::critical(nullptr, PACKAGE_NAME,
550  // message cannot be translated because translations have not been initialized
551  QString::fromStdString("Error parsing command line arguments: %1.").arg(QString::fromStdString(error)));
552  return EXIT_FAILURE;
553  }
554 
555  // Error out when loose non-argument tokens are encountered on command line
556  // However, allow BIP-21 URIs only if no options follow
557  bool payment_server_token_seen = false;
558  for (int i = 1; i < argc; i++) {
559  QString arg(argv[i]);
560  bool invalid_token = !arg.startsWith("-");
561 #ifdef ENABLE_WALLET
562  if (arg.startsWith(BITCOIN_IPC_PREFIX, Qt::CaseInsensitive)) {
563  invalid_token &= false;
564  payment_server_token_seen = true;
565  }
566 #endif
567  if (payment_server_token_seen && arg.startsWith("-")) {
568  InitError(Untranslated(strprintf("Options ('%s') cannot follow a BIP-21 payment URI", argv[i])));
569  QMessageBox::critical(nullptr, PACKAGE_NAME,
570  // message cannot be translated because translations have not been initialized
571  QString::fromStdString("Options ('%1') cannot follow a BIP-21 payment URI").arg(QString::fromStdString(argv[i])));
572  return EXIT_FAILURE;
573  }
574  if (invalid_token) {
575  InitError(Untranslated(strprintf("Command line contains unexpected token '%s', see bitcoin-qt -h for a list of options.", argv[i])));
576  QMessageBox::critical(nullptr, PACKAGE_NAME,
577  // message cannot be translated because translations have not been initialized
578  QString::fromStdString("Command line contains unexpected token '%1', see bitcoin-qt -h for a list of options.").arg(QString::fromStdString(argv[i])));
579  return EXIT_FAILURE;
580  }
581  }
582 
583  // Now that the QApplication is setup and we have parsed our parameters, we can set the platform style
584  app.setupPlatformStyle();
585 
587  // must be set before OptionsModel is initialized or translations are loaded,
588  // as it is used to locate QSettings
589  QApplication::setOrganizationName(QAPP_ORG_NAME);
590  QApplication::setOrganizationDomain(QAPP_ORG_DOMAIN);
591  QApplication::setApplicationName(QAPP_APP_NAME_DEFAULT);
592 
594  // Now that QSettings are accessible, initialize translations
595  QTranslator qtTranslatorBase, qtTranslator, translatorBase, translator;
596  initTranslations(qtTranslatorBase, qtTranslator, translatorBase, translator);
597 
598  // Show help message immediately after parsing command-line options (for "-lang") and setting locale,
599  // but before showing splash screen.
600  if (HelpRequested(gArgs) || gArgs.IsArgSet("-version")) {
601  HelpMessageDialog help(nullptr, gArgs.IsArgSet("-version"));
602  help.showOrPrint();
603  return EXIT_SUCCESS;
604  }
605 
606  // Install global event filter that makes sure that long tooltips can be word-wrapped
607  app.installEventFilter(new GUIUtil::ToolTipToRichTextFilter(TOOLTIP_WRAP_THRESHOLD, &app));
608 
610  // User language is set up: pick a data directory
611  bool did_show_intro = false;
612  int64_t prune_MiB = 0; // Intro dialog prune configuration
613  // Gracefully exit if the user cancels
614  if (!Intro::showIfNeeded(did_show_intro, prune_MiB)) return EXIT_SUCCESS;
615 
618  // - Do not call gArgs.GetDataDirNet() before this step finishes
619  // - Do not call Params() before this step
620  // - QSettings() will use the new application name after this, resulting in network-specific settings
621  // - Needs to be done before createOptionsModel
622  if (auto error = common::InitConfig(gArgs, ErrorSettingsRead)) {
623  InitError(error->message, error->details);
624  if (error->status == common::ConfigStatus::FAILED_WRITE) {
625  // Show a custom error message to provide more information in the
626  // case of a datadir write error.
627  ErrorSettingsWrite(error->message, error->details);
628  } else if (error->status != common::ConfigStatus::ABORTED) {
629  // Show a generic message in other cases, and no additional error
630  // message in the case of a read error if the user decided to abort.
631  QMessageBox::critical(nullptr, PACKAGE_NAME, QObject::tr("Error: %1").arg(QString::fromStdString(error->message.translated)));
632  }
633  return EXIT_FAILURE;
634  }
635 #ifdef ENABLE_WALLET
636  // Parse URIs on command line
638 #endif
639 
640  QScopedPointer<const NetworkStyle> networkStyle(NetworkStyle::instantiate(Params().GetChainType()));
641  assert(!networkStyle.isNull());
642  // Allow for separate UI settings for testnets
643  QApplication::setApplicationName(networkStyle->getAppName());
644  // Re-initialize translations after changing application name (language in network-specific settings can be different)
645  initTranslations(qtTranslatorBase, qtTranslator, translatorBase, translator);
646 
647 #ifdef ENABLE_WALLET
649  // - Do this early as we don't want to bother initializing if we are just calling IPC
650  // - Do this *after* setting up the data directory, as the data directory hash is used in the name
651  // of the server.
652  // - Do this after creating app and setting up translations, so errors are
653  // translated properly.
655  exit(EXIT_SUCCESS);
656 
657  // Start up the payment server early, too, so impatient users that click on
658  // bitcoin: links repeatedly have their payment requests routed to this process:
660  app.createPaymentServer();
661  }
662 #endif // ENABLE_WALLET
663 
665  // Install global event filter that makes sure that out-of-focus labels do not contain text cursor.
666  app.installEventFilter(new GUIUtil::LabelOutOfFocusEventFilter(&app));
667 #if defined(Q_OS_WIN)
668  // Install global event filter for processing Windows session related Windows messages (WM_QUERYENDSESSION and WM_ENDSESSION)
669  // Note: it is safe to call app.node() in the lambda below despite the fact
670  // that app.createNode() hasn't been called yet, because native events will
671  // not be processed until the Qt event loop is executed.
672  qApp->installNativeEventFilter(new WinShutdownMonitor([&app] { app.node().startShutdown(); }));
673 #endif
674  // Install qDebug() message handler to route to debug.log
675  qInstallMessageHandler(DebugMessageHandler);
676  // Allow parameter interaction before we create the options model
677  app.parameterSetup();
679 
680  if (gArgs.GetBoolArg("-splash", DEFAULT_SPLASHSCREEN) && !gArgs.GetBoolArg("-min", false))
681  app.createSplashScreen(networkStyle.data());
682 
683  app.createNode(*init);
684 
685  // Load GUI settings from QSettings
686  if (!app.createOptionsModel(gArgs.GetBoolArg("-resetguisettings", false))) {
687  return EXIT_FAILURE;
688  }
689 
690  if (did_show_intro) {
691  // Store intro dialog settings other than datadir (network specific)
692  app.InitPruneSetting(prune_MiB);
693  }
694 
695  try
696  {
697  app.createWindow(networkStyle.data());
698  // Perform base initialization before spinning up initialization/shutdown thread
699  // This is acceptable because this function only contains steps that are quick to execute,
700  // so the GUI thread won't be held up.
701  if (app.baseInitialize()) {
702  app.requestInitialize();
703 #if defined(Q_OS_WIN)
704  WinShutdownMonitor::registerShutdownBlockReason(QObject::tr("%1 didn't yet exit safely…").arg(PACKAGE_NAME), (HWND)app.getMainWinId());
705 #endif
706  app.exec();
707  } else {
708  // A dialog with detailed error will have been shown by InitError()
709  return EXIT_FAILURE;
710  }
711  } catch (const std::exception& e) {
712  PrintExceptionContinue(&e, "Runaway exception");
713  app.handleRunawayException(QString::fromStdString(app.node().getWarnings().translated));
714  } catch (...) {
715  PrintExceptionContinue(nullptr, "Runaway exception");
716  app.handleRunawayException(QString::fromStdString(app.node().getWarnings().translated));
717  }
718  return app.node().getExitStatus();
719 }
int64_t CAmount
Amount in satoshis (Can be negative)
Definition: amount.h:12
bool HelpRequested(const ArgsManager &args)
Definition: args.cpp:659
ArgsManager gArgs
Definition: args.cpp:41
#define PACKAGE_NAME
#define PACKAGE_BUGREPORT
SetupEnvironment()
Definition: system.cpp:59
return EXIT_SUCCESS
static bool ErrorSettingsRead(const bilingual_str &error, const std::vector< std::string > &details)
Definition: bitcoin.cpp:178
static void RegisterMetaTypes()
Definition: bitcoin.cpp:90
static int qt_argc
Definition: bitcoin.cpp:221
static QString GetLangTerritory()
Definition: bitcoin.cpp:116
int GuiMain(int argc, char *argv[])
Definition: bitcoin.cpp:503
static void ErrorSettingsWrite(const bilingual_str &error, const std::vector< std::string > &details)
Definition: bitcoin.cpp:197
static void SetupUIArgs(ArgsManager &argsman)
Definition: bitcoin.cpp:493
static const char * qt_argv
Definition: bitcoin.cpp:222
static void initTranslations(QTranslator &qtTranslatorBase, QTranslator &qtTranslator, QTranslator &translatorBase, QTranslator &translator)
Set up translations.
Definition: bitcoin.cpp:132
void DebugMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg)
Definition: bitcoin.cpp:211
const CChainParams & Params()
Return the currently selected parameters.
@ ALLOW_ANY
disable validation
Definition: args.h:104
@ DEBUG_ONLY
Definition: args.h:112
bool ParseParameters(int argc, const char *const argv[], std::string &error)
Definition: args.cpp:177
bool GetSettingsPath(fs::path *filepath=nullptr, bool temp=false, bool backup=false) const
Get settings file path, or return false if read-write settings were disabled with -nosettings.
Definition: args.cpp:374
bool IsArgSet(const std::string &strArg) const
Return true if the given argument has been manually set.
Definition: args.cpp:369
std::string GetArg(const std::string &strArg, const std::string &strDefault) const
Return string argument or default value.
Definition: args.cpp:455
bool SoftSetBoolArg(const std::string &strArg, bool fValue)
Set a boolean argument if it doesn't already have a value.
Definition: args.cpp:536
bool GetBoolArg(const std::string &strArg, bool fDefault) const
Return boolean argument or default value.
Definition: args.cpp:505
void AddArg(const std::string &name, const std::string &help, unsigned int flags, const OptionsCategory &cat)
Add argument.
Definition: args.cpp:562
Main Bitcoin application object.
Definition: bitcoin.h:37
bool createOptionsModel(bool resetSettings)
Create options model.
Definition: bitcoin.cpp:262
std::optional< InitExecutor > m_executor
Definition: bitcoin.h:95
void requestedInitialize()
ClientModel * clientModel
Definition: bitcoin.h:97
void InitPruneSetting(int64_t prune_MiB)
Initialize prune setting.
Definition: bitcoin.cpp:341
void createSplashScreen(const NetworkStyle *networkStyle)
Create splash screen.
Definition: bitcoin.cpp:297
void requestShutdown()
Request core shutdown.
Definition: bitcoin.cpp:353
SplashScreen * m_splash
Definition: bitcoin.h:106
void windowShown(BitcoinGUI *window)
void initializeResult(bool success, interfaces::BlockAndHeaderTipInfo tip_info)
Definition: bitcoin.cpp:403
void createNode(interfaces::Init &init)
Create or spawn node.
Definition: bitcoin.cpp:304
QTimer * pollShutdownTimer
Definition: bitcoin.h:99
BitcoinGUI * window
Definition: bitcoin.h:98
const PlatformStyle * platformStyle
Definition: bitcoin.h:104
bool baseInitialize()
Basic initialization, before starting initialization/shutdown thread. Return true on success.
Definition: bitcoin.cpp:311
void createWindow(const NetworkStyle *networkStyle)
Create main window.
Definition: bitcoin.cpp:284
void parameterSetup()
parameter interaction/setup based on rules
Definition: bitcoin.cpp:331
void handleRunawayException(const QString &message)
Handle runaway exceptions. Shows a message box with the problem and quits the program.
Definition: bitcoin.cpp:456
OptionsModel * optionsModel
Definition: bitcoin.h:96
bool event(QEvent *e) override
Definition: bitcoin.cpp:483
void setupPlatformStyle()
Setup platform style.
Definition: bitcoin.cpp:232
std::unique_ptr< interfaces::Node > m_node
Definition: bitcoin.h:107
std::unique_ptr< QWidget > shutdownWindow
Definition: bitcoin.h:105
void requestInitialize()
Request core initialization.
Definition: bitcoin.cpp:346
WId getMainWinId() const
Get window identifier of QMainWindow (BitcoinGUI)
Definition: bitcoin.cpp:475
void handleNonFatalException(const QString &message)
A helper function that shows a message box with details about a non-fatal exception.
Definition: bitcoin.cpp:465
interfaces::Node & node() const
Definition: bitcoin.h:71
Bitcoin GUI main class.
Definition: bitcoingui.h:70
static const std::string DEFAULT_UIPLATFORM
Definition: bitcoingui.h:74
void setClientModel(ClientModel *clientModel=nullptr, interfaces::BlockAndHeaderTipInfo *tip_info=nullptr)
Set the client model.
Definition: bitcoingui.cpp:605
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:102
void detectShutdown()
called by a timer to check if shutdown has been requested
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:54
OptionsModel * getOptionsModel()
Qt event filter that intercepts QEvent::FocusOut events for QLabel objects, and resets their ‘textInt...
Definition: guiutil.h:208
Qt event filter that intercepts ToolTipChange events, and replaces the tooltip with a rich text repre...
Definition: guiutil.h:188
"Help message" dialog box
Definition: utilitydialog.h:21
void initialize()
void initializeResult(bool success, interfaces::BlockAndHeaderTipInfo tip_info)
void runawayException(const QString &message)
void shutdownResult()
static bool showIfNeeded(bool &did_show_intro, int64_t &prune_MiB)
Determine data directory.
Definition: intro.cpp:207
static const NetworkStyle * instantiate(const ChainType networkId)
Get style associated with provided network id, or 0 if not known.
Interface from Qt to configuration data structure for Bitcoin client.
Definition: optionsmodel.h:43
void SetPruneTargetGB(int prune_target_gb)
bool Init(bilingual_str &error)
bool getMinimizeToTray() const
Definition: optionsmodel.h:102
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:19
static const PlatformStyle * instantiate(const QString &platformId)
Get style associated with provided platform name, or 0 if not known.
static QWidget * showShutdownWindow(QMainWindow *window)
Class for the splashscreen with information of the running client.
Definition: splashscreen.h:27
void setNode(interfaces::Node &node)
Controller between interfaces::Node, WalletModel instances and the GUI.
static bool isWalletEnabled()
Path class wrapper to block calls to the fs::path(std::string) implicit constructor and the fs::path:...
Definition: fs.h:33
Initial interface created when a process is first started, and used to give and get access to other i...
Definition: init.h:30
virtual bool baseInitialize()=0
Initialize app dependencies.
virtual bilingual_str getWarnings()=0
Get warnings.
virtual void startShutdown()=0
Start shutdown.
virtual int getExitStatus()=0
Get exit status.
256-bit opaque blob.
Definition: uint256.h:106
SyncType
Definition: clientmodel.h:39
void PrintExceptionContinue(const std::exception *pex, std::string_view thread_name)
Definition: exception.cpp:36
static constexpr auto SHUTDOWN_POLLING_DELAY
Definition: guiconstants.h:17
static const int TOOLTIP_WRAP_THRESHOLD
Definition: guiconstants.h:44
#define QAPP_ORG_NAME
Definition: guiconstants.h:49
static const bool DEFAULT_SPLASHSCREEN
Definition: guiconstants.h:25
#define QAPP_APP_NAME_DEFAULT
Definition: guiconstants.h:51
#define QAPP_ORG_DOMAIN
Definition: guiconstants.h:50
void InitLogging(const ArgsManager &args)
Initialize global loggers.
Definition: init.cpp:815
void SetupServerArgs(ArgsManager &argsman)
Register all arguments with the ArgsManager.
Definition: init.cpp:438
void InitParameterInteraction(ArgsManager &args)
Parameter interaction: change current parameters depending on various rules.
Definition: init.cpp:723
CClientUIInterface uiInterface
bool InitError(const bilingual_str &str)
Show error message.
static const bool DEFAULT_CHOOSE_DATADIR
Definition: intro.h:12
#define LogPrint(category,...)
Definition: logging.h:263
#define LogPrintf(...)
Definition: logging.h:244
@ QT
Definition: logging.h:60
QString MakeHtmlLink(const QString &source, const QString &link)
Replaces a plain text link with an HTML tagged one.
Definition: guiutil.cpp:987
void LogQtInfo()
Writes to debug.log short info about the used Qt and the host system.
Definition: guiutil.cpp:916
void LoadFont(const QString &file_name)
Loads the font from the file specified by file_name, aborts if it fails.
Definition: guiutil.cpp:294
@ ABORTED
Aborted by user.
@ FAILED_WRITE
Failed to write settings.json.
std::optional< ConfigError > InitConfig(ArgsManager &args, SettingsAbortFn settings_abort_fn)
Definition: init.cpp:18
static auto quoted(const std::string &s)
Definition: fs.h:95
static std::string PathToString(const path &path)
Convert path object to a byte string.
Definition: fs.h:151
std::unique_ptr< Init > MakeGuiInit(int argc, char *argv[])
Return implementation of Init interface for the gui process.
Definition: bitcoin-gui.cpp:44
void ThreadSetInternalName(std::string &&)
Set the internal (in-memory) name of the current thread only.
Definition: threadnames.cpp:65
AddressPurpose
Address purpose field that has been been stored with wallet sending and receiving addresses since BIP...
Definition: types.h:60
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:50
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:22
static int PruneMiBtoGB(int64_t mib)
Convert configured prune target MiB to displayed GB.
Definition: optionsmodel.h:29
QT_END_NAMESPACE const QString BITCOIN_IPC_PREFIX
static RPCHelpMan help()
Definition: server.cpp:143
std::string MakeUnorderedList(const std::vector< std::string > &items)
Create an unordered multi-line list of items.
Definition: string.h:90
Bilingual messages:
Definition: translation.h:18
std::string translated
Definition: translation.h:20
std::string original
Definition: translation.h:19
Block and header tip information.
Definition: node.h:50
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1162
bilingual_str Untranslated(std::string original)
Mark a bilingual_str as untranslated.
Definition: translation.h:48
assert(!tx.IsCoinBase())
SynchronizationState
Current sync state passed to tip changed callbacks.
Definition: validation.h:80