Wire up send
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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, "");
|
||||
},
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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++) {
|
||||
|
||||
Reference in New Issue
Block a user