diff --git a/src/connection.cpp b/src/connection.cpp index 8c1e268..157118b 100644 --- a/src/connection.cpp +++ b/src/connection.cpp @@ -16,13 +16,6 @@ ConnectionLoader::ConnectionLoader(MainWindow* main, RPC* rpc) { connD = new Ui_ConnectionDialog(); connD->setupUi(d); connD->topIcon->setBasePixmap(QIcon(":/icons/res/icon.ico").pixmap(256, 256)); - - // Center on screen - QRect screenGeometry = QApplication::desktop()->screenGeometry(d); - int x = (screenGeometry.width() - d->width()) / 2; - int y = (screenGeometry.height() - d->height()) / 2; - d->move(x, y); - } ConnectionLoader::~ConnectionLoader() { @@ -31,7 +24,11 @@ ConnectionLoader::~ConnectionLoader() { } void ConnectionLoader::loadConnection() { - d->show(); + QTimer::singleShot(1, [=]() { this->doAutoConnect(); }); + d->exec(); +} + +void ConnectionLoader::doAutoConnect() { // Priority 1: Try to connect to detect zcash.conf and connect to it. auto config = autoDetectZcashConf(); @@ -44,7 +41,7 @@ void ConnectionLoader::loadConnection() { this->showInformation("Starting Embedded zcashd"); if (this->startEmbeddedZcashd()) { // Embedded zcashd started up. Wait a second and then refresh the connection - QTimer::singleShot(1000, [=]() { loadConnection(); } ); + QTimer::singleShot(1000, [=]() { doAutoConnect(); } ); } else { // Errored out, show error and exit QString explanation = QString() % "Couldn't start the embedded zcashd.\n\n" % @@ -70,6 +67,23 @@ void ConnectionLoader::loadConnection() { } } +QString randomPassword() { + static const char alphanum[] = + "0123456789" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz"; + + const int passwordLength = 10; + char* s = new char[passwordLength + 1]; + + for (int i = 0; i < passwordLength; ++i) { + s[i] = alphanum[rand() % (sizeof(alphanum) - 1)]; + } + + s[passwordLength] = 0; + return QString::fromStdString(s); +} + /** * This will create a new zcash.conf, download zcash parameters. */ @@ -93,13 +107,14 @@ void ConnectionLoader::createZcashConf() { out << "server=1\n"; out << "rpcuser=zec-qt-wallet\n"; - out << "rpcpassword=" % QString::number(std::rand()) << "\n"; + out << "rpcpassword=" % randomPassword() << "\n"; file.close(); - this->loadConnection(); + this->doAutoConnect(); }); } + void ConnectionLoader::downloadParams(std::function cb) { // Add all the files to the download queue downloadQueue = new QQueue(); @@ -216,20 +231,19 @@ bool ConnectionLoader::startEmbeddedZcashd() { qDebug() << "Starting zcashd"; QFileInfo fi(Settings::getInstance()->getExecName()); #ifdef Q_OS_LINUX - auto zcashdProgram = "zcashd"; + auto zcashdProgram = fi.dir().absoluteFilePath("zcashd"); #elif defined(Q_OS_DARWIN) - auto zcashdProgram = "zcashd"; + auto zcashdProgram = fi.dir().absoluteFilePath("zcashd"); #else - auto zcashdProgram = "zcashd.exe"; + auto zcashdProgram = fi.dir().absoluteFilePath("zcashd.exe"); #endif if (!QFile(zcashdProgram).exists()) { - qDebug() << "Can't find zcashd"; + qDebug() << "Can't find zcashd at " << zcashdProgram; return false; } ezcashd = new QProcess(main); - ezcashd->setWorkingDirectory(fi.dir().absolutePath()); QObject::connect(ezcashd, &QProcess::started, [=] () { qDebug() << "zcashd started"; }); @@ -251,7 +265,7 @@ bool ConnectionLoader::startEmbeddedZcashd() { void ConnectionLoader::doManualConnect() { auto config = loadFromSettings(); - if (config.get() == nullptr) { + if (!config) { // Nothing configured, show an error QString explanation = QString() % "A manual connection was requested, but the settings are not configured.\n\n" @@ -277,11 +291,13 @@ void ConnectionLoader::doManualConnect() { } void ConnectionLoader::doRPCSetConnection(Connection* conn) { - if (ezcashd != nullptr) { + if (ezcashd) { rpc->setEZcashd(ezcashd); } rpc->setConnection(conn); + d->accept(); + delete this; } @@ -350,10 +366,12 @@ void ConnectionLoader::showInformation(QString info, QString detail) { /** * Show error will close the loading dialog and show an error. */ -void ConnectionLoader::showError(QString explanation) { - d->hide(); - main->ui->statusBar->showMessage("Connection Error"); +void ConnectionLoader::showError(QString explanation) { + rpc->setEZcashd(nullptr); + rpc->noConnection(); + QMessageBox::critical(main, "Connection Error", explanation, QMessageBox::Ok); + d->close(); } QString ConnectionLoader::locateZcashConfFile() { @@ -551,4 +569,4 @@ void Connection::showTxError(const QString& error) { */ void Connection::shutdown() { shutdownInProgress = true; -} \ No newline at end of file +} diff --git a/src/connection.h b/src/connection.h index 95e157f..f416653 100644 --- a/src/connection.h +++ b/src/connection.h @@ -41,6 +41,7 @@ private: Connection* makeConnection(std::shared_ptr config); + void doAutoConnect(); void doManualConnect(); void createZcashConf(); @@ -53,7 +54,6 @@ private: bool startEmbeddedZcashd(); void refreshZcashdState(Connection* connection, std::function refused); - int getProgressFromStatus(QString status); void showError(QString explanation); void showInformation(QString info, QString detail = ""); diff --git a/src/connection.ui b/src/connection.ui index 704f9d9..9a33ed6 100644 --- a/src/connection.ui +++ b/src/connection.ui @@ -52,7 +52,7 @@ - Connection Status + Starting Up Qt::AlignCenter diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index fd489dd..505f209 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -373,13 +373,6 @@ void MainWindow::setupSettingsModal() { QIntValidator validator(0, 65535); settings.port->setValidator(&validator); - // Load current values into the dialog - auto conf = Settings::getInstance()->getSettings(); - settings.hostname->setText(conf.host); - settings.port->setText(conf.port); - settings.rpcuser->setText(conf.rpcuser); - settings.rpcpassword->setText(conf.rpcpassword); - // If values are coming from zcash.conf, then disable all the fields auto zcashConfLocation = Settings::getInstance()->getZcashdConfLocation(); if (!zcashConfLocation.isEmpty()) { @@ -390,6 +383,13 @@ void MainWindow::setupSettingsModal() { settings.rpcpassword->setEnabled(false); } else { + // Load current values into the dialog + auto conf = Settings::getInstance()->getSettings(); + settings.hostname->setText(conf.host); + settings.port->setText(conf.port); + settings.rpcuser->setText(conf.rpcuser); + settings.rpcpassword->setText(conf.rpcpassword); + settings.confMsg->setText("No local zcash.conf found. Please configure connection manually."); settings.hostname->setEnabled(true); settings.port->setEnabled(true); diff --git a/src/mainwindow.ui b/src/mainwindow.ui index 3fc26f4..0a4aacd 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -316,8 +316,8 @@ 0 0 - 920 - 334 + 922 + 376 @@ -767,7 +767,7 @@ - TextLabel + Loading... @@ -781,7 +781,7 @@ - TextLabel + Loading... @@ -802,7 +802,7 @@ - TextLabel + Loading... @@ -864,7 +864,7 @@ 0 0 968 - 22 + 21 diff --git a/src/rpc.cpp b/src/rpc.cpp index db5da25..11ca9ae 100644 --- a/src/rpc.cpp +++ b/src/rpc.cpp @@ -9,8 +9,8 @@ using json = nlohmann::json; RPC::RPC(MainWindow* main) { auto cl = new ConnectionLoader(main, this); - // Show a default no connection message until we can connect. - cl->loadConnection(); + // Execute the load connection async, so we can set up the rest of RPC properly. + QTimer::singleShot(1, [=]() {cl->loadConnection(); }); this->main = main; this->ui = main->ui; @@ -66,6 +66,9 @@ RPC::~RPC() { void RPC::setEZcashd(QProcess* p) { ezcashd = p; + + if (ezcashd == nullptr) + ui->tabWidget->removeTab(4); } void RPC::setConnection(Connection* c) { @@ -326,8 +329,10 @@ void RPC::fillTxJsonParams(json& params, Tx tx) { } -void RPC::noConnection() { - ui->statusBar->showMessage("No Connection to zcashd"); +void RPC::noConnection() { + QIcon i = QApplication::style()->standardIcon(QStyle::SP_MessageBoxCritical); + main->statusIcon->setPixmap(i.pixmap(16, 16)); + main->statusLabel->setText("No Connection"); } // Refresh received z txs by calling z_listreceivedbyaddress/gettransaction @@ -439,7 +444,6 @@ void RPC::refreshReceivedZTrans(QList zaddrs) { ); } - /// This will refresh all the balance data from zcashd void RPC::refresh(bool force) { if (conn == nullptr) @@ -482,7 +486,7 @@ void RPC::getInfoThenRefresh(bool force) { } // Get network sol/s - if (ezcashd != nullptr) { + if (ezcashd) { int conns = reply["connections"].get(); json payload = { @@ -498,11 +502,7 @@ void RPC::getInfoThenRefresh(bool force) { ui->numconnections->setText(QString::number(conns)); ui->solrate->setText(QString::number(solrate) % " Sol/s"); }); - } else { - qDebug() << "removing tab!"; - ui->tabWidget->removeTab(4); - } - + } // Call to see if the blockchain is syncing. json payload = { @@ -519,6 +519,18 @@ void RPC::getInfoThenRefresh(bool force) { Settings::getInstance()->setSyncing(isSyncing); Settings::getInstance()->setBlockNumber(blockNumber); + // Update zcashd tab if it exists + if (ezcashd && isSyncing) { + // 895 / ~426530 (0 % ) + const qint64 genisisTimeMSec = 1477638000000; + qint64 estBlocks = (QDateTime::currentMSecsSinceEpoch() - genisisTimeMSec) / 2.5 / 60 / 1000; + // Round to nearest 10 + estBlocks = ((estBlocks + 5) / 10) * 10; + ui->blockheight->setText(ui->blockheight->text() % /*" / ~" % QString::number(estBlocks) % */ + " ( " % QString::number(progress * 100, 'f', 0) % "% )"); + } + + // Update the status bar QString statusText = QString() % (isSyncing ? "Syncing" : "Connected") % " (" % @@ -825,7 +837,7 @@ void RPC::refreshZECPrice() { } for (const json& item : parsed.get()) { - if (item["symbol"].get().compare("ZEC") == 0) { + if (item["symbol"].get() == "ZEC") { QString price = QString::fromStdString(item["price_usd"].get()); qDebug() << "ZEC Price=" << price; Settings::getInstance()->setZECPrice(price.toDouble()); @@ -859,19 +871,22 @@ void RPC::shutdownZcashd() { conn->doRPCWithDefaultErrorHandling(payload, [=](auto) {}); conn->shutdown(); + QDialog d(main); + Ui_ConnectionDialog connD; + connD.setupUi(&d); + connD.topIcon->setBasePixmap(QIcon(":/icons/res/icon.ico").pixmap(256, 256)); + connD.status->setText("Please wait for zec-qt-wallet to exit"); + connD.statusDetail->setText("Waiting for zcashd to exit"); - QMessageBox d(main); - d.setIcon(QMessageBox::Icon::Information); - d.setWindowTitle("Waiting for zcashd to exit"); - d.setText("Please wait for zcashd to exit. Don't click OK!"); - d.setStandardButtons(QMessageBox::NoButton); - QTimer waiter(main); // We capture by reference all the local variables because of the d.exec() // below, which blocks this function until we exit. + int waitCount = 0; QObject::connect(&waiter, &QTimer::timeout, [&] () { - if (ezcashd->atEnd() && ezcashd->processId() == 0) { + waitCount++; + if ((ezcashd->atEnd() && ezcashd->processId() == 0) || + waitCount > 30) { qDebug() << "Ended"; waiter.stop(); QTimer::singleShot(1000, [&]() { d.accept(); }); diff --git a/src/rpc.h b/src/rpc.h index 6d2d8e9..958a733 100644 --- a/src/rpc.h +++ b/src/rpc.h @@ -59,16 +59,14 @@ public: void importTPrivKey(QString addr, bool rescan, const std::function& cb); void shutdownZcashd(); + void noConnection(); void getAllPrivKeys(const std::function>)>); Turnstile* getTurnstile() { return turnstile; } Connection* getConnection() { return conn; } - private: - void noConnection(); - void refreshBalances(); void refreshTransactions(); diff --git a/src/senttxstore.cpp b/src/senttxstore.cpp index f5d587d..bb77a8b 100644 --- a/src/senttxstore.cpp +++ b/src/senttxstore.cpp @@ -31,7 +31,7 @@ QList SentTxStore::readSentTxFile() { QJsonDocument jsonDoc; data.open(QFile::ReadOnly); - jsonDoc = QJsonDocument().fromJson(data.readAll()); + jsonDoc = QJsonDocument::fromJson(data.readAll()); data.close(); QList items; @@ -87,7 +87,7 @@ void SentTxStore::addToSentTx(Tx tx, QString txid) { QJsonObject txItem; txItem["type"] = "sent"; txItem["from"] = tx.fromAddr; - txItem["datetime"] = QDateTime().currentMSecsSinceEpoch() / (qint64)1000; + txItem["datetime"] = QDateTime::currentMSecsSinceEpoch() / (qint64)1000; txItem["address"] = QString(); // The sent address is blank, to be consistent with t-Addr sent behaviour txItem["txid"] = txid; txItem["amount"] = -totalAmount; diff --git a/src/settings.cpp b/src/settings.cpp index fa7fa9a..38fee88 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -5,9 +5,6 @@ Settings* Settings::instance = nullptr; -Settings::~Settings() { -} - bool Settings::getSaveZtxs() { // Load from the QT Settings. return QSettings().value("options/savesenttx", true).toBool(); @@ -122,4 +119,4 @@ QString Settings::getZECUSDDisplayFormat(double bal) { return getZECDisplayFormat(bal) % " (" % getUSDFormat(bal) % ")"; else return getZECDisplayFormat(bal); -} \ No newline at end of file +} diff --git a/src/turnstile.cpp b/src/turnstile.cpp index fb2211f..64ec6e0 100644 --- a/src/turnstile.cpp +++ b/src/turnstile.cpp @@ -14,8 +14,6 @@ Turnstile::Turnstile(RPC* _rpc, MainWindow* mainwindow) { this->mainwindow = mainwindow; } -Turnstile::~Turnstile() { -} void printPlan(QList plan) { for (auto item : plan) { @@ -118,7 +116,7 @@ void Turnstile::planMigration(QString zaddr, QString destAddr, int numsplits, in // The first migration is shifted to the current block, so the user sees something // happening immediately - if (migItems.size() == 0) { + if (migItems.empty()) { // Show error and abort QMessageBox::warning(mainwindow, "Locked funds", @@ -220,9 +218,7 @@ Turnstile::getNextStep(QList& plan) { bool Turnstile::isMigrationPresent() { auto plan = readMigrationPlan(); - if (plan.isEmpty()) return false; - - return true; + return !plan.isEmpty(); } ProgressReport Turnstile::getPlanProgress() { diff --git a/src/turnstile.h b/src/turnstile.h index a73af50..aba1a3e 100644 --- a/src/turnstile.h +++ b/src/turnstile.h @@ -39,7 +39,6 @@ class Turnstile { public: Turnstile(RPC* _rpc, MainWindow* mainwindow); - ~Turnstile(); void planMigration(QString zaddr, QString destAddr, int splits, int numBlocks); QList splitAmount(double amount, int parts);