From 1756c0b239caf5f2ac26082671d70d09a2331596 Mon Sep 17 00:00:00 2001 From: Aditya Kulkarni Date: Tue, 20 Nov 2018 14:41:45 -0800 Subject: [PATCH] #58 - Verify params on startup --- src/connection.cpp | 98 ++++++++++++++++++++++++++++++++-------------- src/connection.h | 1 + src/mainwindow.cpp | 2 + src/mainwindow.h | 2 + 4 files changed, 73 insertions(+), 30 deletions(-) diff --git a/src/connection.cpp b/src/connection.cpp index 871216e..651b1ec 100644 --- a/src/connection.cpp +++ b/src/connection.cpp @@ -30,8 +30,15 @@ void ConnectionLoader::loadConnection() { } void ConnectionLoader::doAutoConnect(bool tryEzcashdStart) { - // Priority 1: Try to connect to detect zcash.conf and connect to it. + // Priority 1: Ensure all params are present. + if (!verifyParams()) { + downloadParams([=]() { this->doAutoConnect(); }); + return; + } + + // Priority 2: Try to connect to detect zcash.conf and connect to it. auto config = autoDetectZcashConf(); + main->logger->write("Attempting autoconnect"); if (config.get() != nullptr) { auto connection = makeConnection(config); @@ -43,6 +50,7 @@ void ConnectionLoader::doAutoConnect(bool tryEzcashdStart) { this->showInformation("Starting embedded zcashd"); if (this->startEmbeddedZcashd()) { // Embedded zcashd started up. Wait a second and then refresh the connection + main->logger->write("Embedded zcashd started up, trying autoconnect in 1 sec"); QTimer::singleShot(1000, [=]() { doAutoConnect(); } ); } else { // Something is wrong. This is happenening intermittently on Mac platforms. @@ -51,10 +59,12 @@ void ConnectionLoader::doAutoConnect(bool tryEzcashdStart) { // - QProcess ended, but the embedded zcashd is still in the background. // We're going to attempt to connect to the one in the background one last time // and see if that works, else throw an error + main->logger->write("Something is wrong, trying no-retry autoconnect in 2 sec"); QTimer::singleShot(2000, [=]() { doAutoConnect(/* don't attempt to start ezcashd */ false); }); } } else { // We tried to start ezcashd previously, and it didn't work. So, show the error. + main->logger->write("Couldn't start embedded zcashd for unknown reason"); QString explanation = QString() % "Couldn't start the embedded zcashd.\n\n" % "Please try restarting.\n\nIfIf you previously started zcashd with custom arguments, you might need to reset zcash.conf.\n\n" % "If all else fails, please run zcashd manually." % @@ -64,6 +74,7 @@ void ConnectionLoader::doAutoConnect(bool tryEzcashdStart) { } else { // zcash.conf exists, there's no connection, and the user asked us not to start zcashd. Error! + main->logger->write("Not using embedded and couldn't connect to zcashd"); QString explanation = QString() % "Couldn't connect to zcashd configured in zcash.conf.\n\n" % "Not starting embedded zcashd because --no-embedded was passed"; this->showError(explanation); @@ -101,35 +112,35 @@ QString randomPassword() { * This will create a new zcash.conf, download Zcash parameters. */ void ConnectionLoader::createZcashConf() { - // Fetch params. After params are fetched, create the zcash.conf file and - // try loading the connection again - downloadParams([=] () { - auto confLocation = zcashConfWritableLocation(); - qDebug() << "Creating file " << confLocation; - - QFileInfo fi(confLocation); - QDir().mkdir(fi.dir().absolutePath()); - - QFile file(confLocation); - if (!file.open(QIODevice::ReadWrite | QIODevice::Truncate)) { - qDebug() << "Could not create zcash.conf, returning"; - return; - } - - QTextStream out(&file); + main->logger->write("createZcashConf"); + + auto confLocation = zcashConfWritableLocation(); + main->logger->write("Creating file " + confLocation); + + QFileInfo fi(confLocation); + QDir().mkdir(fi.dir().absolutePath()); + + QFile file(confLocation); + if (!file.open(QIODevice::ReadWrite | QIODevice::Truncate)) { + main->logger->write("Could not create zcash.conf, returning"); + return; + } - out << "server=1\n"; - out << "addnode=mainnet.z.cash\n"; - out << "rpcuser=zec-qt-wallet\n"; - out << "rpcpassword=" % randomPassword() << "\n"; - file.close(); + QTextStream out(&file); + + out << "server=1\n"; + out << "addnode=mainnet.z.cash\n"; + out << "rpcuser=zec-qt-wallet\n"; + out << "rpcpassword=" % randomPassword() << "\n"; + file.close(); - this->doAutoConnect(); - }); + // Now that zcash.conf exists, try to autoconnect again + this->doAutoConnect(); } void ConnectionLoader::downloadParams(std::function cb) { + main->logger->write("Adding params to download queue"); // Add all the files to the download queue downloadQueue = new QQueue(); client = new QNetworkAccessManager(main); @@ -155,6 +166,7 @@ void ConnectionLoader::doNextDownload(std::function cb) { delete downloadQueue; client->deleteLater(); + main->logger->write("All Downloads done"); this->showInformation("All Downloads Finished Successfully!"); cb(); return; @@ -167,7 +179,7 @@ void ConnectionLoader::doNextDownload(std::function cb) { QString paramsDir = zcashParamsDir(); if (QFile(QDir(paramsDir).filePath(filename)).exists()) { - qDebug() << filename << " already exists, skipping "; + main->logger->write(filename + " already exists, skipping"); doNextDownload(cb); return; @@ -177,8 +189,10 @@ void ConnectionLoader::doNextDownload(std::function cb) { currentOutput = new QFile(QDir(paramsDir).filePath(filename + ".part")); if (!currentOutput->open(QIODevice::WriteOnly)) { + main->logger->write("Couldn't open " + currentOutput->fileName() + " for writing"); this->showError("Couldn't download params. Please check the help site for more info."); } + main->logger->write("Downloading to " + filename); qDebug() << "Downloading " << url << " to " << filename; QNetworkRequest request(url); @@ -209,6 +223,7 @@ void ConnectionLoader::doNextDownload(std::function cb) { // Download Finished QObject::connect(currentDownload, &QNetworkReply::finished, [=] () { // Rename file + main->logger->write("Finished downloading " + filename); currentOutput->rename(QDir(paramsDir).filePath(filename)); currentOutput->close(); @@ -216,7 +231,8 @@ void ConnectionLoader::doNextDownload(std::function cb) { currentOutput->deleteLater(); if (currentDownload->error()) { - this->showError("Downloading " + filename + " failed/ Please check the help site for more info"); + main->logger->write("Downloading " + filename + " failed"); + this->showError("Downloading " + filename + " failed. Please check the help site for more info"); } else { doNextDownload(cb); } @@ -231,6 +247,8 @@ void ConnectionLoader::doNextDownload(std::function cb) { bool ConnectionLoader::startEmbeddedZcashd() { if (!Settings::getInstance()->useEmbedded()) return false; + + main->logger->write("Trying to start embedded zcashd"); // Static because it needs to survive even after this method returns. static QString processStdErrOutput; @@ -263,6 +281,7 @@ bool ConnectionLoader::startEmbeddedZcashd() { if (!QFile(zcashdProgram).exists()) { qDebug() << "Can't find zcashd at " << zcashdProgram; + main->logger->write("Can't find zcashd at " + zcashdProgram); return false; } @@ -282,7 +301,7 @@ bool ConnectionLoader::startEmbeddedZcashd() { QObject::connect(ezcashd, &QProcess::readyReadStandardError, [=]() { auto output = ezcashd->readAllStandardError(); - qDebug() << "zcashd stderr:" << output; + main->logger->write("zcashd stderr:" + output); processStdErrOutput.append(output); }); @@ -375,6 +394,7 @@ void ConnectionLoader::refreshZcashdState(Connection* connection, std::function< if (err == QNetworkReply::NetworkError::ConnectionRefusedError) { refused(); } else if (err == QNetworkReply::NetworkError::AuthenticationRequiredError) { + main->logger->write("Authentication failed"); QString explanation = QString() % "Authentication failed. The username / password you specified was " % "not accepted by zcashd. Try changing it in the Edit->Settings menu"; @@ -392,7 +412,7 @@ void ConnectionLoader::refreshZcashdState(Connection* connection, std::function< dots = 0; } this->showInformation("Your zcashd is starting up. Please wait.", status); - + main->logger->write("Waiting to zcashd to come online."); // Refresh after one second QTimer::singleShot(1000, [=]() { this->refreshZcashdState(connection, refused); }); } @@ -424,6 +444,8 @@ QString ConnectionLoader::locateZcashConfFile() { #else auto confLocation = QStandardPaths::locate(QStandardPaths::AppDataLocation, "../../Zcash/zcash.conf"); #endif + + main->logger->write("Found zcashconf at " + QDir::cleanPath(confLocation)); return QDir::cleanPath(confLocation); } @@ -436,7 +458,8 @@ QString ConnectionLoader::zcashConfWritableLocation() { auto confLocation = QDir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)).filePath("../../Zcash/zcash.conf"); #endif - return confLocation; + main->logger->write("Found zcashconf at " + QDir::cleanPath(confLocation)); + return QDir::cleanPath(confLocation); } QString ConnectionLoader::zcashParamsDir() { @@ -449,12 +472,26 @@ QString ConnectionLoader::zcashParamsDir() { #endif if (!paramsLocation.exists()) { + main->logger->write("Creating params location at " + paramsLocation.absolutePath()); QDir().mkpath(paramsLocation.absolutePath()); } + main->logger->write("Found zcash params directory at " + paramsLocation.absolutePath()); return paramsLocation.absolutePath(); } +bool ConnectionLoader::verifyParams() { + QDir paramsDir(zcashParamsDir()); + + if (!QFile(paramsDir.filePath("sapling-output.params")).exists()) return false; + if (!QFile(paramsDir.filePath("sapling-spend.params")).exists()) return false; + if (!QFile(paramsDir.filePath("sprout-proving.key")).exists()) return false; + if (!QFile(paramsDir.filePath("sprout-verifying.key")).exists()) return false; + if (!QFile(paramsDir.filePath("sprout-groth16.params")).exists()) return false; + + return true; +} + /** * Try to automatically detect a zcash.conf file in the correct location and load parameters */ @@ -506,9 +543,10 @@ std::shared_ptr ConnectionLoader::autoDetectZcashConf() { // If rpcport is not in the file, and it was not set by the testnet=1 flag, then go to default if (zcashconf->port.isEmpty()) zcashconf->port = "8232"; - file.close(); + // In addition to the zcash.conf file, also double check the params. + return std::shared_ptr(zcashconf); } diff --git a/src/connection.h b/src/connection.h index b072939..865de62 100644 --- a/src/connection.h +++ b/src/connection.h @@ -50,6 +50,7 @@ private: QString zcashConfWritableLocation(); QString zcashParamsDir(); + bool verifyParams(); void downloadParams(std::function cb); void doNextDownload(std::function cb); bool startEmbeddedZcashd(); diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 2df86a3..0494e78 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -23,6 +23,7 @@ MainWindow::MainWindow(QWidget *parent) : ui(new Ui::MainWindow) { ui->setupUi(this); + logger = new Logger(this, QDir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)).filePath("zec-qt-wallet.log")); // Status Bar setupStatusBar(); @@ -1040,4 +1041,5 @@ MainWindow::~MainWindow() delete labelCompleter; delete loadingMovie; + delete logger; } diff --git a/src/mainwindow.h b/src/mainwindow.h index 237aa4d..e7d9f42 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -2,6 +2,7 @@ #define MAINWINDOW_H #include "precompiled.h" +#include "logger.h" // Forward declare to break circular dependency. class RPC; @@ -45,6 +46,7 @@ public: QLabel* loadingLabel; QWidget* zcashdtab; + Logger* logger; private: void closeEvent(QCloseEvent* event);