From 62981fb570f0570cfda26ab19923a7e7fd704c4e Mon Sep 17 00:00:00 2001 From: "Jonathan \"Duke\" Leto" Date: Wed, 13 Nov 2019 08:09:31 -0800 Subject: [PATCH] add sat value and lag to status bar; delete zboard/turnstile stuff --- silentdragon.pro | 5 - src/main.cpp | 1 - src/mainwindow.cpp | 333 ----------------------------------- src/rpc.cpp | 78 ++------ src/settings.cpp | 18 +- src/settings.h | 5 + src/turnstile.cpp | 372 --------------------------------------- src/turnstile.h | 69 -------- src/turnstile.ui | 235 ------------------------- src/turnstileprogress.ui | 192 -------------------- 10 files changed, 22 insertions(+), 1286 deletions(-) delete mode 100644 src/turnstile.cpp delete mode 100644 src/turnstile.h delete mode 100644 src/turnstile.ui delete mode 100644 src/turnstileprogress.ui diff --git a/silentdragon.pro b/silentdragon.pro index 34e8866..b780e94 100644 --- a/silentdragon.pro +++ b/silentdragon.pro @@ -46,7 +46,6 @@ SOURCES += \ src/sendtab.cpp \ src/senttxstore.cpp \ src/txtablemodel.cpp \ - src/turnstile.cpp \ src/qrcodelabel.cpp \ src/connection.cpp \ src/fillediconlabel.cpp \ @@ -73,7 +72,6 @@ HEADERS += \ src/settings.h \ src/txtablemodel.h \ src/senttxstore.h \ - src/turnstile.h \ src/qrcodelabel.h \ src/connection.h \ src/fillediconlabel.h \ @@ -93,15 +91,12 @@ FORMS += \ src/settings.ui \ src/about.ui \ src/confirm.ui \ - src/turnstile.ui \ - src/turnstileprogress.ui \ src/privkey.ui \ src/memodialog.ui \ src/viewalladdresses.ui \ src/validateaddress.ui \ src/viewalladdresses.ui \ src/connection.ui \ - src/zboard.ui \ src/addressbook.ui \ src/viewalladdresses.ui \ src/mobileappconnector.ui \ diff --git a/src/main.cpp b/src/main.cpp index 5f121a5..a503e47 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,7 +4,6 @@ #include "mainwindow.h" #include "rpc.h" #include "settings.h" -#include "turnstile.h" #include "version.h" diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 8a75885..d75dec6 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -6,19 +6,15 @@ #include "ui_mainwindow.h" #include "ui_mobileappconnector.h" #include "ui_addressbook.h" -#include "ui_zboard.h" #include "ui_privkey.h" #include "ui_about.h" #include "ui_settings.h" -#include "ui_turnstile.h" -#include "ui_turnstileprogress.h" #include "ui_viewalladdresses.h" #include "ui_validateaddress.h" #include "rpc.h" #include "balancestablemodel.h" #include "settings.h" #include "version.h" -#include "turnstile.h" #include "senttxstore.h" #include "connection.h" #include "requestdialog.h" @@ -89,9 +85,6 @@ MainWindow::MainWindow(QWidget *parent) : // Export transactions QObject::connect(ui->actionExport_transactions, &QAction::triggered, this, &MainWindow::exportTransactions); - // z-Board.net - QObject::connect(ui->actionz_board_net, &QAction::triggered, this, &MainWindow::postToZBoard); - // Validate Address QObject::connect(ui->actionValidate_Address, &QAction::triggered, this, &MainWindow::validateAddress); @@ -126,7 +119,6 @@ MainWindow::MainWindow(QWidget *parent) : setupTransactionsTab(); setupReceiveTab(); setupBalancesTab(); - setupTurnstileDialog(); setupZcashdTab(); rpc = new RPC(this); @@ -206,208 +198,6 @@ void MainWindow::closeEvent(QCloseEvent* event) { QMainWindow::closeEvent(event); } -void MainWindow::turnstileProgress() { - Ui_TurnstileProgress progress; - QDialog d(this); - progress.setupUi(&d); - Settings::saveRestore(&d); - - QIcon icon = QApplication::style()->standardIcon(QStyle::SP_MessageBoxWarning); - progress.msgIcon->setPixmap(icon.pixmap(64, 64)); - - bool migrationFinished = false; - auto fnUpdateProgressUI = [=, &migrationFinished] () mutable { - // Get the plan progress - if (rpc->getTurnstile()->isMigrationPresent()) { - auto curProgress = rpc->getTurnstile()->getPlanProgress(); - - progress.progressTxt->setText(QString::number(curProgress.step) % QString(" / ") % QString::number(curProgress.totalSteps)); - progress.progressBar->setValue(100 * curProgress.step / curProgress.totalSteps); - - auto nextTxBlock = curProgress.nextBlock - Settings::getInstance()->getBlockNumber(); - - progress.fromAddr->setText(curProgress.from); - progress.toAddr->setText(curProgress.to); - - if (curProgress.step == curProgress.totalSteps) { - migrationFinished = true; - auto txt = QString("Turnstile migration finished"); - if (curProgress.hasErrors) { - txt = txt + ". There were some errors.\n\nYour funds are all in your wallet, so you should be able to finish moving them manually."; - } - progress.nextTx->setText(txt); - } else { - progress.nextTx->setText(QString("Next transaction in ") - % QString::number(nextTxBlock < 0 ? 0 : nextTxBlock) - % " blocks via " % curProgress.via % "\n" - % (nextTxBlock <= 0 ? "(waiting for confirmations)" : "")); - } - - } else { - progress.progressTxt->setText(""); - progress.progressBar->setValue(0); - progress.nextTx->setText("No turnstile migration is in progress"); - } - }; - - QTimer progressTimer(this); - QObject::connect(&progressTimer, &QTimer::timeout, fnUpdateProgressUI); - progressTimer.start(Settings::updateSpeed); - fnUpdateProgressUI(); - - auto curProgress = rpc->getTurnstile()->getPlanProgress(); - - // Abort button - if (curProgress.step != curProgress.totalSteps) - progress.buttonBox->button(QDialogButtonBox::Discard)->setText("Abort"); - else - progress.buttonBox->button(QDialogButtonBox::Discard)->setVisible(false); - - // Abort button clicked - QObject::connect(progress.buttonBox->button(QDialogButtonBox::Discard), &QPushButton::clicked, [&] () { - if (curProgress.step != curProgress.totalSteps) { - auto abort = QMessageBox::warning(this, "Are you sure you want to Abort?", - "Are you sure you want to abort the migration?\nAll further transactions will be cancelled.\nAll your funds are still in your wallet.", - QMessageBox::Yes, QMessageBox::No); - if (abort == QMessageBox::Yes) { - rpc->getTurnstile()->removeFile(); - d.close(); - ui->statusBar->showMessage("Automatic Sapling turnstile migration aborted."); - } - } - }); - - d.exec(); - if (migrationFinished || curProgress.step == curProgress.totalSteps) { - // Finished, so delete the file - rpc->getTurnstile()->removeFile(); - } -} - -void MainWindow::turnstileDoMigration(QString fromAddr) { - // Return if there is no connection - if (rpc->getAllZAddresses() == nullptr) - return; - - // If a migration is already in progress, show the progress dialog instead - if (rpc->getTurnstile()->isMigrationPresent()) { - turnstileProgress(); - return; - } - - Ui_Turnstile turnstile; - QDialog d(this); - turnstile.setupUi(&d); - Settings::saveRestore(&d); - - QIcon icon = QApplication::style()->standardIcon(QStyle::SP_MessageBoxInformation); - turnstile.msgIcon->setPixmap(icon.pixmap(64, 64)); - - auto fnGetAllSproutBalance = [=] () { - double bal = 0; - for (auto addr : *rpc->getAllZAddresses()) { - if (Settings::getInstance()->isSproutAddress(addr)) { - bal += rpc->getAllBalances()->value(addr); - } - } - - return bal; - }; - - turnstile.fromBalance->setText(Settings::getZECUSDDisplayFormat(fnGetAllSproutBalance())); - for (auto addr : *rpc->getAllZAddresses()) { - auto bal = rpc->getAllBalances()->value(addr); - if (Settings::getInstance()->isSaplingAddress(addr)) { - turnstile.migrateTo->addItem(addr, bal); - } else { - turnstile.migrateZaddList->addItem(addr, bal); - } - } - - auto fnUpdateSproutBalance = [=] (QString addr) { - double bal = 0; - - // The currentText contains the balance as well, so strip that. - if (addr.contains("(")) { - addr = addr.left(addr.indexOf("(")); - } - - if (addr.startsWith("All")) { - bal = fnGetAllSproutBalance(); - } else { - bal = rpc->getAllBalances()->value(addr); - } - - auto balTxt = Settings::getZECUSDDisplayFormat(bal); - - if (bal < Turnstile::minMigrationAmount) { - turnstile.fromBalance->setStyleSheet("color: red;"); - turnstile.fromBalance->setText(balTxt % " [You need at least " - % Settings::getZECDisplayFormat(Turnstile::minMigrationAmount) - % " for automatic migration]"); - turnstile.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); - } else { - turnstile.fromBalance->setStyleSheet(""); - turnstile.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true); - turnstile.fromBalance->setText(balTxt); - } - }; - - if (!fromAddr.isEmpty()) - turnstile.migrateZaddList->setCurrentText(fromAddr); - - fnUpdateSproutBalance(turnstile.migrateZaddList->currentText()); - - // Combo box selection event - QObject::connect(turnstile.migrateZaddList, &QComboBox::currentTextChanged, fnUpdateSproutBalance); - - // Privacy level combobox - // Num tx over num blocks - QList> privOptions; - privOptions.push_back(std::make_tuple(3, 576)); - privOptions.push_back(std::make_tuple(5, 1152)); - privOptions.push_back(std::make_tuple(10, 2304)); - - QObject::connect(turnstile.privLevel, QOverload::of(&QComboBox::currentIndexChanged), [=] (auto idx) { - // Update the fees - turnstile.minerFee->setText( - Settings::getZECUSDDisplayFormat(std::get<0>(privOptions[idx]) * Settings::getMinerFee())); - }); - - for (auto i : privOptions) { - turnstile.privLevel->addItem(QString::number((int)(std::get<1>(i) / 24 / 24)) % " days (" % // 24 blks/hr * 24 hrs per day - QString::number(std::get<1>(i)) % " blocks, ~" % - QString::number(std::get<0>(i)) % " txns)" - ); - } - - turnstile.buttonBox->button(QDialogButtonBox::Ok)->setText("Start"); - - if (d.exec() == QDialog::Accepted) { - auto privLevel = privOptions[turnstile.privLevel->currentIndex()]; - rpc->getTurnstile()->planMigration( - turnstile.migrateZaddList->currentText(), - turnstile.migrateTo->currentText(), - std::get<0>(privLevel), std::get<1>(privLevel)); - - QMessageBox::information(this, "Backup your wallet.dat", - "The migration will now start. You can check progress in the File -> Sapling Turnstile menu.\n\nYOU MUST BACKUP YOUR wallet.dat NOW!\n\nNew Addresses have been added to your wallet which will be used for the migration.", - QMessageBox::Ok); - } -} - -void MainWindow::setupTurnstileDialog() { - // Turnstile migration - QObject::connect(ui->actionTurnstile_Migration, &QAction::triggered, [=] () { - // If there is current migration that is present, show the progress button - if (rpc->getTurnstile()->isMigrationPresent()) - turnstileProgress(); - else - turnstileDoMigration(); - }); - -} - void MainWindow::setupStatusBar() { // Status Bar loadingLabel = new QLabel(); @@ -727,122 +517,6 @@ void MainWindow::validateAddress() { } -void MainWindow::postToZBoard() { - QDialog d(this); - Ui_zboard zb; - zb.setupUi(&d); - Settings::saveRestore(&d); - - if (rpc->getConnection() == nullptr) - return; - - // Fill the from field with sapling addresses. - for (auto i = rpc->getAllBalances()->keyBegin(); i != rpc->getAllBalances()->keyEnd(); i++) { - if (Settings::getInstance()->isSaplingAddress(*i) && rpc->getAllBalances()->value(*i) > 0) { - zb.fromAddr->addItem(*i); - } - } - - QMap topics; - // Insert the main topic automatically - topics.insert("#Main_Area", Settings::getInstance()->isTestnet() ? Settings::getDonationAddr() : Settings::getZboardAddr()); - zb.topicsList->addItem(topics.firstKey()); - // Then call the API to get topics, and if it returns successfully, then add the rest of the topics - rpc->getZboardTopics([&](QMap topicsMap) { - for (auto t : topicsMap.keys()) { - topics.insert(t, Settings::getInstance()->isTestnet() ? Settings::getDonationAddr() : topicsMap[t]); - zb.topicsList->addItem(t); - } - }); - - // Testnet warning - if (Settings::getInstance()->isTestnet()) { - zb.testnetWarning->setText(tr("You are on testnet, your post won't actually appear on z-board.net")); - } - else { - zb.testnetWarning->setText(""); - } - - QRegExpValidator v(QRegExp("^[a-zA-Z0-9_]{3,20}$"), zb.postAs); - zb.postAs->setValidator(&v); - - zb.feeAmount->setText(Settings::getZECUSDDisplayFormat(Settings::getZboardAmount() + Settings::getMinerFee())); - - auto fnBuildNameMemo = [=]() -> QString { - auto memo = zb.memoTxt->toPlainText().trimmed(); - if (!zb.postAs->text().trimmed().isEmpty()) - memo = zb.postAs->text().trimmed() + ":: " + memo; - return memo; - }; - - auto fnUpdateMemoSize = [=]() { - QString txt = fnBuildNameMemo(); - zb.memoSize->setText(QString::number(txt.toUtf8().size()) + "/512"); - - if (txt.toUtf8().size() <= 512) { - // Everything is fine - zb.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true); - zb.memoSize->setStyleSheet(""); - } - else { - // Overweight - zb.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); - zb.memoSize->setStyleSheet("color: red;"); - } - - // Disallow blank memos - if (zb.memoTxt->toPlainText().trimmed().isEmpty()) { - zb.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); - } - else { - zb.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true); - } - }; - - // Memo text changed - QObject::connect(zb.memoTxt, &QPlainTextEdit::textChanged, fnUpdateMemoSize); - QObject::connect(zb.postAs, &QLineEdit::textChanged, fnUpdateMemoSize); - - zb.memoTxt->setFocus(); - fnUpdateMemoSize(); - - if (d.exec() == QDialog::Accepted) { - // Create a transaction. - Tx tx; - - // Send from your first sapling address that has a balance. - tx.fromAddr = zb.fromAddr->currentText(); - if (tx.fromAddr.isEmpty()) { - QMessageBox::critical(this, "Error Posting Message", tr("You need a sapling address with available balance to post"), QMessageBox::Ok); - return; - } - - auto memo = zb.memoTxt->toPlainText().trimmed(); - if (!zb.postAs->text().trimmed().isEmpty()) - memo = zb.postAs->text().trimmed() + ":: " + memo; - - auto toAddr = topics[zb.topicsList->currentText()]; - tx.toAddrs.push_back(ToFields{ toAddr, Settings::getZboardAmount(), memo, memo.toUtf8().toHex() }); - tx.fee = Settings::getMinerFee(); - - // And send the Tx - rpc->executeTransaction(tx, [=] (QString opid) { - ui->statusBar->showMessage(tr("Computing Tx: ") % opid); - }, - [=] (QString /*opid*/, QString txid) { - ui->statusBar->showMessage(Settings::txidStatusMessage + " " + txid); - }, - [=] (QString opid, QString errStr) { - ui->statusBar->showMessage(QObject::tr(" Tx ") % opid % QObject::tr(" failed"), 15 * 1000); - - if (!opid.isEmpty()) - errStr = QObject::tr("The transaction with id ") % opid % QObject::tr(" failed. The error was") + ":\n\n" + errStr; - - QMessageBox::critical(this, QObject::tr("Transaction Error"), errStr, QMessageBox::Ok); - }); - } -} - void MainWindow::doImport(QList* keys) { if (rpc->getConnection() == nullptr) { // No connection, just return @@ -1232,13 +906,6 @@ void MainWindow::setupBalancesTab() { }); } - //TODO: No sprout UTXOs on the Hush chain, should we remove all turnstile code? - if (Settings::getInstance()->isSproutAddress(addr)) { - menu.addAction(tr("Migrate to Sapling"), [=] () { - this->turnstileDoMigration(addr); - }); - } - menu.exec(ui->balancesTable->viewport()->mapToGlobal(pos)); }); } diff --git a/src/rpc.cpp b/src/rpc.cpp index 822b420..aeec65b 100644 --- a/src/rpc.cpp +++ b/src/rpc.cpp @@ -1,9 +1,9 @@ +// Copyright 2019 The Hush Developers #include "rpc.h" #include "addressbook.h" #include "settings.h" #include "senttxstore.h" -#include "turnstile.h" #include "version.h" #include "websockets.h" @@ -18,8 +18,6 @@ RPC::RPC(MainWindow* main) { this->main = main; this->ui = main->ui; - this->turnstile = new Turnstile(this, main); - // Setup balances table model balancesTableModel = new BalancesTableModel(main->ui->balancesTable); main->ui->balancesTable->setModel(balancesTableModel); @@ -62,7 +60,6 @@ RPC::~RPC() { delete transactionsTableModel; delete balancesTableModel; - delete turnstile; delete utxos; delete allBalances; @@ -591,9 +588,6 @@ void RPC::getInfoThenRefresh(bool force) { // Something changed, so refresh everything. lastBlock = curBlock; - // See if the turnstile migration has any steps that need to be done. - turnstile->executeMigrationStep(); - refreshBalances(); refreshAddresses(); // This calls refreshZSentTransactions() and refreshReceivedZTrans() refreshTransactions(); @@ -691,9 +685,10 @@ void RPC::getInfoThenRefresh(bool force) { QString::number(blockNumber) % (isSyncing ? ("/" % QString::number(progress*100, 'f', 2) % "%") : QString()) % ") " % - " Notarized: " % QString::number(notarized) % - " HUSH/USD=$" % QString::number( (double) Settings::getInstance()->getZECPrice() ); - main->statusLabel->setText(statusText); + " Lag: " % QString::number(blockNumber - notarized) % + " HUSH/USD=$" % QString::number( (double) Settings::getInstance()->getZECPrice() ) % + " " % QString::number( Settings::getInstance()->getBTCPrice() ) % "sat"; + main->statusLabel->setText(statusText); auto zecPrice = Settings::getUSDFormat(1); QString tooltip; @@ -1113,6 +1108,7 @@ void RPC::refreshZECPrice() { qDebug() << reply->errorString(); } Settings::getInstance()->setZECPrice(0); + Settings::getInstance()->setBTCPrice(0); return; } @@ -1121,6 +1117,7 @@ void RPC::refreshZECPrice() { auto parsed = json::parse(all, nullptr, false); if (parsed.is_discarded()) { Settings::getInstance()->setZECPrice(0); + Settings::getInstance()->setBTCPrice(0); return; } @@ -1134,7 +1131,9 @@ void RPC::refreshZECPrice() { // TODO: support BTC/EUR prices as well //QString price = QString::fromStdString(hush["usd"].get()); qDebug() << "HUSH = $" << QString::number((double)hush["usd"]); + qDebug() << "HUSH = " << QString::number((double)hush["btc"]) << " sat "; Settings::getInstance()->setZECPrice( hush["usd"] ); + Settings::getInstance()->setBTCPrice( (unsigned int) 100000000 * (double)hush["btc"] ); return; } else { @@ -1147,17 +1146,18 @@ void RPC::refreshZECPrice() { // If nothing, then set the price to 0; Settings::getInstance()->setZECPrice(0); + Settings::getInstance()->setBTCPrice(0); }); } void RPC::shutdownZcashd() { // Shutdown embedded zcashd if it was started if (ezcashd == nullptr || ezcashd->processId() == 0 || conn == nullptr) { - // No zcashd running internally, just return + // No hushd running internally, just return return; } - std::string method = "stop"; + std::string method = "stop"; conn->doRPCWithDefaultErrorHandling(makePayload(method), [=](auto) {}); conn->shutdown(); @@ -1203,60 +1203,6 @@ void RPC::shutdownZcashd() { } -// Fetch the Z-board topics list -void RPC::getZboardTopics(std::function)> cb) { - if (conn == nullptr) - return noConnection(); - - QUrl cmcURL("http://z-board.net/listTopics"); - - QNetworkRequest req; - req.setUrl(cmcURL); - - QNetworkReply *reply = conn->restclient->get(req); - - QObject::connect(reply, &QNetworkReply::finished, [=] { - reply->deleteLater(); - - try { - if (reply->error() != QNetworkReply::NoError) { - auto parsed = json::parse(reply->readAll(), nullptr, false); - if (!parsed.is_discarded() && !parsed["error"]["message"].is_null()) { - qDebug() << QString::fromStdString(parsed["error"]["message"]); - } - else { - qDebug() << reply->errorString(); - } - return; - } - - auto all = reply->readAll(); - - auto parsed = json::parse(all, nullptr, false); - if (parsed.is_discarded()) { - return; - } - - QMap topics; - for (const json& item : parsed["topics"].get()) { - if (item.find("addr") == item.end() || item.find("topicName") == item.end()) - return; - - QString addr = QString::fromStdString(item["addr"].get()); - QString topic = QString::fromStdString(item["topicName"].get()); - - topics.insert(topic, addr); - } - - cb(topics); - } - catch (...) { - // If anything at all goes wrong, just set the price to 0 and move on. - qDebug() << QString("Caught something nasty"); - } - }); -} - /** * Get a Sapling address from the user's wallet */ diff --git a/src/settings.cpp b/src/settings.cpp index 663c29d..540afab 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -159,6 +159,11 @@ double Settings::getZECPrice() { return zecPrice; } +unsigned int Settings::getBTCPrice() { + // in satoshis + return btcPrice; +} + bool Settings::getAutoShield() { // Load from Qt settings return QSettings().value("options/autoshield", false).toBool(); @@ -310,19 +315,6 @@ double Settings::getMinerFee() { return 0.0001; } -double Settings::getZboardAmount() { - return 0.0001; -} - -QString Settings::getZboardAddr() { - if (Settings::getInstance()->isTestnet()) { - return getDonationAddr(); - } - else { - return "zs10m00rvkhfm4f7n23e4sxsx275r7ptnggx39ygl0vy46j9mdll5c97gl6dxgpk0njuptg2mn9w5s"; - } -} - bool Settings::isValidSaplingPrivateKey(QString pk) { if (isTestnet()) { QRegExp zspkey("^secret-extended-key-test[0-9a-z]{278}$", Qt::CaseInsensitive); diff --git a/src/settings.h b/src/settings.h index 03234d4..9756896 100644 --- a/src/settings.h +++ b/src/settings.h @@ -1,3 +1,4 @@ +// Copyright 2019 The Hush developers #ifndef SETTINGS_H #define SETTINGS_H @@ -88,7 +89,9 @@ public: const QString& getZcashdConfLocation() { return _confLocation; } void setZECPrice(double p) { zecPrice = p; } + void setBTCPrice(unsigned int p) { btcPrice = p; } double getZECPrice(); + unsigned int getBTCPrice(); void setPeers(int peers); int getPeers(); @@ -126,6 +129,7 @@ public: static const QString labelRegExp; + //TODO: add these as advanced options, with sane minimums static const int updateSpeed = 10 * 1000; // 10 sec static const int quickUpdateSpeed = 3 * 1000; // 3 sec static const int priceRefreshSpeed = 15 * 60 * 1000; // 15 mins @@ -148,6 +152,7 @@ private: int _peerConnections = 0; double zecPrice = 0.0; + unsigned int btcPrice = 0.0; }; #endif // SETTINGS_H diff --git a/src/turnstile.cpp b/src/turnstile.cpp deleted file mode 100644 index df58b15..0000000 --- a/src/turnstile.cpp +++ /dev/null @@ -1,372 +0,0 @@ -#include "turnstile.h" -#include "mainwindow.h" -#include "balancestablemodel.h" -#include "rpc.h" -#include "settings.h" - -using json = nlohmann::json; - -Turnstile::Turnstile(RPC* _rpc, MainWindow* mainwindow) { - this->rpc = _rpc; - this->mainwindow = mainwindow; -} - - -void printPlan(QList plan) { - for (auto item : plan) { - //qDebug() << item.fromAddr << item.intTAddr - // << item.destAddr << item.amount << item.blockNumber << item.status; - } -} - -QString Turnstile::writeableFile() { - auto filename = QStringLiteral("turnstilemigrationplan.dat"); - - auto dir = QDir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)); - if (!dir.exists()) - QDir().mkpath(dir.absolutePath()); - - if (Settings::getInstance()->isTestnet()) { - return dir.filePath("testnet-" % filename); - } else { - return dir.filePath(filename); - } -} - -void Turnstile::removeFile() { - QFile(writeableFile()).remove(); -} - -// Data stream write/read methods for migration items -QDataStream &operator<<(QDataStream& ds, const TurnstileMigrationItem& item) { - return ds << QString("v1") << item.fromAddr << item.intTAddr - << item.destAddr << item.amount << item.blockNumber << item.status; -} - -QDataStream &operator>>(QDataStream& ds, TurnstileMigrationItem& item) { - QString version; - return ds >> version >> item.fromAddr >> item.intTAddr - >> item.destAddr >> item.amount >> item.blockNumber >> item.status; -} - -void Turnstile::writeMigrationPlan(QList plan) { - //qDebug() << QString("Writing plan"); - printPlan(plan); - - QFile file(writeableFile()); - file.open(QIODevice::ReadWrite | QIODevice::Truncate); - QDataStream out(&file); // we will serialize the data into the file - out << plan; - file.close(); -} - -QList Turnstile::readMigrationPlan() { - QFile file(writeableFile()); - - QList plan; - if (!file.exists()) return plan; - - file.open(QIODevice::ReadOnly); - QDataStream in(&file); // read the data serialized from the file - in >> plan; - - file.close(); - - // Sort to see when the next step is. - std::sort(plan.begin(), plan.end(), [&] (auto a, auto b) { - return a.blockNumber < b.blockNumber; - }); - - return plan; -} - -void Turnstile::planMigration(QString zaddr, QString destAddr, int numsplits, int numBlocks) { - // First, get the balance and split up the amounts - auto bal = rpc->getAllBalances()->value(zaddr); - auto splits = splitAmount(bal, numsplits); - - // Then, generate an intermediate t-address for each part using getBatchRPC - rpc->getConnection()->doBatchRPC(splits, - [=] (double /*unused*/) { - json payload = { - {"jsonrpc", "1.0"}, - {"id", "someid"}, - {"method", "getnewaddress"}, - }; - return payload; - }, - [=] (QMap* newAddrs) { - // Get block numbers - auto curBlock = Settings::getInstance()->getBlockNumber(); - auto blockNumbers = getBlockNumbers(curBlock, curBlock + numBlocks, splits.size()); - - // Assign the amounts to the addresses. - QList migItems; - - for (int i=0; i < splits.size(); i++) { - auto tAddr = newAddrs->values()[i].get(); - auto item = TurnstileMigrationItem { zaddr, QString::fromStdString(tAddr), destAddr, - blockNumbers[i], splits[i], - TurnstileMigrationItemStatus::NotStarted }; - migItems.push_back(item); - } - - // The first migration is shifted to the current block, so the user sees something - // happening immediately - if (migItems.empty()) { - // Show error and abort - QMessageBox::warning(mainwindow, - QObject::tr("Locked funds"), - QObject::tr("Could not initiate migration.\nYou either have unconfirmed funds or the balance is too low for an automatic migration.")); - return; - } - - migItems[0].blockNumber = curBlock; - - std::sort(migItems.begin(), migItems.end(), [&] (auto a, auto b) { - return a.blockNumber < b.blockNumber; - }); - - writeMigrationPlan(migItems); - rpc->refresh(true); // Force refresh, to start the migration immediately - } - ); -} - - -QList Turnstile::getBlockNumbers(int start, int end, int count) { - QList blocks; - // Generate 'count' numbers between [start, end] - for (int i=0; i < count; i++) { - auto blk = (std::rand() % (end - start)) + start; - blocks.push_back(blk); - } - - return blocks; -} - - // Need at least 0.0005 ZEC for this -double Turnstile::minMigrationAmount = 0.0005; - -QList Turnstile::splitAmount(double amount, int parts) { - QList amounts; - - if (amount < minMigrationAmount) - return amounts; - - fillAmounts(amounts, amount, parts); - //qDebug() << amounts; - - // Ensure they all add up! - double sumofparts = 0; - for (auto a : amounts) { - sumofparts += a; - } - - // Add the Tx fees - sumofparts += amounts.size() * Settings::getMinerFee(); - - return amounts; -} - -void Turnstile::fillAmounts(QList& amounts, double amount, int count) { - if (count == 1 || amount < 0.01) { - // Also account for the fees needed to send all these transactions - auto actual = amount - (Settings::getMinerFee() * (amounts.size() + 1)); - - amounts.push_back(actual); - return; - } - - // Get a random amount off the total amount and call recursively. - // Multiply by hundred, because we'll operate on 0.01 ZEC minimum. We'll divide by 100 later on - // in this function. - double curAmount = std::rand() % (int)std::floor(amount * 100); - - // Try to round it off - auto places = (int)std::floor(std::log10(curAmount)); - if (places > 0) { - auto a = std::pow(10, places); - curAmount = std::floor(curAmount / a) * a; - } - - // And divide by 100 - curAmount = curAmount / 100; - - if (curAmount > 0) - amounts.push_back(curAmount); - - fillAmounts(amounts, amount - curAmount, count - 1); -} - -QList::Iterator -Turnstile::getNextStep(QList& plan) { - // Get to the next unexecuted step - auto fnIsEligibleItem = [&] (auto item) { - return item.status == TurnstileMigrationItemStatus::NotStarted || - item.status == TurnstileMigrationItemStatus::SentToT; - }; - - // Find the next step - auto nextStep = std::find_if(plan.begin(), plan.end(), fnIsEligibleItem); - return nextStep; -} - -bool Turnstile::isMigrationPresent() { - auto plan = readMigrationPlan(); - return !plan.isEmpty(); -} - -ProgressReport Turnstile::getPlanProgress() { - auto plan = readMigrationPlan(); - - auto nextStep = getNextStep(plan); - - auto step = std::distance(plan.begin(), nextStep) * 2; // 2 steps per item - if (nextStep != plan.end() && - nextStep->status == TurnstileMigrationItemStatus::SentToT) - step++; - - auto total = plan.size(); - - auto nextBlock = nextStep == plan.end() ? 0 : nextStep->blockNumber; - - bool hasErrors = std::find_if(plan.begin(), plan.end(), [=] (auto i) { - return i.status == TurnstileMigrationItemStatus::NotEnoughBalance || - i.status == TurnstileMigrationItemStatus::UnknownError; - }) != plan.end(); - - auto stepData = (nextStep == plan.end() ? std::prev(nextStep) : nextStep); - - return ProgressReport{(int)step, total*2, nextBlock, hasErrors, stepData->fromAddr, stepData->destAddr, stepData->intTAddr}; -} - -void Turnstile::executeMigrationStep() { - // Do a step only if not syncing, else wait for the blockchain to catch up - if (Settings::getInstance()->isSyncing()) - return; - - auto plan = readMigrationPlan(); - - //qDebug() << QString("Executing step"); - printPlan(plan); - - // Get to the next unexecuted step - auto fnIsEligibleItem = [&] (auto item) { - return item.status == TurnstileMigrationItemStatus::NotStarted || - item.status == TurnstileMigrationItemStatus::SentToT; - }; - - // Fn to find if there are any unconfirmed funds for this address. - auto fnHasUnconfirmed = [=] (QString addr) { - auto utxoset = rpc->getUTXOs(); - return std::find_if(utxoset->begin(), utxoset->end(), [=] (auto utxo) { - return utxo.address == addr && utxo.confirmations == 0 && utxo.spendable; - }) != utxoset->end(); - }; - - // Find the next step - auto nextStep = std::find_if(plan.begin(), plan.end(), fnIsEligibleItem); - - if (nextStep == plan.end()) - return; // Nothing to do - - if (nextStep->blockNumber > Settings::getInstance()->getBlockNumber()) - return; - - // Is this the last step for this address? - auto lastStep = std::find_if(std::next(nextStep), plan.end(), fnIsEligibleItem) == plan.end(); - - // Execute this step - if (nextStep->status == TurnstileMigrationItemStatus::NotStarted) { - // Does this z addr have enough balance? - if (fnHasUnconfirmed(nextStep->fromAddr)) { - //qDebug() << QString("unconfirmed, waiting"); - return; - } - - auto balance = rpc->getAllBalances()->value(nextStep->fromAddr); - if (nextStep->amount > balance) { - qDebug() << "Not enough balance!"; - nextStep->status = TurnstileMigrationItemStatus::NotEnoughBalance; - writeMigrationPlan(plan); - return; - } - - auto to = ToFields{ nextStep->intTAddr, nextStep->amount, "", "" }; - - // If this is the last step, then send the remaining amount instead of the actual amount. - if (lastStep) { - auto remainingAmount = balance - Settings::getMinerFee(); - if (remainingAmount > 0) { - to.amount = remainingAmount; - } - } - - // Create the Tx - auto tx = Tx{ nextStep->fromAddr, { to }, Settings::getMinerFee() }; - - // And send it - doSendTx(tx, [=] () { - // Update status and write plan to disk - nextStep->status = TurnstileMigrationItemStatus::SentToT; - writeMigrationPlan(plan); - }); - } else if (nextStep->status == TurnstileMigrationItemStatus::SentToT) { - // First thing to do is check to see if the funds are confirmed. - // We'll check both the original sprout address and the intermediate t-addr for safety. - if (fnHasUnconfirmed(nextStep->intTAddr) || fnHasUnconfirmed(nextStep->fromAddr)) { - //qDebug() << QString("unconfirmed, waiting"); - return; - } - - // Sometimes, we check too quickly, and the unspent UTXO is not updated yet, so we'll - // double check to see if there is enough balance. - if (!rpc->getAllBalances()->keys().contains(nextStep->intTAddr)) { - //qDebug() << QString("The intermediate t-address doesn't have balance, even though it seems to be confirmed"); - return; - } - - // Send it to the final destination address. - auto bal = rpc->getAllBalances()->value(nextStep->intTAddr); - auto sendAmt = bal - Settings::getMinerFee(); - - if (sendAmt < 0) { - qDebug() << "Not enough balance!." << bal << ":" << sendAmt; - nextStep->status = TurnstileMigrationItemStatus::NotEnoughBalance; - writeMigrationPlan(plan); - return; - } - - QList to = { ToFields{ nextStep->destAddr, sendAmt, "", "" } }; - - // Create the Tx - auto tx = Tx{ nextStep->intTAddr, to, Settings::getMinerFee()}; - - // And send it - doSendTx(tx, [=] () { - // Update status and write plan to disk - nextStep->status = TurnstileMigrationItemStatus::SentToZS; - writeMigrationPlan(plan); - }); - } -} - -void Turnstile::doSendTx(Tx tx, std::function cb) { - rpc->executeTransaction(tx, [=] (QString opid) { - mainwindow->ui->statusBar->showMessage(QObject::tr("Computing Tx: ") % opid); - }, - [=] (QString /*opid*/, QString txid) { - mainwindow->ui->statusBar->showMessage(Settings::txidStatusMessage + " " + txid); - cb(); - }, - [=] (QString opid, QString errStr) { - mainwindow->ui->statusBar->showMessage(QObject::tr(" Tx ") % opid % QObject::tr(" failed"), 15 * 1000); - - if (!opid.isEmpty()) - errStr = QObject::tr("The transaction with id ") % opid % QObject::tr(" failed. The error was") + ":\n\n" + errStr; - - QMessageBox::critical(mainwindow, QObject::tr("Transaction Error"), errStr, QMessageBox::Ok); - }); - -} diff --git a/src/turnstile.h b/src/turnstile.h deleted file mode 100644 index dfa5dae..0000000 --- a/src/turnstile.h +++ /dev/null @@ -1,69 +0,0 @@ -#ifndef TURNSTILE_H -#define TURNSTILE_H - -#include "precompiled.h" - -class RPC; -class MainWindow; -struct Tx; - - -struct TurnstileMigrationItem { - QString fromAddr; - QString intTAddr; - QString destAddr; - int blockNumber; - double amount; - int status; -}; - -enum TurnstileMigrationItemStatus { - NotStarted = 0, - SentToT, - SentToZS, - NotEnoughBalance, - UnknownError -}; - -struct ProgressReport { - int step; - int totalSteps; - int nextBlock; - bool hasErrors; - QString from; - QString to; - QString via; -}; - -class Turnstile -{ -public: - Turnstile(RPC* _rpc, MainWindow* mainwindow); - - void planMigration(QString zaddr, QString destAddr, int splits, int numBlocks); - QList splitAmount(double amount, int parts); - void fillAmounts(QList& amounts, double amount, int count); - - QList readMigrationPlan(); - void writeMigrationPlan(QList plan); - void removeFile(); - - void executeMigrationStep(); - ProgressReport getPlanProgress(); - bool isMigrationPresent(); - - static double minMigrationAmount; -private: - QList getBlockNumbers(int start, int end, int count); - QString writeableFile(); - - void doSendTx(Tx tx, std::function cb); - - - QList::Iterator getNextStep(QList& plan); - - RPC* rpc; - MainWindow* mainwindow; -}; - -#endif diff --git a/src/turnstile.ui b/src/turnstile.ui deleted file mode 100644 index 378bfa9..0000000 --- a/src/turnstile.ui +++ /dev/null @@ -1,235 +0,0 @@ - - - Turnstile - - - - 0 - 0 - 565 - 416 - - - - Turnstile Migration - - - - - - Turnstile Migration - - - - - - - - - - - Qt::AlignCenter - - - - - - - - 0 - 0 - - - - Migrate over - - - - - - - - 0 - 0 - - - - From - - - - - - - - 0 - 0 - - - - false - - - - - - - - - - - 0 - 0 - - - - - - - - <html><head/><body><p>Funds from Sprout z-Addresses (which start with &quot;zc&quot;) need to be moved to the upgraded Sapling z-Addresses (which start with &quot;zs&quot;). The funds cannot be moved directly, but need to be sent through intermediate &quot;transparent&quot; addresses in privacy-preserving way.</p><p>This migration can be done automatically for you.</p></body></html> - - - true - - - - - - - - 0 - 0 - - - - To - - - - - - - - - - Qt::Horizontal - - - - - - - Balance - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - 0 - 0 - - - - Miner Fees - - - - - - - - 0 - 0 - - - - 0.0004 ZEC $0.04 - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - - Total Balance - - - - - - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - - - AddressCombo - QComboBox -
addresscombo.h
-
-
- - - - buttonBox - accepted() - Turnstile - accept() - - - 248 - 254 - - - 157 - 274 - - - - - buttonBox - rejected() - Turnstile - reject() - - - 316 - 260 - - - 286 - 274 - - - - -
diff --git a/src/turnstileprogress.ui b/src/turnstileprogress.ui deleted file mode 100644 index d52b72e..0000000 --- a/src/turnstileprogress.ui +++ /dev/null @@ -1,192 +0,0 @@ - - - TurnstileProgress - - - - 0 - 0 - 400 - 300 - - - - Turnstile Migration Progress - - - - - - From - - - - - - - To - - - - - - - From Address - - - - - - - 4 / 12 - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 0 - 0 - - - - Please ensure you have your wallet.dat backed up! - - - true - - - - - - - Next Transaction in 4 hours - - - - - - - 33 - - - - - - - Qt::Horizontal - - - - - - - Migration Progress - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Close|QDialogButtonBox::Discard - - - false - - - - - - - - 0 - 0 - - - - TextLabel - - - Qt::AlignCenter - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - Qt::Horizontal - - - - - - - To Address - - - - - - - Qt::Horizontal - - - - - - - - - buttonBox - accepted() - TurnstileProgress - accept() - - - 248 - 254 - - - 157 - 274 - - - - - buttonBox - rejected() - TurnstileProgress - reject() - - - 316 - 260 - - - 286 - 274 - - - - -