Support 2.0.5 sapling turnstile
This commit is contained in:
@@ -381,11 +381,17 @@ void MainWindow::turnstileDoMigration(QString fromAddr) {
|
||||
void MainWindow::setupTurnstileDialog() {
|
||||
// Turnstile migration
|
||||
QObject::connect(ui->actionTurnstile_Migration, &QAction::triggered, [=] () {
|
||||
// If there is current migration that is present, show the progress button
|
||||
if (rpc->getTurnstile()->isMigrationPresent())
|
||||
turnstileProgress();
|
||||
else
|
||||
turnstileDoMigration();
|
||||
// If the underlying zcashd has support for the migration, use that.
|
||||
// Else, show the ZecWallet turnstile tool
|
||||
if (rpc->getMigrationStatus()->available) {
|
||||
Turnstile::showZcashdMigration(this);
|
||||
} 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);
|
||||
|
||||
usedAddresses = new QMap<QString, bool>();
|
||||
|
||||
// Initialize the migration status to unavailable.
|
||||
this->migrationStatus.available = false;
|
||||
}
|
||||
|
||||
RPC::~RPC() {
|
||||
@@ -568,8 +571,9 @@ void RPC::getInfoThenRefresh(bool force) {
|
||||
turnstile->executeMigrationStep();
|
||||
|
||||
refreshBalances();
|
||||
refreshAddresses(); // This calls refreshZSentTransactions() and refreshReceivedZTrans()
|
||||
refreshAddresses(); // This calls refreshZSentTransactions() and refreshReceivedZTrans()
|
||||
refreshTransactions();
|
||||
refreshMigration(); // Sapling turnstile migration status.
|
||||
}
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
/**
|
||||
* 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() {
|
||||
if (conn == nullptr)
|
||||
return noConnection();
|
||||
|
||||
17
src/rpc.h
17
src/rpc.h
@@ -31,6 +31,15 @@ struct WatchedTx {
|
||||
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
|
||||
{
|
||||
public:
|
||||
@@ -88,10 +97,14 @@ public:
|
||||
Turnstile* getTurnstile() { return turnstile; }
|
||||
Connection* getConnection() { return conn; }
|
||||
|
||||
const MigrationStatus* getMigrationStatus() { return &migrationStatus; }
|
||||
void setMigrationStatus(bool enabled);
|
||||
|
||||
private:
|
||||
void refreshBalances();
|
||||
|
||||
void refreshTransactions();
|
||||
void refreshMigration();
|
||||
void refreshSentZTrans();
|
||||
void refreshReceivedZTrans(QList<QString> zaddresses);
|
||||
|
||||
@@ -108,6 +121,7 @@ private:
|
||||
void getZAddresses (const std::function<void(json)>& cb);
|
||||
void getTAddresses (const std::function<void(json)>& cb);
|
||||
|
||||
|
||||
Connection* conn = nullptr;
|
||||
QProcess* ezcashd = nullptr;
|
||||
|
||||
@@ -130,6 +144,9 @@ private:
|
||||
MainWindow* main;
|
||||
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
|
||||
QString currentBalance;
|
||||
};
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
#include "balancestablemodel.h"
|
||||
#include "rpc.h"
|
||||
#include "settings.h"
|
||||
#include "ui_migration.h"
|
||||
|
||||
|
||||
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();
|
||||
bool isMigrationPresent();
|
||||
|
||||
static void showZcashdMigration(MainWindow* parent);
|
||||
|
||||
static double minMigrationAmount;
|
||||
private:
|
||||
QList<int> getBlockNumbers(int start, int end, int count);
|
||||
@@ -66,4 +68,27 @@ private:
|
||||
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
|
||||
|
||||
@@ -86,6 +86,7 @@ HEADERS += \
|
||||
|
||||
FORMS += \
|
||||
src/mainwindow.ui \
|
||||
src/migration.ui \
|
||||
src/recurringpayments.ui \
|
||||
src/settings.ui \
|
||||
src/about.ui \
|
||||
|
||||
Reference in New Issue
Block a user