Support 2.0.5 sapling turnstile
This commit is contained in:
@@ -381,11 +381,17 @@ void MainWindow::turnstileDoMigration(QString fromAddr) {
|
|||||||
void MainWindow::setupTurnstileDialog() {
|
void MainWindow::setupTurnstileDialog() {
|
||||||
// Turnstile migration
|
// Turnstile migration
|
||||||
QObject::connect(ui->actionTurnstile_Migration, &QAction::triggered, [=] () {
|
QObject::connect(ui->actionTurnstile_Migration, &QAction::triggered, [=] () {
|
||||||
// If there is current migration that is present, show the progress button
|
// If the underlying zcashd has support for the migration, use that.
|
||||||
if (rpc->getTurnstile()->isMigrationPresent())
|
// Else, show the ZecWallet turnstile tool
|
||||||
turnstileProgress();
|
if (rpc->getMigrationStatus()->available) {
|
||||||
else
|
Turnstile::showZcashdMigration(this);
|
||||||
turnstileDoMigration();
|
} else {
|
||||||
|
// If there is current migration that is present, show the progress button
|
||||||
|
if (rpc->getTurnstile()->isMigrationPresent())
|
||||||
|
turnstileProgress();
|
||||||
|
else
|
||||||
|
turnstileDoMigration();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
139
src/migration.ui
Normal file
139
src/migration.ui
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>MigrationDialog</class>
|
||||||
|
<widget class="QDialog" name="MigrationDialog">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>511</width>
|
||||||
|
<height>498</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Migration Turnstile</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<item row="9" column="0" colspan="2">
|
||||||
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="standardButtons">
|
||||||
|
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="7" column="0" colspan="2">
|
||||||
|
<widget class="QGroupBox" name="groupBox">
|
||||||
|
<property name="title">
|
||||||
|
<string>Migration History</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_2">
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="QLabel" name="label_4">
|
||||||
|
<property name="text">
|
||||||
|
<string>Migrated Amount</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="2">
|
||||||
|
<widget class="QLabel" name="lblUnMigrated">
|
||||||
|
<property name="text">
|
||||||
|
<string notr="true">TextLabel</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="1" colspan="2">
|
||||||
|
<widget class="QTableView" name="tblTxids">
|
||||||
|
<attribute name="horizontalHeaderStretchLastSection">
|
||||||
|
<bool>true</bool>
|
||||||
|
</attribute>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="2">
|
||||||
|
<widget class="QLabel" name="lblMigrated">
|
||||||
|
<property name="text">
|
||||||
|
<string notr="true">TextLabel</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="text">
|
||||||
|
<string>Unmigrated Amount</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="0" colspan="2">
|
||||||
|
<widget class="QCheckBox" name="chkEnabled">
|
||||||
|
<property name="text">
|
||||||
|
<string>Sprout -> Sapling migration enabled</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0" colspan="2">
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string>If enabled, zcashd will slowly migrate your Sprout shielded funds to your Sapling address. </string>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="0" colspan="2">
|
||||||
|
<widget class="Line" name="line">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0" colspan="2">
|
||||||
|
<widget class="QLabel" name="lblSaplingAddress">
|
||||||
|
<property name="text">
|
||||||
|
<string notr="true"/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>accepted()</signal>
|
||||||
|
<receiver>MigrationDialog</receiver>
|
||||||
|
<slot>accept()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>248</x>
|
||||||
|
<y>254</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>157</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>rejected()</signal>
|
||||||
|
<receiver>MigrationDialog</receiver>
|
||||||
|
<slot>reject()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>316</x>
|
||||||
|
<y>260</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>286</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
</ui>
|
||||||
49
src/rpc.cpp
49
src/rpc.cpp
@@ -52,6 +52,9 @@ RPC::RPC(MainWindow* main) {
|
|||||||
txTimer->start(Settings::updateSpeed);
|
txTimer->start(Settings::updateSpeed);
|
||||||
|
|
||||||
usedAddresses = new QMap<QString, bool>();
|
usedAddresses = new QMap<QString, bool>();
|
||||||
|
|
||||||
|
// Initialize the migration status to unavailable.
|
||||||
|
this->migrationStatus.available = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
RPC::~RPC() {
|
RPC::~RPC() {
|
||||||
@@ -568,8 +571,9 @@ void RPC::getInfoThenRefresh(bool force) {
|
|||||||
turnstile->executeMigrationStep();
|
turnstile->executeMigrationStep();
|
||||||
|
|
||||||
refreshBalances();
|
refreshBalances();
|
||||||
refreshAddresses(); // This calls refreshZSentTransactions() and refreshReceivedZTrans()
|
refreshAddresses(); // This calls refreshZSentTransactions() and refreshReceivedZTrans()
|
||||||
refreshTransactions();
|
refreshTransactions();
|
||||||
|
refreshMigration(); // Sapling turnstile migration status.
|
||||||
}
|
}
|
||||||
|
|
||||||
int connections = reply["connections"].get<json::number_integer_t>();
|
int connections = reply["connections"].get<json::number_integer_t>();
|
||||||
@@ -755,6 +759,49 @@ bool RPC::processUnspent(const json& reply, QMap<QString, double>* balancesMap,
|
|||||||
return anyUnconfirmed;
|
return anyUnconfirmed;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refresh the turnstile migration status
|
||||||
|
*/
|
||||||
|
void RPC::refreshMigration() {
|
||||||
|
// Turnstile migration is only supported in zcashd v2.0.5 and above
|
||||||
|
if (Settings::getInstance()->getZcashdVersion() < 2000552)
|
||||||
|
return;
|
||||||
|
|
||||||
|
json payload = {
|
||||||
|
{"jsonrpc", "1.0"},
|
||||||
|
{"id", "someid"},
|
||||||
|
{"method", "z_getmigrationstatus"},
|
||||||
|
};
|
||||||
|
|
||||||
|
conn->doRPCWithDefaultErrorHandling(payload, [=](json reply) {
|
||||||
|
this->migrationStatus.available = true;
|
||||||
|
this->migrationStatus.enabled = reply["enabled"].get<json::boolean_t>();
|
||||||
|
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();
|
||||||
|
|
||||||
|
this->migrationStatus.txids.empty();
|
||||||
|
for (auto& it : reply["migration_txids"].get<json::array_t>()) {
|
||||||
|
this->migrationStatus.txids.push_back(QString::fromStdString(it.get<json::string_t>()));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void RPC::setMigrationStatus(bool enabled) {
|
||||||
|
json payload = {
|
||||||
|
{"jsonrpc", "1.0"},
|
||||||
|
{"id", "someid"},
|
||||||
|
{"method", "z_setmigration"},
|
||||||
|
{"params", {enabled}}
|
||||||
|
};
|
||||||
|
|
||||||
|
conn->doRPCWithDefaultErrorHandling(payload, [=](json) {
|
||||||
|
// Ignore return value.
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void RPC::refreshBalances() {
|
void RPC::refreshBalances() {
|
||||||
if (conn == nullptr)
|
if (conn == nullptr)
|
||||||
return noConnection();
|
return noConnection();
|
||||||
|
|||||||
17
src/rpc.h
17
src/rpc.h
@@ -31,6 +31,15 @@ struct WatchedTx {
|
|||||||
std::function<void(QString, QString)> error;
|
std::function<void(QString, QString)> error;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct MigrationStatus {
|
||||||
|
bool available; // Whether the underlying zcashd supports migration?
|
||||||
|
bool enabled;
|
||||||
|
QString saplingAddress;
|
||||||
|
double unmigrated;
|
||||||
|
double migrated;
|
||||||
|
QList<QString> txids;
|
||||||
|
};
|
||||||
|
|
||||||
class RPC
|
class RPC
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -88,10 +97,14 @@ public:
|
|||||||
Turnstile* getTurnstile() { return turnstile; }
|
Turnstile* getTurnstile() { return turnstile; }
|
||||||
Connection* getConnection() { return conn; }
|
Connection* getConnection() { return conn; }
|
||||||
|
|
||||||
|
const MigrationStatus* getMigrationStatus() { return &migrationStatus; }
|
||||||
|
void setMigrationStatus(bool enabled);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void refreshBalances();
|
void refreshBalances();
|
||||||
|
|
||||||
void refreshTransactions();
|
void refreshTransactions();
|
||||||
|
void refreshMigration();
|
||||||
void refreshSentZTrans();
|
void refreshSentZTrans();
|
||||||
void refreshReceivedZTrans(QList<QString> zaddresses);
|
void refreshReceivedZTrans(QList<QString> zaddresses);
|
||||||
|
|
||||||
@@ -108,6 +121,7 @@ private:
|
|||||||
void getZAddresses (const std::function<void(json)>& cb);
|
void getZAddresses (const std::function<void(json)>& cb);
|
||||||
void getTAddresses (const std::function<void(json)>& cb);
|
void getTAddresses (const std::function<void(json)>& cb);
|
||||||
|
|
||||||
|
|
||||||
Connection* conn = nullptr;
|
Connection* conn = nullptr;
|
||||||
QProcess* ezcashd = nullptr;
|
QProcess* ezcashd = nullptr;
|
||||||
|
|
||||||
@@ -130,6 +144,9 @@ private:
|
|||||||
MainWindow* main;
|
MainWindow* main;
|
||||||
Turnstile* turnstile;
|
Turnstile* turnstile;
|
||||||
|
|
||||||
|
// 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
|
// Current balance in the UI. If this number updates, then refresh the UI
|
||||||
QString currentBalance;
|
QString currentBalance;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
#include "balancestablemodel.h"
|
#include "balancestablemodel.h"
|
||||||
#include "rpc.h"
|
#include "rpc.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
|
#include "ui_migration.h"
|
||||||
|
|
||||||
|
|
||||||
using json = nlohmann::json;
|
using json = nlohmann::json;
|
||||||
|
|
||||||
@@ -375,3 +377,91 @@ void Turnstile::doSendTx(Tx tx, std::function<void(void)> cb) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Methods for zcashd native Migration
|
||||||
|
void Turnstile::showZcashdMigration(MainWindow* parent) {
|
||||||
|
// If it is not enabled, don't show the dialog
|
||||||
|
if (! parent->getRPC()->getMigrationStatus()->available)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Ui_MigrationDialog md;
|
||||||
|
QDialog d(parent);
|
||||||
|
md.setupUi(&d);
|
||||||
|
Settings::saveRestore(&d);
|
||||||
|
|
||||||
|
MigrationTxns model(md.tblTxids, parent->getRPC()->getMigrationStatus()->txids);
|
||||||
|
md.tblTxids->setModel(&model);
|
||||||
|
|
||||||
|
// Table right click
|
||||||
|
md.tblTxids->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||||
|
QObject::connect(md.tblTxids, &QTableView::customContextMenuRequested, [=, &model] (QPoint pos) {
|
||||||
|
QModelIndex index = md.tblTxids->indexAt(pos);
|
||||||
|
if (index.row() < 0) return;
|
||||||
|
|
||||||
|
QMenu menu(parent);
|
||||||
|
QString txid = model.getTxid(index.row());
|
||||||
|
|
||||||
|
menu.addAction(QObject::tr("View on block explorer"), [=] () {
|
||||||
|
QString url;
|
||||||
|
if (Settings::getInstance()->isTestnet()) {
|
||||||
|
url = "https://explorer.testnet.z.cash/tx/" + txid;
|
||||||
|
} else {
|
||||||
|
url = "https://explorer.zcha.in/transactions/" + txid;
|
||||||
|
}
|
||||||
|
QDesktopServices::openUrl(QUrl(url));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
auto* status = parent->getRPC()->getMigrationStatus();
|
||||||
|
|
||||||
|
md.chkEnabled->setChecked(status->enabled);
|
||||||
|
md.lblSaplingAddress->setText(status->saplingAddress);
|
||||||
|
md.lblUnMigrated->setText(Settings::getZECDisplayFormat(status->unmigrated));
|
||||||
|
md.lblMigrated->setText(Settings::getZECDisplayFormat(status->migrated));
|
||||||
|
|
||||||
|
if (d.exec() == QDialog::Accepted) {
|
||||||
|
// Update the migration status if it changed
|
||||||
|
if (md.chkEnabled->isChecked() != status->enabled) {
|
||||||
|
parent->getRPC()->setMigrationStatus(md.chkEnabled->isChecked());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MigrationTxns::MigrationTxns(QTableView *parent, QList<QString> txids)
|
||||||
|
: QAbstractTableModel(parent) {
|
||||||
|
headers << tr("Txid");
|
||||||
|
this->txids = txids;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int MigrationTxns::rowCount(const QModelIndex&) const {
|
||||||
|
return txids.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
int MigrationTxns::columnCount(const QModelIndex&) const {
|
||||||
|
return headers.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString MigrationTxns::getTxid(int row) const {
|
||||||
|
return txids.at(row);
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant MigrationTxns::data(const QModelIndex &index, int role) const {
|
||||||
|
if (role == Qt::DisplayRole) {
|
||||||
|
switch(index.column()) {
|
||||||
|
case 0: return txids.at(index.row());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QVariant MigrationTxns::headerData(int section, Qt::Orientation orientation, int role) const {
|
||||||
|
if (role == Qt::DisplayRole && orientation == Qt::Horizontal) {
|
||||||
|
return headers.at(section);
|
||||||
|
}
|
||||||
|
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|||||||
@@ -52,6 +52,8 @@ public:
|
|||||||
ProgressReport getPlanProgress();
|
ProgressReport getPlanProgress();
|
||||||
bool isMigrationPresent();
|
bool isMigrationPresent();
|
||||||
|
|
||||||
|
static void showZcashdMigration(MainWindow* parent);
|
||||||
|
|
||||||
static double minMigrationAmount;
|
static double minMigrationAmount;
|
||||||
private:
|
private:
|
||||||
QList<int> getBlockNumbers(int start, int end, int count);
|
QList<int> getBlockNumbers(int start, int end, int count);
|
||||||
@@ -66,4 +68,27 @@ private:
|
|||||||
MainWindow* mainwindow;
|
MainWindow* mainwindow;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Classes for zcashd 2.0.5 native migration
|
||||||
|
|
||||||
|
|
||||||
|
class MigrationTxns : public QAbstractTableModel {
|
||||||
|
|
||||||
|
public:
|
||||||
|
MigrationTxns(QTableView* parent, QList<QString> txids);
|
||||||
|
~MigrationTxns() = default;
|
||||||
|
|
||||||
|
int rowCount(const QModelIndex &parent) const;
|
||||||
|
int columnCount(const QModelIndex &parent) const;
|
||||||
|
QVariant data(const QModelIndex &index, int role) const;
|
||||||
|
QVariant headerData(int section, Qt::Orientation orientation, int role) const;
|
||||||
|
|
||||||
|
QString getTxid(int row) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QList<QString> txids;
|
||||||
|
QStringList headers;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -86,6 +86,7 @@ HEADERS += \
|
|||||||
|
|
||||||
FORMS += \
|
FORMS += \
|
||||||
src/mainwindow.ui \
|
src/mainwindow.ui \
|
||||||
|
src/migration.ui \
|
||||||
src/recurringpayments.ui \
|
src/recurringpayments.ui \
|
||||||
src/settings.ui \
|
src/settings.ui \
|
||||||
src/about.ui \
|
src/about.ui \
|
||||||
|
|||||||
Reference in New Issue
Block a user