Execute migration steps
This commit is contained in:
@@ -56,7 +56,6 @@ private:
|
|||||||
|
|
||||||
Tx createTxFromSendPage();
|
Tx createTxFromSendPage();
|
||||||
bool confirmTx(Tx tx, ToFields devFee);
|
bool confirmTx(Tx tx, ToFields devFee);
|
||||||
void fillTxJsonParams(json& params, Tx tx);
|
|
||||||
|
|
||||||
void cancelButton();
|
void cancelButton();
|
||||||
void sendButton();
|
void sendButton();
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
/* Add C++ includes here */
|
/* Add C++ includes here */
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <iomanip>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|||||||
34
src/rpc.cpp
34
src/rpc.cpp
@@ -286,6 +286,33 @@ void RPC::handleTxError(const QString& error) {
|
|||||||
msg.exec();
|
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
|
// Refresh received z txs by calling z_listreceivedbyaddress/gettransaction
|
||||||
void RPC::refreshReceivedZTrans(QList<QString> zaddrs) {
|
void RPC::refreshReceivedZTrans(QList<QString> zaddrs) {
|
||||||
|
|
||||||
@@ -296,7 +323,6 @@ void RPC::refreshReceivedZTrans(QList<QString> zaddrs) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// This method is complicated because z_listreceivedbyaddress only returns the txid, and
|
// 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.
|
// 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,
|
// Additionally, it has to be done in batches, because there are multiple z-Addresses,
|
||||||
@@ -464,7 +490,11 @@ void RPC::updateUI(bool anyUnconfirmed) {
|
|||||||
|
|
||||||
// Temp
|
// Temp
|
||||||
Turnstile t(this);
|
Turnstile t(this);
|
||||||
t.planMigration(zaddresses->at(1), zaddresses->at(0));
|
// t.planMigration(
|
||||||
|
// "ztsKtGwc7JTEHxQq1xiRWyU9o1sheA3tYjcaFTBfVtp4RKJ782U6pH9STEYUoWQiGn1epfRMmFhkWCUyCSCqByNj9HKnzKU",
|
||||||
|
// "ztbGDqgkmXQjheivgeirwEvJLD4SUNqsWCGwxwVg4YpGz1ARR8P2rXaptkT14z3NDKamcxNmQuvmvktyokMs7HkutRNSx1D"
|
||||||
|
// );
|
||||||
|
t.executeMigrationStep();
|
||||||
|
|
||||||
ui->unconfirmedWarning->setVisible(anyUnconfirmed);
|
ui->unconfirmedWarning->setVisible(anyUnconfirmed);
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ public:
|
|||||||
void refreshAddresses(); // Refresh wallet Z-addrs
|
void refreshAddresses(); // Refresh wallet Z-addrs
|
||||||
void refreshZECPrice();
|
void refreshZECPrice();
|
||||||
|
|
||||||
|
void fillTxJsonParams(json& params, Tx tx);
|
||||||
void sendZTransaction (json params, const std::function<void(json)>& cb);
|
void sendZTransaction (json params, const std::function<void(json)>& cb);
|
||||||
void watchTxStatus();
|
void watchTxStatus();
|
||||||
void addNewTxToWatch(Tx tx, const QString& newOpid);
|
void addNewTxToWatch(Tx tx, const QString& newOpid);
|
||||||
|
|||||||
@@ -7,8 +7,6 @@
|
|||||||
|
|
||||||
#include "precompiled.h"
|
#include "precompiled.h"
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <iomanip>
|
|
||||||
using json = nlohmann::json;
|
using json = nlohmann::json;
|
||||||
|
|
||||||
void MainWindow::setupSendTab() {
|
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
|
// Send button clicked
|
||||||
void MainWindow::sendButton() {
|
void MainWindow::sendButton() {
|
||||||
Tx tx = createTxFromSendPage();
|
Tx tx = createTxFromSendPage();
|
||||||
@@ -509,7 +483,7 @@ void MainWindow::sendButton() {
|
|||||||
tx.toAddrs.push_back(devFee);
|
tx.toAddrs.push_back(devFee);
|
||||||
|
|
||||||
json params = json::array();
|
json params = json::array();
|
||||||
fillTxJsonParams(params, tx);
|
rpc->fillTxJsonParams(params, tx);
|
||||||
std::cout << std::setw(2) << params << std::endl;
|
std::cout << std::setw(2) << params << std::endl;
|
||||||
|
|
||||||
// And send the Tx
|
// And send the Tx
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#include "turnstile.h"
|
#include "turnstile.h"
|
||||||
|
#include "mainwindow.h"
|
||||||
#include "rpc.h"
|
#include "rpc.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
@@ -14,6 +15,13 @@ Turnstile::Turnstile(RPC* _rpc) {
|
|||||||
Turnstile::~Turnstile() {
|
Turnstile::~Turnstile() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void printPlan(QList<TurnstileMigrationItem> plan) {
|
||||||
|
for (auto item : plan) {
|
||||||
|
qDebug() << item.fromAddr << item.intTAddr
|
||||||
|
<< item.destAddr << item.amount << item.blockNumber << item.chaff << item.status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QString Turnstile::writeableFile() {
|
QString Turnstile::writeableFile() {
|
||||||
auto filename = QStringLiteral("turnstilemigrationplan.dat");
|
auto filename = QStringLiteral("turnstilemigrationplan.dat");
|
||||||
|
|
||||||
@@ -41,6 +49,9 @@ QDataStream &operator>>(QDataStream& ds, TurnstileMigrationItem& item) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Turnstile::writeMigrationPlan(QList<TurnstileMigrationItem> plan) {
|
void Turnstile::writeMigrationPlan(QList<TurnstileMigrationItem> plan) {
|
||||||
|
qDebug() << QString("Writing plan");
|
||||||
|
printPlan(plan);
|
||||||
|
|
||||||
QFile file(writeableFile());
|
QFile file(writeableFile());
|
||||||
file.open(QIODevice::ReadWrite | QIODevice::Truncate);
|
file.open(QIODevice::ReadWrite | QIODevice::Truncate);
|
||||||
QDataStream out(&file); // we will serialize the data into the file
|
QDataStream out(&file); // we will serialize the data into the file
|
||||||
@@ -59,13 +70,19 @@ QList<TurnstileMigrationItem> Turnstile::readMigrationPlan() {
|
|||||||
in >> plan;
|
in >> plan;
|
||||||
|
|
||||||
file.close();
|
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;
|
return plan;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Turnstile::planMigration(QString zaddr, QString destAddr) {
|
void Turnstile::planMigration(QString zaddr, QString destAddr) {
|
||||||
// First, get the balance and split up the amounts
|
// First, get the balance and split up the amounts
|
||||||
auto bal = rpc->getAllBalances()->value(zaddr);
|
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
|
// Then, generate an intermediate t-Address for each part using getBatchRPC
|
||||||
rpc->getBatchRPC<double>(splits,
|
rpc->getBatchRPC<double>(splits,
|
||||||
@@ -80,7 +97,7 @@ void Turnstile::planMigration(QString zaddr, QString destAddr) {
|
|||||||
[=] (QMap<double, json>* newAddrs) {
|
[=] (QMap<double, json>* newAddrs) {
|
||||||
// Get block numbers
|
// Get block numbers
|
||||||
auto curBlock = Settings::getInstance()->getBlockNumber();
|
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.
|
// Assign the amounts to the addresses.
|
||||||
QList<TurnstileMigrationItem> migItems;
|
QList<TurnstileMigrationItem> migItems;
|
||||||
@@ -103,15 +120,11 @@ void Turnstile::planMigration(QString zaddr, QString destAddr) {
|
|||||||
|
|
||||||
writeMigrationPlan(migItems);
|
writeMigrationPlan(migItems);
|
||||||
auto readPlan = readMigrationPlan();
|
auto readPlan = readMigrationPlan();
|
||||||
|
|
||||||
for (auto item : readPlan) {
|
|
||||||
qDebug() << item.fromAddr << item.intTAddr
|
|
||||||
<< item.destAddr << item.amount << item.blockNumber << item.chaff << item.status;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
QList<int> Turnstile::getBlockNumbers(int start, int end, int count) {
|
QList<int> Turnstile::getBlockNumbers(int start, int end, int count) {
|
||||||
QList<int> blocks;
|
QList<int> blocks;
|
||||||
// Generate 'count' numbers between [start, end]
|
// Generate 'count' numbers between [start, end]
|
||||||
@@ -180,3 +193,99 @@ void Turnstile::fillAmounts(QList<double>& amounts, double amount, int count) {
|
|||||||
|
|
||||||
fillAmounts(amounts, amount - curAmount, count - 1);
|
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<ToFields> 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<ToFields> 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<void(void)> 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<json::string_t>());
|
||||||
|
qDebug() << opid;
|
||||||
|
//ui->statusBar->showMessage("Computing Tx: " % opid);
|
||||||
|
|
||||||
|
// And then start monitoring the transaction
|
||||||
|
rpc->addNewTxToWatch(tx, opid);
|
||||||
|
|
||||||
|
cb();
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
#ifndef TURNSTILE_H
|
#ifndef TURNSTILE_H
|
||||||
#define TURNSTILE_H
|
#define TURNSTILE_H
|
||||||
|
|
||||||
|
|
||||||
#include "precompiled.h"
|
#include "precompiled.h"
|
||||||
|
|
||||||
class RPC;
|
class RPC;
|
||||||
|
struct Tx;
|
||||||
|
|
||||||
struct TurnstileMigrationItem {
|
struct TurnstileMigrationItem {
|
||||||
QString fromAddr;
|
QString fromAddr;
|
||||||
@@ -30,16 +30,21 @@ public:
|
|||||||
Turnstile(RPC* _rpc);
|
Turnstile(RPC* _rpc);
|
||||||
~Turnstile();
|
~Turnstile();
|
||||||
|
|
||||||
void planMigration(QString zaddr, QString destAddr);
|
void planMigration(QString zaddr, QString destAddr);
|
||||||
QList<double> splitAmount(double amount, int parts);
|
QList<double> splitAmount(double amount, int parts);
|
||||||
void fillAmounts(QList<double>& amounts, double amount, int count);
|
void fillAmounts(QList<double>& amounts, double amount, int count);
|
||||||
|
|
||||||
void writeMigrationPlan(QList<TurnstileMigrationItem> plan);
|
|
||||||
QList<TurnstileMigrationItem> readMigrationPlan();
|
QList<TurnstileMigrationItem> readMigrationPlan();
|
||||||
|
void writeMigrationPlan(QList<TurnstileMigrationItem> plan);
|
||||||
|
|
||||||
|
void executeMigrationStep();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QList<int> getBlockNumbers(int start, int end, int count);
|
QList<int> getBlockNumbers(int start, int end, int count);
|
||||||
QString writeableFile();
|
QString writeableFile();
|
||||||
|
|
||||||
|
void doSendTx(Tx tx, std::function<void(void)> cb);
|
||||||
|
|
||||||
RPC* rpc;
|
RPC* rpc;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -19,13 +19,17 @@ const QString Utils::getDonationAddr() {
|
|||||||
return "t1KfJJrSuVYmnNLrw7EZHRv1kZY3zdGGLyb";
|
return "t1KfJJrSuVYmnNLrw7EZHRv1kZY3zdGGLyb";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const QString Utils::getDevSproutAddr() {
|
||||||
|
return "ztbGDqgkmXQjheivgeirwEvJLD4SUNqsWCGwxwVg4YpGz1ARR8P2rXaptkT14z3NDKamcxNmQuvmvktyokMs7HkutRNSx1D";
|
||||||
|
}
|
||||||
|
|
||||||
// Get the dev fee address based on the transaction
|
// Get the dev fee address based on the transaction
|
||||||
const QString Utils::getDevAddr(Tx tx) {
|
const QString Utils::getDevAddr(Tx tx) {
|
||||||
auto testnetAddrLookup = [=] (const QString& addr) -> QString {
|
auto testnetAddrLookup = [=] (const QString& addr) -> QString {
|
||||||
if (addr.startsWith("ztestsapling")) {
|
if (addr.startsWith("ztestsapling")) {
|
||||||
return "ztestsapling1kdp74adyfsmm9838jaupgfyx3npgw8ut63stjjx757pc248cuc0ymzphqeux60c64qe5qt68ygh";
|
return "ztestsapling1kdp74adyfsmm9838jaupgfyx3npgw8ut63stjjx757pc248cuc0ymzphqeux60c64qe5qt68ygh";
|
||||||
} else if (addr.startsWith("zt")) {
|
} else if (addr.startsWith("zt")) {
|
||||||
return "ztbGDqgkmXQjheivgeirwEvJLD4SUNqsWCGwxwVg4YpGz1ARR8P2rXaptkT14z3NDKamcxNmQuvmvktyokMs7HkutRNSx1D";
|
return getDevSproutAddr();
|
||||||
} else {
|
} else {
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ public:
|
|||||||
static const QString txidStatusMessage;
|
static const QString txidStatusMessage;
|
||||||
|
|
||||||
static const QString getTokenName();
|
static const QString getTokenName();
|
||||||
|
static const QString getDevSproutAddr();
|
||||||
static const QString getDevAddr(Tx tx);
|
static const QString getDevAddr(Tx tx);
|
||||||
static const QString getDonationAddr();
|
static const QString getDonationAddr();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user