From 59396320783f03c657ec6eeb6bff559c82816d28 Mon Sep 17 00:00:00 2001 From: Aditya Kulkarni Date: Mon, 7 Oct 2019 12:45:11 -0700 Subject: [PATCH] Rename RPC to Controller --- src/addressbook.cpp | 2 +- src/connection.cpp | 4 +- src/connection.h | 6 +- src/controller.cpp | 895 +++++++++++++++++++++++++++++++++++++++ src/controller.h | 129 +++++- src/main.cpp | 2 +- src/mainwindow.cpp | 4 +- src/mainwindow.h | 6 +- src/recurring.cpp | 4 +- src/requestdialog.cpp | 2 +- src/rpc.cpp | 54 +-- src/rpc.h | 128 ------ src/sendtab.cpp | 2 +- src/senttxstore.h | 2 +- src/turnstile.cpp | 2 +- src/txtablemodel.cpp | 2 +- src/viewalladdresses.cpp | 2 +- src/viewalladdresses.h | 6 +- src/websockets.cpp | 2 +- zec-qt-wallet.pro | 2 - 20 files changed, 1074 insertions(+), 182 deletions(-) delete mode 100644 src/rpc.h diff --git a/src/addressbook.cpp b/src/addressbook.cpp index 4ef2d2b..81c004d 100644 --- a/src/addressbook.cpp +++ b/src/addressbook.cpp @@ -3,7 +3,7 @@ #include "ui_mainwindow.h" #include "settings.h" #include "mainwindow.h" -#include "rpc.h" +#include "controller.h" AddressBookModel::AddressBookModel(QTableView *parent) diff --git a/src/connection.cpp b/src/connection.cpp index 9547c2f..020ad57 100644 --- a/src/connection.cpp +++ b/src/connection.cpp @@ -3,13 +3,13 @@ #include "settings.h" #include "ui_connection.h" #include "ui_createzcashconfdialog.h" -#include "rpc.h" +#include "controller.h" #include "precompiled.h" using json = nlohmann::json; -ConnectionLoader::ConnectionLoader(MainWindow* main, RPC* rpc) { +ConnectionLoader::ConnectionLoader(MainWindow* main, Controller* rpc) { this->main = main; this->rpc = rpc; diff --git a/src/connection.h b/src/connection.h index d01f76f..51bac1f 100644 --- a/src/connection.h +++ b/src/connection.h @@ -7,7 +7,7 @@ using json = nlohmann::json; -class RPC; +class Controller; enum ConnectionType { DetectedConfExternalZcashD = 1, @@ -34,7 +34,7 @@ class Connection; class ConnectionLoader { public: - ConnectionLoader(MainWindow* main, RPC* rpc); + ConnectionLoader(MainWindow* main, Controller* rpc); ~ConnectionLoader(); void loadConnection(); @@ -71,7 +71,7 @@ private: Ui_ConnectionDialog* connD; MainWindow* main; - RPC* rpc; + Controller* rpc; QNetworkReply* currentDownload = nullptr; QFile* currentOutput = nullptr; diff --git a/src/controller.cpp b/src/controller.cpp index e69de29..90087c2 100644 --- a/src/controller.cpp +++ b/src/controller.cpp @@ -0,0 +1,895 @@ +#include "controller.h" + +#include "addressbook.h" +#include "settings.h" +#include "senttxstore.h" +#include "turnstile.h" +#include "version.h" +#include "websockets.h" + +using json = nlohmann::json; + +Controller::Controller(MainWindow* main) { + auto cl = new ConnectionLoader(main, this); + + // 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; + + // Setup balances table model + balancesTableModel = new BalancesTableModel(main->ui->balancesTable); + main->ui->balancesTable->setModel(balancesTableModel); + + // Setup transactions table model + transactionsTableModel = new TxTableModel(ui->transactionsTable); + main->ui->transactionsTable->setModel(transactionsTableModel); + + // Set up timer to refresh Price + priceTimer = new QTimer(main); + QObject::connect(priceTimer, &QTimer::timeout, [=]() { + if (Settings::getInstance()->getAllowFetchPrices()) + refreshZECPrice(); + }); + priceTimer->start(Settings::priceRefreshSpeed); // Every hour + + // Set up a timer to refresh the UI every few seconds + timer = new QTimer(main); + QObject::connect(timer, &QTimer::timeout, [=]() { + refresh(); + }); + timer->start(Settings::updateSpeed); + + // Set up the timer to watch for tx status + txTimer = new QTimer(main); + QObject::connect(txTimer, &QTimer::timeout, [=]() { + watchTxStatus(); + }); + // Start at every 10s. When an operation is pending, this will change to every second + txTimer->start(Settings::updateSpeed); + + // Create the data model + model = new DataModel(); + + // Crate the ZcashdRPC + zrpc = new ZcashdRPC(); + + // Initialize the migration status to unavailable. + this->migrationStatus.available = false; +} + +Controller::~Controller() { + delete timer; + delete txTimer; + + delete transactionsTableModel; + delete balancesTableModel; + + delete model; + delete zrpc; +} + +void Controller::setEZcashd(QProcess* p) { + ezcashd = p; + + if (ezcashd && ui->tabWidget->widget(4) == nullptr) { + ui->tabWidget->addTab(main->zcashdtab, "zcashd"); + } +} + +// Called when a connection to zcashd is available. +void Controller::setConnection(Connection* c) { + if (c == nullptr) return; + + this->zrpc->setConnection(c); + + ui->statusBar->showMessage("Ready!"); + + // See if we need to remove the reindex/rescan flags from the zcash.conf file + auto zcashConfLocation = Settings::getInstance()->getZcashdConfLocation(); + Settings::removeFromZcashConf(zcashConfLocation, "rescan"); + Settings::removeFromZcashConf(zcashConfLocation, "reindex"); + + // If we're allowed to get the Zec Price, get the prices + if (Settings::getInstance()->getAllowFetchPrices()) + refreshZECPrice(); + + // If we're allowed to check for updates, check for a new release + if (Settings::getInstance()->getCheckForUpdates()) + checkForUpdate(); + + // Force update, because this might be coming from a settings update + // where we need to immediately refresh + refresh(true); +} + + +// Build the RPC JSON Parameters for this tx +void Controller::fillTxJsonParams(json& params, Tx tx) { + Q_ASSERT(params.is_array()); + // Get all the addresses and amounts + json allRecepients = json::array(); + + // For each addr/amt/memo, construct the JSON and also build the confirm dialog box + for (int i=0; i < tx.toAddrs.size(); i++) { + auto toAddr = tx.toAddrs[i]; + + // Construct the JSON params + json rec = json::object(); + rec["address"] = toAddr.addr.toStdString(); + // Force it through string for rounding. Without this, decimal points beyond 8 places + // will appear, causing an "invalid amount" error + rec["amount"] = Settings::getDecimalString(toAddr.amount).toStdString(); //.toDouble(); + if (Settings::isZAddress(toAddr.addr) && !toAddr.encodedMemo.trimmed().isEmpty()) + rec["memo"] = toAddr.encodedMemo.toStdString(); + + allRecepients.push_back(rec); + } + + // Add sender + params.push_back(tx.fromAddr.toStdString()); + params.push_back(allRecepients); + + // Add fees if custom fees are allowed. + if (Settings::getInstance()->getAllowCustomFees()) { + params.push_back(1); // minconf + params.push_back(tx.fee); + } +} + + +void Controller::noConnection() { + QIcon i = QApplication::style()->standardIcon(QStyle::SP_MessageBoxCritical); + main->statusIcon->setPixmap(i.pixmap(16, 16)); + main->statusIcon->setToolTip(""); + main->statusLabel->setText(QObject::tr("No Connection")); + main->statusLabel->setToolTip(""); + main->ui->statusBar->showMessage(QObject::tr("No Connection"), 1000); + + // Clear balances table. + QMap emptyBalances; + QList emptyOutputs; + balancesTableModel->setNewData(emptyBalances, emptyOutputs); + + // Clear Transactions table. + QList emptyTxs; + transactionsTableModel->addTData(emptyTxs); + transactionsTableModel->addZRecvData(emptyTxs); + transactionsTableModel->addZSentData(emptyTxs); + + // Clear balances + ui->balSheilded->setText(""); + ui->balTransparent->setText(""); + ui->balTotal->setText(""); + + ui->balSheilded->setToolTip(""); + ui->balTransparent->setToolTip(""); + ui->balTotal->setToolTip(""); + + // Clear send tab from address + ui->inputsCombo->clear(); +} + +// Refresh received z txs by calling z_listreceivedbyaddress/gettransaction +void Controller::refreshReceivedZTrans(QList zaddrs) { + if (!zrpc->haveConnection()) + return noConnection(); + + // We'll only refresh the received Z txs if settings allows us. + if (!Settings::getInstance()->getSaveZtxs()) { + QList emptylist; + transactionsTableModel->addZRecvData(emptylist); + return; + } + + zrpc->fetchReceivedZTrans(zaddrs, + [=] (QString addr) { + model->markAddressUsed(addr); + }, + [=] (QList txdata) { + transactionsTableModel->addZRecvData(txdata); + } + ); +} + +/// This will refresh all the balance data from zcashd +void Controller::refresh(bool force) { + if (!zrpc->haveConnection()) + return noConnection(); + + getInfoThenRefresh(force); +} + + +void Controller::getInfoThenRefresh(bool force) { + if (!zrpc->haveConnection()) + return noConnection(); + + static bool prevCallSucceeded = false; + + zrpc->fetchInfo([=] (const json& reply) { + prevCallSucceeded = true; + // Testnet? + if (!reply["testnet"].is_null()) { + Settings::getInstance()->setTestnet(reply["testnet"].get()); + }; + + // Recurring pamynets are testnet only + if (!Settings::getInstance()->isTestnet()) + main->disableRecurring(); + + // Connected, so display checkmark. + QIcon i(":/icons/res/connected.gif"); + main->statusIcon->setPixmap(i.pixmap(16, 16)); + + static int lastBlock = 0; + int curBlock = reply["blocks"].get(); + int version = reply["version"].get(); + Settings::getInstance()->setZcashdVersion(version); + + // See if recurring payments needs anything + Recurring::getInstance()->processPending(main); + + if ( force || (curBlock != lastBlock) ) { + // Something changed, so refresh everything. + lastBlock = curBlock; + + refreshBalances(); + refreshAddresses(); // This calls refreshZSentTransactions() and refreshReceivedZTrans() + refreshTransactions(); + refreshMigration(); // Sapling turnstile migration status. + } + + int connections = reply["connections"].get(); + Settings::getInstance()->setPeers(connections); + + if (connections == 0) { + // If there are no peers connected, then the internet is probably off or something else is wrong. + QIcon i = QApplication::style()->standardIcon(QStyle::SP_MessageBoxWarning); + main->statusIcon->setPixmap(i.pixmap(16, 16)); + } + + // Get network sol/s + if (ezcashd) { + zrpc->fetchNetSolOps([=] (qint64 solrate) { + ui->numconnections->setText(QString::number(connections)); + ui->solrate->setText(QString::number(solrate) % " Sol/s"); + }); + } + + // Call to see if the blockchain is syncing. + zrpc->fetchBlockchainInfo([=](const json& reply) { + auto progress = reply["verificationprogress"].get(); + bool isSyncing = progress < 0.9999; // 99.99% + int blockNumber = reply["blocks"].get(); + + int estimatedheight = 0; + if (reply.find("estimatedheight") != reply.end()) { + estimatedheight = reply["estimatedheight"].get(); + } + + Settings::getInstance()->setSyncing(isSyncing); + Settings::getInstance()->setBlockNumber(blockNumber); + + // Update zcashd tab if it exists + if (ezcashd) { + if (isSyncing) { + QString txt = QString::number(blockNumber); + if (estimatedheight > 0) { + txt = txt % " / ~" % QString::number(estimatedheight); + } + txt = txt % " ( " % QString::number(progress * 100, 'f', 2) % "% )"; + ui->blockheight->setText(txt); + ui->heightLabel->setText(QObject::tr("Downloading blocks")); + } else { + // If syncing is finished, we may have to remove the ibdskiptxverification + // flag from zcash.conf + if (getConnection() != nullptr && getConnection()->config->skiptxverification) { + getConnection()->config->skiptxverification = false; + Settings::removeFromZcashConf(Settings::getInstance()->getZcashdConfLocation(), + "ibdskiptxverification"); + } + + ui->blockheight->setText(QString::number(blockNumber)); + ui->heightLabel->setText(QObject::tr("Block height")); + } + } + + // Update the status bar + QString statusText = QString() % + (isSyncing ? QObject::tr("Syncing") : QObject::tr("Connected")) % + " (" % + (Settings::getInstance()->isTestnet() ? QObject::tr("testnet:") : "") % + QString::number(blockNumber) % + (isSyncing ? ("/" % QString::number(progress*100, 'f', 2) % "%") : QString()) % + ")"; + main->statusLabel->setText(statusText); + + // Update the balances view to show a warning if the node is still syncing + ui->lblSyncWarning->setVisible(isSyncing); + ui->lblSyncWarningReceive->setVisible(isSyncing); + + auto zecPrice = Settings::getInstance()->getUSDFromZecAmount(1); + QString tooltip; + if (connections > 0) { + tooltip = QObject::tr("Connected to zcashd"); + } + else { + tooltip = QObject::tr("zcashd has no peer connections"); + } + tooltip = tooltip % "(v " % QString::number(Settings::getInstance()->getZcashdVersion()) % ")"; + + if (!zecPrice.isEmpty()) { + tooltip = "1 " % Settings::getTokenName() % " = " % zecPrice % "\n" % tooltip; + } + main->statusLabel->setToolTip(tooltip); + main->statusIcon->setToolTip(tooltip); + }); + + }, [=](QNetworkReply* reply, const json&) { + // zcashd has probably disappeared. + this->noConnection(); + + // Prevent multiple dialog boxes, because these are called async + static bool shown = false; + if (!shown && prevCallSucceeded) { // show error only first time + shown = true; + QMessageBox::critical(main, QObject::tr("Connection Error"), QObject::tr("There was an error connecting to zcashd. The error was") + ": \n\n" + + reply->errorString(), QMessageBox::StandardButton::Ok); + shown = false; + } + + prevCallSucceeded = false; + }); +} + +void Controller::refreshAddresses() { + if (!zrpc->haveConnection()) + return noConnection(); + + auto newzaddresses = new QList(); + + zrpc->fetchZAddresses([=] (json reply) { + for (auto& it : reply.get()) { + auto addr = QString::fromStdString(it.get()); + newzaddresses->push_back(addr); + } + + model->replaceZaddresses(newzaddresses); + + // Refresh the sent and received txs from all these z-addresses + refreshSentZTrans(); + refreshReceivedZTrans(model->getAllZAddresses()); + }); + + + auto newtaddresses = new QList(); + zrpc->fetchTAddresses([=] (json reply) { + for (auto& it : reply.get()) { + auto addr = QString::fromStdString(it.get()); + if (Settings::isTAddress(addr)) + newtaddresses->push_back(addr); + } + + model->replaceTaddresses(newtaddresses); + }); +} + +// Function to create the data model and update the views, used below. +void Controller::updateUI(bool anyUnconfirmed) { + ui->unconfirmedWarning->setVisible(anyUnconfirmed); + + // Update balances model data, which will update the table too + balancesTableModel->setNewData(model->getAllBalances(), model->getUTXOs()); + + // Update from address + main->updateFromCombo(); +}; + +// Function to process reply of the listunspent and z_listunspent API calls, used below. +bool Controller::processUnspent(const json& reply, QMap* balancesMap, QList* newUtxos) { + bool anyUnconfirmed = false; + for (auto& it : reply.get()) { + QString qsAddr = QString::fromStdString(it["address"]); + auto confirmations = it["confirmations"].get(); + if (confirmations == 0) { + anyUnconfirmed = true; + } + + newUtxos->push_back( + UnspentOutput{ qsAddr, QString::fromStdString(it["txid"]), + Settings::getDecimalString(it["amount"].get()), + (int)confirmations, it["spendable"].get() }); + + (*balancesMap)[qsAddr] = (*balancesMap)[qsAddr] + it["amount"].get(); + } + return anyUnconfirmed; +}; + +/** + * Refresh the turnstile migration status + */ +void Controller::refreshMigration() { + // Turnstile migration is only supported in zcashd v2.0.5 and above + if (Settings::getInstance()->getZcashdVersion() < 2000552) + return; + + zrpc->fetchMigrationStatus([=](json reply) { + this->migrationStatus.available = true; + this->migrationStatus.enabled = reply["enabled"].get(); + this->migrationStatus.saplingAddress = QString::fromStdString(reply["destination_address"]); + this->migrationStatus.unmigrated = QString::fromStdString(reply["unmigrated_amount"]).toDouble(); + this->migrationStatus.migrated = QString::fromStdString(reply["finalized_migrated_amount"]).toDouble(); + + QList ids; + for (auto& it : reply["migration_txids"].get()) { + ids.push_back(QString::fromStdString(it.get())); + } + this->migrationStatus.txids = ids; + }); +} + +void Controller::refreshBalances() { + if (!zrpc->haveConnection()) + return noConnection(); + + // 1. Get the Balances + zrpc->fetchBalance([=] (json reply) { + auto balT = QString::fromStdString(reply["transparent"]).toDouble(); + auto balZ = QString::fromStdString(reply["private"]).toDouble(); + auto balTotal = QString::fromStdString(reply["total"]).toDouble(); + + AppDataModel::getInstance()->setBalances(balT, balZ); + + ui->balSheilded ->setText(Settings::getZECDisplayFormat(balZ)); + ui->balTransparent->setText(Settings::getZECDisplayFormat(balT)); + ui->balTotal ->setText(Settings::getZECDisplayFormat(balTotal)); + + + ui->balSheilded ->setToolTip(Settings::getZECDisplayFormat(balZ)); + ui->balTransparent->setToolTip(Settings::getZECDisplayFormat(balT)); + ui->balTotal ->setToolTip(Settings::getZECDisplayFormat(balTotal)); + }); + + // 2. Get the UTXOs + // First, create a new UTXO list. It will be replacing the existing list when everything is processed. + auto newUtxos = new QList(); + auto newBalances = new QMap(); + + // Call the Transparent and Z unspent APIs serially and then, once they're done, update the UI + zrpc->fetchTransparentUnspent([=] (json reply) { + auto anyTUnconfirmed = processUnspent(reply, newBalances, newUtxos); + + zrpc->fetchZUnspent([=] (json reply) { + auto anyZUnconfirmed = processUnspent(reply, newBalances, newUtxos); + + // Swap out the balances and UTXOs + model->replaceBalances(newBalances); + model->replaceUTXOs(newUtxos); + + updateUI(anyTUnconfirmed || anyZUnconfirmed); + + main->balancesReady(); + }); + }); +} + +void Controller::refreshTransactions() { + if (!zrpc->haveConnection()) + return noConnection(); + + zrpc->fetchTransactions([=] (json reply) { + QList txdata; + + for (auto& it : reply.get()) { + double fee = 0; + if (!it["fee"].is_null()) { + fee = it["fee"].get(); + } + + QString address = (it["address"].is_null() ? "" : QString::fromStdString(it["address"])); + + TransactionItem tx{ + QString::fromStdString(it["category"]), + (qint64)it["time"].get(), + address, + QString::fromStdString(it["txid"]), + it["amount"].get() + fee, + static_cast(it["confirmations"].get()), + "", "" }; + + txdata.push_back(tx); + if (!address.isEmpty()) + model->markAddressUsed(address); + } + + // Update model data, which updates the table view + transactionsTableModel->addTData(txdata); + }); +} + +// Read sent Z transactions from the file. +void Controller::refreshSentZTrans() { + if (!zrpc->haveConnection()) + return noConnection(); + + auto sentZTxs = SentTxStore::readSentTxFile(); + + // If there are no sent z txs, then empty the table. + // This happens when you clear history. + if (sentZTxs.isEmpty()) { + transactionsTableModel->addZSentData(sentZTxs); + return; + } + + QList txids; + + for (auto sentTx: sentZTxs) { + txids.push_back(sentTx.txid); + } + + // Look up all the txids to get the confirmation count for them. + zrpc->fetchReceivedTTrans(txids, sentZTxs, [=](auto newSentZTxs) { + transactionsTableModel->addZSentData(newSentZTxs); + }); +} + +void Controller::addNewTxToWatch(const QString& newOpid, WatchedTx wtx) { + watchingOps.insert(newOpid, wtx); + + watchTxStatus(); +} + +/** + * Execute a transaction with the standard UI. i.e., standard status bar message and standard error + * handling + */ +void Controller::executeStandardUITransaction(Tx tx) { + executeTransaction(tx, + [=] (QString opid) { + ui->statusBar->showMessage(QObject::tr("Computing Tx: ") % opid); + }, + [=] (QString, 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(main, QObject::tr("Transaction Error"), errStr, QMessageBox::Ok); + } + ); +} + + +// Execute a transaction! +void Controller::executeTransaction(Tx tx, + const std::function submitted, + const std::function computed, + const std::function error) { + // First, create the json params + json params = json::array(); + fillTxJsonParams(params, tx); + std::cout << std::setw(2) << params << std::endl; + + zrpc->sendZTransaction(params, [=](const json& reply) { + QString opid = QString::fromStdString(reply.get()); + + // And then start monitoring the transaction + addNewTxToWatch( opid, WatchedTx { opid, tx, computed, error} ); + submitted(opid); + }, + [=](QString errStr) { + error("", errStr); + }); +} + + +void Controller::watchTxStatus() { + if (!zrpc->haveConnection()) + return noConnection(); + + zrpc->fetchOpStatus([=] (const json& reply) { + // There's an array for each item in the status + for (auto& it : reply.get()) { + // If we were watching this Tx and its status became "success", then we'll show a status bar alert + QString id = QString::fromStdString(it["id"]); + if (watchingOps.contains(id)) { + // And if it ended up successful + QString status = QString::fromStdString(it["status"]); + main->loadingLabel->setVisible(false); + + if (status == "success") { + auto txid = QString::fromStdString(it["result"]["txid"]); + + SentTxStore::addToSentTx(watchingOps[id].tx, txid); + + auto wtx = watchingOps[id]; + watchingOps.remove(id); + wtx.completed(id, txid); + + // Refresh balances to show unconfirmed balances + refresh(true); + } else if (status == "failed") { + // If it failed, then we'll actually show a warning. + auto errorMsg = QString::fromStdString(it["error"]["message"]); + + auto wtx = watchingOps[id]; + watchingOps.remove(id); + wtx.error(id, errorMsg); + } + } + + if (watchingOps.isEmpty()) { + txTimer->start(Settings::updateSpeed); + } else { + txTimer->start(Settings::quickUpdateSpeed); + } + } + + // If there is some op that we are watching, then show the loading bar, otherwise hide it + if (watchingOps.empty()) { + main->loadingLabel->setVisible(false); + } else { + main->loadingLabel->setVisible(true); + main->loadingLabel->setToolTip(QString::number(watchingOps.size()) + QObject::tr(" tx computing. This can take several minutes.")); + } + }); +} + +void Controller::checkForUpdate(bool silent) { + if (!zrpc->haveConnection()) + return noConnection(); + + QUrl cmcURL("https://api.github.com/repos/ZcashFoundation/zecwallet/releases"); + + QNetworkRequest req; + req.setUrl(cmcURL); + + QNetworkReply *reply = getConnection()->restclient->get(req); + + QObject::connect(reply, &QNetworkReply::finished, [=] { + reply->deleteLater(); + + try { + if (reply->error() == QNetworkReply::NoError) { + + auto releases = QJsonDocument::fromJson(reply->readAll()).array(); + QVersionNumber maxVersion(0, 0, 0); + + for (QJsonValue rel : releases) { + if (!rel.toObject().contains("tag_name")) + continue; + + QString tag = rel.toObject()["tag_name"].toString(); + if (tag.startsWith("v")) + tag = tag.right(tag.length() - 1); + + if (!tag.isEmpty()) { + auto v = QVersionNumber::fromString(tag); + if (v > maxVersion) + maxVersion = v; + } + } + + auto currentVersion = QVersionNumber::fromString(APP_VERSION); + + // Get the max version that the user has hidden updates for + QSettings s; + auto maxHiddenVersion = QVersionNumber::fromString(s.value("update/lastversion", "0.0.0").toString()); + + qDebug() << "Version check: Current " << currentVersion << ", Available " << maxVersion; + + if (maxVersion > currentVersion && (!silent || maxVersion > maxHiddenVersion)) { + auto ans = QMessageBox::information(main, QObject::tr("Update Available"), + QObject::tr("A new release v%1 is available! You have v%2.\n\nWould you like to visit the releases page?") + .arg(maxVersion.toString()) + .arg(currentVersion.toString()), + QMessageBox::Yes, QMessageBox::Cancel); + if (ans == QMessageBox::Yes) { + QDesktopServices::openUrl(QUrl("https://github.com/ZcashFoundation/zecwallet/releases")); + } else { + // If the user selects cancel, don't bother them again for this version + s.setValue("update/lastversion", maxVersion.toString()); + } + } else { + if (!silent) { + QMessageBox::information(main, QObject::tr("No updates available"), + QObject::tr("You already have the latest release v%1") + .arg(currentVersion.toString())); + } + } + } + } + catch (...) { + // If anything at all goes wrong, just set the price to 0 and move on. + qDebug() << QString("Caught something nasty"); + } + }); +} + +// Get the ZEC->USD price from coinmarketcap using their API +void Controller::refreshZECPrice() { + if (!zrpc->haveConnection()) + return noConnection(); + + QUrl cmcURL("https://api.coinmarketcap.com/v1/ticker/"); + + QNetworkRequest req; + req.setUrl(cmcURL); + + QNetworkReply *reply = getConnection()->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(); + } + Settings::getInstance()->setZECPrice(0); + return; + } + + auto all = reply->readAll(); + + auto parsed = json::parse(all, nullptr, false); + if (parsed.is_discarded()) { + Settings::getInstance()->setZECPrice(0); + return; + } + + for (const json& item : parsed.get()) { + if (item["symbol"].get() == Settings::getTokenName().toStdString()) { + QString price = QString::fromStdString(item["price_usd"].get()); + qDebug() << Settings::getTokenName() << " Price=" << price; + Settings::getInstance()->setZECPrice(price.toDouble()); + + return; + } + } + } catch (...) { + // If anything at all goes wrong, just set the price to 0 and move on. + qDebug() << QString("Caught something nasty"); + } + + // If nothing, then set the price to 0; + Settings::getInstance()->setZECPrice(0); + }); +} + +void Controller::shutdownZcashd() { + // Shutdown embedded zcashd if it was started + if (ezcashd == nullptr || ezcashd->processId() == 0 || ~zrpc->haveConnection()) { + // No zcashd running internally, just return + return; + } + + json payload = { + {"jsonrpc", "1.0"}, + {"id", "someid"}, + {"method", "stop"} + }; + + getConnection()->doRPCWithDefaultErrorHandling(payload, [=](auto) {}); + getConnection()->shutdown(); + + QDialog d(main); + Ui_ConnectionDialog connD; + connD.setupUi(&d); + connD.topIcon->setBasePixmap(QIcon(":/icons/res/icon.ico").pixmap(256, 256)); + connD.status->setText(QObject::tr("Please wait for ZecWallet to exit")); + connD.statusDetail->setText(QObject::tr("Waiting for zcashd to exit")); + + 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, [&] () { + waitCount++; + + if ((ezcashd->atEnd() && ezcashd->processId() == 0) || + waitCount > 30 || + getConnection()->config->zcashDaemon) { // If zcashd is daemon, then we don't have to do anything else + qDebug() << "Ended"; + waiter.stop(); + QTimer::singleShot(1000, [&]() { d.accept(); }); + } else { + qDebug() << "Not ended, continuing to wait..."; + } + }); + waiter.start(1000); + + // Wait for the zcash process to exit. + if (!Settings::getInstance()->isHeadless()) { + d.exec(); + } else { + while (waiter.isActive()) { + QCoreApplication::processEvents(); + + QThread::sleep(1); + } + } +} + + +// // Fetch the Z-board topics list +// void Controller::getZboardTopics(std::function)> cb) { +// if (!zrpc->haveConnection()) +// 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 + */ +QString Controller::getDefaultSaplingAddress() { + for (QString addr: model->getAllZAddresses()) { + if (Settings::getInstance()->isSaplingAddress(addr)) + return addr; + } + + return QString(); +} + +QString Controller::getDefaultTAddress() { + if (model->getAllTAddresses().length() > 0) + return model->getAllTAddresses().at(0); + else + return QString(); +} diff --git a/src/controller.h b/src/controller.h index ab0c014..aef931c 100644 --- a/src/controller.h +++ b/src/controller.h @@ -1 +1,128 @@ -// \ No newline at end of file +#ifndef RPCCLIENT_H +#define RPCCLIENT_H + +#include "precompiled.h" + +#include "datamodel.h" +#include "balancestablemodel.h" +#include "txtablemodel.h" +#include "ui_mainwindow.h" +#include "mainwindow.h" +#include "zcashdrpc.h" +#include "connection.h" + +using json = nlohmann::json; + +struct WatchedTx { + QString opid; + Tx tx; + std::function completed; + std::function error; +}; + +struct MigrationStatus { + bool available; // Whether the underlying zcashd supports migration? + bool enabled; + QString saplingAddress; + double unmigrated; + double migrated; + QList txids; +}; + +class Controller +{ +public: + Controller(MainWindow* main); + ~Controller(); + + DataModel* getModel() { return model; } + + Connection* getConnection() { return zrpc->getConnection(); } + void setConnection(Connection* c); + + void setEZcashd(QProcess* p); + const QProcess* getEZcashD() { return ezcashd; } + + void refresh(bool force = false); + void refreshAddresses(); + + void checkForUpdate(bool silent = true); + void refreshZECPrice(); + //void getZboardTopics(std::function)> cb); + + void executeStandardUITransaction(Tx tx); + + void executeTransaction(Tx tx, + const std::function submitted, + const std::function computed, + const std::function error); + + void fillTxJsonParams(json& params, Tx tx); + + void watchTxStatus(); + + const QMap getWatchingTxns() { return watchingOps; } + void addNewTxToWatch(const QString& newOpid, WatchedTx wtx); + + const TxTableModel* getTransactionsModel() { return transactionsTableModel; } + + void shutdownZcashd(); + void noConnection(); + bool isEmbedded() { return ezcashd != nullptr; } + + void createNewZaddr(bool sapling, const std::function& cb) { zrpc->createNewZaddr(sapling, cb); } + void createNewTaddr(const std::function& cb) { zrpc->createNewTaddr(cb); } + + void validateAddress(QString address, const std::function& cb) { zrpc->validateAddress(address, cb); } + + void fetchZPrivKey(QString addr, const std::function& cb) { zrpc->fetchZPrivKey(addr, cb); } + void fetchTPrivKey(QString addr, const std::function& cb) { zrpc->fetchTPrivKey(addr, cb); } + void fetchAllPrivKeys(const std::function>)> cb) { zrpc->fetchAllPrivKeys(cb); } + + void importZPrivKey(QString addr, bool rescan, const std::function& cb) { zrpc->importZPrivKey(addr, rescan, cb); } + void importTPrivKey(QString addr, bool rescan, const std::function& cb) { zrpc->importTPrivKey(addr, rescan, cb); } + + QString getDefaultSaplingAddress(); + QString getDefaultTAddress(); + + const MigrationStatus* getMigrationStatus() { return &migrationStatus; } + void setMigrationStatus(bool status) { zrpc->setMigrationStatus(status); } + +private: + void refreshBalances(); + + void refreshTransactions(); + void refreshMigration(); + void refreshSentZTrans(); + void refreshReceivedZTrans(QList zaddresses); + + bool processUnspent (const json& reply, QMap* newBalances, QList* newUtxos); + void updateUI (bool anyUnconfirmed); + + void getInfoThenRefresh(bool force); + + QProcess* ezcashd = nullptr; + + QMap watchingOps; + + TxTableModel* transactionsTableModel = nullptr; + BalancesTableModel* balancesTableModel = nullptr; + + DataModel* model; + ZcashdRPC* zrpc; + + QTimer* timer; + QTimer* txTimer; + QTimer* priceTimer; + + Ui::MainWindow* ui; + MainWindow* main; + + // Sapling turnstile migration status (for the zcashd v2.0.5 tool) + MigrationStatus migrationStatus; + + // Current balance in the UI. If this number updates, then refresh the UI + QString currentBalance; +}; + +#endif // RPCCLIENT_H diff --git a/src/main.cpp b/src/main.cpp index b1b1dd4..20fed6a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2,7 +2,7 @@ #include "precompiled.h" #include "mainwindow.h" -#include "rpc.h" +#include "controller.h" #include "settings.h" #include "turnstile.h" diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index a49ff74..07ecf95 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -13,7 +13,7 @@ #include "ui_turnstileprogress.h" #include "ui_viewalladdresses.h" #include "ui_validateaddress.h" -#include "rpc.h" +#include "controller.h" #include "balancestablemodel.h" #include "settings.h" #include "version.h" @@ -144,7 +144,7 @@ MainWindow::MainWindow(QWidget *parent) : setupTurnstileDialog(); setupZcashdTab(); - rpc = new RPC(this); + rpc = new Controller(this); restoreSavedStates(); diff --git a/src/mainwindow.h b/src/mainwindow.h index 89a890d..7593247 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -7,7 +7,7 @@ #include "recurring.h" // Forward declare to break circular dependency. -class RPC; +class Controller; class Settings; class WSServer; class WormholeClient; @@ -42,7 +42,7 @@ public: ~MainWindow(); void updateLabelsAutoComplete(); - RPC* getRPC() { return rpc; } + Controller* getRPC() { return rpc; } QCompleter* getLabelCompleter() { return labelCompleter; } QRegExpValidator* getAmountValidator() { return amtValidator; } @@ -139,7 +139,7 @@ private: WSServer* wsserver = nullptr; WormholeClient* wormhole = nullptr; - RPC* rpc = nullptr; + Controller* rpc = nullptr; QCompleter* labelCompleter = nullptr; QRegExpValidator* amtValidator = nullptr; QRegExpValidator* feesValidator = nullptr; diff --git a/src/recurring.cpp b/src/recurring.cpp index e0097be..501f727 100644 --- a/src/recurring.cpp +++ b/src/recurring.cpp @@ -1,7 +1,7 @@ #include "recurring.h" #include "mainwindow.h" -#include "rpc.h" +#include "controller.h" #include "settings.h" #include "ui_newrecurring.h" #include "ui_recurringdialog.h" @@ -142,7 +142,7 @@ RecurringPaymentInfo* Recurring::getNewRecurringFromTx(QWidget* parent, MainWind } // Wire up ZEC/USD toggle - QObject::connect(ui.cmbCurrency, QOverload::of(&QComboBox::currentIndexChanged), [&](QString c) { + QObject::connect(ui.cmbCurrency, &QComboBox::currentTextChanged, [&](QString c) { if (tx.toAddrs.length() < 1) return; diff --git a/src/requestdialog.cpp b/src/requestdialog.cpp index f3fa12e..352a757 100644 --- a/src/requestdialog.cpp +++ b/src/requestdialog.cpp @@ -3,7 +3,7 @@ #include "settings.h" #include "addressbook.h" #include "mainwindow.h" -#include "rpc.h" +#include "controller.h" #include "settings.h" #include "precompiled.h" diff --git a/src/rpc.cpp b/src/rpc.cpp index fb0f84b..90087c2 100644 --- a/src/rpc.cpp +++ b/src/rpc.cpp @@ -1,4 +1,4 @@ -#include "rpc.h" +#include "controller.h" #include "addressbook.h" #include "settings.h" @@ -9,7 +9,7 @@ using json = nlohmann::json; -RPC::RPC(MainWindow* main) { +Controller::Controller(MainWindow* main) { auto cl = new ConnectionLoader(main, this); // Execute the load connection async, so we can set up the rest of RPC properly. @@ -59,7 +59,7 @@ RPC::RPC(MainWindow* main) { this->migrationStatus.available = false; } -RPC::~RPC() { +Controller::~Controller() { delete timer; delete txTimer; @@ -70,7 +70,7 @@ RPC::~RPC() { delete zrpc; } -void RPC::setEZcashd(QProcess* p) { +void Controller::setEZcashd(QProcess* p) { ezcashd = p; if (ezcashd && ui->tabWidget->widget(4) == nullptr) { @@ -79,7 +79,7 @@ void RPC::setEZcashd(QProcess* p) { } // Called when a connection to zcashd is available. -void RPC::setConnection(Connection* c) { +void Controller::setConnection(Connection* c) { if (c == nullptr) return; this->zrpc->setConnection(c); @@ -106,7 +106,7 @@ void RPC::setConnection(Connection* c) { // Build the RPC JSON Parameters for this tx -void RPC::fillTxJsonParams(json& params, Tx tx) { +void Controller::fillTxJsonParams(json& params, Tx tx) { Q_ASSERT(params.is_array()); // Get all the addresses and amounts json allRecepients = json::array(); @@ -139,7 +139,7 @@ void RPC::fillTxJsonParams(json& params, Tx tx) { } -void RPC::noConnection() { +void Controller::noConnection() { QIcon i = QApplication::style()->standardIcon(QStyle::SP_MessageBoxCritical); main->statusIcon->setPixmap(i.pixmap(16, 16)); main->statusIcon->setToolTip(""); @@ -172,7 +172,7 @@ void RPC::noConnection() { } // Refresh received z txs by calling z_listreceivedbyaddress/gettransaction -void RPC::refreshReceivedZTrans(QList zaddrs) { +void Controller::refreshReceivedZTrans(QList zaddrs) { if (!zrpc->haveConnection()) return noConnection(); @@ -194,7 +194,7 @@ void RPC::refreshReceivedZTrans(QList zaddrs) { } /// This will refresh all the balance data from zcashd -void RPC::refresh(bool force) { +void Controller::refresh(bool force) { if (!zrpc->haveConnection()) return noConnection(); @@ -202,7 +202,7 @@ void RPC::refresh(bool force) { } -void RPC::getInfoThenRefresh(bool force) { +void Controller::getInfoThenRefresh(bool force) { if (!zrpc->haveConnection()) return noConnection(); @@ -344,7 +344,7 @@ void RPC::getInfoThenRefresh(bool force) { }); } -void RPC::refreshAddresses() { +void Controller::refreshAddresses() { if (!zrpc->haveConnection()) return noConnection(); @@ -377,7 +377,7 @@ void RPC::refreshAddresses() { } // Function to create the data model and update the views, used below. -void RPC::updateUI(bool anyUnconfirmed) { +void Controller::updateUI(bool anyUnconfirmed) { ui->unconfirmedWarning->setVisible(anyUnconfirmed); // Update balances model data, which will update the table too @@ -388,7 +388,7 @@ void RPC::updateUI(bool anyUnconfirmed) { }; // Function to process reply of the listunspent and z_listunspent API calls, used below. -bool RPC::processUnspent(const json& reply, QMap* balancesMap, QList* newUtxos) { +bool Controller::processUnspent(const json& reply, QMap* balancesMap, QList* newUtxos) { bool anyUnconfirmed = false; for (auto& it : reply.get()) { QString qsAddr = QString::fromStdString(it["address"]); @@ -410,7 +410,7 @@ bool RPC::processUnspent(const json& reply, QMap* balancesMap, /** * Refresh the turnstile migration status */ -void RPC::refreshMigration() { +void Controller::refreshMigration() { // Turnstile migration is only supported in zcashd v2.0.5 and above if (Settings::getInstance()->getZcashdVersion() < 2000552) return; @@ -430,7 +430,7 @@ void RPC::refreshMigration() { }); } -void RPC::refreshBalances() { +void Controller::refreshBalances() { if (!zrpc->haveConnection()) return noConnection(); @@ -475,7 +475,7 @@ void RPC::refreshBalances() { }); } -void RPC::refreshTransactions() { +void Controller::refreshTransactions() { if (!zrpc->haveConnection()) return noConnection(); @@ -510,7 +510,7 @@ void RPC::refreshTransactions() { } // Read sent Z transactions from the file. -void RPC::refreshSentZTrans() { +void Controller::refreshSentZTrans() { if (!zrpc->haveConnection()) return noConnection(); @@ -535,7 +535,7 @@ void RPC::refreshSentZTrans() { }); } -void RPC::addNewTxToWatch(const QString& newOpid, WatchedTx wtx) { +void Controller::addNewTxToWatch(const QString& newOpid, WatchedTx wtx) { watchingOps.insert(newOpid, wtx); watchTxStatus(); @@ -545,7 +545,7 @@ void RPC::addNewTxToWatch(const QString& newOpid, WatchedTx wtx) { * Execute a transaction with the standard UI. i.e., standard status bar message and standard error * handling */ -void RPC::executeStandardUITransaction(Tx tx) { +void Controller::executeStandardUITransaction(Tx tx) { executeTransaction(tx, [=] (QString opid) { ui->statusBar->showMessage(QObject::tr("Computing Tx: ") % opid); @@ -566,7 +566,7 @@ void RPC::executeStandardUITransaction(Tx tx) { // Execute a transaction! -void RPC::executeTransaction(Tx tx, +void Controller::executeTransaction(Tx tx, const std::function submitted, const std::function computed, const std::function error) { @@ -588,7 +588,7 @@ void RPC::executeTransaction(Tx tx, } -void RPC::watchTxStatus() { +void Controller::watchTxStatus() { if (!zrpc->haveConnection()) return noConnection(); @@ -640,7 +640,7 @@ void RPC::watchTxStatus() { }); } -void RPC::checkForUpdate(bool silent) { +void Controller::checkForUpdate(bool silent) { if (!zrpc->haveConnection()) return noConnection(); @@ -712,7 +712,7 @@ void RPC::checkForUpdate(bool silent) { } // Get the ZEC->USD price from coinmarketcap using their API -void RPC::refreshZECPrice() { +void Controller::refreshZECPrice() { if (!zrpc->haveConnection()) return noConnection(); @@ -765,7 +765,7 @@ void RPC::refreshZECPrice() { }); } -void RPC::shutdownZcashd() { +void Controller::shutdownZcashd() { // Shutdown embedded zcashd if it was started if (ezcashd == nullptr || ezcashd->processId() == 0 || ~zrpc->haveConnection()) { // No zcashd running internally, just return @@ -822,7 +822,7 @@ void RPC::shutdownZcashd() { // // Fetch the Z-board topics list -// void RPC::getZboardTopics(std::function)> cb) { +// void Controller::getZboardTopics(std::function)> cb) { // if (!zrpc->haveConnection()) // return noConnection(); @@ -878,7 +878,7 @@ void RPC::shutdownZcashd() { /** * Get a Sapling address from the user's wallet */ -QString RPC::getDefaultSaplingAddress() { +QString Controller::getDefaultSaplingAddress() { for (QString addr: model->getAllZAddresses()) { if (Settings::getInstance()->isSaplingAddress(addr)) return addr; @@ -887,7 +887,7 @@ QString RPC::getDefaultSaplingAddress() { return QString(); } -QString RPC::getDefaultTAddress() { +QString Controller::getDefaultTAddress() { if (model->getAllTAddresses().length() > 0) return model->getAllTAddresses().at(0); else diff --git a/src/rpc.h b/src/rpc.h deleted file mode 100644 index 6ceb10c..0000000 --- a/src/rpc.h +++ /dev/null @@ -1,128 +0,0 @@ -#ifndef RPCCLIENT_H -#define RPCCLIENT_H - -#include "precompiled.h" - -#include "datamodel.h" -#include "balancestablemodel.h" -#include "txtablemodel.h" -#include "ui_mainwindow.h" -#include "mainwindow.h" -#include "zcashdrpc.h" -#include "connection.h" - -using json = nlohmann::json; - -struct WatchedTx { - QString opid; - Tx tx; - std::function completed; - std::function error; -}; - -struct MigrationStatus { - bool available; // Whether the underlying zcashd supports migration? - bool enabled; - QString saplingAddress; - double unmigrated; - double migrated; - QList txids; -}; - -class RPC -{ -public: - RPC(MainWindow* main); - ~RPC(); - - DataModel* getModel() { return model; } - - Connection* getConnection() { return zrpc->getConnection(); } - void setConnection(Connection* c); - - void setEZcashd(QProcess* p); - const QProcess* getEZcashD() { return ezcashd; } - - void refresh(bool force = false); - void refreshAddresses(); - - void checkForUpdate(bool silent = true); - void refreshZECPrice(); - //void getZboardTopics(std::function)> cb); - - void executeStandardUITransaction(Tx tx); - - void executeTransaction(Tx tx, - const std::function submitted, - const std::function computed, - const std::function error); - - void fillTxJsonParams(json& params, Tx tx); - - void watchTxStatus(); - - const QMap getWatchingTxns() { return watchingOps; } - void addNewTxToWatch(const QString& newOpid, WatchedTx wtx); - - const TxTableModel* getTransactionsModel() { return transactionsTableModel; } - - void shutdownZcashd(); - void noConnection(); - bool isEmbedded() { return ezcashd != nullptr; } - - void createNewZaddr(bool sapling, const std::function& cb) { zrpc->createNewZaddr(sapling, cb); } - void createNewTaddr(const std::function& cb) { zrpc->createNewTaddr(cb); } - - void validateAddress(QString address, const std::function& cb) { zrpc->validateAddress(address, cb); } - - void fetchZPrivKey(QString addr, const std::function& cb) { zrpc->fetchZPrivKey(addr, cb); } - void fetchTPrivKey(QString addr, const std::function& cb) { zrpc->fetchTPrivKey(addr, cb); } - void fetchAllPrivKeys(const std::function>)> cb) { zrpc->fetchAllPrivKeys(cb); } - - void importZPrivKey(QString addr, bool rescan, const std::function& cb) { zrpc->importZPrivKey(addr, rescan, cb); } - void importTPrivKey(QString addr, bool rescan, const std::function& cb) { zrpc->importTPrivKey(addr, rescan, cb); } - - QString getDefaultSaplingAddress(); - QString getDefaultTAddress(); - - const MigrationStatus* getMigrationStatus() { return &migrationStatus; } - void setMigrationStatus(bool status) { zrpc->setMigrationStatus(status); } - -private: - void refreshBalances(); - - void refreshTransactions(); - void refreshMigration(); - void refreshSentZTrans(); - void refreshReceivedZTrans(QList zaddresses); - - bool processUnspent (const json& reply, QMap* newBalances, QList* newUtxos); - void updateUI (bool anyUnconfirmed); - - void getInfoThenRefresh(bool force); - - QProcess* ezcashd = nullptr; - - QMap watchingOps; - - TxTableModel* transactionsTableModel = nullptr; - BalancesTableModel* balancesTableModel = nullptr; - - DataModel* model; - ZcashdRPC* zrpc; - - QTimer* timer; - QTimer* txTimer; - QTimer* priceTimer; - - Ui::MainWindow* ui; - MainWindow* main; - - // Sapling turnstile migration status (for the zcashd v2.0.5 tool) - MigrationStatus migrationStatus; - - // Current balance in the UI. If this number updates, then refresh the UI - QString currentBalance; -}; - -#endif // RPCCLIENT_H diff --git a/src/sendtab.cpp b/src/sendtab.cpp index db583ad..62a0226 100644 --- a/src/sendtab.cpp +++ b/src/sendtab.cpp @@ -5,7 +5,7 @@ #include "ui_memodialog.h" #include "ui_newrecurring.h" #include "settings.h" -#include "rpc.h" +#include "controller.h" #include "recurring.h" using json = nlohmann::json; diff --git a/src/senttxstore.h b/src/senttxstore.h index a62fb67..9093a00 100644 --- a/src/senttxstore.h +++ b/src/senttxstore.h @@ -3,7 +3,7 @@ #include "precompiled.h" #include "mainwindow.h" -#include "rpc.h" +#include "controller.h" class SentTxStore { public: diff --git a/src/turnstile.cpp b/src/turnstile.cpp index 3e133d2..da79f33 100644 --- a/src/turnstile.cpp +++ b/src/turnstile.cpp @@ -1,7 +1,7 @@ #include "turnstile.h" #include "mainwindow.h" #include "balancestablemodel.h" -#include "rpc.h" +#include "controller.h" #include "settings.h" #include "ui_migration.h" diff --git a/src/txtablemodel.cpp b/src/txtablemodel.cpp index e2d3651..395d82f 100644 --- a/src/txtablemodel.cpp +++ b/src/txtablemodel.cpp @@ -1,6 +1,6 @@ #include "txtablemodel.h" #include "settings.h" -#include "rpc.h" +#include "controller.h" TxTableModel::TxTableModel(QObject *parent) : QAbstractTableModel(parent) { diff --git a/src/viewalladdresses.cpp b/src/viewalladdresses.cpp index de00926..0a7d06d 100644 --- a/src/viewalladdresses.cpp +++ b/src/viewalladdresses.cpp @@ -1,7 +1,7 @@ #include "viewalladdresses.h" #include "settings.h" -ViewAllAddressesModel::ViewAllAddressesModel(QTableView *parent, QList taddrs, RPC* rpc) +ViewAllAddressesModel::ViewAllAddressesModel(QTableView *parent, QList taddrs, Controller* rpc) : QAbstractTableModel(parent) { headers << tr("Address") << tr("Balance (%1)").arg(Settings::getTokenName()); addresses = taddrs; diff --git a/src/viewalladdresses.h b/src/viewalladdresses.h index 4e9e3d4..20b7094 100644 --- a/src/viewalladdresses.h +++ b/src/viewalladdresses.h @@ -2,12 +2,12 @@ #define VIEWALLADDRESSES_H #include "precompiled.h" -#include "rpc.h" +#include "controller.h" class ViewAllAddressesModel : public QAbstractTableModel { public: - ViewAllAddressesModel(QTableView* parent, QList taddrs, RPC* rpc); + ViewAllAddressesModel(QTableView* parent, QList taddrs, Controller* rpc); ~ViewAllAddressesModel() = default; int rowCount(const QModelIndex &parent) const; @@ -18,7 +18,7 @@ public: private: QList addresses; QStringList headers; - RPC* rpc; + Controller* rpc; }; #endif \ No newline at end of file diff --git a/src/websockets.cpp b/src/websockets.cpp index c102658..78822da 100644 --- a/src/websockets.cpp +++ b/src/websockets.cpp @@ -1,6 +1,6 @@ #include "websockets.h" -#include "rpc.h" +#include "controller.h" #include "settings.h" #include "ui_mobileappconnector.h" #include "version.h" diff --git a/zec-qt-wallet.pro b/zec-qt-wallet.pro index 61ea805..b69fe6b 100644 --- a/zec-qt-wallet.pro +++ b/zec-qt-wallet.pro @@ -38,7 +38,6 @@ CONFIG += c++14 SOURCES += \ src/main.cpp \ src/mainwindow.cpp \ - src/rpc.cpp \ src/balancestablemodel.cpp \ src/3rdparty/qrcode/BitBuffer.cpp \ src/3rdparty/qrcode/QrCode.cpp \ @@ -68,7 +67,6 @@ SOURCES += \ HEADERS += \ src/mainwindow.h \ src/precompiled.h \ - src/rpc.h \ src/balancestablemodel.h \ src/3rdparty/qrcode/BitBuffer.hpp \ src/3rdparty/qrcode/QrCode.hpp \