diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index f0861c5..b721438 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -68,12 +68,6 @@ MainWindow::MainWindow(QWidget *parent) : } void MainWindow::setupTurnstileDialog() { - //Turnstile t(this); - // t.planMigration( - // "ztsKtGwc7JTEHxQq1xiRWyU9o1sheA3tYjcaFTBfVtp4RKJ782U6pH9STEYUoWQiGn1epfRMmFhkWCUyCSCqByNj9HKnzKU", - // "ztbGDqgkmXQjheivgeirwEvJLD4SUNqsWCGwxwVg4YpGz1ARR8P2rXaptkT14z3NDKamcxNmQuvmvktyokMs7HkutRNSx1D" - // ); - //t.executeMigrationStep(); // Turnstile migration QObject::connect(ui->actionTurnstile_Migration, &QAction::triggered, [=] () { @@ -117,18 +111,39 @@ void MainWindow::setupTurnstileDialog() { turnstile.fromBalance->setText(Settings::getInstance()->getZECUSDDisplayFormat(bal)); }); - turnstile.privLevel->addItem("Good - 3 tx over 3 days"); - turnstile.privLevel->addItem("Excellent - 5 tx over 5 days"); - turnstile.privLevel->addItem("Paranoid - 10 tx over 7 days"); + // Privacy level combobox + // Num tx over num blocks + QList> privOptions; + privOptions.push_back(QPair(3, 3)); + privOptions.push_back(QPair(5, 5)); + privOptions.push_back(QPair(10, 7)); + + QObject::connect(turnstile.privLevel, QOverload::of(&QComboBox::currentIndexChanged), [=] (auto idx) { + // Update the fees + turnstile.minerFee->setText( + Settings::getInstance()->getZECUSDDisplayFormat(privOptions[idx].first * Utils::getMinerFee())); + }); + + turnstile.privLevel->addItem("Good - 3 tx over 3 blocks"); + turnstile.privLevel->addItem("Excellent - 5 tx over 5 blocks"); + turnstile.privLevel->addItem("Paranoid - 10 tx over 7 blocks"); turnstile.buttonBox->button(QDialogButtonBox::Ok)->setText("Start"); if (d.exec() == QDialog::Accepted) { + auto privLevel = privOptions[turnstile.privLevel->currentIndex()]; rpc->getTurnstile()->planMigration( - turnstile.migrateZaddList->currentText(), turnstile.migrateTo->currentText()); + turnstile.migrateZaddList->currentText(), + turnstile.migrateTo->currentText(), + privLevel.first, privLevel.second); + + QMessageBox::information(this, "Backup your wallet.dat", + "The migration will now start. You can check progress in the File -> Turnstile Migration menu.\n\nYOU MUST BACKUP YOUR wallet.dat NOW!.\n\nNew Addresses have been added to your wallet which will be used for the migration.", + QMessageBox::Ok); } }); + // Progress update button QObject::connect(ui->actionProgress, &QAction::triggered, [=] () { Ui_TurnstileProgress progress; QDialog d(this); @@ -138,6 +153,37 @@ void MainWindow::setupTurnstileDialog() { progress.msgIcon->setPixmap(icon.pixmap(64, 64)); progress.buttonBox->button(QDialogButtonBox::Cancel)->setText("Abort"); + + auto fnUpdateProgressUI = [=] () { + // Get the plan progress + if (rpc->getTurnstile()->isMigrationActive()) { + auto curProgress = rpc->getTurnstile()->getPlanProgress(); + + progress.progressTxt->setText(QString::number(curProgress.step) % QString(" / ") % QString::number(curProgress.totalSteps)); + progress.progressBar->setValue(100 * curProgress.step / curProgress.totalSteps); + + auto nextTxBlock = curProgress.nextBlock - Settings::getInstance()->getBlockNumber(); + + if (curProgress.step == curProgress.totalSteps) { + progress.nextTx->setText("Turnstile migration finished"); + } else { + progress.nextTx->setText(QString("Next transaction in ") + % QString::number(nextTxBlock < 0 ? 0 : nextTxBlock) + % " blocks"); + } + + } else { + progress.progressTxt->setText(""); + progress.progressBar->setValue(0); + progress.nextTx->setText("No turnstile migration is in progress"); + } + }; + + QTimer progressTimer(this); + QObject::connect(&progressTimer, &QTimer::timeout, fnUpdateProgressUI); + progressTimer.start(Utils::updateSpeed); + fnUpdateProgressUI(); + d.exec(); }); } diff --git a/src/turnstile.cpp b/src/turnstile.cpp index 4c717b5..c1b278a 100644 --- a/src/turnstile.cpp +++ b/src/turnstile.cpp @@ -80,10 +80,10 @@ QList Turnstile::readMigrationPlan() { return plan; } -void Turnstile::planMigration(QString zaddr, QString destAddr) { +void Turnstile::planMigration(QString zaddr, QString destAddr, int numsplits, int numBlocks) { // First, get the balance and split up the amounts auto bal = rpc->getAllBalances()->value(zaddr); - auto splits = splitAmount(bal, 5); + auto splits = splitAmount(bal, numsplits); // Then, generate an intermediate t-Address for each part using getBatchRPC rpc->getBatchRPC(splits, @@ -98,7 +98,7 @@ void Turnstile::planMigration(QString zaddr, QString destAddr) { [=] (QMap* newAddrs) { // Get block numbers auto curBlock = Settings::getInstance()->getBlockNumber(); - auto blockNumbers = getBlockNumbers(curBlock, curBlock + 3, splits.size()); + auto blockNumbers = getBlockNumbers(curBlock, curBlock + numBlocks, splits.size()); // Assign the amounts to the addresses. QList migItems; @@ -195,6 +195,47 @@ void Turnstile::fillAmounts(QList& amounts, double amount, int count) { fillAmounts(amounts, amount - curAmount, count - 1); } +QList::Iterator +Turnstile::getNextStep(QList& plan) { + // Get to the next unexecuted step + auto fnIsEligibleItem = [&] (auto item) { + return item.status == TurnstileMigrationItemStatus::NotStarted || + item.status == TurnstileMigrationItemStatus::SentToT; + }; + + // // 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(); + // }; + + // Find the next step + auto nextStep = std::find_if(plan.begin(), plan.end(), fnIsEligibleItem); + return nextStep; +} + +bool Turnstile::isMigrationActive() { + auto plan = readMigrationPlan(); + if (plan.isEmpty()) return false; + + return true; +} + +ProgressReport Turnstile::getPlanProgress() { + auto plan = readMigrationPlan(); + + auto nextStep = getNextStep(plan); + + auto step = std::distance(plan.begin(), nextStep); + auto total = plan.size(); + + auto nextBlock = nextStep == plan.end() ? 0 : nextStep->blockNumber; + + return ProgressReport{(int)step*2, total*2, nextBlock}; +} + void Turnstile::executeMigrationStep() { auto plan = readMigrationPlan(); diff --git a/src/turnstile.h b/src/turnstile.h index 0a4ff88..a08e504 100644 --- a/src/turnstile.h +++ b/src/turnstile.h @@ -23,13 +23,19 @@ enum TurnstileMigrationItemStatus { UnknownError }; +struct ProgressReport { + int step; + int totalSteps; + int nextBlock; +}; + class Turnstile { public: Turnstile(RPC* _rpc); ~Turnstile(); - void planMigration(QString zaddr, QString destAddr); + void planMigration(QString zaddr, QString destAddr, int splits, int numBlocks); QList splitAmount(double amount, int parts); void fillAmounts(QList& amounts, double amount, int count); @@ -37,6 +43,8 @@ public: void writeMigrationPlan(QList plan); void executeMigrationStep(); + ProgressReport getPlanProgress(); + bool isMigrationActive(); private: QList getBlockNumbers(int start, int end, int count); @@ -44,6 +52,9 @@ private: void doSendTx(Tx tx, std::function cb); + + QList::Iterator getNextStep(QList& plan); + RPC* rpc; }; diff --git a/src/turnstile.ui b/src/turnstile.ui index 03af43e..acf6e64 100644 --- a/src/turnstile.ui +++ b/src/turnstile.ui @@ -151,7 +151,7 @@ - + 0 diff --git a/src/turnstileprogress.ui b/src/turnstileprogress.ui index 5b09ebd..3c337aa 100644 --- a/src/turnstileprogress.ui +++ b/src/turnstileprogress.ui @@ -45,14 +45,14 @@ - + Next Transaction in 4 hours - + 4 / 12 diff --git a/src/ui_turnstile.h b/src/ui_turnstile.h index b787a6a..fe1d77c 100644 --- a/src/ui_turnstile.h +++ b/src/ui_turnstile.h @@ -42,7 +42,7 @@ public: QLabel *fromBalance; QSpacerItem *verticalSpacer; QLabel *label_5; - QLabel *label_7; + QLabel *minerFee; QLabel *label_3; QDialogButtonBox *buttonBox; @@ -141,16 +141,16 @@ public: gridLayout->addWidget(label_5, 6, 0, 1, 1); - label_7 = new QLabel(groupBox); - label_7->setObjectName(QStringLiteral("label_7")); + minerFee = new QLabel(groupBox); + minerFee->setObjectName(QStringLiteral("minerFee")); QSizePolicy sizePolicy2(QSizePolicy::Expanding, QSizePolicy::Preferred); sizePolicy2.setHorizontalStretch(0); sizePolicy2.setVerticalStretch(0); - sizePolicy2.setHeightForWidth(label_7->sizePolicy().hasHeightForWidth()); - label_7->setSizePolicy(sizePolicy2); - label_7->setAlignment(Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter); + sizePolicy2.setHeightForWidth(minerFee->sizePolicy().hasHeightForWidth()); + minerFee->setSizePolicy(sizePolicy2); + minerFee->setAlignment(Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter); - gridLayout->addWidget(label_7, 6, 1, 1, 2); + gridLayout->addWidget(minerFee, 6, 1, 1, 2); label_3 = new QLabel(groupBox); label_3->setObjectName(QStringLiteral("label_3")); @@ -190,7 +190,7 @@ public: label_9->setText(QApplication::translate("Turnstile", "To", nullptr)); fromBalance->setText(QApplication::translate("Turnstile", "Balance", nullptr)); label_5->setText(QApplication::translate("Turnstile", "Miner Fees", nullptr)); - label_7->setText(QApplication::translate("Turnstile", "0.0004 ZEC $0.04", nullptr)); + minerFee->setText(QApplication::translate("Turnstile", "0.0004 ZEC $0.04", nullptr)); label_3->setText(QApplication::translate("Turnstile", "Total Balance", nullptr)); } // retranslateUi diff --git a/src/ui_turnstileprogress.h b/src/ui_turnstileprogress.h index 2d34909..0f5f48d 100644 --- a/src/ui_turnstileprogress.h +++ b/src/ui_turnstileprogress.h @@ -28,8 +28,8 @@ public: QProgressBar *progressBar; QLabel *label_4; QFrame *line; - QLabel *label; - QLabel *label_3; + QLabel *nextTx; + QLabel *progressTxt; QLabel *label_2; QLabel *msgIcon; QDialogButtonBox *buttonBox; @@ -67,16 +67,16 @@ public: gridLayout->addWidget(line, 4, 0, 1, 3); - label = new QLabel(TurnstileProgress); - label->setObjectName(QStringLiteral("label")); + nextTx = new QLabel(TurnstileProgress); + nextTx->setObjectName(QStringLiteral("nextTx")); - gridLayout->addWidget(label, 5, 0, 1, 3); + gridLayout->addWidget(nextTx, 5, 0, 1, 3); - label_3 = new QLabel(TurnstileProgress); - label_3->setObjectName(QStringLiteral("label_3")); - label_3->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); + progressTxt = new QLabel(TurnstileProgress); + progressTxt->setObjectName(QStringLiteral("progressTxt")); + progressTxt->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); - gridLayout->addWidget(label_3, 2, 2, 1, 1); + gridLayout->addWidget(progressTxt, 2, 2, 1, 1); label_2 = new QLabel(TurnstileProgress); label_2->setObjectName(QStringLiteral("label_2")); @@ -124,8 +124,8 @@ public: { TurnstileProgress->setWindowTitle(QApplication::translate("TurnstileProgress", "Dialog", nullptr)); label_4->setText(QApplication::translate("TurnstileProgress", "Please Ensure you have your wallet.dat backed up!", nullptr)); - label->setText(QApplication::translate("TurnstileProgress", "Next Transaction in 4 hours", nullptr)); - label_3->setText(QApplication::translate("TurnstileProgress", "4 / 12", nullptr)); + nextTx->setText(QApplication::translate("TurnstileProgress", "Next Transaction in 4 hours", nullptr)); + progressTxt->setText(QApplication::translate("TurnstileProgress", "4 / 12", nullptr)); label_2->setText(QApplication::translate("TurnstileProgress", "Migration Progress", nullptr)); msgIcon->setText(QApplication::translate("TurnstileProgress", "TextLabel", nullptr)); } // retranslateUi