From 9268574588b625c1385029daf9a66527a90fe4d9 Mon Sep 17 00:00:00 2001 From: Aditya Kulkarni Date: Thu, 25 Oct 2018 15:31:09 -0700 Subject: [PATCH] simple working --- src/mainwindow.cpp | 17 +++++----- src/rpc.cpp | 8 ++++- src/rpc.h | 8 +++-- src/turnstile.cpp | 78 ++++++++++++++++++++++++++-------------------- src/turnstile.h | 1 - 5 files changed, 68 insertions(+), 44 deletions(-) diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 7a8a9f9..f0861c5 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -8,6 +8,7 @@ #include "balancestablemodel.h" #include "settings.h" #include "utils.h" +#import "turnstile.h" #include "senttxstore.h" #include "precompiled.h" @@ -83,7 +84,7 @@ void MainWindow::setupTurnstileDialog() { QIcon icon = QApplication::style()->standardIcon(QStyle::SP_MessageBoxInformation); turnstile.msgIcon->setPixmap(icon.pixmap(64, 64)); - auto getAllSproutBalance = [=] () { + auto fnGetAllSproutBalance = [=] () { double bal = 0; for (auto addr : *rpc->getAllZAddresses()) { if (Settings::getInstance()->isSproutAddress(addr)) { @@ -95,19 +96,20 @@ void MainWindow::setupTurnstileDialog() { }; turnstile.migrateZaddList->addItem("All Sprout z-Addrs"); - turnstile.fromBalance->setText(Settings::getInstance()->getZECUSDDisplayFormat(getAllSproutBalance())); + turnstile.fromBalance->setText(Settings::getInstance()->getZECUSDDisplayFormat(fnGetAllSproutBalance())); for (auto addr : *rpc->getAllZAddresses()) { if (Settings::getInstance()->isSaplingAddress(addr)) { turnstile.migrateTo->addItem(addr); } else { - turnstile.migrateZaddList->addItem(addr); + if (rpc->getAllBalances()->value(addr) > 0) + turnstile.migrateZaddList->addItem(addr); } } QObject::connect(turnstile.migrateZaddList, &QComboBox::currentTextChanged, [=] (auto addr) { double bal = 0; if (addr.startsWith("All")) { - bal = getAllSproutBalance(); + bal = fnGetAllSproutBalance(); } else { bal = rpc->getAllBalances()->value(addr); } @@ -121,11 +123,12 @@ void MainWindow::setupTurnstileDialog() { turnstile.buttonBox->button(QDialogButtonBox::Ok)->setText("Start"); - d.exec(); + if (d.exec() == QDialog::Accepted) { + rpc->getTurnstile()->planMigration( + turnstile.migrateZaddList->currentText(), turnstile.migrateTo->currentText()); + } }); - - QObject::connect(ui->actionProgress, &QAction::triggered, [=] () { Ui_TurnstileProgress progress; QDialog d(this); diff --git a/src/rpc.cpp b/src/rpc.cpp index f3174ea..94f21f4 100644 --- a/src/rpc.cpp +++ b/src/rpc.cpp @@ -11,6 +11,8 @@ RPC::RPC(QNetworkAccessManager* client, MainWindow* main) { this->main = main; this->ui = main->ui; + this->turnstile = new Turnstile(this); + // Setup balances table model balancesTableModel = new BalancesTableModel(main->ui->balancesTable); main->ui->balancesTable->setModel(balancesTableModel); @@ -56,6 +58,7 @@ RPC::~RPC() { delete transactionsTableModel; delete balancesTableModel; + delete turnstile; delete utxos; delete allBalances; @@ -300,7 +303,7 @@ void RPC::fillTxJsonParams(json& params, Tx tx) { // Construct the JSON params json rec = json::object(); rec["address"] = toAddr.addr.toStdString(); - rec["amount"] = toAddr.amount; + rec["amount"] = QString::number(toAddr.amount, 'f', 8).toDouble(); // Force it through string for rounding if (toAddr.addr.startsWith("z") && !toAddr.encodedMemo.trimmed().isEmpty()) rec["memo"] = toAddr.encodedMemo.toStdString(); @@ -487,6 +490,9 @@ void RPC::refreshAddresses() { // Function to create the data model and update the views, used below. void RPC::updateUI(bool anyUnconfirmed) { + // See if the turnstile migration has any steps that need to be done. + turnstile->executeMigrationStep(); + ui->unconfirmedWarning->setVisible(anyUnconfirmed); // Update balances model data, which will update the table too diff --git a/src/rpc.h b/src/rpc.h index 9972816..dd9b3dd 100644 --- a/src/rpc.h +++ b/src/rpc.h @@ -11,6 +11,7 @@ using json = nlohmann::json; +class Turnstile; struct TransactionItem { QString type; @@ -44,8 +45,10 @@ public: void reloadConnectionInfo(); - void newZaddr (bool sapling, const std::function& cb); - void newTaddr (const std::function& cb); + void newZaddr(bool sapling, const std::function& cb); + void newTaddr(const std::function& cb); + + Turnstile* getTurnstile() { return turnstile; } // Batch method. Note: Because of the template, it has to be in the header file. template @@ -139,6 +142,7 @@ private: Ui::MainWindow* ui; MainWindow* main; + Turnstile* turnstile; // Current balance in the UI. If this number updates, then refresh the UI QString currentBalance; diff --git a/src/turnstile.cpp b/src/turnstile.cpp index 82ea092..f649a4f 100644 --- a/src/turnstile.cpp +++ b/src/turnstile.cpp @@ -1,5 +1,6 @@ #include "turnstile.h" #include "mainwindow.h" +#include "unspentoutput.h" #include "rpc.h" #include "utils.h" #include "settings.h" @@ -18,7 +19,7 @@ Turnstile::~Turnstile() { void printPlan(QList plan) { for (auto item : plan) { qDebug() << item.fromAddr << item.intTAddr - << item.destAddr << item.amount << item.blockNumber << item.chaff << item.status; + << item.destAddr << item.amount << item.blockNumber << item.status; } } @@ -39,13 +40,13 @@ QString Turnstile::writeableFile() { // 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.chaff << item.status; + << 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.chaff >> item.status; + >> item.destAddr >> item.amount >> item.blockNumber >> item.status; } void Turnstile::writeMigrationPlan(QList plan) { @@ -105,19 +106,19 @@ void Turnstile::planMigration(QString zaddr, QString destAddr) { 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], i == splits.size() -1, + blockNumbers[i], splits[i], TurnstileMigrationItemStatus::NotStarted }; migItems.push_back(item); } - std::sort(migItems.begin(), migItems.end(), [&] (auto a, auto b) { - return a.blockNumber < b.blockNumber; - }); - // The first migration is shifted to the current block, so the user sees something // happening immediately migItems[0].blockNumber = curBlock; + std::sort(migItems.begin(), migItems.end(), [&] (auto a, auto b) { + return a.blockNumber < b.blockNumber; + }); + writeMigrationPlan(migItems); auto readPlan = readMigrationPlan(); } @@ -149,6 +150,9 @@ QList Turnstile::splitAmount(double amount, int parts) { for (auto a : amounts) { sumofparts += a; } + + // Add the Tx fees + sumofparts += amounts.size() * Utils::getMinerFee(); Q_ASSERT(sumofparts == amount); return amounts; @@ -163,18 +167,10 @@ void Turnstile::fillAmounts(QList& amounts, double amount, int count) { // Get the rounded value to 4 decimal places (approx $0.01) double actual = std::floor(amount * 10000) / 10000; - // Reduce the Dev Tx fee from the amount - actual = actual - 0.0001; //Utils::getDevFee(); - // Also account for the fees needed to send all these transactions actual = actual - (Utils::getMinerFee() * (amounts.size() + 1)); - // Calculate the chaff. - double chaff = amount - actual; - amounts.push_back(actual); - if (chaff > 0.00000001) // zcash is split down to 8 decimal places - amounts.push_back(chaff); return; } @@ -182,6 +178,7 @@ void Turnstile::fillAmounts(QList& amounts, double amount, int count) { auto curAmount = std::rand() % (int)std::floor(amount); // Try to round it off + // TODO: Do this via log if (curAmount > 1000) { curAmount = std::floor(curAmount / 100) * 100; } else if (curAmount > 100) { @@ -201,21 +198,30 @@ void Turnstile::executeMigrationStep() { printPlan(plan); // Get to the next unexecuted step - auto eligibleItem = [&] (auto item) { - return !item.chaff && - (item.status == TurnstileMigrationItemStatus::NotStarted || - item.status == TurnstileMigrationItemStatus::SentToT); + 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; + }) != utxoset->end(); }; - auto nextStep = std::find_if(plan.begin(), plan.end(), eligibleItem); - if (nextStep == plan.end()) return; // Nothing to do - qDebug() << nextStep->blockNumber << ":" << Settings::getInstance()->getBlockNumber(); - if (nextStep->blockNumber > Settings::getInstance()->getBlockNumber()) return; + // 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(), [&] (auto item) { - return item.fromAddr == nextStep->fromAddr && eligibleItem(item); - }) == plan.end(); + auto lastStep = std::find_if(std::next(nextStep), plan.end(), fnIsEligibleItem) == plan.end(); // Execute this step if (nextStep->status == TurnstileMigrationItemStatus::NotStarted) { @@ -228,19 +234,18 @@ void Turnstile::executeMigrationStep() { return; } - QList to = { ToFields{ nextStep->intTAddr, nextStep->amount, "", "" } }; + auto to = ToFields{ nextStep->intTAddr, nextStep->amount, "", "" }; - // If this is the last step, then add chaff and the dev fee to the tx + // If this is the last step, then send the remaining amount instead of the actual amount. if (lastStep) { - auto remainingAmount = balance - nextStep->amount; + auto remainingAmount = balance - Utils::getMinerFee(); if (remainingAmount > 0) { - auto devFee = ToFields{ Utils::getDevSproutAddr(), remainingAmount, "", "" }; - to.push_back(devFee); + to.amount = remainingAmount; } } // Create the Tx - auto tx = Tx{ nextStep->fromAddr, to, Utils::getMinerFee() }; + auto tx = Tx{ nextStep->fromAddr, { to }, Utils::getMinerFee() }; // And send it doSendTx(tx, [=] () { @@ -250,6 +255,12 @@ void Turnstile::executeMigrationStep() { }); } else if (nextStep->status == TurnstileMigrationItemStatus::SentToT) { + // First thing to do is check to see if the funds are confirmed. + if (fnHasUnconfirmed(nextStep->intTAddr)) { + qDebug() << QString("unconfirmed, waiting"); + return; + } + // Send it to the final destination address. auto bal = rpc->getAllBalances()->value(nextStep->intTAddr); auto sendAmt = bal - Utils::getMinerFee(); @@ -262,6 +273,7 @@ void Turnstile::executeMigrationStep() { } QList to = { ToFields{ nextStep->destAddr, sendAmt, "", "" } }; + // Create the Tx auto tx = Tx{ nextStep->intTAddr, to, Utils::getMinerFee() }; diff --git a/src/turnstile.h b/src/turnstile.h index 915ba54..e012bf1 100644 --- a/src/turnstile.h +++ b/src/turnstile.h @@ -12,7 +12,6 @@ struct TurnstileMigrationItem { QString destAddr; int blockNumber; double amount; - bool chaff; int status; };