Merge bitcoin/bitcoin#27150: Deduplicate bitcoind and bitcoin-qt init code

802cc1ef53 Deduplicate bitcoind and bitcoin-qt init code (Ryan Ofsky)
d172b5c671 Add InitError(error, details) overload (Ryan Ofsky)
3db2874bd7 Extend bilingual_str support for tinyformat (Ryan Ofsky)
c361df90b9 scripted-diff: Remove double newlines after some init errors (Ryan Ofsky)

Pull request description:

  Add common InitConfig function to deduplicate bitcoind and bitcoin-qt code reading config files and creating the datadir.

  Noticed the duplicate code while reviewing #27073 and want to remove it because difference in bitcoin-qt and bitcoind behavior make it hard to evaluate changes like #27073

  There are a few minor changes in behavior:

  - In bitcoin-qt, when there is a problem reading the configuration file, the GUI error text has changed from "Error: Cannot parse configuration file:" to "Error reading configuration file:" to be consistent with bitcoind.
  - In bitcoind, when there is a problem reading the settings.json file, the error text has changed from "Failed loading settings file" to "Settings file could not be read" to be consistent with bitcoin-qt.
  - In bitcoind, when there is a problem writing the settings.json file, the error text has changed from "Failed saving settings file" to "Settings file could not be written" to be consistent with bitcoin-qt.
  - In bitcoin-qt, if there datadir is not accessible (e.g. no permission to read), there is an normal error dialog showing "Error: filesystem error: status: Permission denied [.../settings.json]", instead of an uncaught exception.

ACKs for top commit:
  Sjors:
    Light review ACK 802cc1ef53
  TheCharlatan:
    ACK 802cc1ef53
  achow101:
    ACK 802cc1ef53

Tree-SHA512: 9c78d277e9ed595fa8ce286b97d2806e1ec06ddbbe7bd3434bd9dd7b456faf8d989f71231e97311f36edb9caaec645a50c730bd7514b8e0fe6e6f7741b13d981
This commit is contained in:
Andrew Chow committed 2023-03-07 13:05:01 -05:00
commit fc037c8c83
16 files changed
+221 -154

No files matched your search

+45 -77
View File
@@ -9,6 +9,7 @@
#include <qt/bitcoin.h>
#include <chainparams.h>
#include <common/init.h>
#include <init.h>
#include <interfaces/handler.h>
#include <interfaces/init.h>
@@ -165,54 +166,36 @@ static void initTranslations(QTranslator &qtTranslatorBase, QTranslator &qtTrans
}
}
static bool InitSettings()
static bool ErrorSettingsRead(const bilingual_str& error, const std::vector<std::string>& details)
{
gArgs.EnsureDataDir();
if (!gArgs.GetSettingsPath()) {
return true; // Do nothing if settings file disabled.
}
std::vector<std::string> errors;
if (!gArgs.ReadSettingsFile(&errors)) {
std::string error = QT_TRANSLATE_NOOP("bitcoin-core", "Settings file could not be read");
std::string error_translated = QCoreApplication::translate("bitcoin-core", error.c_str()).toStdString();
InitError(Untranslated(strprintf("%s:\n%s\n", error, MakeUnorderedList(errors))));
QMessageBox messagebox(QMessageBox::Critical, PACKAGE_NAME, QString::fromStdString(strprintf("%s.", error_translated)), QMessageBox::Reset | QMessageBox::Abort);
/*: Explanatory text shown on startup when the settings file cannot be read.
Prompts user to make a choice between resetting or aborting. */
messagebox.setInformativeText(QObject::tr("Do you want to reset settings to default values, or to abort without making changes?"));
messagebox.setDetailedText(QString::fromStdString(MakeUnorderedList(errors)));
messagebox.setTextFormat(Qt::PlainText);
messagebox.setDefaultButton(QMessageBox::Reset);
switch (messagebox.exec()) {
case QMessageBox::Reset:
break;
case QMessageBox::Abort:
return false;
default:
assert(false);
}
}
errors.clear();
if (!gArgs.WriteSettingsFile(&errors)) {
std::string error = QT_TRANSLATE_NOOP("bitcoin-core", "Settings file could not be written");
std::string error_translated = QCoreApplication::translate("bitcoin-core", error.c_str()).toStdString();
InitError(Untranslated(strprintf("%s:\n%s\n", error, MakeUnorderedList(errors))));
QMessageBox messagebox(QMessageBox::Critical, PACKAGE_NAME, QString::fromStdString(strprintf("%s.", error_translated)), QMessageBox::Ok);
/*: Explanatory text shown on startup when the settings file could not be written.
Prompts user to check that we have the ability to write to the file.
Explains that the user has the option of running without a settings file.*/
messagebox.setInformativeText(QObject::tr("A fatal error occurred. Check that settings file is writable, or try running with -nosettings."));
messagebox.setDetailedText(QString::fromStdString(MakeUnorderedList(errors)));
messagebox.setTextFormat(Qt::PlainText);
messagebox.setDefaultButton(QMessageBox::Ok);
messagebox.exec();
QMessageBox messagebox(QMessageBox::Critical, PACKAGE_NAME, QString::fromStdString(strprintf("%s.", error.translated)), QMessageBox::Reset | QMessageBox::Abort);
/*: Explanatory text shown on startup when the settings file cannot be read.
Prompts user to make a choice between resetting or aborting. */
messagebox.setInformativeText(QObject::tr("Do you want to reset settings to default values, or to abort without making changes?"));
messagebox.setDetailedText(QString::fromStdString(MakeUnorderedList(details)));
messagebox.setTextFormat(Qt::PlainText);
messagebox.setDefaultButton(QMessageBox::Reset);
switch (messagebox.exec()) {
case QMessageBox::Reset:
return false;
case QMessageBox::Abort:
return true;
default:
assert(false);
}
return true;
}
static void ErrorSettingsWrite(const bilingual_str& error, const std::vector<std::string>& details)
{
QMessageBox messagebox(QMessageBox::Critical, PACKAGE_NAME, QString::fromStdString(strprintf("%s.", error.translated)), QMessageBox::Ok);
/*: Explanatory text shown on startup when the settings file could not be written.
Prompts user to check that we have the ability to write to the file.
Explains that the user has the option of running without a settings file.*/
messagebox.setInformativeText(QObject::tr("A fatal error occurred. Check that settings file is writable, or try running with -nosettings."));
messagebox.setDetailedText(QString::fromStdString(MakeUnorderedList(details)));
messagebox.setTextFormat(Qt::PlainText);
messagebox.setDefaultButton(QMessageBox::Ok);
messagebox.exec();
}
/* qDebug() message handler --> debug.log */
@@ -546,7 +529,7 @@ int GuiMain(int argc, char* argv[])
SetupUIArgs(gArgs);
std::string error;
if (!gArgs.ParseParameters(argc, argv, error)) {
InitError(strprintf(Untranslated("Error parsing command line arguments: %s\n"), error));
InitError(strprintf(Untranslated("Error parsing command line arguments: %s"), error));
// Create a message box, because the gui has neither been created nor has subscribed to core signals
QMessageBox::critical(nullptr, PACKAGE_NAME,
// message cannot be translated because translations have not been initialized
@@ -587,34 +570,23 @@ int GuiMain(int argc, char* argv[])
// Gracefully exit if the user cancels
if (!Intro::showIfNeeded(did_show_intro, prune_MiB)) return EXIT_SUCCESS;
/// 6a. Determine availability of data directory
if (!CheckDataDirOption(gArgs)) {
InitError(strprintf(Untranslated("Specified data directory \"%s\" does not exist.\n"), gArgs.GetArg("-datadir", "")));
QMessageBox::critical(nullptr, PACKAGE_NAME,
QObject::tr("Error: Specified data directory \"%1\" does not exist.").arg(QString::fromStdString(gArgs.GetArg("-datadir", ""))));
return EXIT_FAILURE;
}
try {
/// 6b. Parse bitcoin.conf
/// - Do not call gArgs.GetDataDirNet() before this step finishes
if (!gArgs.ReadConfigFiles(error, true)) {
InitError(strprintf(Untranslated("Error reading configuration file: %s\n"), error));
QMessageBox::critical(nullptr, PACKAGE_NAME,
QObject::tr("Error: Cannot parse configuration file: %1.").arg(QString::fromStdString(error)));
return EXIT_FAILURE;
/// 6-7. Parse bitcoin.conf, determine network, switch to network specific
/// options, and create datadir and settings.json.
// - Do not call gArgs.GetDataDirNet() before this step finishes
// - Do not call Params() before this step
// - QSettings() will use the new application name after this, resulting in network-specific settings
// - Needs to be done before createOptionsModel
if (auto error = common::InitConfig(gArgs, ErrorSettingsRead)) {
InitError(error->message, error->details);
if (error->status == common::ConfigStatus::FAILED_WRITE) {
// Show a custom error message to provide more information in the
// case of a datadir write error.
ErrorSettingsWrite(error->message, error->details);
} else if (error->status != common::ConfigStatus::ABORTED) {
// Show a generic message in other cases, and no additional error
// message in the case of a read error if the user decided to abort.
QMessageBox::critical(nullptr, PACKAGE_NAME, QObject::tr("Error: %1").arg(QString::fromStdString(error->message.translated)));
}
/// 7. Determine network (and switch to network specific options)
// - Do not call Params() before this step
// - Do this after parsing the configuration file, as the network can be switched there
// - QSettings() will use the new application name after this, resulting in network-specific settings
// - Needs to be done before createOptionsModel
// Check for chain settings (Params() calls are only valid after this clause)
SelectParams(gArgs.GetChainName());
} catch(std::exception &e) {
InitError(Untranslated(strprintf("%s\n", e.what())));
QMessageBox::critical(nullptr, PACKAGE_NAME, QObject::tr("Error: %1").arg(e.what()));
return EXIT_FAILURE;
}
#ifdef ENABLE_WALLET
@@ -622,10 +594,6 @@ int GuiMain(int argc, char* argv[])
PaymentServer::ipcParseCommandLine(argc, argv);
#endif
if (!InitSettings()) {
return EXIT_FAILURE;
}
QScopedPointer<const NetworkStyle> networkStyle(NetworkStyle::instantiate(Params().NetworkIDString()));
assert(!networkStyle.isNull());
// Allow for separate UI settings for testnets