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