diff --git a/README.md b/README.md index da8bfb7..037fc09 100644 --- a/README.md +++ b/README.md @@ -17,17 +17,17 @@ Pass `--no-embedded` to disable the embedded hushd and force SilentDragon to con ## Compiling from source SilentDragon is written in C++ 14, and can be compiled with g++/clang++/visual c++. It also depends on Qt5, which you can get from [here](https://www.qt.io/download). Note that if you are compiling from source, you won't get the embedded hushd by default. You can either run an external hushd, or compile hushd as well. -See detailed build instructions [on the wiki](https://github.com/MyHush/SilentDragon/wiki/Compiling-from-source-code) ### Building on Linux ``` +sudo apt-get install qt5-default qt5-qmake libqt5websockets5-dev git clone https://github.com/MyHush/SilentDragon.git cd SilentDragon qmake silentdragon.pro CONFIG+=debug make -j$(nproc) -./SilentDragon +./silentdragon ``` ### Building on Windows @@ -60,6 +60,21 @@ make ./SilentDragon.app/Contents/MacOS/SilentDragon ``` +### Emulating the embedded node + +In binary releases, SilentDragon will use node binaries in the current directory to sync a node from scratch. +It does not attempt to download them, it bundles them. To simulate this from a developer setup, you can symlink +these four files in your Git repo: + +``` + ln -s ../hush3/src/hushd + ln -s ../hush3/src/hush-cli + ln -s ../hush3/src/komodod + ln -s ../hush3/src/komodo-cli +``` + +The above assumes silentdragon and hush3 git repos are in the same directory. File names on Windows will need to be tweaked. + ### Support For support or other questions, Join [Discord](https://myhush.org/discord), or tweet at [@MyHushTeam](https://twitter.com/MyHushTeam) or [file an issue](https://github.com/MyHush/SilentDragon/issues). diff --git a/src/connection.cpp b/src/connection.cpp index 4c971d8..818e59a 100644 --- a/src/connection.cpp +++ b/src/connection.cpp @@ -14,6 +14,7 @@ ConnectionLoader::ConnectionLoader(MainWindow* main, RPC* rpc) { this->rpc = rpc; d = new QDialog(main); + d->setWindowFlags(d->windowFlags() & ~(Qt::WindowCloseButtonHint | Qt::WindowContextHelpButtonHint)); connD = new Ui_ConnectionDialog(); connD->setupUi(d); QPixmap logo(":/img/res/logobig.gif"); @@ -51,29 +52,29 @@ void ConnectionLoader::doAutoConnect(bool tryEzcashdStart) { // Refused connection. So try and start embedded zcashd if (Settings::getInstance()->useEmbedded()) { if (tryEzcashdStart) { - this->showInformation(QObject::tr("Starting embedded zcashd")); + this->showInformation(QObject::tr("Starting embedded hushd")); 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"); + main->logger->write("Embedded hushd started up, trying autoconnect in 1 sec"); QTimer::singleShot(1000, [=]() { doAutoConnect(); } ); } else { if (config->zcashDaemon) { - // zcashd is configured to run as a daemon, so we must wait for a few seconds + // hushd is configured to run as a daemon, so we must wait for a few seconds // to let it start up. - main->logger->write("zcashd is daemon=1. Waiting for it to start up"); - this->showInformation(QObject::tr("zcashd is set to run as daemon"), QObject::tr("Waiting for zcashd")); - QTimer::singleShot(5000, [=]() { doAutoConnect(/* don't attempt to start ezcashd */ false); }); + main->logger->write("hushd is daemon=1. Waiting for it to start up"); + this->showInformation(QObject::tr("hushd is set to run as daemon"), QObject::tr("Waiting for hushd")); + QTimer::singleShot(5000, [=]() { doAutoConnect(/* don't attempt to start ehushd */ false); }); } else { // Something is wrong. // 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("Unknown problem while trying to start zcashd"); + main->logger->write("Unknown problem while trying to start hushd!"); 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"); + main->logger->write("Couldn't start embedded hushd for unknown reason"); QString explanation; if (config->zcashDaemon) { explanation = QString() % QObject::tr("You have komodod set to start as a daemon, which can cause problems " @@ -81,9 +82,9 @@ void ConnectionLoader::doAutoConnect(bool tryEzcashdStart) { "Please remove the following line from your HUSH3.conf and restart SilentDragon\n" "daemon=1"); } else { - explanation = QString() % QObject::tr("Couldn't start the embedded komodod.\n\n" + explanation = QString() % QObject::tr("Couldn't start the embedded hushd.\n\n" "Please try restarting.\n\nIf you previously started komodod with custom arguments, you might need to reset HUSH3.conf.\n\n" - "If all else fails, please run zcashd manually.") % + "If all else fails, please run hushd manually.") % (ezcashd ? QObject::tr("The process returned") + ":\n\n" % ezcashd->errorString() : QString("")); } @@ -178,15 +179,23 @@ void ConnectionLoader::createZcashConf() { QFile file(confLocation); if (!file.open(QIODevice::ReadWrite | QIODevice::Truncate)) { main->logger->write("Could not create HUSH3.conf, returning"); + + QString explanation = QString() % QObject::tr("Could not create HUSH3.conf."); + this->showError(explanation); return; } QTextStream out(&file); + out << "# Autogenerated by Silent Dragon\n"; out << "server=1\n"; out << "rpcuser=hush\n"; out << "rpcpassword=" % randomPassword() << "\n"; + out << "rpcport=18031\n"; out << "txindex=1\n"; + out << "addressindex=1\n"; + out << "spentindex=1\n"; + out << "timestampindex=1\n"; out << "rpcworkqueue=256\n"; out << "rpcallowip=127.0.0.1\n"; @@ -209,11 +218,9 @@ void ConnectionLoader::downloadParams(std::function cb) { // Add all the files to the download queue downloadQueue = new QQueue(); client = new QNetworkAccessManager(main); - + downloadQueue->enqueue(QUrl("https://z.cash/downloads/sapling-output.params")); - downloadQueue->enqueue(QUrl("https://z.cash/downloads/sapling-spend.params")); - downloadQueue->enqueue(QUrl("https://z.cash/downloads/sprout-proving.key")); - downloadQueue->enqueue(QUrl("https://z.cash/downloads/sprout-verifying.key")); + downloadQueue->enqueue(QUrl("https://z.cash/downloads/sapling-spend.params")); downloadQueue->enqueue(QUrl("https://z.cash/downloads/sprout-groth16.params")); doNextDownload(cb); @@ -333,39 +340,44 @@ bool ConnectionLoader::startEmbeddedZcashd() { // Finally, start zcashd QDir appPath(QCoreApplication::applicationDirPath()); #ifdef Q_OS_LINUX - auto zcashdProgram = appPath.absoluteFilePath("komodod"); + auto zcashdProgram = appPath.absoluteFilePath("hushd"); if (!QFile(zcashdProgram).exists()) { - zcashdProgram = appPath.absoluteFilePath("komodod"); + zcashdProgram = appPath.absoluteFilePath("hushd"); } #elif defined(Q_OS_DARWIN) - auto zcashdProgram = appPath.absoluteFilePath("komodod"); + auto zcashdProgram = appPath.absoluteFilePath("hushd"); +#elif defined(Q_OS_WIN64) + auto zcashdProgram = appPath.absoluteFilePath("hushd.bat"); #else - auto zcashdProgram = appPath.absoluteFilePath("komodod.exe"); + //TODO: Not Linux + not darwin DOES NOT EQUAL windows!!! + auto zcashdProgram = appPath.absoluteFilePath("hushd"); #endif if (!QFile(zcashdProgram).exists()) { - qDebug() << "Can't find zcashd at " << zcashdProgram; - main->logger->write("Can't find zcashd at " + zcashdProgram); + qDebug() << "Can't find hushd at " << zcashdProgram; + main->logger->write("Can't find hushd at " + zcashdProgram); return false; } - ezcashd = new QProcess(main); - QObject::connect(ezcashd, &QProcess::started, [=] () { - //qDebug() << "zcashd started"; + ezcashd = std::shared_ptr(new QProcess(main)); + QObject::connect(ezcashd.get(), &QProcess::started, [=] () { + qDebug() << "Embedded hushd started"; }); - QObject::connect(ezcashd, QOverload::of(&QProcess::finished), - [=](int, QProcess::ExitStatus) { - //qDebug() << "zcashd finished with code " << exitCode << "," << exitStatus; + QObject::connect(ezcashd.get(), QOverload::of(&QProcess::finished), + [=](int exitCode, QProcess::ExitStatus exitStatus) { + qDebug() << "hushd finished with code " << exitCode << "," << exitStatus; }); - QObject::connect(ezcashd, &QProcess::errorOccurred, [&] (auto) { - //qDebug() << "Couldn't start zcashd: " << error; + QObject::connect(ezcashd.get(), &QProcess::errorOccurred, [&] (QProcess::ProcessError error) { + qDebug() << "Couldn't start hushd: " << error; }); - QObject::connect(ezcashd, &QProcess::readyReadStandardError, [=]() { - auto output = ezcashd->readAllStandardError(); - main->logger->write("hushd stderr:" + output); + std::weak_ptr weak_obj(ezcashd); + auto ptr_main(main); + QObject::connect(ezcashd.get(), &QProcess::readyReadStandardError, [weak_obj, ptr_main]() { + auto output = weak_obj.lock()->readAllStandardError(); + ptr_main->logger->write("hushd stderr:" + output); processStdErrOutput.append(output); }); @@ -375,7 +387,7 @@ bool ConnectionLoader::startEmbeddedZcashd() { ezcashd->start(zcashdProgram); #else ezcashd->setWorkingDirectory(appPath.absolutePath()); - ezcashd->start("komodo.exe"); + ezcashd->start(zcashdProgram); #endif // Q_OS_LINUX @@ -448,10 +460,10 @@ void ConnectionLoader::refreshZcashdState(Connection* connection, std::function< }; connection->doRPC(payload, [=] (auto) { - // Success, hide the dialog if it was shown. - d->hide(); + // Success main->logger->write("hushd is online."); - this->doRPCSetConnection(connection); + // Delay 1 second to ensure loading (splash) is seen at least 1 second. + QTimer::singleShot(1000, [=]() { this->doRPCSetConnection(connection); }); }, [=] (auto reply, auto res) { // Failed, see what it is. @@ -563,13 +575,14 @@ QString ConnectionLoader::zcashParamsDir() { bool ConnectionLoader::verifyParams() { QDir paramsDir(zcashParamsDir()); + qDebug() << "Verifying param files exist"; + if (!QFile(paramsDir.filePath("sapling-output.params")).exists()) return false; if (!QFile(paramsDir.filePath("sapling-spend.params")).exists()) return false; - //TODO: sprout probably not needed - 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; + qDebug() << "All param files found!"; + return true; } diff --git a/src/connection.h b/src/connection.h index 9e140be..e192d49 100644 --- a/src/connection.h +++ b/src/connection.h @@ -64,7 +64,7 @@ private: void doRPCSetConnection(Connection* conn); - QProcess* ezcashd = nullptr; + std::shared_ptr ezcashd; QDialog* d; Ui_ConnectionDialog* connD; diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 2c09989..466cbcc 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -601,16 +601,14 @@ void MainWindow::addressBook() { void MainWindow::donate() { - // Set up a donation to me :) removeExtraAddresses(); - ui->Address1->setText(Settings::getDonationAddr( - Settings::getInstance()->isSaplingAddress(ui->inputsCombo->currentText()))); + ui->Address1->setText(Settings::getDonationAddr(true)); ui->Address1->setCursorPosition(0); - ui->Amount1->setText("0.01"); - ui->MemoTxt1->setText(tr("Thanks for supporting SilentDragon!")); + ui->Amount1->setText("0.00"); + ui->MemoTxt1->setText(tr("Some feedback about SilentDragon or Hush...")); - ui->statusBar->showMessage(tr("Donate 0.01 ") % Settings::getTokenName() % tr(" to support SilentDragon")); + ui->statusBar->showMessage(tr("Send Duke some private and shielded feedback about ") % Settings::getTokenName() % tr(" or SilentDragon")); // And switch to the send tab. ui->tabWidget->setCurrentIndex(1); @@ -855,7 +853,7 @@ void MainWindow::importPrivKey() { pui.buttonBox->button(QDialogButtonBox::Save)->setVisible(false); pui.helpLbl->setText(QString() % tr("Please paste your private keys here, one per line") % ".\n" % - tr("The keys will be imported into your connected komodod node")); + tr("The keys will be imported into your connected Hush node")); if (d.exec() == QDialog::Accepted && !pui.privKeyTxt->toPlainText().trimmed().isEmpty()) { auto rawkeys = pui.privKeyTxt->toPlainText().trimmed().split("\n"); @@ -876,7 +874,7 @@ void MainWindow::importPrivKey() { // Show the dialog that keys will be imported. QMessageBox::information(this, - "Imported", tr("The keys were imported. It may take several minutes to rescan the blockchain. Until then, functionality may be limited"), + "Imported", tr("The keys were imported! It may take several minutes to rescan the blockchain. Until then, functionality may be limited"), QMessageBox::Ok); } } @@ -967,7 +965,7 @@ void MainWindow::exportKeys(QString addr) { // Wire up save button QObject::connect(pui.buttonBox->button(QDialogButtonBox::Save), &QPushButton::clicked, [=] () { QString fileName = QFileDialog::getSaveFileName(this, tr("Save File"), - allKeys ? "zcash-all-privatekeys.txt" : "zcash-privatekey.txt"); + allKeys ? "hush-all-privatekeys.txt" : "hush-privatekey.txt"); QFile file(fileName); if (!file.open(QIODevice::WriteOnly)) { QMessageBox::information(this, tr("Unable to open file"), file.errorString()); diff --git a/src/mainwindow.ui b/src/mainwindow.ui index d20b7de..abd8d60 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -1213,7 +1213,7 @@ - &Donate + &Send Duke Feedback diff --git a/src/rpc.cpp b/src/rpc.cpp index b6dd038..74c0264 100644 --- a/src/rpc.cpp +++ b/src/rpc.cpp @@ -73,7 +73,7 @@ RPC::~RPC() { delete conn; } -void RPC::setEZcashd(QProcess* p) { +void RPC::setEZcashd(std::shared_ptr p) { ezcashd = p; if (ezcashd && ui->tabWidget->widget(4) == nullptr) { @@ -1127,6 +1127,7 @@ void RPC::shutdownZcashd() { conn->shutdown(); QDialog d(main); + d.setWindowFlags(d.windowFlags() & ~(Qt::WindowCloseButtonHint | Qt::WindowContextHelpButtonHint)); Ui_ConnectionDialog connD; connD.setupUi(&d); connD.topIcon->setBasePixmap(QIcon(":/icons/res/icon.ico").pixmap(256, 256)); @@ -1142,7 +1143,8 @@ void RPC::shutdownZcashd() { waitCount++; if ((ezcashd->atEnd() && ezcashd->processId() == 0) || - waitCount > 30 || + ezcashd->state() == QProcess::NotRunning || + waitCount > 30 || conn->config->zcashDaemon) { // If zcashd is daemon, then we don't have to do anything else qDebug() << "Ended"; waiter.stop(); diff --git a/src/rpc.h b/src/rpc.h index 7cc6610..3b95a71 100644 --- a/src/rpc.h +++ b/src/rpc.h @@ -38,8 +38,8 @@ public: ~RPC(); void setConnection(Connection* c); - void setEZcashd(QProcess* p); - const QProcess* getEZcashD() { return ezcashd; } + void setEZcashd(std::shared_ptr p); + const QProcess* getEZcashD() { return ezcashd.get(); } void refresh(bool force = false); @@ -109,7 +109,7 @@ private: void getTAddresses (const std::function& cb); Connection* conn = nullptr; - QProcess* ezcashd = nullptr; + std::shared_ptr ezcashd = nullptr; QList* utxos = nullptr; QMap* allBalances = nullptr; diff --git a/src/settings.cpp b/src/settings.cpp index ea08fe1..803870f 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -199,16 +199,10 @@ QString Settings::getTokenName() { } QString Settings::getDonationAddr(bool sapling) { - if (Settings::getInstance()->isTestnet()) - if (sapling) - return "ztestsapling1wn6889vznyu42wzmkakl2effhllhpe4azhu696edg2x6me4kfsnmqwpglaxzs7tmqsq7kudemp5"; - else - return "ztn6fYKBii4Fp4vbGhkPgrtLU4XjXp4ZBMZgShtopmDGbn1L2JLTYbBp2b7SSkNr9F3rQeNZ9idmoR7s4JCVUZ7iiM5byhF"; - else - if (sapling) - return "zs1knmre6w5dyy2mjdxw2g8v93adr3fh9jtwqx76863557sjunlqq563cftxaz05saskyyn72xm2hv"; - else - return "zcEgrceTwvoiFdEvPWcsJHAMrpLsprMF6aRJiQa3fan5ZphyXLPuHghnEPrEPRoEVzUy65GnMVyCTRdkT6BYBepnXh6NBYs"; + if (Settings::getInstance()->isTestnet()) { + return "ztestsaplingXXX"; + } + return "zs1aq4xnrkjlnxx0zesqye7jz3dfrf3rjh7q5z6u8l6mwyqqaam3gx3j2fkqakp33v93yavq46j83q"; } bool Settings::addToZcashConf(QString confLocation, QString line) {