Wire up send

This commit is contained in:
Aditya Kulkarni
2019-10-18 13:17:21 -07:00
parent 5d86deeb5f
commit 3c2b3c513f
13 changed files with 117 additions and 226 deletions

View File

@@ -100,7 +100,7 @@ void ConnectionLoader::showError(QString explanation) {
* Connection, Executor and Callback Class
************************************************************************************/
void Executor::run() {
char* resp = litelib_execute(this->cmd.toStdString().c_str());
char* resp = litelib_execute(this->cmd.toStdString().c_str(), this->args.toStdString().c_str());
// Copy the string, since we need to return this back to rust
char* resp_copy = new char[strlen(resp) + 1];
@@ -111,14 +111,17 @@ void Executor::run() {
memset(resp_copy, '-', strlen(resp_copy));
delete[] resp_copy;
qDebug() << "Reply=" << reply;
qDebug() << "Reply=" << reply;
auto parsed = json::parse(reply.toStdString().c_str(), nullptr, false);
const bool isGuiThread =
QThread::currentThread() == QCoreApplication::instance()->thread();
if (parsed.is_discarded() || parsed.is_null()) {
emit handleError(reply);
} else {
const bool isGuiThread =
QThread::currentThread() == QCoreApplication::instance()->thread();
qDebug() << "executing RPC: isGUI=" << isGuiThread;
emit responseReady(parsed);
emit responseReady(parsed);
}
}

View File

@@ -39,14 +39,6 @@ Controller::Controller(MainWindow* main) {
});
timer->start(Settings::updateSpeed);
// Set up the timer to watch for tx status
txTimer = new QTimer(main);
QObject::connect(txTimer, &QTimer::timeout, [=]() {
watchTxStatus();
});
// Start at every 10s. When an operation is pending, this will change to every second
txTimer->start(Settings::updateSpeed);
// Create the data model
model = new DataModel();
@@ -94,10 +86,8 @@ void Controller::setConnection(Connection* c) {
// Build the RPC JSON Parameters for this tx
void Controller::fillTxJsonParams(json& params, Tx tx) {
Q_ASSERT(params.is_array());
// Get all the addresses and amounts
json allRecepients = json::array();
void Controller::fillTxJsonParams(json& allRecepients, Tx tx) {
Q_ASSERT(allRecepients.is_array());
// For each addr/amt/memo, construct the JSON and also build the confirm dialog box
for (int i=0; i < tx.toAddrs.size(); i++) {
@@ -106,24 +96,18 @@ void Controller::fillTxJsonParams(json& params, Tx tx) {
// Construct the JSON params
json rec = json::object();
rec["address"] = toAddr.addr.toStdString();
// Force it through string for rounding. Without this, decimal points beyond 8 places
// will appear, causing an "invalid amount" error
rec["amount"] = Settings::getDecimalString(toAddr.amount).toStdString(); //.toDouble();
if (Settings::isZAddress(toAddr.addr) && !toAddr.encodedMemo.trimmed().isEmpty())
rec["memo"] = toAddr.encodedMemo.toStdString();
rec["amount"] = toAddr.amount;
if (Settings::isZAddress(toAddr.addr) && !toAddr.memo.trimmed().isEmpty())
rec["memo"] = toAddr.memo.toStdString();
allRecepients.push_back(rec);
}
// Add sender
params.push_back(tx.fromAddr.toStdString());
params.push_back(allRecepients);
// Add fees if custom fees are allowed.
if (Settings::getInstance()->getAllowCustomFees()) {
params.push_back(1); // minconf
params.push_back(tx.fee);
}
// // Add fees if custom fees are allowed.
// if (Settings::getInstance()->getAllowCustomFees()) {
// params.push_back(1); // minconf
// params.push_back(tx.fee);
// }
}
@@ -396,22 +380,13 @@ void Controller::refreshTransactions() {
});
}
void Controller::addNewTxToWatch(const QString& newOpid, WatchedTx wtx) {
watchingOps.insert(newOpid, wtx);
watchTxStatus();
}
/**
* Execute a transaction with the standard UI. i.e., standard status bar message and standard error
* handling
*/
void Controller::executeStandardUITransaction(Tx tx) {
executeTransaction(tx,
[=] (QString opid) {
ui->statusBar->showMessage(QObject::tr("Computing Tx: ") % opid);
},
[=] (QString, QString txid) {
executeTransaction(tx,
[=] (QString txid) {
ui->statusBar->showMessage(Settings::txidStatusMessage + " " + txid);
},
[=] (QString opid, QString errStr) {
@@ -428,20 +403,20 @@ void Controller::executeStandardUITransaction(Tx tx) {
// Execute a transaction!
void Controller::executeTransaction(Tx tx,
const std::function<void(QString opid)> submitted,
const std::function<void(QString opid, QString txid)> computed,
const std::function<void(QString opid, QString errStr)> error) {
const std::function<void(QString txid)> submitted,
const std::function<void(QString txid, QString errStr)> error) {
// First, create the json params
json params = json::array();
fillTxJsonParams(params, tx);
std::cout << std::setw(2) << params << std::endl;
zrpc->sendZTransaction(params, [=](const json& reply) {
QString opid = QString::fromStdString(reply.get<json::string_t>());
zrpc->sendTransaction(QString::fromStdString(params.dump()), [=](const json& reply) {
if (reply["result"].is_null() || reply["result"] != "success") {
error("", "Couldn't understand Response: " + QString::fromStdString(reply.dump()));
}
// And then start monitoring the transaction
addNewTxToWatch( opid, WatchedTx { opid, tx, computed, error} );
submitted(opid);
QString txid = QString::fromStdString(reply["txid"].get<json::string_t>());
submitted(txid);
},
[=](QString errStr) {
error("", errStr);
@@ -449,56 +424,6 @@ void Controller::executeTransaction(Tx tx,
}
void Controller::watchTxStatus() {
if (!zrpc->haveConnection())
return noConnection();
zrpc->fetchOpStatus([=] (const json& reply) {
// There's an array for each item in the status
for (auto& it : reply.get<json::array_t>()) {
// If we were watching this Tx and its status became "success", then we'll show a status bar alert
QString id = QString::fromStdString(it["id"]);
if (watchingOps.contains(id)) {
// And if it ended up successful
QString status = QString::fromStdString(it["status"]);
main->loadingLabel->setVisible(false);
if (status == "success") {
auto txid = QString::fromStdString(it["result"]["txid"]);
auto wtx = watchingOps[id];
watchingOps.remove(id);
wtx.completed(id, txid);
// Refresh balances to show unconfirmed balances
refresh(true);
} else if (status == "failed") {
// If it failed, then we'll actually show a warning.
auto errorMsg = QString::fromStdString(it["error"]["message"]);
auto wtx = watchingOps[id];
watchingOps.remove(id);
wtx.error(id, errorMsg);
}
}
if (watchingOps.isEmpty()) {
txTimer->start(Settings::updateSpeed);
} else {
txTimer->start(Settings::quickUpdateSpeed);
}
}
// If there is some op that we are watching, then show the loading bar, otherwise hide it
if (watchingOps.empty()) {
main->loadingLabel->setVisible(false);
} else {
main->loadingLabel->setVisible(true);
main->loadingLabel->setToolTip(QString::number(watchingOps.size()) + QObject::tr(" tx computing. This can take several minutes."));
}
});
}
void Controller::checkForUpdate(bool silent) {
if (!zrpc->haveConnection())
return noConnection();

View File

@@ -50,17 +50,11 @@ public:
void executeStandardUITransaction(Tx tx);
void executeTransaction(Tx tx,
const std::function<void(QString opid)> submitted,
const std::function<void(QString opid, QString txid)> computed,
const std::function<void(QString opid, QString errStr)> error);
const std::function<void(QString txid)> submitted,
const std::function<void(QString txid, QString errStr)> error);
void fillTxJsonParams(json& params, Tx tx);
void watchTxStatus();
const QMap<QString, WatchedTx> getWatchingTxns() { return watchingOps; }
void addNewTxToWatch(const QString& newOpid, WatchedTx wtx);
const TxTableModel* getTransactionsModel() { return transactionsTableModel; }
void shutdownZcashd();
@@ -94,8 +88,6 @@ private:
QProcess* ezcashd = nullptr;
QMap<QString, WatchedTx> watchingOps;
TxTableModel* transactionsTableModel = nullptr;
BalancesTableModel* balancesTableModel = nullptr;

View File

@@ -158,25 +158,12 @@ void LiteInterface::fetchTransactions(const std::function<void(json)>& cb) {
conn->doRPCWithDefaultErrorHandling("list", "", cb);
}
void LiteInterface::sendZTransaction(json params, const std::function<void(json)>& cb,
void LiteInterface::sendTransaction(QString params, const std::function<void(json)>& cb,
const std::function<void(QString)>& err) {
if (conn == nullptr)
return;
// json payload = {
// {"jsonrpc", "1.0"},
// {"id", "someid"},
// {"method", "z_sendmany"},
// {"params", params}
// };
// conn->doRPC(payload, cb, [=] (auto reply, auto parsed) {
// if (!parsed.is_discarded() && !parsed["error"]["message"].is_null()) {
// err(QString::fromStdString(parsed["error"]["message"]));
// } else {
// err(reply->errorString());
// }
// });
conn->doRPC("send", params, cb, err);
}
void LiteInterface::fetchInfo(const std::function<void(json)>& cb,

View File

@@ -68,7 +68,7 @@ public:
void fetchAllPrivKeys(const std::function<void(QList<QPair<QString, QString>>)>);
void sendZTransaction(json params, const std::function<void(json)>& cb, const std::function<void(QString)>& err);
void sendTransaction(QString params, const std::function<void(json)>& cb, const std::function<void(QString)>& err);
private:
Connection* conn = nullptr;

View File

@@ -18,8 +18,7 @@ using json = nlohmann::json;
struct ToFields {
QString addr;
double amount;
QString txtMemo;
QString encodedMemo;
QString memo;
};
// Struct used to represent a Transaction.

View File

@@ -137,7 +137,7 @@ RecurringPaymentInfo* Recurring::getNewRecurringFromTx(QWidget* parent, MainWind
// Default is USD
ui.lblAmt->setText(Settings::getUSDFromZecAmount(tx.toAddrs[0].amount));
ui.txtMemo->setPlainText(tx.toAddrs[0].txtMemo);
ui.txtMemo->setPlainText(tx.toAddrs[0].memo);
ui.txtMemo->setEnabled(false);
}
@@ -199,7 +199,7 @@ RecurringPaymentInfo* Recurring::getNewRecurringFromTx(QWidget* parent, MainWind
void Recurring::updateInfoWithTx(RecurringPaymentInfo* r, Tx tx) {
r->toAddr = tx.toAddrs[0].addr;
r->memo = tx.toAddrs[0].txtMemo;
r->memo = tx.toAddrs[0].memo;
r->fromAddr = tx.fromAddr;
if (r->currency.isEmpty() || r->currency == "USD") {
r->currency = "USD";
@@ -485,7 +485,7 @@ void Recurring::executeRecurringPayment(MainWindow* main, RecurringPaymentInfo r
if (paymentNumbers.size() > 1)
amt *= paymentNumbers.size();
tx.toAddrs.append(ToFields { rpi.toAddr, amt, rpi.memo, rpi.memo.toUtf8().toHex() });
tx.toAddrs.append(ToFields { rpi.toAddr, amt, rpi.memo });
// To prevent some weird race conditions, we immediately mark the payment as paid.
// If something goes wrong, we'll get the error callback below, and the status will be
@@ -514,10 +514,8 @@ void Recurring::executeRecurringPayment(MainWindow* main, RecurringPaymentInfo r
* Execute a send Tx
*/
void Recurring::doSendTx(MainWindow* mainwindow, Tx tx, std::function<void(QString, QString)> cb) {
mainwindow->getRPC()->executeTransaction(tx, [=] (QString opid) {
mainwindow->ui->statusBar->showMessage(QObject::tr("Computing Recurring Tx: ") % opid);
},
[=] (QString /*opid*/, QString txid) {
mainwindow->getRPC()->executeTransaction(tx,
[=] (QString txid) {
mainwindow->ui->statusBar->showMessage(Settings::txidStatusMessage + " " + txid);
cb(txid, "");
},

View File

@@ -521,7 +521,7 @@ Tx MainWindow::createTxFromSendPage() {
totalAmt += amt;
QString memo = ui->sendToWidgets->findChild<QLabel*>(QString("MemoTxt") % QString::number(i+1))->text().trimmed();
tx.toAddrs.push_back( ToFields{addr, amt, memo, memo.toUtf8().toHex()} );
tx.toAddrs.push_back( ToFields{addr, amt, memo} );
}
if (Settings::getInstance()->getAllowCustomFees()) {
@@ -550,7 +550,7 @@ Tx MainWindow::createTxFromSendPage() {
if (Settings::getDecimalString(change) != "0") {
QString changeMemo = tr("Change from ") + tx.fromAddr;
tx.toAddrs.push_back(ToFields{ *saplingAddr, change, changeMemo, changeMemo.toUtf8().toHex() });
tx.toAddrs.push_back(ToFields{ *saplingAddr, change, changeMemo });
}
}
}
@@ -649,11 +649,11 @@ bool MainWindow::confirmTx(Tx tx, RecurringPaymentInfo* rpi) {
confirm.gridLayout->addWidget(AmtUSD, row, 2, 1, 1);
// Memo
if (Settings::isZAddress(toAddr.addr) && !toAddr.txtMemo.isEmpty()) {
if (Settings::isZAddress(toAddr.addr) && !toAddr.memo.isEmpty()) {
row++;
auto Memo = new QLabel(confirm.sendToAddrs);
Memo->setObjectName(QStringLiteral("Memo") % QString::number(i + 1));
Memo->setText(toAddr.txtMemo);
Memo->setText(toAddr.memo);
QFont font1 = Addr->font();
font1.setPointSize(font1.pointSize() - 1);
Memo->setFont(font1);
@@ -769,12 +769,7 @@ void MainWindow::sendButton() {
// And send the Tx
rpc->executeTransaction(tx,
// Submitted
[=] (QString opid) {
ui->statusBar->showMessage(tr("Computing Tx: ") % opid);
},
// Accepted
[=] (QString, QString txid) {
[=] (QString txid) {
ui->statusBar->showMessage(Settings::txidStatusMessage + " " + txid);
// If this was a recurring payment, update the payment with the info

View File

@@ -683,7 +683,7 @@ void AppDataServer::processSendTx(QJsonObject sendTx, MainWindow* mainwindow, st
});
tx.fromAddr = bals[0].first;
tx.toAddrs = { ToFields{ sendTx["to"].toString(), amt, sendTx["memo"].toString(), sendTx["memo"].toString().toUtf8().toHex()} };
tx.toAddrs = { ToFields{ sendTx["to"].toString(), amt, sendTx["memo"].toString()} };
// TODO: Respect the autoshield change setting
@@ -699,9 +699,7 @@ void AppDataServer::processSendTx(QJsonObject sendTx, MainWindow* mainwindow, st
// And send the Tx
mainwindow->getRPC()->executeTransaction(tx,
[=] (QString) {},
// Submitted Tx successfully
[=] (QString, QString txid) {
[=] (QString txid) {
auto r = QJsonDocument(QJsonObject{
{"version", 1.0},
{"command", "sendTxSubmitted"},
@@ -771,20 +769,6 @@ void AppDataServer::processGetInfo(QJsonObject jobj, MainWindow* mainWindow, std
void AppDataServer::processGetTransactions(MainWindow* mainWindow, std::shared_ptr<ClientWebSocket> pClient) {
QJsonArray txns;
auto model = mainWindow->getRPC()->getTransactionsModel();
// Manually add pending ops, so that computing transactions will also show up
auto wtxns = mainWindow->getRPC()->getWatchingTxns();
for (auto opid : wtxns.keys()) {
txns.append(QJsonObject{
{"type", "send"},
{"datetime", QDateTime::currentSecsSinceEpoch()},
{"amount", Settings::getDecimalString(wtxns[opid].tx.toAddrs[0].amount)},
{"txid", ""},
{"address", wtxns[opid].tx.toAddrs[0].addr},
{"memo", wtxns[opid].tx.toAddrs[0].txtMemo},
{"confirmations", 0}
});
}
// Add transactions
for (int i = 0; i < model->rowCount(QModelIndex()) && i < Settings::getMaxMobileAppTxns(); i++) {