Move all RPC to connection class
This commit is contained in:
@@ -90,7 +90,7 @@ Connection* ConnectionLoader::makeConnection(std::shared_ptr<ConnectionConfig> c
|
|||||||
QString headerData = "Basic " + userpass.toLocal8Bit().toBase64();
|
QString headerData = "Basic " + userpass.toLocal8Bit().toBase64();
|
||||||
request->setRawHeader("Authorization", headerData.toLocal8Bit());
|
request->setRawHeader("Authorization", headerData.toLocal8Bit());
|
||||||
|
|
||||||
return new Connection(client, request, config);
|
return new Connection(main, client, request, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConnectionLoader::refreshZcashdState(Connection* connection) {
|
void ConnectionLoader::refreshZcashdState(Connection* connection) {
|
||||||
@@ -105,7 +105,8 @@ void ConnectionLoader::refreshZcashdState(Connection* connection) {
|
|||||||
d->hide();
|
d->hide();
|
||||||
rpc->setConnection(connection);
|
rpc->setConnection(connection);
|
||||||
},
|
},
|
||||||
[=] (auto err, auto res) {
|
[=] (auto reply, auto res) {
|
||||||
|
auto err = reply->error();
|
||||||
// Failed, see what it is.
|
// Failed, see what it is.
|
||||||
qDebug() << err << ":" << QString::fromStdString(res.dump());
|
qDebug() << err << ":" << QString::fromStdString(res.dump());
|
||||||
|
|
||||||
@@ -251,10 +252,11 @@ std::shared_ptr<ConnectionConfig> ConnectionLoader::loadFromSettings() {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
Connection::Connection(QNetworkAccessManager* c, QNetworkRequest* r, std::shared_ptr<ConnectionConfig> conf) {
|
Connection::Connection(MainWindow* m, QNetworkAccessManager* c, QNetworkRequest* r, std::shared_ptr<ConnectionConfig> conf) {
|
||||||
this->restclient = c;
|
this->restclient = c;
|
||||||
this->request = r;
|
this->request = r;
|
||||||
this->config = conf;
|
this->config = conf;
|
||||||
|
this->main = m;
|
||||||
}
|
}
|
||||||
|
|
||||||
Connection::~Connection() {
|
Connection::~Connection() {
|
||||||
@@ -265,7 +267,7 @@ Connection::~Connection() {
|
|||||||
|
|
||||||
|
|
||||||
void Connection::doRPC(const json& payload, const std::function<void(json)>& cb,
|
void Connection::doRPC(const json& payload, const std::function<void(json)>& cb,
|
||||||
const std::function<void(QNetworkReply::NetworkError, const json&)>& ne) {
|
const std::function<void(QNetworkReply*, const json&)>& ne) {
|
||||||
QNetworkReply *reply = restclient->post(*request, QByteArray::fromStdString(payload.dump()));
|
QNetworkReply *reply = restclient->post(*request, QByteArray::fromStdString(payload.dump()));
|
||||||
|
|
||||||
QObject::connect(reply, &QNetworkReply::finished, [=] {
|
QObject::connect(reply, &QNetworkReply::finished, [=] {
|
||||||
@@ -273,16 +275,45 @@ void Connection::doRPC(const json& payload, const std::function<void(json)>& cb,
|
|||||||
|
|
||||||
if (reply->error() != QNetworkReply::NoError) {
|
if (reply->error() != QNetworkReply::NoError) {
|
||||||
auto parsed = json::parse(reply->readAll(), nullptr, false);
|
auto parsed = json::parse(reply->readAll(), nullptr, false);
|
||||||
ne(reply->error(), parsed);
|
ne(reply, parsed);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto parsed = json::parse(reply->readAll(), nullptr, false);
|
auto parsed = json::parse(reply->readAll(), nullptr, false);
|
||||||
if (parsed.is_discarded()) {
|
if (parsed.is_discarded()) {
|
||||||
ne(reply->error(), "Unknown error");
|
ne(reply, "Unknown error");
|
||||||
}
|
}
|
||||||
|
|
||||||
cb(parsed["result"]);
|
cb(parsed["result"]);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Connection::doRPCWithDefaultErrorHandling(const json& payload, const std::function<void(json)>& cb) {
|
||||||
|
doRPC(payload, cb, [=] (auto reply, auto parsed) {
|
||||||
|
if (!parsed.is_discarded() && !parsed["error"]["message"].is_null()) {
|
||||||
|
showTxError(QString::fromStdString(parsed["error"]["message"]));
|
||||||
|
} else {
|
||||||
|
showTxError(reply->errorString());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void Connection::doRPCIgnoreError(const json& payload, const std::function<void(json)>& cb) {
|
||||||
|
doRPC(payload, cb, [=] (auto, auto) {
|
||||||
|
// Ignored error handling
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void Connection::showTxError(const QString& error) {
|
||||||
|
if (error.isNull()) return;
|
||||||
|
|
||||||
|
QMessageBox msg(main);
|
||||||
|
msg.setIcon(QMessageBox::Icon::Critical);
|
||||||
|
msg.setWindowTitle("Transaction Error");
|
||||||
|
|
||||||
|
msg.setText("There was an error sending the transaction. The error was: \n\n"
|
||||||
|
+ error);
|
||||||
|
|
||||||
|
msg.exec();
|
||||||
|
}
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
#ifndef CONNECTION_H
|
#ifndef CONNECTION_H
|
||||||
#define CONNECTION_H
|
#define CONNECTION_H
|
||||||
|
|
||||||
|
#include "mainwindow.h"
|
||||||
#include "ui_connection.h"
|
#include "ui_connection.h"
|
||||||
#include "precompiled.h"
|
#include "precompiled.h"
|
||||||
|
|
||||||
using json = nlohmann::json;
|
using json = nlohmann::json;
|
||||||
|
|
||||||
class MainWindow;
|
|
||||||
class RPC;
|
class RPC;
|
||||||
|
|
||||||
enum ConnectionType {
|
enum ConnectionType {
|
||||||
@@ -59,17 +59,67 @@ private:
|
|||||||
*/
|
*/
|
||||||
class Connection {
|
class Connection {
|
||||||
public:
|
public:
|
||||||
Connection(QNetworkAccessManager* c, QNetworkRequest* r, std::shared_ptr<ConnectionConfig> conf);
|
Connection(MainWindow* m, QNetworkAccessManager* c, QNetworkRequest* r, std::shared_ptr<ConnectionConfig> conf);
|
||||||
~Connection();
|
~Connection();
|
||||||
|
|
||||||
|
|
||||||
QNetworkAccessManager* restclient;
|
QNetworkAccessManager* restclient;
|
||||||
QNetworkRequest* request;
|
QNetworkRequest* request;
|
||||||
std::shared_ptr<ConnectionConfig> config;
|
std::shared_ptr<ConnectionConfig> config;
|
||||||
|
MainWindow* main;
|
||||||
|
|
||||||
void doRPC(const json& payload, const std::function<void(json)>& cb,
|
void doRPC(const json& payload, const std::function<void(json)>& cb,
|
||||||
const std::function<void(QNetworkReply::NetworkError, const json&)>& ne);
|
const std::function<void(QNetworkReply*, const json&)>& ne);
|
||||||
|
void doRPCWithDefaultErrorHandling(const json& payload, const std::function<void(json)>& cb);
|
||||||
|
void doRPCIgnoreError(const json& payload, const std::function<void(json)>& cb) ;
|
||||||
|
|
||||||
|
void showTxError(const QString& error);
|
||||||
|
|
||||||
|
// Batch method. Note: Because of the template, it has to be in the header file.
|
||||||
|
template<class T>
|
||||||
|
void doBatchRPC(const QList<T>& payloads,
|
||||||
|
std::function<json(T)> payloadGenerator,
|
||||||
|
std::function<void(QMap<T, json>*)> cb) {
|
||||||
|
auto responses = new QMap<T, json>(); // zAddr -> list of responses for each call.
|
||||||
|
int totalSize = payloads.size();
|
||||||
|
|
||||||
|
for (auto item: payloads) {
|
||||||
|
json payload = payloadGenerator(item);
|
||||||
|
|
||||||
|
QNetworkReply *reply = restclient->post(*request, QByteArray::fromStdString(payload.dump()));
|
||||||
|
|
||||||
|
QObject::connect(reply, &QNetworkReply::finished, [=] {
|
||||||
|
reply->deleteLater();
|
||||||
|
|
||||||
|
auto all = reply->readAll();
|
||||||
|
auto parsed = json::parse(all.toStdString(), nullptr, false);
|
||||||
|
|
||||||
|
if (reply->error() != QNetworkReply::NoError) {
|
||||||
|
qDebug() << QString::fromStdString(parsed.dump());
|
||||||
|
qDebug() << reply->errorString();
|
||||||
|
|
||||||
|
(*responses)[item] = json::object(); // Empty object
|
||||||
|
} else {
|
||||||
|
if (parsed.is_discarded()) {
|
||||||
|
(*responses)[item] = json::object(); // Empty object
|
||||||
|
} else {
|
||||||
|
(*responses)[item] = parsed["result"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
auto waitTimer = new QTimer(main);
|
||||||
|
QObject::connect(waitTimer, &QTimer::timeout, [=]() {
|
||||||
|
if (responses->size() == totalSize) {
|
||||||
|
waitTimer->stop();
|
||||||
|
|
||||||
|
cb(responses);
|
||||||
|
|
||||||
|
waitTimer->deleteLater();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
waitTimer->start(100);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
161
src/rpc.cpp
161
src/rpc.cpp
@@ -71,32 +71,6 @@ void RPC::setConnection(Connection* c) {
|
|||||||
refresh();
|
refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RPC::doRPC(const json& payload, const std::function<void(json)>& cb) {
|
|
||||||
QNetworkReply *reply = conn->restclient->post(*conn->request, QByteArray::fromStdString(payload.dump()));
|
|
||||||
|
|
||||||
QObject::connect(reply, &QNetworkReply::finished, [=] {
|
|
||||||
reply->deleteLater();
|
|
||||||
|
|
||||||
if (reply->error() != QNetworkReply::NoError) {
|
|
||||||
auto parsed = json::parse(reply->readAll(), nullptr, false);
|
|
||||||
if (!parsed.is_discarded() && !parsed["error"]["message"].is_null()) {
|
|
||||||
handleConnectionError(QString::fromStdString(parsed["error"]["message"]));
|
|
||||||
} else {
|
|
||||||
handleConnectionError(reply->errorString());
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto parsed = json::parse(reply->readAll(), nullptr, false);
|
|
||||||
if (parsed.is_discarded()) {
|
|
||||||
handleConnectionError("Unknown error");
|
|
||||||
}
|
|
||||||
|
|
||||||
cb(parsed["result"]);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void RPC::getZAddresses(const std::function<void(json)>& cb) {
|
void RPC::getZAddresses(const std::function<void(json)>& cb) {
|
||||||
json payload = {
|
json payload = {
|
||||||
{"jsonrpc", "1.0"},
|
{"jsonrpc", "1.0"},
|
||||||
@@ -104,7 +78,7 @@ void RPC::getZAddresses(const std::function<void(json)>& cb) {
|
|||||||
{"method", "z_listaddresses"},
|
{"method", "z_listaddresses"},
|
||||||
};
|
};
|
||||||
|
|
||||||
doRPC(payload, cb);
|
conn->doRPCWithDefaultErrorHandling(payload, cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RPC::getTransparentUnspent(const std::function<void(json)>& cb) {
|
void RPC::getTransparentUnspent(const std::function<void(json)>& cb) {
|
||||||
@@ -115,7 +89,7 @@ void RPC::getTransparentUnspent(const std::function<void(json)>& cb) {
|
|||||||
{"params", {0}} // Get UTXOs with 0 confirmations as well.
|
{"params", {0}} // Get UTXOs with 0 confirmations as well.
|
||||||
};
|
};
|
||||||
|
|
||||||
doRPC(payload, cb);
|
conn->doRPCWithDefaultErrorHandling(payload, cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RPC::getZUnspent(const std::function<void(json)>& cb) {
|
void RPC::getZUnspent(const std::function<void(json)>& cb) {
|
||||||
@@ -126,7 +100,7 @@ void RPC::getZUnspent(const std::function<void(json)>& cb) {
|
|||||||
{"params", {0}} // Get UTXOs with 0 confirmations as well.
|
{"params", {0}} // Get UTXOs with 0 confirmations as well.
|
||||||
};
|
};
|
||||||
|
|
||||||
doRPC(payload, cb);
|
conn->doRPCWithDefaultErrorHandling(payload, cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RPC::newZaddr(bool sapling, const std::function<void(json)>& cb) {
|
void RPC::newZaddr(bool sapling, const std::function<void(json)>& cb) {
|
||||||
@@ -137,7 +111,7 @@ void RPC::newZaddr(bool sapling, const std::function<void(json)>& cb) {
|
|||||||
{"params", { sapling ? "sapling" : "sprout" }},
|
{"params", { sapling ? "sapling" : "sprout" }},
|
||||||
};
|
};
|
||||||
|
|
||||||
doRPC(payload, cb);
|
conn->doRPCWithDefaultErrorHandling(payload, cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RPC::newTaddr(const std::function<void(json)>& cb) {
|
void RPC::newTaddr(const std::function<void(json)>& cb) {
|
||||||
@@ -147,7 +121,7 @@ void RPC::newTaddr(const std::function<void(json)>& cb) {
|
|||||||
{"method", "getnewaddress"},
|
{"method", "getnewaddress"},
|
||||||
};
|
};
|
||||||
|
|
||||||
doRPC(payload, cb);
|
conn->doRPCWithDefaultErrorHandling(payload, cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RPC::getZPrivKey(QString addr, const std::function<void(json)>& cb) {
|
void RPC::getZPrivKey(QString addr, const std::function<void(json)>& cb) {
|
||||||
@@ -158,7 +132,7 @@ void RPC::getZPrivKey(QString addr, const std::function<void(json)>& cb) {
|
|||||||
{"params", { addr.toStdString() }},
|
{"params", { addr.toStdString() }},
|
||||||
};
|
};
|
||||||
|
|
||||||
doRPC(payload, cb);
|
conn->doRPCWithDefaultErrorHandling(payload, cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RPC::getTPrivKey(QString addr, const std::function<void(json)>& cb) {
|
void RPC::getTPrivKey(QString addr, const std::function<void(json)>& cb) {
|
||||||
@@ -169,7 +143,7 @@ void RPC::getTPrivKey(QString addr, const std::function<void(json)>& cb) {
|
|||||||
{"params", { addr.toStdString() }},
|
{"params", { addr.toStdString() }},
|
||||||
};
|
};
|
||||||
|
|
||||||
doRPC(payload, cb);
|
conn->doRPCWithDefaultErrorHandling(payload, cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RPC::importZPrivKey(QString addr, bool rescan, const std::function<void(json)>& cb) {
|
void RPC::importZPrivKey(QString addr, bool rescan, const std::function<void(json)>& cb) {
|
||||||
@@ -180,7 +154,7 @@ void RPC::importZPrivKey(QString addr, bool rescan, const std::function<void(jso
|
|||||||
{"params", { addr.toStdString(), (rescan? "yes" : "no") }},
|
{"params", { addr.toStdString(), (rescan? "yes" : "no") }},
|
||||||
};
|
};
|
||||||
|
|
||||||
doSendRPC(payload, cb);
|
conn->doRPCWithDefaultErrorHandling(payload, cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -192,7 +166,7 @@ void RPC::importTPrivKey(QString addr, bool rescan, const std::function<void(jso
|
|||||||
{"params", { addr.toStdString(), (rescan? "yes" : "no") }},
|
{"params", { addr.toStdString(), (rescan? "yes" : "no") }},
|
||||||
};
|
};
|
||||||
|
|
||||||
doSendRPC(payload, cb);
|
conn->doRPCWithDefaultErrorHandling(payload, cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -204,7 +178,7 @@ void RPC::getBalance(const std::function<void(json)>& cb) {
|
|||||||
{"params", {0}} // Get Unconfirmed balance as well.
|
{"params", {0}} // Get Unconfirmed balance as well.
|
||||||
};
|
};
|
||||||
|
|
||||||
doRPC(payload, cb);
|
conn->doRPCWithDefaultErrorHandling(payload, cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RPC::getTransactions(const std::function<void(json)>& cb) {
|
void RPC::getTransactions(const std::function<void(json)>& cb) {
|
||||||
@@ -214,39 +188,7 @@ void RPC::getTransactions(const std::function<void(json)>& cb) {
|
|||||||
{"method", "listtransactions"}
|
{"method", "listtransactions"}
|
||||||
};
|
};
|
||||||
|
|
||||||
doRPC(payload, cb);
|
conn->doRPCWithDefaultErrorHandling(payload, cb);
|
||||||
}
|
|
||||||
|
|
||||||
void RPC::doSendRPC(const json& payload, const std::function<void(json)>& cb, const std::function<void(QString)>& err) {
|
|
||||||
QNetworkReply *reply = conn->restclient->post(*conn->request, QByteArray::fromStdString(payload.dump()));
|
|
||||||
|
|
||||||
QObject::connect(reply, &QNetworkReply::finished, [=] {
|
|
||||||
reply->deleteLater();
|
|
||||||
|
|
||||||
if (reply->error() != QNetworkReply::NoError) {
|
|
||||||
auto parsed = json::parse(reply->readAll(), nullptr, false);
|
|
||||||
if (!parsed.is_discarded() && !parsed["error"]["message"].is_null()) {
|
|
||||||
err(QString::fromStdString(parsed["error"]["message"]));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
err(reply->errorString());
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto parsed = json::parse(reply->readAll(), nullptr, false);
|
|
||||||
if (parsed.is_discarded()) {
|
|
||||||
err("Unknown error");
|
|
||||||
}
|
|
||||||
|
|
||||||
cb(parsed["result"]);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Default implementation of a Send RPC that default shows an error message box with the error.
|
|
||||||
void RPC::doSendRPC(const json& payload, const std::function<void(json)>& cb) {
|
|
||||||
doSendRPC(payload, cb, [=](auto error) { this->handleTxError(error); });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RPC::sendZTransaction(json params, const std::function<void(json)>& cb) {
|
void RPC::sendZTransaction(json params, const std::function<void(json)>& cb) {
|
||||||
@@ -257,76 +199,9 @@ void RPC::sendZTransaction(json params, const std::function<void(json)>& cb) {
|
|||||||
{"params", params}
|
{"params", params}
|
||||||
};
|
};
|
||||||
|
|
||||||
doSendRPC(payload, cb);
|
conn->doRPCWithDefaultErrorHandling(payload, cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RPC::handleConnectionError(const QString& error) {
|
|
||||||
if (error.isNull()) return;
|
|
||||||
|
|
||||||
QIcon icon = QApplication::style()->standardIcon(QStyle::SP_MessageBoxCritical);
|
|
||||||
main->statusIcon->setPixmap(icon.pixmap(16, 16));
|
|
||||||
main->statusLabel->setText("No Connection");
|
|
||||||
|
|
||||||
if (firstTime) {
|
|
||||||
this->firstTime = false;
|
|
||||||
|
|
||||||
QMessageBox msg(main);
|
|
||||||
msg.setIcon(QMessageBox::Icon::Critical);
|
|
||||||
msg.setWindowTitle("Connection Error");
|
|
||||||
|
|
||||||
QString explanation;
|
|
||||||
if (error.contains("authentication", Qt::CaseInsensitive)) {
|
|
||||||
explanation = QString()
|
|
||||||
% "\n\nThis is most likely because of misconfigured rpcuser/rpcpassword. "
|
|
||||||
% "zcashd needs the following options set in ~/.zcash/zcash.conf\n\n"
|
|
||||||
% "rpcuser=<someusername>\n"
|
|
||||||
% "rpcpassword=<somepassword>\n"
|
|
||||||
% "\nIf you're connecting to a remote note, you can change the username/password in the "
|
|
||||||
% "File->Settings menu.";
|
|
||||||
} else if (error.contains("connection refused", Qt::CaseInsensitive)) {
|
|
||||||
auto confLocation = Settings::getInstance()->getZcashdConfLocation();
|
|
||||||
if (confLocation.isEmpty()) {
|
|
||||||
explanation = QString()
|
|
||||||
% "\n\nA zcash.conf was not found on this machine. If you are connecting to a remote/non-standard node "
|
|
||||||
% "please set the host/port and user/password in the File->Settings menu.";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
explanation = QString()
|
|
||||||
% "\n\nA zcash.conf was found at\n" % confLocation
|
|
||||||
% "\nbut we can't connect to zcashd. Is rpcuser=<user> and rpcpassword=<pass> set in the zcash.conf file?";
|
|
||||||
}
|
|
||||||
} else if (error.contains("internal server error", Qt::CaseInsensitive) ||
|
|
||||||
error.contains("rewinding", Qt::CaseInsensitive) ||
|
|
||||||
error.contains("loading", Qt::CaseInsensitive)) {
|
|
||||||
explanation = QString()
|
|
||||||
% "\n\nIf you just started zcashd, then it's still loading and you might have to wait a while. If zcashd is ready, then you've run into "
|
|
||||||
% "something unexpected, and might need to file a bug report here: https://github.com/adityapk00/zec-qt-wallet/issues";
|
|
||||||
} else {
|
|
||||||
explanation = QString()
|
|
||||||
% "\n\nThis is most likely an internal error. Something unexpected happened. "
|
|
||||||
% "You might need to file a bug report here: https://github.com/adityapk00/zec-qt-wallet/issues";
|
|
||||||
}
|
|
||||||
|
|
||||||
msg.setText("There was a network connection error. The error was: \n\n"
|
|
||||||
+ error + explanation);
|
|
||||||
|
|
||||||
msg.exec();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RPC::handleTxError(const QString& error) {
|
|
||||||
if (error.isNull()) return;
|
|
||||||
|
|
||||||
QMessageBox msg(main);
|
|
||||||
msg.setIcon(QMessageBox::Icon::Critical);
|
|
||||||
msg.setWindowTitle("Transaction Error");
|
|
||||||
|
|
||||||
msg.setText("There was an error sending the transaction. The error was: \n\n"
|
|
||||||
+ error);
|
|
||||||
|
|
||||||
msg.exec();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Build the RPC JSON Parameters for this tx (with the dev fee included if applicable)
|
// Build the RPC JSON Parameters for this tx (with the dev fee included if applicable)
|
||||||
@@ -377,7 +252,7 @@ void RPC::refreshReceivedZTrans(QList<QString> zaddrs) {
|
|||||||
// and each z-Addr can have multiple received txs.
|
// and each z-Addr can have multiple received txs.
|
||||||
|
|
||||||
// 1. For each z-Addr, get list of received txs
|
// 1. For each z-Addr, get list of received txs
|
||||||
getBatchRPC<QString>(zaddrs,
|
conn->doBatchRPC<QString>(zaddrs,
|
||||||
[=] (QString zaddr) {
|
[=] (QString zaddr) {
|
||||||
json payload = {
|
json payload = {
|
||||||
{"jsonrpc", "1.0"},
|
{"jsonrpc", "1.0"},
|
||||||
@@ -414,7 +289,7 @@ void RPC::refreshReceivedZTrans(QList<QString> zaddrs) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 2. For all txids, go and get the details of that txid.
|
// 2. For all txids, go and get the details of that txid.
|
||||||
getBatchRPC<QString>(txids.toList(),
|
conn->doBatchRPC<QString>(txids.toList(),
|
||||||
[=] (QString txid) {
|
[=] (QString txid) {
|
||||||
json payload = {
|
json payload = {
|
||||||
{"jsonrpc", "1.0"},
|
{"jsonrpc", "1.0"},
|
||||||
@@ -488,7 +363,7 @@ void RPC::getInfoThenRefresh(bool force) {
|
|||||||
{"method", "getinfo"}
|
{"method", "getinfo"}
|
||||||
};
|
};
|
||||||
|
|
||||||
doRPC(payload, [=] (const json& reply) {
|
conn->doRPCIgnoreError(payload, [=] (const json& reply) {
|
||||||
// Testnet?
|
// Testnet?
|
||||||
if (!reply["testnet"].is_null()) {
|
if (!reply["testnet"].is_null()) {
|
||||||
Settings::getInstance()->setTestnet(reply["testnet"].get<json::boolean_t>());
|
Settings::getInstance()->setTestnet(reply["testnet"].get<json::boolean_t>());
|
||||||
@@ -517,7 +392,7 @@ void RPC::getInfoThenRefresh(bool force) {
|
|||||||
{"method", "getblockchaininfo"}
|
{"method", "getblockchaininfo"}
|
||||||
};
|
};
|
||||||
|
|
||||||
doRPC(payload, [=](const json& reply) {
|
conn->doRPCIgnoreError(payload, [=](const json& reply) {
|
||||||
auto progress = reply["verificationprogress"].get<double>();
|
auto progress = reply["verificationprogress"].get<double>();
|
||||||
bool isSyncing = progress < 0.999; // 99.9%
|
bool isSyncing = progress < 0.999; // 99.9%
|
||||||
int blockNumber = reply["blocks"].get<json::number_unsigned_t>();
|
int blockNumber = reply["blocks"].get<json::number_unsigned_t>();
|
||||||
@@ -693,7 +568,7 @@ void RPC::refreshSentZTrans() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Look up all the txids to get the confirmation count for them.
|
// Look up all the txids to get the confirmation count for them.
|
||||||
getBatchRPC<QString>(txids,
|
conn->doBatchRPC<QString>(txids,
|
||||||
[=] (QString txid) {
|
[=] (QString txid) {
|
||||||
json payload = {
|
json payload = {
|
||||||
{"jsonrpc", "1.0"},
|
{"jsonrpc", "1.0"},
|
||||||
@@ -741,7 +616,7 @@ void RPC::watchTxStatus() {
|
|||||||
{"method", "z_getoperationstatus"},
|
{"method", "z_getoperationstatus"},
|
||||||
};
|
};
|
||||||
|
|
||||||
doRPC(payload, [=] (const json& reply) {
|
conn->doRPCWithDefaultErrorHandling(payload, [=] (const json& reply) {
|
||||||
// There's an array for each item in the status
|
// There's an array for each item in the status
|
||||||
for (auto& it : reply.get<json::array_t>()) {
|
for (auto& it : reply.get<json::array_t>()) {
|
||||||
// If we were watching this Tx and it's status became "success", then we'll show a status bar alert
|
// If we were watching this Tx and it's status became "success", then we'll show a status bar alert
|
||||||
|
|||||||
56
src/rpc.h
56
src/rpc.h
@@ -56,64 +56,12 @@ public:
|
|||||||
void importZPrivKey(QString addr, bool rescan, const std::function<void(json)>& cb);
|
void importZPrivKey(QString addr, bool rescan, const std::function<void(json)>& cb);
|
||||||
void importTPrivKey(QString addr, bool rescan, const std::function<void(json)>& cb);
|
void importTPrivKey(QString addr, bool rescan, const std::function<void(json)>& cb);
|
||||||
|
|
||||||
Turnstile* getTurnstile() { return turnstile; }
|
Turnstile* getTurnstile() { return turnstile; }
|
||||||
|
Connection* getConnection() { return conn; }
|
||||||
// Batch method. Note: Because of the template, it has to be in the header file.
|
|
||||||
template<class T>
|
|
||||||
void getBatchRPC(const QList<T>& payloads,
|
|
||||||
std::function<json(T)> payloadGenerator,
|
|
||||||
std::function<void(QMap<T, json>*)> cb) {
|
|
||||||
auto responses = new QMap<T, json>(); // zAddr -> list of responses for each call.
|
|
||||||
int totalSize = payloads.size();
|
|
||||||
|
|
||||||
for (auto item: payloads) {
|
|
||||||
json payload = payloadGenerator(item);
|
|
||||||
|
|
||||||
QNetworkReply *reply = conn->restclient->post(*conn->request, QByteArray::fromStdString(payload.dump()));
|
|
||||||
|
|
||||||
QObject::connect(reply, &QNetworkReply::finished, [=] {
|
|
||||||
reply->deleteLater();
|
|
||||||
|
|
||||||
auto all = reply->readAll();
|
|
||||||
auto parsed = json::parse(all.toStdString(), nullptr, false);
|
|
||||||
|
|
||||||
if (reply->error() != QNetworkReply::NoError) {
|
|
||||||
qDebug() << QString::fromStdString(parsed.dump());
|
|
||||||
qDebug() << reply->errorString();
|
|
||||||
|
|
||||||
(*responses)[item] = json::object(); // Empty object
|
|
||||||
} else {
|
|
||||||
if (parsed.is_discarded()) {
|
|
||||||
(*responses)[item] = json::object(); // Empty object
|
|
||||||
} else {
|
|
||||||
(*responses)[item] = parsed["result"];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
auto waitTimer = new QTimer(main);
|
|
||||||
QObject::connect(waitTimer, &QTimer::timeout, [=]() {
|
|
||||||
if (responses->size() == totalSize) {
|
|
||||||
waitTimer->stop();
|
|
||||||
|
|
||||||
cb(responses);
|
|
||||||
|
|
||||||
waitTimer->deleteLater();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
waitTimer->start(100);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void noConnection();
|
void noConnection();
|
||||||
|
|
||||||
void doRPC (const json& payload, const std::function<void(json)>& cb);
|
|
||||||
void doSendRPC(const json& payload, const std::function<void(json)>& cb);
|
|
||||||
void doSendRPC(const json& payload, const std::function<void(json)>& cb, const std::function<void(QString)>& err);
|
|
||||||
|
|
||||||
void refreshBalances();
|
void refreshBalances();
|
||||||
|
|
||||||
void refreshTransactions();
|
void refreshTransactions();
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ void Turnstile::planMigration(QString zaddr, QString destAddr, int numsplits, in
|
|||||||
auto splits = splitAmount(bal, numsplits);
|
auto splits = splitAmount(bal, numsplits);
|
||||||
|
|
||||||
// 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->getConnection()->doBatchRPC<double>(splits,
|
||||||
[=] (double /*unused*/) {
|
[=] (double /*unused*/) {
|
||||||
json payload = {
|
json payload = {
|
||||||
{"jsonrpc", "1.0"},
|
{"jsonrpc", "1.0"},
|
||||||
|
|||||||
Reference in New Issue
Block a user