Merge pull request #32 from adityapk00/embedded
Embedded zcashd for windows and linux
This commit is contained in:
@@ -6,5 +6,8 @@
|
|||||||
<file>res/connected.gif</file>
|
<file>res/connected.gif</file>
|
||||||
<file>res/loading.gif</file>
|
<file>res/loading.gif</file>
|
||||||
<file>res/icon.ico</file>
|
<file>res/icon.ico</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
|
<qresource prefix="/img">
|
||||||
|
<file>res/zcashdlogo.gif</file>
|
||||||
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|||||||
BIN
res/zcashdlogo.gif
Normal file
BIN
res/zcashdlogo.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.1 KiB |
@@ -15,48 +15,287 @@ ConnectionLoader::ConnectionLoader(MainWindow* main, RPC* rpc) {
|
|||||||
d = new QDialog(main);
|
d = new QDialog(main);
|
||||||
connD = new Ui_ConnectionDialog();
|
connD = new Ui_ConnectionDialog();
|
||||||
connD->setupUi(d);
|
connD->setupUi(d);
|
||||||
|
connD->topIcon->setBasePixmap(QIcon(":/icons/res/icon.ico").pixmap(256, 256));
|
||||||
// Center on screen
|
|
||||||
QRect screenGeometry = QApplication::desktop()->screenGeometry(d);
|
|
||||||
int x = (screenGeometry.width() - d->width()) / 2;
|
|
||||||
int y = (screenGeometry.height() - d->height()) / 2;
|
|
||||||
d->move(x, y);
|
|
||||||
connD->buttonBox->setEnabled(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ConnectionLoader::~ConnectionLoader() {
|
ConnectionLoader::~ConnectionLoader() {
|
||||||
delete d;
|
delete d;
|
||||||
delete connD;
|
delete connD;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConnectionLoader::loadConnection() {
|
void ConnectionLoader::loadConnection() {
|
||||||
|
QTimer::singleShot(1, [=]() { this->doAutoConnect(); });
|
||||||
|
d->exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectionLoader::doAutoConnect() {
|
||||||
// Priority 1: Try to connect to detect zcash.conf and connect to it.
|
// Priority 1: Try to connect to detect zcash.conf and connect to it.
|
||||||
auto config = autoDetectZcashConf();
|
auto config = autoDetectZcashConf();
|
||||||
|
|
||||||
// If not autodetected, go and read the UI Settings
|
if (config.get() != nullptr) {
|
||||||
if (config.get() == nullptr) {
|
auto connection = makeConnection(config);
|
||||||
config = loadFromSettings();
|
|
||||||
|
|
||||||
if (config.get() == nullptr) {
|
refreshZcashdState(connection, [=] () {
|
||||||
// Nothing configured, show an error
|
// Refused connection. So try and start embedded zcashd
|
||||||
QString explanation = QString()
|
if (Settings::getInstance()->useEmbedded()) {
|
||||||
% "A zcash.conf was not found on this machine.\n\n"
|
this->showInformation("Starting Embedded zcashd");
|
||||||
% "If you are connecting to a remote/non-standard node "
|
if (this->startEmbeddedZcashd()) {
|
||||||
% "please set the host/port and user/password in the Edit->Settings menu.";
|
// Embedded zcashd started up. Wait a second and then refresh the connection
|
||||||
|
QTimer::singleShot(1000, [=]() { doAutoConnect(); } );
|
||||||
|
} else {
|
||||||
|
// Errored out, show error and exit
|
||||||
|
QString explanation = QString() % "Couldn't start the embedded zcashd.\n\n" %
|
||||||
|
"Maybe the zcash-params are corrupt? Please delete your zcash-params directory and restart.\n\n" %
|
||||||
|
(ezcashd ? "The process returned:\n\n" % ezcashd->errorString() : QString(""));
|
||||||
|
this->showError(explanation);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// zcash.conf exists, there's no connection, and the user asked us not to start zcashd. Error!
|
||||||
|
QString explanation = QString() % "Couldn't connect to zcashd configured in zcash.conf.\n\n" %
|
||||||
|
"Not starting embedded zcashd because --no-embedded was passed";
|
||||||
|
this->showError(explanation);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if (Settings::getInstance()->useEmbedded()) {
|
||||||
|
// zcash.conf was not found, so create one
|
||||||
|
createZcashConf();
|
||||||
|
} else {
|
||||||
|
// Fall back to manual connect
|
||||||
|
doManualConnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
showError(explanation);
|
QString randomPassword() {
|
||||||
doRPCSetConnection(nullptr);
|
static const char alphanum[] =
|
||||||
|
"0123456789"
|
||||||
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||||
|
"abcdefghijklmnopqrstuvwxyz";
|
||||||
|
|
||||||
|
const int passwordLength = 10;
|
||||||
|
char* s = new char[passwordLength + 1];
|
||||||
|
|
||||||
|
for (int i = 0; i < passwordLength; ++i) {
|
||||||
|
s[i] = alphanum[rand() % (sizeof(alphanum) - 1)];
|
||||||
|
}
|
||||||
|
|
||||||
|
s[passwordLength] = 0;
|
||||||
|
return QString::fromStdString(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This will create a new zcash.conf, download zcash parameters.
|
||||||
|
*/
|
||||||
|
void ConnectionLoader::createZcashConf() {
|
||||||
|
// Fetch params. After params are fetched, create the zcash.conf file and
|
||||||
|
// try loading the connection again
|
||||||
|
downloadParams([=] () {
|
||||||
|
auto confLocation = zcashConfWritableLocation();
|
||||||
|
qDebug() << "Creating file " << confLocation;
|
||||||
|
|
||||||
|
QFileInfo fi(confLocation);
|
||||||
|
QDir().mkdir(fi.dir().absolutePath());
|
||||||
|
|
||||||
|
QFile file(confLocation);
|
||||||
|
if (!file.open(QIODevice::ReadWrite | QIODevice::Truncate)) {
|
||||||
|
qDebug() << "Could not create zcash.conf, returning";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QTextStream out(&file);
|
||||||
|
|
||||||
|
out << "server=1\n";
|
||||||
|
out << "rpcuser=zec-qt-wallet\n";
|
||||||
|
out << "rpcpassword=" % randomPassword() << "\n";
|
||||||
|
file.close();
|
||||||
|
|
||||||
|
this->doAutoConnect();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ConnectionLoader::downloadParams(std::function<void(void)> cb) {
|
||||||
|
// Add all the files to the download queue
|
||||||
|
downloadQueue = new QQueue<QUrl>();
|
||||||
|
client = new QNetworkAccessManager(main);
|
||||||
|
|
||||||
|
downloadQueue->enqueue(QUrl("https://z.cash/downloads/sapling-output.params"));
|
||||||
|
downloadQueue->enqueue(QUrl("https://z.cash/downloads/sapling-spend.params"));
|
||||||
|
downloadQueue->enqueue(QUrl("https://z.cash/downloads/sprout-proving.key"));
|
||||||
|
downloadQueue->enqueue(QUrl("https://z.cash/downloads/sprout-verifying.key"));
|
||||||
|
downloadQueue->enqueue(QUrl("https://z.cash/downloads/sprout-groth16.params"));
|
||||||
|
|
||||||
|
doNextDownload(cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectionLoader::doNextDownload(std::function<void(void)> cb) {
|
||||||
|
auto fnSaveFileName = [&] (QUrl url) {
|
||||||
|
QString path = url.path();
|
||||||
|
QString basename = QFileInfo(path).fileName();
|
||||||
|
|
||||||
|
return basename;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (downloadQueue->isEmpty()) {
|
||||||
|
delete downloadQueue;
|
||||||
|
client->deleteLater();
|
||||||
|
|
||||||
|
this->showInformation("All Downloads Finished Successfully!");
|
||||||
|
cb();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QUrl url = downloadQueue->dequeue();
|
||||||
|
int filesRemaining = downloadQueue->size();
|
||||||
|
|
||||||
|
QString filename = fnSaveFileName(url);
|
||||||
|
QString paramsDir = zcashParamsDir();
|
||||||
|
|
||||||
|
if (QFile(QDir(paramsDir).filePath(filename)).exists()) {
|
||||||
|
qDebug() << filename << " already exists, skipping ";
|
||||||
|
doNextDownload(cb);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The downloaded file is written to a new name, and then renamed when the operation completes.
|
||||||
|
currentOutput = new QFile(QDir(paramsDir).filePath(filename + ".part"));
|
||||||
|
|
||||||
|
if (!currentOutput->open(QIODevice::WriteOnly)) {
|
||||||
|
this->showError("Couldn't download params. Please check the help site for more info.");
|
||||||
|
}
|
||||||
|
qDebug() << "Downloading " << url << " to " << filename;
|
||||||
|
|
||||||
|
QNetworkRequest request(url);
|
||||||
|
request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||||
|
currentDownload = client->get(request);
|
||||||
|
downloadTime.start();
|
||||||
|
|
||||||
|
// Download Progress
|
||||||
|
QObject::connect(currentDownload, &QNetworkReply::downloadProgress, [=] (auto done, auto total) {
|
||||||
|
// calculate the download speed
|
||||||
|
double speed = done * 1000.0 / downloadTime.elapsed();
|
||||||
|
QString unit;
|
||||||
|
if (speed < 1024) {
|
||||||
|
unit = "bytes/sec";
|
||||||
|
} else if (speed < 1024*1024) {
|
||||||
|
speed /= 1024;
|
||||||
|
unit = "kB/s";
|
||||||
|
} else {
|
||||||
|
speed /= 1024*1024;
|
||||||
|
unit = "MB/s";
|
||||||
|
}
|
||||||
|
|
||||||
|
this->showInformation(
|
||||||
|
"Downloading " % filename % (filesRemaining > 1 ? " ( +" % QString::number(filesRemaining) % " more remaining )" : QString("")),
|
||||||
|
QString::number(done/1024/1024, 'f', 0) % "MB of " % QString::number(total/1024/1024, 'f', 0) + "MB at " % QString::number(speed, 'f', 2) % unit);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Download Finished
|
||||||
|
QObject::connect(currentDownload, &QNetworkReply::finished, [=] () {
|
||||||
|
// Rename file
|
||||||
|
currentOutput->rename(QDir(paramsDir).filePath(filename));
|
||||||
|
|
||||||
|
currentOutput->close();
|
||||||
|
currentDownload->deleteLater();
|
||||||
|
currentOutput->deleteLater();
|
||||||
|
|
||||||
|
if (currentDownload->error()) {
|
||||||
|
this->showError("Downloading " + filename + " failed/ Please check the help site for more info");
|
||||||
|
} else {
|
||||||
|
doNextDownload(cb);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Download new data available.
|
||||||
|
QObject::connect(currentDownload, &QNetworkReply::readyRead, [=] () {
|
||||||
|
currentOutput->write(currentDownload->readAll());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ConnectionLoader::startEmbeddedZcashd() {
|
||||||
|
if (!Settings::getInstance()->useEmbedded())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (ezcashd != nullptr) {
|
||||||
|
if (ezcashd->state() == QProcess::NotRunning) {
|
||||||
|
qDebug() << "Process started and then crashed";
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally, start zcashd
|
||||||
|
qDebug() << "Starting zcashd";
|
||||||
|
QFileInfo fi(Settings::getInstance()->getExecName());
|
||||||
|
#ifdef Q_OS_LINUX
|
||||||
|
auto zcashdProgram = fi.dir().absoluteFilePath("zcashd");
|
||||||
|
#elif defined(Q_OS_DARWIN)
|
||||||
|
auto zcashdProgram = fi.dir().absoluteFilePath("zcashd");
|
||||||
|
#else
|
||||||
|
auto zcashdProgram = fi.dir().absoluteFilePath("zcashd.exe");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!QFile(zcashdProgram).exists()) {
|
||||||
|
qDebug() << "Can't find zcashd at " << zcashdProgram;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ezcashd = new QProcess(main);
|
||||||
|
QObject::connect(ezcashd, &QProcess::started, [=] () {
|
||||||
|
qDebug() << "zcashd started";
|
||||||
|
});
|
||||||
|
|
||||||
|
QObject::connect(ezcashd, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
|
||||||
|
[=](int exitCode, QProcess::ExitStatus exitStatus) {
|
||||||
|
qDebug() << "zcashd finished with code " << exitCode << "," << exitStatus;
|
||||||
|
});
|
||||||
|
|
||||||
|
QObject::connect(ezcashd, &QProcess::errorOccurred, [&] (auto error) mutable {
|
||||||
|
qDebug() << "Couldn't start zcashd: " << error;
|
||||||
|
});
|
||||||
|
|
||||||
|
ezcashd->start(zcashdProgram);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectionLoader::doManualConnect() {
|
||||||
|
auto config = loadFromSettings();
|
||||||
|
|
||||||
|
if (!config) {
|
||||||
|
// Nothing configured, show an error
|
||||||
|
QString explanation = QString()
|
||||||
|
% "A manual connection was requested, but the settings are not configured.\n\n"
|
||||||
|
% "Please set the host/port and user/password in the Edit->Settings menu.";
|
||||||
|
|
||||||
|
showError(explanation);
|
||||||
|
doRPCSetConnection(nullptr);
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto connection = makeConnection(config);
|
auto connection = makeConnection(config);
|
||||||
refreshZcashdState(connection);
|
refreshZcashdState(connection, [=] () {
|
||||||
|
QString explanation = QString()
|
||||||
|
% "Could not connect to zcashd configured in settings.\n\n"
|
||||||
|
% "Please set the host/port and user/password in the Edit->Settings menu.";
|
||||||
|
|
||||||
|
showError(explanation);
|
||||||
|
doRPCSetConnection(nullptr);
|
||||||
|
|
||||||
|
return;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConnectionLoader::doRPCSetConnection(Connection* conn) {
|
void ConnectionLoader::doRPCSetConnection(Connection* conn) {
|
||||||
|
rpc->setEZcashd(ezcashd);
|
||||||
rpc->setConnection(conn);
|
rpc->setConnection(conn);
|
||||||
|
|
||||||
|
d->accept();
|
||||||
|
|
||||||
delete this;
|
delete this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,7 +318,7 @@ Connection* ConnectionLoader::makeConnection(std::shared_ptr<ConnectionConfig> c
|
|||||||
return new Connection(main, client, request, config);
|
return new Connection(main, client, request, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConnectionLoader::refreshZcashdState(Connection* connection) {
|
void ConnectionLoader::refreshZcashdState(Connection* connection, std::function<void(void)> refused) {
|
||||||
json payload = {
|
json payload = {
|
||||||
{"jsonrpc", "1.0"},
|
{"jsonrpc", "1.0"},
|
||||||
{"id", "someid"},
|
{"id", "someid"},
|
||||||
@@ -91,53 +330,49 @@ void ConnectionLoader::refreshZcashdState(Connection* connection) {
|
|||||||
d->hide();
|
d->hide();
|
||||||
this->doRPCSetConnection(connection);
|
this->doRPCSetConnection(connection);
|
||||||
},
|
},
|
||||||
[=] (auto reply, auto res) {
|
[=] (auto reply, auto res) {
|
||||||
auto err = reply->error();
|
|
||||||
// Failed, see what it is.
|
// Failed, see what it is.
|
||||||
|
auto err = reply->error();
|
||||||
//qDebug() << err << ":" << QString::fromStdString(res.dump());
|
//qDebug() << err << ":" << QString::fromStdString(res.dump());
|
||||||
|
|
||||||
if (err == QNetworkReply::NetworkError::ConnectionRefusedError) {
|
if (err == QNetworkReply::NetworkError::ConnectionRefusedError) {
|
||||||
auto isZcashConfFound = connection->config.get()->usingZcashConf;
|
refused();
|
||||||
QString explanation = QString()
|
|
||||||
% (isZcashConfFound ? "A zcash.conf file was found, but a" : "A")
|
|
||||||
% " connection to zcashd could not be established.\n\n"
|
|
||||||
% "If you are connecting to a remote/non-standard node "
|
|
||||||
% "please set the host/port and user/password in the Edit->Settings menu";
|
|
||||||
|
|
||||||
this->showError(explanation);
|
|
||||||
} else if (err == QNetworkReply::NetworkError::AuthenticationRequiredError) {
|
} else if (err == QNetworkReply::NetworkError::AuthenticationRequiredError) {
|
||||||
QString explanation = QString()
|
QString explanation = QString()
|
||||||
% "Authentication failed. The username / password you specified was "
|
% "Authentication failed. The username / password you specified was "
|
||||||
% "not accepted by zcashd. Try changing it in the Edit->Settings menu";
|
% "not accepted by zcashd. Try changing it in the Edit->Settings menu";
|
||||||
|
|
||||||
this->showError(explanation);
|
this->showError(explanation);
|
||||||
} else if (err == QNetworkReply::NetworkError::InternalServerError && !res.is_discarded()) {
|
} else if (err == QNetworkReply::NetworkError::InternalServerError &&
|
||||||
d->show();
|
!res.is_discarded()) {
|
||||||
|
|
||||||
// The server is loading, so just poll until it succeeds
|
// The server is loading, so just poll until it succeeds
|
||||||
QString status = QString::fromStdString(res["error"]["message"]);
|
QString status = QString::fromStdString(res["error"]["message"]);
|
||||||
|
this->showInformation("Your zcashd is starting up. Please wait.", status);
|
||||||
QIcon icon = QApplication::style()->standardIcon(QStyle::SP_MessageBoxInformation);
|
|
||||||
connD->icon->setPixmap(icon.pixmap(128, 128));
|
|
||||||
connD->status->setText("Your zcashd is starting up. Please wait.\n\n" % status);
|
|
||||||
|
|
||||||
// Refresh after one second
|
// Refresh after one second
|
||||||
QTimer::singleShot(1000, [=]() { this->refreshZcashdState(connection); });
|
QTimer::singleShot(1000, [=]() { this->refreshZcashdState(connection, refused); });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConnectionLoader::showError(QString explanation) {
|
void ConnectionLoader::showInformation(QString info, QString detail) {
|
||||||
QMessageBox::critical(main, "Connection Error", explanation, QMessageBox::Ok);
|
connD->status->setText(info);
|
||||||
|
connD->statusDetail->setText(detail);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Try to automatically detect a zcash.conf file in the correct location and load parameters
|
* Show error will close the loading dialog and show an error.
|
||||||
*/
|
*/
|
||||||
std::shared_ptr<ConnectionConfig> ConnectionLoader::autoDetectZcashConf() {
|
void ConnectionLoader::showError(QString explanation) {
|
||||||
|
rpc->setEZcashd(nullptr);
|
||||||
|
rpc->noConnection();
|
||||||
|
|
||||||
|
QMessageBox::critical(main, "Connection Error", explanation, QMessageBox::Ok);
|
||||||
|
d->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ConnectionLoader::locateZcashConfFile() {
|
||||||
#ifdef Q_OS_LINUX
|
#ifdef Q_OS_LINUX
|
||||||
auto confLocation = QStandardPaths::locate(QStandardPaths::HomeLocation, ".zcash/zcash.conf");
|
auto confLocation = QStandardPaths::locate(QStandardPaths::HomeLocation, ".zcash/zcash.conf");
|
||||||
#elif defined(Q_OS_DARWIN)
|
#elif defined(Q_OS_DARWIN)
|
||||||
@@ -145,8 +380,42 @@ std::shared_ptr<ConnectionConfig> ConnectionLoader::autoDetectZcashConf() {
|
|||||||
#else
|
#else
|
||||||
auto confLocation = QStandardPaths::locate(QStandardPaths::AppDataLocation, "../../Zcash/zcash.conf");
|
auto confLocation = QStandardPaths::locate(QStandardPaths::AppDataLocation, "../../Zcash/zcash.conf");
|
||||||
#endif
|
#endif
|
||||||
|
return QDir::cleanPath(confLocation);
|
||||||
|
}
|
||||||
|
|
||||||
confLocation = QDir::cleanPath(confLocation);
|
QString ConnectionLoader::zcashConfWritableLocation() {
|
||||||
|
#ifdef Q_OS_LINUX
|
||||||
|
auto confLocation = QDir(QStandardPaths::writableLocation(QStandardPaths::HomeLocation)).filePath(".zcash/zcash.conf");
|
||||||
|
#elif defined(Q_OS_DARWIN)
|
||||||
|
auto confLocation = QDir(QStandardPaths::writableLocation(QStandardPaths::HomeLocation)).filePath("/Library/Application Support/Zcash/zcash.conf");
|
||||||
|
#else
|
||||||
|
auto confLocation = QDir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)).filePath("../../Zcash/zcash.conf");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return confLocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ConnectionLoader::zcashParamsDir() {
|
||||||
|
#ifdef Q_OS_LINUX
|
||||||
|
auto paramsLocation = QDir(QDir(QStandardPaths::writableLocation(QStandardPaths::HomeLocation)).filePath(".zcash-params"));
|
||||||
|
#elif defined(Q_OS_DARWIN)
|
||||||
|
//auto paramsLocation = QDir(QStandardPaths::writableLocation(QStandardPaths::HomeLocation)).filePath("/Library/Application Support/Zcash/zcash.conf");
|
||||||
|
#else
|
||||||
|
auto paramsLocation = QDir(QDir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)).filePath("../../ZcashParams"));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!paramsLocation.exists()) {
|
||||||
|
QDir().mkpath(paramsLocation.absolutePath());
|
||||||
|
}
|
||||||
|
|
||||||
|
return paramsLocation.absolutePath();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Try to automatically detect a zcash.conf file in the correct location and load parameters
|
||||||
|
*/
|
||||||
|
std::shared_ptr<ConnectionConfig> ConnectionLoader::autoDetectZcashConf() {
|
||||||
|
auto confLocation = locateZcashConfFile();
|
||||||
|
|
||||||
if (confLocation.isNull()) {
|
if (confLocation.isNull()) {
|
||||||
// No zcash file, just return with nothing
|
// No zcash file, just return with nothing
|
||||||
@@ -240,10 +509,19 @@ 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*, const json&)>& ne) {
|
const std::function<void(QNetworkReply*, const json&)>& ne) {
|
||||||
|
if (shutdownInProgress) {
|
||||||
|
qDebug() << "Ignoring RPC because shutdown in progress";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
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, [=] {
|
||||||
reply->deleteLater();
|
reply->deleteLater();
|
||||||
|
if (shutdownInProgress) {
|
||||||
|
qDebug() << "Ignoring callback because shutdown in progress";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
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);
|
||||||
@@ -283,3 +561,10 @@ void Connection::showTxError(const QString& error) {
|
|||||||
QMessageBox::critical(main, "Transaction Error", "There was an error sending the transaction. The error was: \n\n"
|
QMessageBox::critical(main, "Transaction Error", "There was an error sending the transaction. The error was: \n\n"
|
||||||
+ error, QMessageBox::StandardButton::Ok);
|
+ error, QMessageBox::StandardButton::Ok);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prevent all future calls from going through
|
||||||
|
*/
|
||||||
|
void Connection::shutdown() {
|
||||||
|
shutdownInProgress = true;
|
||||||
|
}
|
||||||
|
|||||||
@@ -41,18 +41,39 @@ private:
|
|||||||
|
|
||||||
Connection* makeConnection(std::shared_ptr<ConnectionConfig> config);
|
Connection* makeConnection(std::shared_ptr<ConnectionConfig> config);
|
||||||
|
|
||||||
void refreshZcashdState(Connection* connection);
|
void doAutoConnect();
|
||||||
int getProgressFromStatus(QString status);
|
void doManualConnect();
|
||||||
|
|
||||||
|
void createZcashConf();
|
||||||
|
QString locateZcashConfFile();
|
||||||
|
QString zcashConfWritableLocation();
|
||||||
|
QString zcashParamsDir();
|
||||||
|
|
||||||
|
void downloadParams(std::function<void(void)> cb);
|
||||||
|
void doNextDownload(std::function<void(void)> cb);
|
||||||
|
bool startEmbeddedZcashd();
|
||||||
|
|
||||||
|
void refreshZcashdState(Connection* connection, std::function<void(void)> refused);
|
||||||
|
|
||||||
void showError(QString explanation);
|
void showError(QString explanation);
|
||||||
|
void showInformation(QString info, QString detail = "");
|
||||||
|
|
||||||
void doRPCSetConnection(Connection* conn);
|
void doRPCSetConnection(Connection* conn);
|
||||||
|
|
||||||
|
QProcess* ezcashd = nullptr;
|
||||||
|
|
||||||
QDialog* d;
|
QDialog* d;
|
||||||
Ui_ConnectionDialog* connD;
|
Ui_ConnectionDialog* connD;
|
||||||
|
|
||||||
MainWindow* main;
|
MainWindow* main;
|
||||||
RPC* rpc;
|
RPC* rpc;
|
||||||
|
|
||||||
|
QNetworkReply* currentDownload = nullptr;
|
||||||
|
QFile* currentOutput = nullptr;
|
||||||
|
QQueue<QUrl>* downloadQueue = nullptr;
|
||||||
|
|
||||||
|
QNetworkAccessManager* client = nullptr;
|
||||||
|
QTime downloadTime;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -69,6 +90,8 @@ public:
|
|||||||
std::shared_ptr<ConnectionConfig> config;
|
std::shared_ptr<ConnectionConfig> config;
|
||||||
MainWindow* main;
|
MainWindow* main;
|
||||||
|
|
||||||
|
void shutdown();
|
||||||
|
|
||||||
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*, const json&)>& ne);
|
const std::function<void(QNetworkReply*, const json&)>& ne);
|
||||||
void doRPCWithDefaultErrorHandling(const json& payload, const std::function<void(json)>& cb);
|
void doRPCWithDefaultErrorHandling(const json& payload, const std::function<void(json)>& cb);
|
||||||
@@ -122,6 +145,9 @@ public:
|
|||||||
});
|
});
|
||||||
waitTimer->start(100);
|
waitTimer->start(100);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool shutdownInProgress = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -2,6 +2,9 @@
|
|||||||
<ui version="4.0">
|
<ui version="4.0">
|
||||||
<class>ConnectionDialog</class>
|
<class>ConnectionDialog</class>
|
||||||
<widget class="QDialog" name="ConnectionDialog">
|
<widget class="QDialog" name="ConnectionDialog">
|
||||||
|
<property name="windowModality">
|
||||||
|
<enum>Qt::ApplicationModal</enum>
|
||||||
|
</property>
|
||||||
<property name="geometry">
|
<property name="geometry">
|
||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
@@ -16,98 +19,75 @@
|
|||||||
<property name="modal">
|
<property name="modal">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout">
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
<item row="4" column="1">
|
<property name="leftMargin">
|
||||||
<widget class="QDialogButtonBox" name="buttonBox">
|
<number>0</number>
|
||||||
<property name="orientation">
|
</property>
|
||||||
<enum>Qt::Horizontal</enum>
|
<property name="topMargin">
|
||||||
</property>
|
<number>0</number>
|
||||||
<property name="standardButtons">
|
</property>
|
||||||
<set>QDialogButtonBox::Close</set>
|
<property name="rightMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="FilledIconLabel" name="topIcon">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="0" rowspan="2">
|
<item>
|
||||||
<widget class="QLabel" name="icon">
|
<widget class="Line" name="line_2">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="status">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>TextLabel</string>
|
<string>Starting Up</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="alignment">
|
<property name="alignment">
|
||||||
<set>Qt::AlignCenter</set>
|
<set>Qt::AlignCenter</set>
|
||||||
</property>
|
</property>
|
||||||
<property name="margin">
|
|
||||||
<number>20</number>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="3" 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">
|
|
||||||
<spacer name="verticalSpacer">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Vertical</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>20</width>
|
|
||||||
<height>40</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="1" rowspan="2">
|
|
||||||
<widget class="QLabel" name="status">
|
|
||||||
<property name="text">
|
|
||||||
<string>Connection Status</string>
|
|
||||||
</property>
|
|
||||||
<property name="alignment">
|
|
||||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
|
||||||
</property>
|
|
||||||
<property name="wordWrap">
|
<property name="wordWrap">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="statusDetail">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="Line" name="line">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
|
<customwidgets>
|
||||||
|
<customwidget>
|
||||||
|
<class>FilledIconLabel</class>
|
||||||
|
<extends>QLabel</extends>
|
||||||
|
<header>fillediconlabel.h</header>
|
||||||
|
</customwidget>
|
||||||
|
</customwidgets>
|
||||||
<resources/>
|
<resources/>
|
||||||
<connections>
|
<connections/>
|
||||||
<connection>
|
|
||||||
<sender>buttonBox</sender>
|
|
||||||
<signal>accepted()</signal>
|
|
||||||
<receiver>ConnectionDialog</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>ConnectionDialog</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>
|
</ui>
|
||||||
|
|||||||
27
src/fillediconlabel.cpp
Normal file
27
src/fillediconlabel.cpp
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
#include "fillediconlabel.h"
|
||||||
|
|
||||||
|
FilledIconLabel::FilledIconLabel(QWidget* parent) :
|
||||||
|
QLabel(parent) {
|
||||||
|
this->setMinimumSize(1, 1);
|
||||||
|
setScaledContents(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FilledIconLabel::setBasePixmap(QPixmap pm) {
|
||||||
|
basePm = pm;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When resized, we re-draw the whole pixmap, resizing it as needed.
|
||||||
|
*/
|
||||||
|
void FilledIconLabel::resizeEvent(QResizeEvent*) {
|
||||||
|
QSize sz = size();
|
||||||
|
|
||||||
|
QPixmap scaled = basePm.scaled(sz, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||||
|
|
||||||
|
QPixmap p(sz);
|
||||||
|
p.fill(Qt::white);
|
||||||
|
QPainter painter(&p);
|
||||||
|
painter.drawPixmap((sz.width() - scaled.width()) / 2, (sz.height() - scaled.height()) / 2, scaled);
|
||||||
|
|
||||||
|
QLabel::setPixmap(p);
|
||||||
|
}
|
||||||
21
src/fillediconlabel.h
Normal file
21
src/fillediconlabel.h
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
#ifndef FILLEDICONLABEL_H
|
||||||
|
#define FILLEDICONLABEL_H
|
||||||
|
|
||||||
|
#include "precompiled.h"
|
||||||
|
|
||||||
|
class FilledIconLabel : public QLabel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit FilledIconLabel(QWidget *parent = 0);
|
||||||
|
void setBasePixmap(QPixmap pm);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void resizeEvent(QResizeEvent *);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QPixmap basePm;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // FILLEDICONLABEL_H
|
||||||
@@ -20,6 +20,13 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
std::srand(static_cast<unsigned int>(std::time(nullptr)));
|
std::srand(static_cast<unsigned int>(std::time(nullptr)));
|
||||||
Settings::init();
|
Settings::init();
|
||||||
|
Settings::getInstance()->setExecName(argv[0]);
|
||||||
|
|
||||||
|
if (argc >= 2 && QString::fromStdString(argv[1]) == "--no-embedded") {
|
||||||
|
Settings::getInstance()->setUseEmbedded(false);
|
||||||
|
} else {
|
||||||
|
Settings::getInstance()->setUseEmbedded(true);
|
||||||
|
}
|
||||||
|
|
||||||
QCoreApplication::setOrganizationName("zec-qt-wallet-org");
|
QCoreApplication::setOrganizationName("zec-qt-wallet-org");
|
||||||
QCoreApplication::setApplicationName("zec-qt-wallet");
|
QCoreApplication::setApplicationName("zec-qt-wallet");
|
||||||
|
|||||||
@@ -75,6 +75,7 @@ MainWindow::MainWindow(QWidget *parent) :
|
|||||||
setupRecieveTab();
|
setupRecieveTab();
|
||||||
setupBalancesTab();
|
setupBalancesTab();
|
||||||
setupTurnstileDialog();
|
setupTurnstileDialog();
|
||||||
|
setupZcashdTab();
|
||||||
|
|
||||||
rpc = new RPC(this);
|
rpc = new RPC(this);
|
||||||
|
|
||||||
@@ -97,6 +98,10 @@ void MainWindow::closeEvent(QCloseEvent* event) {
|
|||||||
s.setValue("baltablegeometry", ui->balancesTable->horizontalHeader()->saveState());
|
s.setValue("baltablegeometry", ui->balancesTable->horizontalHeader()->saveState());
|
||||||
s.setValue("tratablegeometry", ui->transactionsTable->horizontalHeader()->saveState());
|
s.setValue("tratablegeometry", ui->transactionsTable->horizontalHeader()->saveState());
|
||||||
|
|
||||||
|
// Let the RPC know to shutdown any running service.
|
||||||
|
rpc->shutdownZcashd();
|
||||||
|
|
||||||
|
// Bubble up
|
||||||
QMainWindow::closeEvent(event);
|
QMainWindow::closeEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -369,13 +374,6 @@ void MainWindow::setupSettingsModal() {
|
|||||||
QIntValidator validator(0, 65535);
|
QIntValidator validator(0, 65535);
|
||||||
settings.port->setValidator(&validator);
|
settings.port->setValidator(&validator);
|
||||||
|
|
||||||
// Load current values into the dialog
|
|
||||||
auto conf = Settings::getInstance()->getSettings();
|
|
||||||
settings.hostname->setText(conf.host);
|
|
||||||
settings.port->setText(conf.port);
|
|
||||||
settings.rpcuser->setText(conf.rpcuser);
|
|
||||||
settings.rpcpassword->setText(conf.rpcpassword);
|
|
||||||
|
|
||||||
// If values are coming from zcash.conf, then disable all the fields
|
// If values are coming from zcash.conf, then disable all the fields
|
||||||
auto zcashConfLocation = Settings::getInstance()->getZcashdConfLocation();
|
auto zcashConfLocation = Settings::getInstance()->getZcashdConfLocation();
|
||||||
if (!zcashConfLocation.isEmpty()) {
|
if (!zcashConfLocation.isEmpty()) {
|
||||||
@@ -386,6 +384,13 @@ void MainWindow::setupSettingsModal() {
|
|||||||
settings.rpcpassword->setEnabled(false);
|
settings.rpcpassword->setEnabled(false);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
// Load current values into the dialog
|
||||||
|
auto conf = Settings::getInstance()->getSettings();
|
||||||
|
settings.hostname->setText(conf.host);
|
||||||
|
settings.port->setText(conf.port);
|
||||||
|
settings.rpcuser->setText(conf.rpcuser);
|
||||||
|
settings.rpcpassword->setText(conf.rpcpassword);
|
||||||
|
|
||||||
settings.confMsg->setText("No local zcash.conf found. Please configure connection manually.");
|
settings.confMsg->setText("No local zcash.conf found. Please configure connection manually.");
|
||||||
settings.hostname->setEnabled(true);
|
settings.hostname->setEnabled(true);
|
||||||
settings.port->setEnabled(true);
|
settings.port->setEnabled(true);
|
||||||
@@ -739,6 +744,10 @@ void MainWindow::setupBalancesTab() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::setupZcashdTab() {
|
||||||
|
ui->zcashdlogo->setBasePixmap(QPixmap(":/img/res/zcashdlogo.gif"));
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::setupTransactionsTab() {
|
void MainWindow::setupTransactionsTab() {
|
||||||
// Double click opens up memo if one exists
|
// Double click opens up memo if one exists
|
||||||
QObject::connect(ui->transactionsTable, &QTableView::doubleClicked, [=] (auto index) {
|
QObject::connect(ui->transactionsTable, &QTableView::doubleClicked, [=] (auto index) {
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ private:
|
|||||||
void setupTransactionsTab();
|
void setupTransactionsTab();
|
||||||
void setupRecieveTab();
|
void setupRecieveTab();
|
||||||
void setupBalancesTab();
|
void setupBalancesTab();
|
||||||
|
void setupZcashdTab();
|
||||||
|
|
||||||
void setupTurnstileDialog();
|
void setupTurnstileDialog();
|
||||||
void setupSettingsModal();
|
void setupSettingsModal();
|
||||||
|
|||||||
@@ -6,8 +6,8 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>889</width>
|
<width>968</width>
|
||||||
<height>603</height>
|
<height>616</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
<item row="0" column="0">
|
<item row="0" column="0">
|
||||||
<widget class="QTabWidget" name="tabWidget">
|
<widget class="QTabWidget" name="tabWidget">
|
||||||
<property name="currentIndex">
|
<property name="currentIndex">
|
||||||
<number>1</number>
|
<number>4</number>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QWidget" name="tab">
|
<widget class="QWidget" name="tab">
|
||||||
<attribute name="title">
|
<attribute name="title">
|
||||||
@@ -316,8 +316,8 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>841</width>
|
<width>922</width>
|
||||||
<height>321</height>
|
<height>376</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="sendToLayout">
|
<layout class="QVBoxLayout" name="sendToLayout">
|
||||||
@@ -715,6 +715,145 @@
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
|
<widget class="QWidget" name="tab_5">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>zcashd</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_7">
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_14">
|
||||||
|
<item>
|
||||||
|
<widget class="FilledIconLabel" name="zcashdlogo">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="scaledContents">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="groupBox_5">
|
||||||
|
<property name="title">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_5">
|
||||||
|
<item row="5" column="0" colspan="3">
|
||||||
|
<widget class="QLabel" name="label_14">
|
||||||
|
<property name="text">
|
||||||
|
<string>You are currently not mining</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="6" column="0">
|
||||||
|
<spacer name="verticalSpacer_4">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="2">
|
||||||
|
<widget class="QLabel" name="numconnections">
|
||||||
|
<property name="text">
|
||||||
|
<string>Loading...</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="label_10">
|
||||||
|
<property name="text">
|
||||||
|
<string>Block height</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="2">
|
||||||
|
<widget class="QLabel" name="solrate">
|
||||||
|
<property name="text">
|
||||||
|
<string>Loading...</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="0">
|
||||||
|
<widget class="QLabel" name="label_12">
|
||||||
|
<property name="text">
|
||||||
|
<string>Network solution rate</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QLabel" name="label_8">
|
||||||
|
<property name="text">
|
||||||
|
<string>Connections</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="2">
|
||||||
|
<widget class="QLabel" name="blockheight">
|
||||||
|
<property name="text">
|
||||||
|
<string>Loading...</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="0" colspan="3">
|
||||||
|
<widget class="Line" name="line_2">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<spacer name="verticalSpacer_3">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="1">
|
||||||
|
<widget class="QLabel" name="label_9">
|
||||||
|
<property name="text">
|
||||||
|
<string>|</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="QLabel" name="label_11">
|
||||||
|
<property name="text">
|
||||||
|
<string>|</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QLabel" name="label_13">
|
||||||
|
<property name="text">
|
||||||
|
<string>|</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
@@ -724,8 +863,8 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>889</width>
|
<width>968</width>
|
||||||
<height>22</height>
|
<height>21</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QMenu" name="menuFile">
|
<widget class="QMenu" name="menuFile">
|
||||||
@@ -835,6 +974,11 @@
|
|||||||
<extends>QLabel</extends>
|
<extends>QLabel</extends>
|
||||||
<header>qrcodelabel.h</header>
|
<header>qrcodelabel.h</header>
|
||||||
</customwidget>
|
</customwidget>
|
||||||
|
<customwidget>
|
||||||
|
<class>FilledIconLabel</class>
|
||||||
|
<extends>QLabel</extends>
|
||||||
|
<header>fillediconlabel.h</header>
|
||||||
|
</customwidget>
|
||||||
</customwidgets>
|
</customwidgets>
|
||||||
<tabstops>
|
<tabstops>
|
||||||
<tabstop>tabWidget</tabstop>
|
<tabstop>tabWidget</tabstop>
|
||||||
|
|||||||
@@ -39,6 +39,8 @@
|
|||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
|
#include <QQueue>
|
||||||
|
#include <QProcess>
|
||||||
#include <QDesktopServices>
|
#include <QDesktopServices>
|
||||||
#include <QtNetwork/QNetworkRequest>
|
#include <QtNetwork/QNetworkRequest>
|
||||||
#include <QtNetwork/QNetworkAccessManager>
|
#include <QtNetwork/QNetworkAccessManager>
|
||||||
|
|||||||
105
src/rpc.cpp
105
src/rpc.cpp
@@ -8,7 +8,9 @@ using json = nlohmann::json;
|
|||||||
|
|
||||||
RPC::RPC(MainWindow* main) {
|
RPC::RPC(MainWindow* main) {
|
||||||
auto cl = new ConnectionLoader(main, this);
|
auto cl = new ConnectionLoader(main, this);
|
||||||
cl->loadConnection();
|
|
||||||
|
// Execute the load connection async, so we can set up the rest of RPC properly.
|
||||||
|
QTimer::singleShot(1, [=]() {cl->loadConnection(); });
|
||||||
|
|
||||||
this->main = main;
|
this->main = main;
|
||||||
this->ui = main->ui;
|
this->ui = main->ui;
|
||||||
@@ -62,12 +64,21 @@ RPC::~RPC() {
|
|||||||
delete conn;
|
delete conn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RPC::setEZcashd(QProcess* p) {
|
||||||
|
ezcashd = p;
|
||||||
|
|
||||||
|
if (ezcashd == nullptr)
|
||||||
|
ui->tabWidget->removeTab(4);
|
||||||
|
}
|
||||||
|
|
||||||
void RPC::setConnection(Connection* c) {
|
void RPC::setConnection(Connection* c) {
|
||||||
if (c == nullptr) return;
|
if (c == nullptr) return;
|
||||||
|
|
||||||
delete conn;
|
delete conn;
|
||||||
this->conn = c;
|
this->conn = c;
|
||||||
|
|
||||||
|
ui->statusBar->showMessage("Ready!");
|
||||||
|
|
||||||
refreshZECPrice();
|
refreshZECPrice();
|
||||||
refresh();
|
refresh();
|
||||||
}
|
}
|
||||||
@@ -209,6 +220,10 @@ void RPC::sendZTransaction(json params, const std::function<void(json)>& cb) {
|
|||||||
* private keys
|
* private keys
|
||||||
*/
|
*/
|
||||||
void RPC::getAllPrivKeys(const std::function<void(QList<QPair<QString, QString>>)> cb) {
|
void RPC::getAllPrivKeys(const std::function<void(QList<QPair<QString, QString>>)> cb) {
|
||||||
|
if (conn == nullptr) {
|
||||||
|
// No connection, just return
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// A special function that will call the callback when two lists have been added
|
// A special function that will call the callback when two lists have been added
|
||||||
auto holder = new QPair<int, QList<QPair<QString, QString>>>();
|
auto holder = new QPair<int, QList<QPair<QString, QString>>>();
|
||||||
@@ -314,8 +329,10 @@ void RPC::fillTxJsonParams(json& params, Tx tx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void RPC::noConnection() {
|
void RPC::noConnection() {
|
||||||
ui->statusBar->showMessage("No Connection to zcashd");
|
QIcon i = QApplication::style()->standardIcon(QStyle::SP_MessageBoxCritical);
|
||||||
|
main->statusIcon->setPixmap(i.pixmap(16, 16));
|
||||||
|
main->statusLabel->setText("No Connection");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Refresh received z txs by calling z_listreceivedbyaddress/gettransaction
|
// Refresh received z txs by calling z_listreceivedbyaddress/gettransaction
|
||||||
@@ -427,7 +444,6 @@ void RPC::refreshReceivedZTrans(QList<QString> zaddrs) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// This will refresh all the balance data from zcashd
|
/// This will refresh all the balance data from zcashd
|
||||||
void RPC::refresh(bool force) {
|
void RPC::refresh(bool force) {
|
||||||
if (conn == nullptr)
|
if (conn == nullptr)
|
||||||
@@ -469,6 +485,25 @@ void RPC::getInfoThenRefresh(bool force) {
|
|||||||
refreshTransactions();
|
refreshTransactions();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get network sol/s
|
||||||
|
if (ezcashd) {
|
||||||
|
int conns = reply["connections"].get<json::number_integer_t>();
|
||||||
|
|
||||||
|
json payload = {
|
||||||
|
{"jsonrpc", "1.0"},
|
||||||
|
{"id", "someid"},
|
||||||
|
{"method", "getnetworksolps"}
|
||||||
|
};
|
||||||
|
|
||||||
|
conn->doRPCIgnoreError(payload, [=](const json& reply) {
|
||||||
|
qint64 solrate = reply.get<json::number_unsigned_t>();
|
||||||
|
|
||||||
|
ui->blockheight->setText(QString::number(curBlock));
|
||||||
|
ui->numconnections->setText(QString::number(conns));
|
||||||
|
ui->solrate->setText(QString::number(solrate) % " Sol/s");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Call to see if the blockchain is syncing.
|
// Call to see if the blockchain is syncing.
|
||||||
json payload = {
|
json payload = {
|
||||||
{"jsonrpc", "1.0"},
|
{"jsonrpc", "1.0"},
|
||||||
@@ -478,12 +513,24 @@ void RPC::getInfoThenRefresh(bool force) {
|
|||||||
|
|
||||||
conn->doRPCIgnoreError(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.995; // 99.59%
|
||||||
int blockNumber = reply["blocks"].get<json::number_unsigned_t>();
|
int blockNumber = reply["blocks"].get<json::number_unsigned_t>();
|
||||||
|
|
||||||
Settings::getInstance()->setSyncing(isSyncing);
|
Settings::getInstance()->setSyncing(isSyncing);
|
||||||
Settings::getInstance()->setBlockNumber(blockNumber);
|
Settings::getInstance()->setBlockNumber(blockNumber);
|
||||||
|
|
||||||
|
// Update zcashd tab if it exists
|
||||||
|
if (ezcashd && isSyncing) {
|
||||||
|
// 895 / ~426530 (0 % )
|
||||||
|
const qint64 genisisTimeMSec = 1477638000000;
|
||||||
|
qint64 estBlocks = (QDateTime::currentMSecsSinceEpoch() - genisisTimeMSec) / 2.5 / 60 / 1000;
|
||||||
|
// Round to nearest 10
|
||||||
|
estBlocks = ((estBlocks + 5) / 10) * 10;
|
||||||
|
ui->blockheight->setText(ui->blockheight->text() % /*" / ~" % QString::number(estBlocks) % */
|
||||||
|
" ( " % QString::number(progress * 100, 'f', 0) % "% )");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the status bar
|
||||||
QString statusText = QString() %
|
QString statusText = QString() %
|
||||||
(isSyncing ? "Syncing" : "Connected") %
|
(isSyncing ? "Syncing" : "Connected") %
|
||||||
" (" %
|
" (" %
|
||||||
@@ -790,7 +837,7 @@ void RPC::refreshZECPrice() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (const json& item : parsed.get<json::array_t>()) {
|
for (const json& item : parsed.get<json::array_t>()) {
|
||||||
if (item["symbol"].get<json::string_t>().compare("ZEC") == 0) {
|
if (item["symbol"].get<json::string_t>() == "ZEC") {
|
||||||
QString price = QString::fromStdString(item["price_usd"].get<json::string_t>());
|
QString price = QString::fromStdString(item["price_usd"].get<json::string_t>());
|
||||||
qDebug() << "ZEC Price=" << price;
|
qDebug() << "ZEC Price=" << price;
|
||||||
Settings::getInstance()->setZECPrice(price.toDouble());
|
Settings::getInstance()->setZECPrice(price.toDouble());
|
||||||
@@ -808,6 +855,52 @@ void RPC::refreshZECPrice() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RPC::shutdownZcashd() {
|
||||||
|
// Shutdown embedded zcashd if it was started
|
||||||
|
if (ezcashd == nullptr || conn == nullptr) {
|
||||||
|
// No zcashd running internally, just return
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
json payload = {
|
||||||
|
{"jsonrpc", "1.0"},
|
||||||
|
{"id", "someid"},
|
||||||
|
{"method", "stop"}
|
||||||
|
};
|
||||||
|
|
||||||
|
conn->doRPCWithDefaultErrorHandling(payload, [=](auto) {});
|
||||||
|
conn->shutdown();
|
||||||
|
|
||||||
|
QDialog d(main);
|
||||||
|
Ui_ConnectionDialog connD;
|
||||||
|
connD.setupUi(&d);
|
||||||
|
connD.topIcon->setBasePixmap(QIcon(":/icons/res/icon.ico").pixmap(256, 256));
|
||||||
|
connD.status->setText("Please wait for zec-qt-wallet to exit");
|
||||||
|
connD.statusDetail->setText("Waiting for zcashd to exit");
|
||||||
|
|
||||||
|
QTimer waiter(main);
|
||||||
|
|
||||||
|
// We capture by reference all the local variables because of the d.exec()
|
||||||
|
// below, which blocks this function until we exit.
|
||||||
|
int waitCount = 0;
|
||||||
|
QObject::connect(&waiter, &QTimer::timeout, [&] () {
|
||||||
|
waitCount++;
|
||||||
|
if ((ezcashd->atEnd() && ezcashd->processId() == 0) ||
|
||||||
|
waitCount > 30) {
|
||||||
|
qDebug() << "Ended";
|
||||||
|
waiter.stop();
|
||||||
|
QTimer::singleShot(1000, [&]() { d.accept(); });
|
||||||
|
} else {
|
||||||
|
qDebug() << "Not ended, continuing to wait...";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
waiter.start(1000);
|
||||||
|
|
||||||
|
// Wait for the zcash process to exit.
|
||||||
|
d.exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Fetch the Z-board topics list
|
// Fetch the Z-board topics list
|
||||||
void RPC::getZboardTopics(std::function<void(QMap<QString, QString>)> cb) {
|
void RPC::getZboardTopics(std::function<void(QMap<QString, QString>)> cb) {
|
||||||
if (conn == nullptr)
|
if (conn == nullptr)
|
||||||
|
|||||||
@@ -32,6 +32,8 @@ public:
|
|||||||
~RPC();
|
~RPC();
|
||||||
|
|
||||||
void setConnection(Connection* c);
|
void setConnection(Connection* c);
|
||||||
|
void setEZcashd(QProcess* p);
|
||||||
|
const QProcess* getEZcashD() { return ezcashd; }
|
||||||
|
|
||||||
void refresh(bool force = false);
|
void refresh(bool force = false);
|
||||||
|
|
||||||
@@ -58,14 +60,15 @@ 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);
|
||||||
|
|
||||||
|
void shutdownZcashd();
|
||||||
|
void noConnection();
|
||||||
|
|
||||||
void getAllPrivKeys(const std::function<void(QList<QPair<QString, QString>>)>);
|
void getAllPrivKeys(const std::function<void(QList<QPair<QString, QString>>)>);
|
||||||
|
|
||||||
Turnstile* getTurnstile() { return turnstile; }
|
Turnstile* getTurnstile() { return turnstile; }
|
||||||
Connection* getConnection() { return conn; }
|
Connection* getConnection() { return conn; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void noConnection();
|
|
||||||
|
|
||||||
void refreshBalances();
|
void refreshBalances();
|
||||||
|
|
||||||
void refreshTransactions();
|
void refreshTransactions();
|
||||||
@@ -88,6 +91,7 @@ private:
|
|||||||
void handleTxError (const QString& error);
|
void handleTxError (const QString& error);
|
||||||
|
|
||||||
Connection* conn = nullptr;
|
Connection* conn = nullptr;
|
||||||
|
QProcess* ezcashd = nullptr;
|
||||||
|
|
||||||
QList<UnspentOutput>* utxos = nullptr;
|
QList<UnspentOutput>* utxos = nullptr;
|
||||||
QMap<QString, double>* allBalances = nullptr;
|
QMap<QString, double>* allBalances = nullptr;
|
||||||
@@ -108,6 +112,7 @@ private:
|
|||||||
|
|
||||||
// Current balance in the UI. If this number updates, then refresh the UI
|
// Current balance in the UI. If this number updates, then refresh the UI
|
||||||
QString currentBalance;
|
QString currentBalance;
|
||||||
|
|
||||||
// First time warning flag for no connection
|
// First time warning flag for no connection
|
||||||
bool firstTime = true;
|
bool firstTime = true;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -9,7 +9,17 @@ if [ -z $MXE_PATH ]; then echo "MXE_PATH is not set. Set it to ~/github/mxe/usr/
|
|||||||
if [ -z $APP_VERSION ]; then echo "APP_VERSION is not set"; exit 1; fi
|
if [ -z $APP_VERSION ]; then echo "APP_VERSION is not set"; exit 1; fi
|
||||||
if [ -z $PREV_VERSION ]; then echo "PREV_VERSION is not set"; exit 1; fi
|
if [ -z $PREV_VERSION ]; then echo "PREV_VERSION is not set"; exit 1; fi
|
||||||
|
|
||||||
echo -n "Version files."
|
if [ ! -f ../zcash/artifacts/zcashd ]; then
|
||||||
|
echo "Couldn't find zcashd in ../zcash/artifacts/. Please build zcashd."
|
||||||
|
exit 1;
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -f ../zcash/artifacts/zcashd.exe ]; then
|
||||||
|
echo "Couldn't find zcashd.exe in ../zcash/artifacts/. Please build zcashd.exe"
|
||||||
|
exit 1;
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -n "Version files....."
|
||||||
# Replace the version number in the .pro file so it gets picked up everywhere
|
# Replace the version number in the .pro file so it gets picked up everywhere
|
||||||
sed -i "s/${PREV_VERSION}/${APP_VERSION}/g" zec-qt-wallet.pro > /dev/null
|
sed -i "s/${PREV_VERSION}/${APP_VERSION}/g" zec-qt-wallet.pro > /dev/null
|
||||||
|
|
||||||
@@ -17,29 +27,29 @@ sed -i "s/${PREV_VERSION}/${APP_VERSION}/g" zec-qt-wallet.pro > /dev/null
|
|||||||
sed -i "s/${PREV_VERSION}/${APP_VERSION}/g" README.md > /dev/null
|
sed -i "s/${PREV_VERSION}/${APP_VERSION}/g" README.md > /dev/null
|
||||||
echo "[OK]"
|
echo "[OK]"
|
||||||
|
|
||||||
echo -n "Cleaning......"
|
echo -n "Cleaning.........."
|
||||||
rm -f bin/linux-zec-qt-wallet*
|
rm -rf bin/*
|
||||||
rm -rf release/
|
|
||||||
rm -rf artifacts/*
|
rm -rf artifacts/*
|
||||||
make distclean > /dev/null
|
make distclean > /dev/null
|
||||||
echo "[OK]"
|
echo "[OK]"
|
||||||
|
|
||||||
echo "Linux"
|
echo ""
|
||||||
|
echo "[Linux]"
|
||||||
|
|
||||||
echo -n "Configuring..."
|
echo -n "Configuring......."
|
||||||
$QT_STATIC/bin/qmake zec-qt-wallet.pro -spec linux-clang CONFIG+=release > /dev/null
|
$QT_STATIC/bin/qmake zec-qt-wallet.pro -spec linux-clang CONFIG+=release > /dev/null
|
||||||
#Mingw seems to have trouble with precompiled headers, so strip that option from the .pro file
|
#Mingw seems to have trouble with precompiled headers, so strip that option from the .pro file
|
||||||
echo "[OK]"
|
echo "[OK]"
|
||||||
|
|
||||||
|
|
||||||
echo -n "Building......"
|
echo -n "Building.........."
|
||||||
rm -rf bin/zec-qt-wallet* > /dev/null
|
rm -rf bin/zec-qt-wallet* > /dev/null
|
||||||
make -j$(nproc) > /dev/null
|
make -j$(nproc) > /dev/null
|
||||||
echo "[OK]"
|
echo "[OK]"
|
||||||
|
|
||||||
|
|
||||||
# Test for Qt
|
# Test for Qt
|
||||||
echo -n "Static link..."
|
echo -n "Static link......."
|
||||||
if [[ $(ldd zec-qt-wallet | grep -i "Qt") ]]; then
|
if [[ $(ldd zec-qt-wallet | grep -i "Qt") ]]; then
|
||||||
echo "FOUND QT; ABORT";
|
echo "FOUND QT; ABORT";
|
||||||
exit 1
|
exit 1
|
||||||
@@ -47,33 +57,38 @@ fi
|
|||||||
echo "[OK]"
|
echo "[OK]"
|
||||||
|
|
||||||
|
|
||||||
echo -n "Packaging....."
|
echo -n "Packaging........."
|
||||||
strip zec-qt-wallet
|
|
||||||
mkdir bin/zec-qt-wallet-v$APP_VERSION > /dev/null
|
mkdir bin/zec-qt-wallet-v$APP_VERSION > /dev/null
|
||||||
|
strip zec-qt-wallet
|
||||||
cp zec-qt-wallet bin/zec-qt-wallet-v$APP_VERSION > /dev/null
|
cp zec-qt-wallet bin/zec-qt-wallet-v$APP_VERSION > /dev/null
|
||||||
|
cp ../zcash/artifacts/zcashd bin/zec-qt-wallet-v$APP_VERSION > /dev/null
|
||||||
cp README.md bin/zec-qt-wallet-v$APP_VERSION > /dev/null
|
cp README.md bin/zec-qt-wallet-v$APP_VERSION > /dev/null
|
||||||
cp LICENSE bin/zec-qt-wallet-v$APP_VERSION > /dev/null
|
cp LICENSE bin/zec-qt-wallet-v$APP_VERSION > /dev/null
|
||||||
cd bin && tar cvf linux-zec-qt-wallet-v$APP_VERSION.tar.gz zec-qt-wallet-v$APP_VERSION/ > /dev/null
|
cd bin && tar cvf linux-zec-qt-wallet-v$APP_VERSION.tar.gz zec-qt-wallet-v$APP_VERSION/ > /dev/null
|
||||||
cd ..
|
cd ..
|
||||||
mkdir artifacts >/dev/null 2>&1
|
mkdir artifacts >/dev/null 2>&1
|
||||||
cp bin/linux-zec-qt-wallet-v$APP_VERSION.tar.gz ./artifacts
|
cp bin/linux-zec-qt-wallet-v$APP_VERSION.tar.gz ./artifacts
|
||||||
|
echo "[OK]"
|
||||||
|
|
||||||
|
|
||||||
if [ -f artifacts/linux-zec-qt-wallet-v$APP_VERSION.tar.gz ] ; then
|
if [ -f artifacts/linux-zec-qt-wallet-v$APP_VERSION.tar.gz ] ; then
|
||||||
echo "[OK]"
|
echo -n "Package contents.."
|
||||||
|
# Test if the package is built OK
|
||||||
echo "Done. Build is artifacts/linux-zec-qt-wallet-v$APP_VERSION.tar.gz"
|
if tar tf "artifacts/linux-zec-qt-wallet-v$APP_VERSION.tar.gz" | wc -l | grep -q "5"; then
|
||||||
echo "Package contents:"
|
echo "[OK]"
|
||||||
tar tf "artifacts/linux-zec-qt-wallet-v$APP_VERSION.tar.gz"
|
else
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
else
|
else
|
||||||
echo "[ERROR]"
|
echo "[ERROR]"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "Windows"
|
echo ""
|
||||||
|
echo "[Windows]"
|
||||||
export PATH=$MXE_PATH:$PATH
|
export PATH=$MXE_PATH:$PATH
|
||||||
|
|
||||||
echo -n "Configuring..."
|
echo -n "Configuring......."
|
||||||
make clean > /dev/null
|
make clean > /dev/null
|
||||||
rm -f zec-qt-wallet-mingw.pro
|
rm -f zec-qt-wallet-mingw.pro
|
||||||
rm -rf release/
|
rm -rf release/
|
||||||
@@ -82,30 +97,38 @@ cat zec-qt-wallet.pro | sed "s/precompile_header/release/g" | sed "s/PRECOMPILED
|
|||||||
echo "[OK]"
|
echo "[OK]"
|
||||||
|
|
||||||
|
|
||||||
echo -n "Building......"
|
echo -n "Building.........."
|
||||||
x86_64-w64-mingw32.static-qmake-qt5 zec-qt-wallet-mingw.pro CONFIG+=release > /dev/null
|
x86_64-w64-mingw32.static-qmake-qt5 zec-qt-wallet-mingw.pro CONFIG+=release > /dev/null
|
||||||
make -j32 > /dev/null
|
make -j32 > /dev/null
|
||||||
echo "[OK]"
|
echo "[OK]"
|
||||||
|
|
||||||
|
|
||||||
echo -n "Packaging....."
|
echo -n "Packaging........."
|
||||||
mkdir release/zec-qt-wallet-v$APP_VERSION
|
mkdir release/zec-qt-wallet-v$APP_VERSION
|
||||||
cp release/zec-qt-wallet.exe release/zec-qt-wallet-v$APP_VERSION
|
cp release/zec-qt-wallet.exe release/zec-qt-wallet-v$APP_VERSION
|
||||||
|
cp ../zcash/artifacts/zcashd.exe release/zec-qt-wallet-v$APP_VERSION > /dev/null
|
||||||
cp README.md release/zec-qt-wallet-v$APP_VERSION
|
cp README.md release/zec-qt-wallet-v$APP_VERSION
|
||||||
cp LICENSE release/zec-qt-wallet-v$APP_VERSION
|
cp LICENSE release/zec-qt-wallet-v$APP_VERSION
|
||||||
cd release && zip -r Windows-zec-qt-wallet-v$APP_VERSION.zip zec-qt-wallet-v$APP_VERSION/ > /dev/null
|
cd release && zip -r Windows-zec-qt-wallet-v$APP_VERSION.zip zec-qt-wallet-v$APP_VERSION/ > /dev/null
|
||||||
cd ..
|
cd ..
|
||||||
mkdir artifacts >/dev/null 2>&1
|
mkdir artifacts >/dev/null 2>&1
|
||||||
cp release/Windows-zec-qt-wallet-v$APP_VERSION.zip ./artifacts
|
cp release/Windows-zec-qt-wallet-v$APP_VERSION.zip ./artifacts
|
||||||
|
echo "[OK]"
|
||||||
|
|
||||||
if [ -f artifacts/Windows-zec-qt-wallet-v$APP_VERSION.zip ] ; then
|
if [ -f artifacts/Windows-zec-qt-wallet-v$APP_VERSION.zip ] ; then
|
||||||
echo "[OK]"
|
echo -n "Package contents.."
|
||||||
|
if unzip -l "artifacts/Windows-zec-qt-wallet-v$APP_VERSION.zip" | wc -l | grep -q "10"; then
|
||||||
echo "Done. Build is artifacts/Windows-zec-qt-wallet-v$APP_VERSION.zip"
|
echo "[OK]"
|
||||||
echo "Package contents:"
|
else
|
||||||
unzip -l "artifacts/Windows-zec-qt-wallet-v$APP_VERSION.zip"
|
echo "[ERROR]"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
else
|
else
|
||||||
echo "[ERROR]"
|
echo "[ERROR]"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Build is artifacts/Windows-zec-qt-wallet-v$APP_VERSION.zip"
|
||||||
|
echo "Build is artifacts/linux-zec-qt-wallet-v$APP_VERSION.tar.gz"
|
||||||
@@ -31,7 +31,7 @@ QList<TransactionItem> SentTxStore::readSentTxFile() {
|
|||||||
QJsonDocument jsonDoc;
|
QJsonDocument jsonDoc;
|
||||||
|
|
||||||
data.open(QFile::ReadOnly);
|
data.open(QFile::ReadOnly);
|
||||||
jsonDoc = QJsonDocument().fromJson(data.readAll());
|
jsonDoc = QJsonDocument::fromJson(data.readAll());
|
||||||
data.close();
|
data.close();
|
||||||
|
|
||||||
QList<TransactionItem> items;
|
QList<TransactionItem> items;
|
||||||
@@ -87,7 +87,7 @@ void SentTxStore::addToSentTx(Tx tx, QString txid) {
|
|||||||
QJsonObject txItem;
|
QJsonObject txItem;
|
||||||
txItem["type"] = "sent";
|
txItem["type"] = "sent";
|
||||||
txItem["from"] = tx.fromAddr;
|
txItem["from"] = tx.fromAddr;
|
||||||
txItem["datetime"] = QDateTime().currentMSecsSinceEpoch() / (qint64)1000;
|
txItem["datetime"] = QDateTime::currentMSecsSinceEpoch() / (qint64)1000;
|
||||||
txItem["address"] = QString(); // The sent address is blank, to be consistent with t-Addr sent behaviour
|
txItem["address"] = QString(); // The sent address is blank, to be consistent with t-Addr sent behaviour
|
||||||
txItem["txid"] = txid;
|
txItem["txid"] = txid;
|
||||||
txItem["amount"] = -totalAmount;
|
txItem["amount"] = -totalAmount;
|
||||||
|
|||||||
@@ -5,9 +5,6 @@
|
|||||||
|
|
||||||
Settings* Settings::instance = nullptr;
|
Settings* Settings::instance = nullptr;
|
||||||
|
|
||||||
Settings::~Settings() {
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Settings::getSaveZtxs() {
|
bool Settings::getSaveZtxs() {
|
||||||
// Load from the QT Settings.
|
// Load from the QT Settings.
|
||||||
return QSettings().value("options/savesenttx", true).toBool();
|
return QSettings().value("options/savesenttx", true).toBool();
|
||||||
@@ -124,11 +121,10 @@ QString Settings::getZECUSDDisplayFormat(double bal) {
|
|||||||
return getZECDisplayFormat(bal);
|
return getZECDisplayFormat(bal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Settings::saveRestore(QDialog* d) {
|
void Settings::saveRestore(QDialog* d) {
|
||||||
d->restoreGeometry(QSettings().value(d->objectName() % "geometry").toByteArray());
|
d->restoreGeometry(QSettings().value(d->objectName() % "geometry").toByteArray());
|
||||||
|
|
||||||
QObject::connect(d, &QDialog::finished, [=](auto) {
|
QObject::connect(d, &QDialog::finished, [=](auto) {
|
||||||
QSettings().setValue(d->objectName() % "geometry", d->saveGeometry());
|
QSettings().setValue(d->objectName() % "geometry", d->saveGeometry());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,12 @@ public:
|
|||||||
bool isSyncing();
|
bool isSyncing();
|
||||||
void setSyncing(bool syncing);
|
void setSyncing(bool syncing);
|
||||||
|
|
||||||
|
QString getExecName() { return _executable; }
|
||||||
|
void setExecName(QString name) { _executable = name; }
|
||||||
|
|
||||||
|
void setUseEmbedded(bool r) { _useEmbedded = r; }
|
||||||
|
bool useEmbedded() { return _useEmbedded; }
|
||||||
|
|
||||||
int getBlockNumber();
|
int getBlockNumber();
|
||||||
void setBlockNumber(int number);
|
void setBlockNumber(int number);
|
||||||
|
|
||||||
@@ -57,9 +63,11 @@ private:
|
|||||||
static Settings* instance;
|
static Settings* instance;
|
||||||
|
|
||||||
QString _confLocation;
|
QString _confLocation;
|
||||||
bool _isTestnet = false;
|
QString _executable;
|
||||||
bool _isSyncing = false;
|
bool _isTestnet = false;
|
||||||
int _blockNumber = 0;
|
bool _isSyncing = false;
|
||||||
|
int _blockNumber = 0;
|
||||||
|
bool _useEmbedded = false;
|
||||||
|
|
||||||
double zecPrice = 0.0;
|
double zecPrice = 0.0;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -14,8 +14,6 @@ Turnstile::Turnstile(RPC* _rpc, MainWindow* mainwindow) {
|
|||||||
this->mainwindow = mainwindow;
|
this->mainwindow = mainwindow;
|
||||||
}
|
}
|
||||||
|
|
||||||
Turnstile::~Turnstile() {
|
|
||||||
}
|
|
||||||
|
|
||||||
void printPlan(QList<TurnstileMigrationItem> plan) {
|
void printPlan(QList<TurnstileMigrationItem> plan) {
|
||||||
for (auto item : plan) {
|
for (auto item : plan) {
|
||||||
@@ -118,7 +116,7 @@ void Turnstile::planMigration(QString zaddr, QString destAddr, int numsplits, in
|
|||||||
|
|
||||||
// The first migration is shifted to the current block, so the user sees something
|
// The first migration is shifted to the current block, so the user sees something
|
||||||
// happening immediately
|
// happening immediately
|
||||||
if (migItems.size() == 0) {
|
if (migItems.empty()) {
|
||||||
// Show error and abort
|
// Show error and abort
|
||||||
QMessageBox::warning(mainwindow,
|
QMessageBox::warning(mainwindow,
|
||||||
"Locked funds",
|
"Locked funds",
|
||||||
@@ -220,9 +218,7 @@ Turnstile::getNextStep(QList<TurnstileMigrationItem>& plan) {
|
|||||||
|
|
||||||
bool Turnstile::isMigrationPresent() {
|
bool Turnstile::isMigrationPresent() {
|
||||||
auto plan = readMigrationPlan();
|
auto plan = readMigrationPlan();
|
||||||
if (plan.isEmpty()) return false;
|
return !plan.isEmpty();
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ProgressReport Turnstile::getPlanProgress() {
|
ProgressReport Turnstile::getPlanProgress() {
|
||||||
|
|||||||
@@ -39,7 +39,6 @@ class Turnstile
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Turnstile(RPC* _rpc, MainWindow* mainwindow);
|
Turnstile(RPC* _rpc, MainWindow* mainwindow);
|
||||||
~Turnstile();
|
|
||||||
|
|
||||||
void planMigration(QString zaddr, QString destAddr, int splits, int numBlocks);
|
void planMigration(QString zaddr, QString destAddr, int splits, int numBlocks);
|
||||||
QList<double> splitAmount(double amount, int parts);
|
QList<double> splitAmount(double amount, int parts);
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ SOURCES += \
|
|||||||
src/utils.cpp \
|
src/utils.cpp \
|
||||||
src/qrcodelabel.cpp \
|
src/qrcodelabel.cpp \
|
||||||
src/connection.cpp \
|
src/connection.cpp \
|
||||||
|
src/fillediconlabel.cpp \
|
||||||
src/addressbook.cpp
|
src/addressbook.cpp
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
@@ -73,6 +74,7 @@ HEADERS += \
|
|||||||
src/utils.h \
|
src/utils.h \
|
||||||
src/qrcodelabel.h \
|
src/qrcodelabel.h \
|
||||||
src/connection.h \
|
src/connection.h \
|
||||||
|
src/fillediconlabel.h \
|
||||||
src/addressbook.h
|
src/addressbook.h
|
||||||
|
|
||||||
FORMS += \
|
FORMS += \
|
||||||
|
|||||||
Reference in New Issue
Block a user