Browse Source

Support 2.0.5 sapling turnstile

Aditya Kulkarni 5 years ago
parent
commit
fcb68823a7
  1. 16
      src/mainwindow.cpp
  2. 139
      src/migration.ui
  3. 49
      src/rpc.cpp
  4. 17
      src/rpc.h
  5. 90
      src/turnstile.cpp
  6. 25
      src/turnstile.h
  7. 1
      zec-qt-wallet.pro

16
src/mainwindow.cpp

@ -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

@ -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 -&gt; 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

@ -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

@ -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;
};

90
src/turnstile.cpp

@ -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();
}

25
src/turnstile.h

@ -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

1
zec-qt-wallet.pro

@ -86,6 +86,7 @@ HEADERS += \
FORMS += \
src/mainwindow.ui \
src/migration.ui \
src/recurringpayments.ui \
src/settings.ui \
src/about.ui \

Loading…
Cancel
Save