From 085694a3701e7798af716b0f63387a16b1ebafa4 Mon Sep 17 00:00:00 2001 From: Aditya Kulkarni Date: Thu, 25 Oct 2018 13:35:49 -0700 Subject: [PATCH] Execute migration steps --- src/mainwindow.h | 1 - src/precompiled.h | 1 + src/rpc.cpp | 34 ++++++++++++- src/rpc.h | 1 + src/sendtab.cpp | 28 +---------- src/turnstile.cpp | 123 +++++++++++++++++++++++++++++++++++++++++++--- src/turnstile.h | 15 ++++-- src/utils.cpp | 6 ++- src/utils.h | 1 + 9 files changed, 167 insertions(+), 43 deletions(-) diff --git a/src/mainwindow.h b/src/mainwindow.h index 9ef337c..6bb90a6 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -56,7 +56,6 @@ private: Tx createTxFromSendPage(); bool confirmTx(Tx tx, ToFields devFee); - void fillTxJsonParams(json& params, Tx tx); void cancelButton(); void sendButton(); diff --git a/src/precompiled.h b/src/precompiled.h index 552226d..8c6b605 100644 --- a/src/precompiled.h +++ b/src/precompiled.h @@ -2,6 +2,7 @@ /* Add C++ includes here */ #include +#include #include #include #include diff --git a/src/rpc.cpp b/src/rpc.cpp index c70a6f1..cbd6d91 100644 --- a/src/rpc.cpp +++ b/src/rpc.cpp @@ -286,6 +286,33 @@ void RPC::handleTxError(const QString& error) { msg.exec(); } + +// Build the RPC JSON Parameters for this tx (with the dev fee included if applicable) +void RPC::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(); + rec["amount"] = toAddr.amount; + if (toAddr.addr.startsWith("z") && !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); +} + + // Refresh received z txs by calling z_listreceivedbyaddress/gettransaction void RPC::refreshReceivedZTrans(QList zaddrs) { @@ -296,7 +323,6 @@ void RPC::refreshReceivedZTrans(QList zaddrs) { return; } - // This method is complicated because z_listreceivedbyaddress only returns the txid, and // we have to make a follow up call to gettransaction to get details of that transaction. // Additionally, it has to be done in batches, because there are multiple z-Addresses, @@ -464,7 +490,11 @@ void RPC::updateUI(bool anyUnconfirmed) { // Temp Turnstile t(this); - t.planMigration(zaddresses->at(1), zaddresses->at(0)); + // t.planMigration( + // "ztsKtGwc7JTEHxQq1xiRWyU9o1sheA3tYjcaFTBfVtp4RKJ782U6pH9STEYUoWQiGn1epfRMmFhkWCUyCSCqByNj9HKnzKU", + // "ztbGDqgkmXQjheivgeirwEvJLD4SUNqsWCGwxwVg4YpGz1ARR8P2rXaptkT14z3NDKamcxNmQuvmvktyokMs7HkutRNSx1D" + // ); + t.executeMigrationStep(); ui->unconfirmedWarning->setVisible(anyUnconfirmed); diff --git a/src/rpc.h b/src/rpc.h index 1bbd6fd..9972816 100644 --- a/src/rpc.h +++ b/src/rpc.h @@ -32,6 +32,7 @@ public: void refreshAddresses(); // Refresh wallet Z-addrs void refreshZECPrice(); + void fillTxJsonParams(json& params, Tx tx); void sendZTransaction (json params, const std::function& cb); void watchTxStatus(); void addNewTxToWatch(Tx tx, const QString& newOpid); diff --git a/src/sendtab.cpp b/src/sendtab.cpp index 5a3c623..fc1c502 100644 --- a/src/sendtab.cpp +++ b/src/sendtab.cpp @@ -7,8 +7,6 @@ #include "precompiled.h" -#include -#include using json = nlohmann::json; void MainWindow::setupSendTab() { @@ -461,30 +459,6 @@ bool MainWindow::confirmTx(Tx tx, ToFields devFee) { } } -// Build the RPC JSON Parameters for this tx (with the dev fee included if applicable) -void MainWindow::fillTxJsonParams(json& params, Tx tx) { - // 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(); - rec["amount"] = toAddr.amount; - if (toAddr.addr.startsWith("z") && !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); -} - // Send button clicked void MainWindow::sendButton() { Tx tx = createTxFromSendPage(); @@ -509,7 +483,7 @@ void MainWindow::sendButton() { tx.toAddrs.push_back(devFee); json params = json::array(); - fillTxJsonParams(params, tx); + rpc->fillTxJsonParams(params, tx); std::cout << std::setw(2) << params << std::endl; // And send the Tx diff --git a/src/turnstile.cpp b/src/turnstile.cpp index 1a8dc02..82ea092 100644 --- a/src/turnstile.cpp +++ b/src/turnstile.cpp @@ -1,4 +1,5 @@ #include "turnstile.h" +#include "mainwindow.h" #include "rpc.h" #include "utils.h" #include "settings.h" @@ -14,6 +15,13 @@ Turnstile::Turnstile(RPC* _rpc) { 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; + } +} + QString Turnstile::writeableFile() { auto filename = QStringLiteral("turnstilemigrationplan.dat"); @@ -41,6 +49,9 @@ QDataStream &operator>>(QDataStream& ds, TurnstileMigrationItem& item) { } 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 @@ -59,13 +70,19 @@ QList Turnstile::readMigrationPlan() { 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) { // First, get the balance and split up the amounts auto bal = rpc->getAllBalances()->value(zaddr); - auto splits = splitAmount(bal+2354, 5); + auto splits = splitAmount(bal, 5); // Then, generate an intermediate t-Address for each part using getBatchRPC rpc->getBatchRPC(splits, @@ -80,7 +97,7 @@ void Turnstile::planMigration(QString zaddr, QString destAddr) { [=] (QMap* newAddrs) { // Get block numbers auto curBlock = Settings::getInstance()->getBlockNumber(); - auto blockNumbers = getBlockNumbers(curBlock, curBlock + 10, splits.size()); + auto blockNumbers = getBlockNumbers(curBlock, curBlock + 3, splits.size()); // Assign the amounts to the addresses. QList migItems; @@ -103,15 +120,11 @@ void Turnstile::planMigration(QString zaddr, QString destAddr) { writeMigrationPlan(migItems); auto readPlan = readMigrationPlan(); - - for (auto item : readPlan) { - qDebug() << item.fromAddr << item.intTAddr - << item.destAddr << item.amount << item.blockNumber << item.chaff << item.status; - } } ); } + QList Turnstile::getBlockNumbers(int start, int end, int count) { QList blocks; // Generate 'count' numbers between [start, end] @@ -179,4 +192,100 @@ void Turnstile::fillAmounts(QList& amounts, double amount, int count) { amounts.push_back(curAmount); fillAmounts(amounts, amount - curAmount, count - 1); +} + +void Turnstile::executeMigrationStep() { + auto plan = readMigrationPlan(); + + qDebug() << QString("Executing step"); + printPlan(plan); + + // Get to the next unexecuted step + auto eligibleItem = [&] (auto item) { + return !item.chaff && + (item.status == TurnstileMigrationItemStatus::NotStarted || + item.status == TurnstileMigrationItemStatus::SentToT); + }; + 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; + + // 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(); + + // Execute this step + if (nextStep->status == TurnstileMigrationItemStatus::NotStarted) { + // Does this z addr have enough balance? + auto balance = rpc->getAllBalances()->value(nextStep->fromAddr); + if (nextStep->amount > balance) { + qDebug() << "Not enough balance!"; + nextStep->status = TurnstileMigrationItemStatus::NotEnoughBalance; + writeMigrationPlan(plan); + return; + } + + QList to = { ToFields{ nextStep->intTAddr, nextStep->amount, "", "" } }; + + // If this is the last step, then add chaff and the dev fee to the tx + if (lastStep) { + auto remainingAmount = balance - nextStep->amount; + if (remainingAmount > 0) { + auto devFee = ToFields{ Utils::getDevSproutAddr(), remainingAmount, "", "" }; + to.push_back(devFee); + } + } + + // Create the Tx + auto tx = Tx{ nextStep->fromAddr, to, Utils::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) { + // Send it to the final destination address. + auto bal = rpc->getAllBalances()->value(nextStep->intTAddr); + auto sendAmt = bal - Utils::getMinerFee(); + + if (sendAmt < 0) { + qDebug() << "Not enough balance!"; + nextStep->status = TurnstileMigrationItemStatus::NotEnoughBalance; + writeMigrationPlan(plan); + return; + } + + QList to = { ToFields{ nextStep->destAddr, sendAmt, "", "" } }; + // Create the Tx + auto tx = Tx{ nextStep->intTAddr, to, Utils::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) { + json params = json::array(); + rpc->fillTxJsonParams(params, tx); + std::cout << std::setw(2) << params << std::endl; + rpc->sendZTransaction(params, [=] (const json& reply) { + QString opid = QString::fromStdString(reply.get()); + qDebug() << opid; + //ui->statusBar->showMessage("Computing Tx: " % opid); + + // And then start monitoring the transaction + rpc->addNewTxToWatch(tx, opid); + + cb(); + }); } \ No newline at end of file diff --git a/src/turnstile.h b/src/turnstile.h index 5acf2ff..b716c39 100644 --- a/src/turnstile.h +++ b/src/turnstile.h @@ -1,10 +1,10 @@ #ifndef TURNSTILE_H #define TURNSTILE_H - #include "precompiled.h" class RPC; +struct Tx; struct TurnstileMigrationItem { QString fromAddr; @@ -30,16 +30,21 @@ public: Turnstile(RPC* _rpc); ~Turnstile(); - void planMigration(QString zaddr, QString destAddr); - QList splitAmount(double amount, int parts); - void fillAmounts(QList& amounts, double amount, int count); + void planMigration(QString zaddr, QString destAddr); + QList splitAmount(double amount, int parts); + void fillAmounts(QList& amounts, double amount, int count); - void writeMigrationPlan(QList plan); QList readMigrationPlan(); + void writeMigrationPlan(QList plan); + + void executeMigrationStep(); private: QList getBlockNumbers(int start, int end, int count); QString writeableFile(); + + void doSendTx(Tx tx, std::function cb); + RPC* rpc; }; diff --git a/src/utils.cpp b/src/utils.cpp index 45ec617..a6dd3c0 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -19,13 +19,17 @@ const QString Utils::getDonationAddr() { return "t1KfJJrSuVYmnNLrw7EZHRv1kZY3zdGGLyb"; } +const QString Utils::getDevSproutAddr() { + return "ztbGDqgkmXQjheivgeirwEvJLD4SUNqsWCGwxwVg4YpGz1ARR8P2rXaptkT14z3NDKamcxNmQuvmvktyokMs7HkutRNSx1D"; +} + // Get the dev fee address based on the transaction const QString Utils::getDevAddr(Tx tx) { auto testnetAddrLookup = [=] (const QString& addr) -> QString { if (addr.startsWith("ztestsapling")) { return "ztestsapling1kdp74adyfsmm9838jaupgfyx3npgw8ut63stjjx757pc248cuc0ymzphqeux60c64qe5qt68ygh"; } else if (addr.startsWith("zt")) { - return "ztbGDqgkmXQjheivgeirwEvJLD4SUNqsWCGwxwVg4YpGz1ARR8P2rXaptkT14z3NDKamcxNmQuvmvktyokMs7HkutRNSx1D"; + return getDevSproutAddr(); } else { return QString(); } diff --git a/src/utils.h b/src/utils.h index 5964e75..8244fcf 100644 --- a/src/utils.h +++ b/src/utils.h @@ -12,6 +12,7 @@ public: static const QString txidStatusMessage; static const QString getTokenName(); + static const QString getDevSproutAddr(); static const QString getDevAddr(Tx tx); static const QString getDonationAddr();