From fef2a7727d311f722336afb4a48012f0b1472880 Mon Sep 17 00:00:00 2001 From: Aditya Kulkarni Date: Tue, 23 Oct 2018 10:32:22 -0700 Subject: [PATCH] Add batch RPC methods --- src/rpc.cpp | 113 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/rpc.h | 6 +++ 2 files changed, 119 insertions(+) diff --git a/src/rpc.cpp b/src/rpc.cpp index 0e1cc0e..3e42b1b 100644 --- a/src/rpc.cpp +++ b/src/rpc.cpp @@ -285,6 +285,116 @@ void RPC::handleTxError(const QString& error) { } +void RPC::getBatchRPC( + const QList& payloads, + std::function payloadGenerator, + std::function*)> cb) +{ + auto responses = new QMap(); // 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); +} + +/// Batch RPC methods +void RPC::getReceivedZTrans(QList zaddrs) { + // 1. For each z-Addr, get list of received txs + getBatchRPC(zaddrs, + [=] (QString zaddr) { + json payload = { + {"jsonrpc", "1.0"}, + {"id", "z_lrba"}, + {"method", "z_listreceivedbyaddress"}, + {"params", {zaddr.toStdString(), 0}} // Accept 0 conf as well. + }; + + return payload; + }, + [=] (QMap* zaddrTxids) { + // Process all txids + QSet txids; + for (auto it = zaddrTxids->constBegin(); it != zaddrTxids->constEnd(); it++) { + for (auto& i : it.value().get()) { + txids.insert(QString::fromStdString(i["txid"].get())); + } + } + + // 2. For all txids, go and get the details of that txid. + getBatchRPC(txids.toList(), + [=] (QString txid) { + json payload = { + {"jsonrpc", "1.0"}, + {"id", "gettx"}, + {"method", "gettransaction"}, + {"params", {txid.toStdString()}} + }; + + return payload; + }, + [=] (QMap* txidDetails) { + // Combine them both together. For every zAddr's txid, get the amount, fee, confirmations and time + for (auto it = zaddrTxids->constBegin(); it != zaddrTxids->constEnd(); it++) { + for (auto& i : it.value().get()) { + auto zaddr = it.key(); + auto txid = QString::fromStdString(i["txid"].get()); + + // Lookup txid in the map + auto txidInfo = txidDetails->value(txid); + + // And then find the values + auto timestamp = txidInfo["time"].get(); + auto amount = i["amount"].get(); + + std::cout << zaddr.toStdString() << ":" << txid.toStdString() << ":" << timestamp << ":" << amount << std::endl; + } + } + + // Cleanup both responses; + delete zaddrTxids; + delete txidDetails; + } + ); + } + ); +} + + /// This will refresh all the balance data from zcashd void RPC::refresh() { // First, test the connection to see if we can actually get info. @@ -356,6 +466,9 @@ void RPC::refreshAddresses() { auto addr = QString::fromStdString(it.get()); zaddresses->push_back(addr); } + + // Temp + getReceivedZTrans(*zaddresses); }); } diff --git a/src/rpc.h b/src/rpc.h index 9936c55..22b5b0c 100644 --- a/src/rpc.h +++ b/src/rpc.h @@ -56,6 +56,12 @@ private: void handleConnectionError (const QString& error); void handleTxError (const QString& error); + // Batch + void getReceivedZTrans(QList zaddrs); + void getBatchRPC(const QList& payloads, + std::function payloadGenerator, + std::function*)> cb); + QNetworkAccessManager* restclient; QNetworkRequest request;