From ed34fa835159fc2cd98ad508243bc4c7cea2a3da Mon Sep 17 00:00:00 2001 From: Bytecoin Developer Date: Tue, 3 Apr 2018 13:52:55 +0300 Subject: [PATCH] Add the batch of release v2.0.1 commits --- CMakeLists.txt | 1 + ReleaseNotes.md | 10 ++ src/addressbookmanager.cpp | 5 +- src/addressbookmanager.h | 4 +- src/addressbookmodel.cpp | 23 ++- src/addressbookmodel.h | 4 +- src/application.cpp | 82 ++++++++- src/application.h | 10 +- src/askpassworddialog.cpp | 2 + src/bytecoin-gui.pro | 25 +-- src/changepassworddialog.cpp | 3 + src/crashdialog.h | 4 +- src/exportkeydialog.cpp | 48 +++++ src/exportkeydialog.h | 30 ++++ src/exportkeydialog.ui | 118 ++++++++++++ src/importkeydialog.cpp | 8 +- src/mainwindow.cpp | 23 ++- src/mainwindow.h | 8 +- src/mainwindow.ui | 54 +++++- src/overviewframe.cpp | 7 +- src/overviewframe.h | 2 +- src/settings.cpp | 4 +- src/walletd.cpp | 335 +++++++++++++++++++++++++++++------ src/walletd.h | 21 ++- src/walletdparamsdialog.cpp | 7 +- src/walletdparamsdialog.h | 2 + src/walletmodel.cpp | 22 ++- src/walletmodel.h | 2 + 28 files changed, 753 insertions(+), 111 deletions(-) create mode 100644 src/exportkeydialog.cpp create mode 100644 src/exportkeydialog.h create mode 100644 src/exportkeydialog.ui diff --git a/CMakeLists.txt b/CMakeLists.txt index aea029c..2b269d5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -78,6 +78,7 @@ set(SOURCES src/createproofdialog.cpp src/checkproofdialog.cpp src/walletdparamsdialog.cpp + src/exportkeydialog.cpp ) diff --git a/ReleaseNotes.md b/ReleaseNotes.md index aac750e..0f62705 100644 --- a/ReleaseNotes.md +++ b/ReleaseNotes.md @@ -1,5 +1,15 @@ ## Release Notes +### v2.0.1 + +- Added possibility to try creating send proofs for transactions not found in history. +- Added support for view-only wallets. +- Fixed the changing password bug. +- Added export of view-only wallets. +- Added export of keys. +- Fixed crash on MacOS while working with address book. +- Fixed minor UI bugs. + ### v2.0.0 - Added creating send proofs. diff --git a/src/addressbookmanager.cpp b/src/addressbookmanager.cpp index f3f963a..7c9009d 100644 --- a/src/addressbookmanager.cpp +++ b/src/addressbookmanager.cpp @@ -127,6 +127,8 @@ void AddressBookManager::removeAddress(AddressIndex _addressIndex) const QString oldLabel = addressObject[ADDRESS_ITEM_LABEL_TAG_NAME].toString(); WalletLogger::debug(tr("[AddressBook] Remove address: label=\"%1\" address=\"%2\"").arg(oldLabel).arg(oldAddress)); + emit beginRemoveAddressSignal(_addressIndex); + addressArray.removeAt(_addressIndex); addressIndexes_.remove(oldAddress); labelIndexes_.remove(oldLabel); @@ -140,7 +142,8 @@ void AddressBookManager::removeAddress(AddressIndex _addressIndex) } addressBook_->setValue(ADDRESS_BOOK_TAG_NAME, addressArray); - emit addressRemovedSignal(_addressIndex); +// emit addressRemovedSignal(_addressIndex); + emit endRemoveAddressSignal(); } void AddressBookManager::buildIndexes() { diff --git a/src/addressbookmanager.h b/src/addressbookmanager.h index a0a4aba..e14fd5c 100644 --- a/src/addressbookmanager.h +++ b/src/addressbookmanager.h @@ -49,7 +49,9 @@ class AddressBookManager : public QObject void addressBookClosedSignal(); void addressAddedSignal(AddressIndex _addressIndex); void addressEditedSignal(AddressIndex _addressIndex); - void addressRemovedSignal(AddressIndex _addressIndex); +// void addressRemovedSignal(AddressIndex _addressIndex); + void beginRemoveAddressSignal(AddressIndex _addressIndex); + void endRemoveAddressSignal(); }; } diff --git a/src/addressbookmodel.cpp b/src/addressbookmodel.cpp index 0733fc4..ee60698 100644 --- a/src/addressbookmodel.cpp +++ b/src/addressbookmodel.cpp @@ -25,7 +25,9 @@ AddressBookModel::AddressBookModel(AddressBookManager* _addressBookManager, QObj { connect(m_addressBookManager, &AddressBookManager::addressAddedSignal, this, &AddressBookModel::addressAdded); connect(m_addressBookManager, &AddressBookManager::addressEditedSignal, this, &AddressBookModel::addressEdited); - connect(m_addressBookManager, &AddressBookManager::addressRemovedSignal, this, &AddressBookModel::addressRemoved); +// connect(m_addressBookManager, &AddressBookManager::addressRemovedSignal, this, &AddressBookModel::addressRemoved); + connect(m_addressBookManager, &AddressBookManager::beginRemoveAddressSignal, this, &AddressBookModel::beginRemoveAddress); + connect(m_addressBookManager, &AddressBookManager::endRemoveAddressSignal, this, &AddressBookModel::endRemoveAddress); addressBookOpened(); } @@ -145,10 +147,21 @@ void AddressBookModel::addressEdited(quintptr _addressIndex) { Q_EMIT dataChanged(index(_addressIndex, 0), index(_addressIndex, columnCount() - 1)); } -void AddressBookModel::addressRemoved(quintptr _addressIndex) { - beginRemoveRows(QModelIndex(), _addressIndex, _addressIndex); - m_rowCount = m_addressBookManager->getAddressCount(); - endRemoveRows(); +//void AddressBookModel::addressRemoved(quintptr _addressIndex) { +// beginRemoveRows(QModelIndex(), _addressIndex, _addressIndex); +// m_rowCount = m_addressBookManager->getAddressCount(); +// endRemoveRows(); +//} + +void AddressBookModel::beginRemoveAddress(quintptr _addressIndex) +{ + beginRemoveRows(QModelIndex(), _addressIndex, _addressIndex); +} + +void AddressBookModel::endRemoveAddress() +{ + m_rowCount = m_addressBookManager->getAddressCount(); + endRemoveRows(); } QVariant AddressBookModel::getDisplayRole(const QModelIndex& _index) const { diff --git a/src/addressbookmodel.h b/src/addressbookmodel.h index 2217aee..c84f93e 100644 --- a/src/addressbookmodel.h +++ b/src/addressbookmodel.h @@ -42,7 +42,9 @@ class AddressBookModel : public QAbstractItemModel Q_SLOT void addressBookClosed(); Q_SLOT void addressAdded(quintptr _addressIndex); Q_SLOT void addressEdited(quintptr _addressIndex); - Q_SLOT void addressRemoved(quintptr _addressIndex); +// Q_SLOT void addressRemoved(quintptr _addressIndex); + Q_SLOT void beginRemoveAddress(quintptr _addressIndex); + Q_SLOT void endRemoveAddress(); private: AddressBookManager* m_addressBookManager; diff --git a/src/application.cpp b/src/application.cpp index 7bfa2a2..044a71f 100644 --- a/src/application.cpp +++ b/src/application.cpp @@ -29,6 +29,7 @@ #include "createproofdialog.h" #include "checkproofdialog.h" #include "walletdparamsdialog.h" +#include "questiondialog.h" namespace WalletGUI { @@ -90,7 +91,7 @@ bool WalletApplication::init() if (!m_lockFile->tryLock()) { WalletLogger::warning(tr("[Application] Bytecoin wallet GUI already running")); - QMessageBox::warning(nullptr, QObject::tr("Fail"), tr("Bytecoin wallet GUI already running")); + QMessageBox::warning(nullptr, QObject::tr("Error"), tr("Bytecoin wallet GUI already running")); return false; } @@ -118,6 +119,8 @@ bool WalletApplication::init() connect(m_mainWindow, &MainWindow::createProofSignal, this, &WalletApplication::createProof); connect(m_mainWindow, &MainWindow::checkProofSignal, this, &WalletApplication::checkProof); connect(m_mainWindow, &MainWindow::showWalletdParamsSignal, this, &WalletApplication::showWalletdParams); + connect(m_mainWindow, &MainWindow::exportViewOnlyKeysSignal, this, &WalletApplication::exportViewOnlyKeys); + connect(m_mainWindow, &MainWindow::exportKeysSignal, this, &WalletApplication::exportKeys); connect(m_mainWindow, &MainWindow::createWalletSignal, this, &WalletApplication::createWallet); connect(m_mainWindow, &MainWindow::importKeysSignal, this, &WalletApplication::importKeys); @@ -226,9 +229,9 @@ void WalletApplication::sendTx(const RpcApi::SendTransaction::Request& req) walletd_->sendTx(req); } -void WalletApplication::sendCreateProof(const QString& txHash, const QString& message) +void WalletApplication::sendCreateProof(const QString& txHash, const QString& message, const QStringList& addresses) { - const RpcApi::CreateSendProof::Request req{txHash, message, QStringList{}}; + const RpcApi::CreateSendProof::Request req{txHash, message, addresses}; walletd_->createProof(req); } @@ -266,8 +269,10 @@ void WalletApplication::runBuiltinWalletd(const QString& walletFile, bool create { if (walletd_) { - delete walletd_; - walletd_ = nullptr; +// delete walletd_; +// walletd_ = nullptr; + + walletd_->deleteLater(); } splashMsg(tr("Running walletd...")); @@ -281,12 +286,15 @@ void WalletApplication::runBuiltinWalletd(const QString& walletFile, bool create connect(walletd, &BuiltinWalletd::daemonFinishedSignal, this, &WalletApplication::detached); connect(walletd, &BuiltinWalletd::requestPasswordSignal, this, &WalletApplication::requestPassword); connect(walletd, &BuiltinWalletd::requestPasswordWithConfirmationSignal, this, &WalletApplication::requestPasswordWithConfirmation); + connect(walletd, &BuiltinWalletd::requestPasswordForExportSignal, this, &WalletApplication::requestPasswordForExport); subscribeToWalletd(); Settings::instance().setConnectionMethod(ConnectionMethod::BUILTIN); Settings::instance().setWalletFile(walletFile); connect(walletd, &BuiltinWalletd::connectedSignal, this, &WalletApplication::builtinRunSignal); + connect(this, &WalletApplication::exportViewOnlyKeysSignal, walletd, &BuiltinWalletd::exportViewOnlyKeys); + connect(this, &WalletApplication::exportKeysSignal, walletd, &BuiltinWalletd::exportKeys); walletd_->run(); } @@ -341,7 +349,7 @@ void WalletApplication::daemonFinished(int exitCode, QProcess::ExitStatus /*exit exitCode); // const QString msg = metaEnum.valueToKey(static_cast(exitCode)); bool showPasswordEdit = false; - QString msg; +/* QString msg; switch(exitCode) { case static_cast(BuiltinWalletd::ReturnCode::BYTECOIND_DATABASE_ERROR): @@ -378,10 +386,18 @@ void WalletApplication::daemonFinished(int exitCode, QProcess::ExitStatus /*exit case static_cast(BuiltinWalletd::ReturnCode::WALLETD_WRONG_ARGS): msg = tr("Wrong arguments passed to walletd."); break; + case static_cast(BuiltinWalletd::ReturnCode::WALLETD_EXPORTKEYS_MORETHANONE): + msg = tr("Walletd cannot export keys for more than one spend keypair"); + break; default: msg = tr("Walletd just crashed. %1. Return code %2. ").arg(walletd->errorString()).arg(exitCode); break; - } + }*/ + + const QString walletdMsg = BuiltinWalletd::errorMessage(static_cast(exitCode)); + const QString msg = !walletdMsg.isEmpty() ? + walletdMsg : + tr("Walletd just crashed. %1. Return code %2. ").arg(walletd->errorString()).arg(exitCode); if (crashDialog_->execWithReason(msg, showPasswordEdit) == QDialog::Accepted) { @@ -479,6 +495,7 @@ void WalletApplication::requestPassword() AskPasswordDialog dlg(false, m_mainWindow); BuiltinWalletd* walletd = static_cast(walletd_); connect(walletd, &BuiltinWalletd::daemonErrorOccurredSignal, &dlg, &AskPasswordDialog::reject); + connect(crashDialog_.data(), &CrashDialog::rejected, &dlg, &AskPasswordDialog::reject); if (dlg.exec() == QDialog::Accepted) walletd->setPassword(dlg.getPassword()); else @@ -496,6 +513,24 @@ void WalletApplication::requestPasswordWithConfirmation() walletd_->stop(); } +void WalletApplication::requestPasswordForExport(QProcess* walletd, QString* pass) +{ + AskPasswordDialog dlg(false, m_mainWindow); + +#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)) + connect( + walletd, &QProcess::errorOccurred, + &dlg, &AskPasswordDialog::reject); +#else + connect( + walletd, static_cast(&QProcess::error), + &dlg, &AskPasswordDialog::reject); +#endif + + if (dlg.exec() == QDialog::Accepted) + dlg.getPassword().swap(*pass); +} + void WalletApplication::requestWalletdAuth(QAuthenticator* authenticator) { AskPasswordDialog dlg(true, m_mainWindow); @@ -511,16 +546,35 @@ void WalletApplication::requestWalletdAuth(QAuthenticator* authenticator) } } -void WalletApplication::createProof(const QString& txHash) +void WalletApplication::createProof(const QString& txHash, bool needToFind) { + QStringList addresses; + + if (needToFind) + { + QuestionDialog qdlg{tr("Question"), tr("Cannot find history for the selected transaction.\nDo you want to try to find appropriate addresses in your address book?"), m_mainWindow}; + if (qdlg.exec() != QDialog::Accepted) + return; + for (auto i = addressBookManager_->getAddressCount() - 1; i >= 0; --i) + addresses.append(addressBookManager_->getAddress(i).address); + } + CreateProofDialog dlg{txHash, m_mainWindow}; - connect(&dlg, &CreateProofDialog::generateProofSignal, this, &WalletApplication::sendCreateProof); + + connect(&dlg, &CreateProofDialog::generateProofSignal, + this, + [this, &addresses](const QString& txHash, const QString& message) + { + sendCreateProof(txHash, message, addresses); + }); + connect(walletd_, &RemoteWalletd::proofsReceivedSignal, &dlg, [&dlg](const RpcApi::Proofs& proofs) { dlg.addProofs(proofs.send_proofs); }); + dlg.exec(); } @@ -546,4 +600,14 @@ void WalletApplication::showWalletdParams() dlg.exec(); } +void WalletApplication::exportViewOnlyKeys() +{ + emit exportViewOnlyKeysSignal(m_mainWindow, QPrivateSignal{}); +} + +void WalletApplication::exportKeys() +{ + emit exportKeysSignal(m_mainWindow, QPrivateSignal{}); +} + } diff --git a/src/application.h b/src/application.h index d5582a6..da19afc 100644 --- a/src/application.h +++ b/src/application.h @@ -66,12 +66,14 @@ class WalletApplication: public QApplication void builtinRunSignal(); void remoteConnectedSignal(); void createWalletdSignal(QPrivateSignal); + void exportViewOnlyKeysSignal(QWidget* parent/*, const QString& exportPath*/, QPrivateSignal); + void exportKeysSignal(QWidget* parent, QPrivateSignal); public slots: void createTx(const RpcApi::CreateTransaction::Request& req); void sendTx(const RpcApi::SendTransaction::Request& req); - void createProof(const QString& txHash); - void sendCreateProof(const QString& txHash, const QString& message); + void createProof(const QString& txHash, bool needToFind); + void sendCreateProof(const QString& txHash, const QString& message, const QStringList& addresses); void checkProof(); void sendCheckProof(const QString& proof); void restartDaemon(); @@ -88,6 +90,9 @@ public slots: void splashMsg(const QString& msg); + void exportViewOnlyKeys(); + void exportKeys(); + private slots: void connectedToWalletd(); void disconnectedFromWalletd(); @@ -96,6 +101,7 @@ private slots: void daemonFinished(int exitCode, QProcess::ExitStatus exitStatus); void requestPassword(); void requestPasswordWithConfirmation(); + void requestPasswordForExport(QProcess* walletd, QString* pass); void requestWalletdAuth(QAuthenticator* authenticator); #ifdef Q_OS_MAC diff --git a/src/askpassworddialog.cpp b/src/askpassworddialog.cpp index dddd435..88e6e90 100644 --- a/src/askpassworddialog.cpp +++ b/src/askpassworddialog.cpp @@ -10,6 +10,8 @@ namespace WalletGUI AskPasswordDialog::AskPasswordDialog(bool askUserName, QWidget *parent) : QDialog(parent, Qt::Dialog) , ui(new Ui::AskPasswordDialog) + , password_("") + , user_("") { ui->setupUi(this); diff --git a/src/bytecoin-gui.pro b/src/bytecoin-gui.pro index f539010..d8d8231 100644 --- a/src/bytecoin-gui.pro +++ b/src/bytecoin-gui.pro @@ -15,27 +15,29 @@ TEMPLATE = app macx: QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.11 macx: ICON = images/bytecoin.icns win32: RC_ICONS = images/bytecoin.ico -win32: VERSION = 2.18.3.20 +win32: VERSION = 2.18.3.29 #QMAKE_CXXFLAGS += -fno-omit-frame-pointer -fsanitize=address,undefined #LIBS += -lasan -lubsan CONFIG += c++14 strict_c++ no-opengl +DESTDIR = $$PWD/../bin + # copy walletd adjacent to bytecoin-gui binary on all 3 platforms win32 { WALLETD_BY_SRC_PATH = $$shell_path($$clean_path("$$PWD/../../bytecoin/bin/walletd.exe")) BYTECOIND_BY_SRC_PATH = $$shell_path($$clean_path("$$PWD/../../bytecoin/bin/bytecoind.exe")) -Debug:BY_DST_PATH = $$shell_path($$clean_path("$$OUT_PWD/debug")) -Release:BY_DST_PATH = $$shell_path($$clean_path("$$OUT_PWD/release")) +Debug:BY_DST_PATH = $$shell_path($$clean_path("$$DESTDIR")) +Release:BY_DST_PATH = $$shell_path($$clean_path("$$DESTDIR")) copywalletd.commands = $(COPY_FILE) $${WALLETD_BY_SRC_PATH} $${BY_DST_PATH} copybytecoind.commands = $(COPY_FILE) $${BYTECOIND_BY_SRC_PATH} $${BY_DST_PATH} }else:macx { -copywalletd.commands += $(COPY_FILE) $$PWD/../../bytecoin/bin/walletd $$OUT_PWD/bytecoin-gui.app/Contents/MacOS -copybytecoind.commands += $(COPY_FILE) $$PWD/../../bytecoin/bin/bytecoind $$OUT_PWD/bytecoin-gui.app/Contents/MacOS +copywalletd.commands += $(COPY_FILE) $$PWD/../../bytecoin/bin/walletd $$DESTDIR/bytecoin-gui.app/Contents/MacOS +copybytecoind.commands += $(COPY_FILE) $$PWD/../../bytecoin/bin/bytecoind $$DESTDIR/bytecoin-gui.app/Contents/MacOS }else { -copywalletd.commands += $(COPY_FILE) $$PWD/../../bytecoin/bin/walletd $$OUT_PWD -copybytecoind.commands += $(COPY_FILE) $$PWD/../../bytecoin/bin/bytecoind $$OUT_PWD +copywalletd.commands += $(COPY_FILE) $$PWD/../../bytecoin/bin/walletd $$DESTDIR +copybytecoind.commands += $(COPY_FILE) $$PWD/../../bytecoin/bin/bytecoind $$DESTDIR } first.depends = $(first) copywalletd copybytecoind export(first.depends) @@ -97,7 +99,8 @@ SOURCES += main.cpp\ PoolTreeView.cpp \ createproofdialog.cpp \ checkproofdialog.cpp \ - walletdparamsdialog.cpp + walletdparamsdialog.cpp \ + exportkeydialog.cpp HEADERS += mainwindow.h \ signalhandler.h \ @@ -156,7 +159,8 @@ HEADERS += mainwindow.h \ PoolTreeView.h \ createproofdialog.h \ checkproofdialog.h \ - walletdparamsdialog.h + walletdparamsdialog.h \ + exportkeydialog.h FORMS += mainwindow.ui \ overviewframe.ui \ @@ -180,7 +184,8 @@ FORMS += mainwindow.ui \ questiondialog.ui \ createproofdialog.ui \ checkproofdialog.ui \ - walletdparamsdialog.ui + walletdparamsdialog.ui \ + exportkeydialog.ui RESOURCES += \ resources.qrc \ diff --git a/src/changepassworddialog.cpp b/src/changepassworddialog.cpp index 2f60a35..d1aad73 100644 --- a/src/changepassworddialog.cpp +++ b/src/changepassworddialog.cpp @@ -11,6 +11,9 @@ namespace WalletGUI { ChangePasswordDialog::ChangePasswordDialog(bool askCurrentPassword, QWidget *parent) : QDialog(parent) , ui(new Ui::ChangePasswordDialog) + , oldPassword_("") + , newPassword_("") + , confirmation_("") { ui->setupUi(this); diff --git a/src/crashdialog.h b/src/crashdialog.h index b5728d5..8079189 100644 --- a/src/crashdialog.h +++ b/src/crashdialog.h @@ -14,7 +14,7 @@ namespace WalletGUI { class MainWindow; -class CrashDialog : private QDialog +class CrashDialog : public QDialog { Q_OBJECT @@ -26,8 +26,6 @@ class CrashDialog : private QDialog int execWithReason(const QString& reason, bool enablePassword); QString getPassword() const; - using QDialog::accept; - public slots: void showDaemonConsole(); diff --git a/src/exportkeydialog.cpp b/src/exportkeydialog.cpp new file mode 100644 index 0000000..94e79f6 --- /dev/null +++ b/src/exportkeydialog.cpp @@ -0,0 +1,48 @@ +#include +#include + +#include "exportkeydialog.h" +#include "ui_exportkeydialog.h" + +namespace WalletGUI +{ + +ExportKeyDialog::ExportKeyDialog(const QString& key, QWidget *parent) + : QDialog(parent) + , ui(new Ui::ExportKeyDialog) +{ + ui->setupUi(this); + ui->keyEdit->setPlainText(key); +} + +ExportKeyDialog::~ExportKeyDialog() +{ + ui->keyEdit->setText(QString{1000, '0'}); + ui->keyEdit->clear(); + delete ui; +} + +void ExportKeyDialog::saveKey() +{ + const QString filePath = + QFileDialog::getSaveFileName( + this, + tr("Save key to..."), + QDir::homePath(), + tr("Key file (*)")); + + if (filePath.isEmpty()) + return; + + QFile keyFile(filePath); + if (!keyFile.open(QIODevice::WriteOnly)) + { + QMessageBox::critical(this, tr("Error"), tr("Failed to save key to the selected file.")); + return; + } + + keyFile.write(QByteArray::fromHex(ui->keyEdit->toPlainText().toUtf8())); + keyFile.close(); +} + +} diff --git a/src/exportkeydialog.h b/src/exportkeydialog.h new file mode 100644 index 0000000..bbe2e89 --- /dev/null +++ b/src/exportkeydialog.h @@ -0,0 +1,30 @@ +#ifndef EXPORTKEYDIALOG_H +#define EXPORTKEYDIALOG_H + +#include + +namespace Ui { +class ExportKeyDialog; +} + +namespace WalletGUI +{ + +class ExportKeyDialog : public QDialog +{ + Q_OBJECT + +public: + explicit ExportKeyDialog(const QString& key, QWidget *parent = 0); + ~ExportKeyDialog(); + +public slots: + void saveKey(); + +private: + Ui::ExportKeyDialog *ui; +}; + +} + +#endif // EXPORTKEYDIALOG_H diff --git a/src/exportkeydialog.ui b/src/exportkeydialog.ui new file mode 100644 index 0000000..aa8ef53 --- /dev/null +++ b/src/exportkeydialog.ui @@ -0,0 +1,118 @@ + + + ExportKeyDialog + + + + 0 + 0 + 366 + 133 + + + + Export keys + + + + + + true + + + false + + + + + + + + + Save to file + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Ok + + + + + + + + + + + buttonBox + accepted() + ExportKeyDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + ExportKeyDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + saveButton + clicked() + ExportKeyDialog + saveKey() + + + 49 + 110 + + + 182 + 66 + + + + + + saveKey() + copyToClipboard() + + diff --git a/src/importkeydialog.cpp b/src/importkeydialog.cpp index efd64a8..deab6a4 100644 --- a/src/importkeydialog.cpp +++ b/src/importkeydialog.cpp @@ -2,6 +2,7 @@ // Licensed under the GNU Lesser General Public License. See LICENSE for details. #include +#include #include "importkeydialog.h" #include "ui_importkeydialog.h" @@ -26,7 +27,7 @@ ImportKeyDialog::~ImportKeyDialog() QByteArray ImportKeyDialog::getKey() const { - return QByteArray::fromHex(ui->keyEdit->toPlainText().toLatin1()); + return QByteArray::fromHex(ui->keyEdit->toPlainText().toUtf8()); } void ImportKeyDialog::loadKey() @@ -36,14 +37,17 @@ void ImportKeyDialog::loadKey() this, tr("Load key from..."), QDir::homePath(), - tr("Key file (*.*)")); + tr("Key file (*)")); if (filePath.isEmpty()) return; QFile keyFile(filePath); if (!keyFile.open(QIODevice::ReadOnly)) + { + QMessageBox::critical(this, tr("Error"), tr("Failed to read key from the selected file.")); return; + } key_ = keyFile.readAll(); keyFile.close(); diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 47a353d..b06d805 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -99,6 +99,7 @@ MainWindow::MainWindow( m_addressesMapper->setModel(walletModel_); m_addressesMapper->addMapping(m_ui->m_addressLabel, WalletModel::COLUMN_ADDRESS, "text"); + m_addressesMapper->addMapping(m_ui->m_viewOnlyLabel, WalletModel::COLUMN_VIEW_ONLY, "text"); m_addressesMapper->toFirst(); connect(walletModel_, &QAbstractItemModel::modelReset, m_addressesMapper, &QDataWidgetMapper::toFirst); @@ -136,6 +137,10 @@ MainWindow::MainWindow( m_ui->m_sendButton->setEnabled(false); m_ui->m_miningButton->setEnabled(false); m_ui->m_overviewButton->setEnabled(false); + m_ui->m_checkProofAction->setEnabled(false); + m_ui->m_changePasswordAction->setEnabled(false); + m_ui->m_exportKeysAction->setEnabled(false); + m_ui->m_exportViewOnlyKeysAction->setEnabled(false); m_ui->m_logButton->setChecked(true); m_ui->m_logFrame->show(); @@ -383,6 +388,8 @@ void MainWindow::setDisconnectedState() m_miningManager->stopMining(); m_ui->m_changePasswordAction->setEnabled(false); m_ui->m_checkProofAction->setEnabled(false); + m_ui->m_exportKeysAction->setEnabled(false); + m_ui->m_exportViewOnlyKeysAction->setEnabled(false); clearTitle(); #ifdef Q_OS_MAC @@ -393,6 +400,8 @@ void MainWindow::setDisconnectedState() void MainWindow::builtinRun() { m_ui->m_changePasswordAction->setEnabled(true); + m_ui->m_exportKeysAction->setEnabled(true); + m_ui->m_exportViewOnlyKeysAction->setEnabled(true); } void MainWindow::jsonErrorResponse(const QString& /*id*/, const QString& errorString) @@ -427,9 +436,9 @@ void MainWindow::packetReceived(const QByteArray& data) m_ui->m_logFrame->addNetworkMessage(QString("<-- ") + QString::fromUtf8(data) + '\n'); } -void MainWindow::createProof(const QString& txHash) +void MainWindow::createProof(const QString& txHash, bool needToFind) { - emit createProofSignal(txHash); + emit createProofSignal(txHash, needToFind); } void MainWindow::checkProof() @@ -442,4 +451,14 @@ void MainWindow::showWalletdParams() emit showWalletdParamsSignal(); } +void MainWindow::exportViewOnlyKeys() +{ + emit exportViewOnlyKeysSignal(); +} + +void MainWindow::exportKeys() +{ + emit exportKeysSignal(); +} + } diff --git a/src/mainwindow.h b/src/mainwindow.h index dcb933d..fed430d 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -65,6 +65,8 @@ class MainWindow : public QMainWindow Q_SLOT void packetSent(const QByteArray& data); Q_SLOT void packetReceived(const QByteArray& data); Q_SLOT void importKeys(); + Q_SLOT void exportViewOnlyKeys(); + Q_SLOT void exportKeys(); protected: void changeEvent(QEvent* event) override; @@ -107,16 +109,18 @@ class MainWindow : public QMainWindow Q_SLOT void remoteWallet(); Q_SLOT void encryptWallet(); - Q_SLOT void createProof(const QString& txHash); + Q_SLOT void createProof(const QString& txHash, bool needToFind); Q_SLOT void checkProof(); Q_SLOT void showWalletdParams(); signals: void createTxSignal(const RpcApi::CreateTransaction::Request& req, QPrivateSignal); void sendTxSignal(const RpcApi::SendTransaction::Request& req, QPrivateSignal); - void createProofSignal(const QString& txHash); + void createProofSignal(const QString& txHash, bool needToFind); void checkProofSignal(); void showWalletdParamsSignal(); + void exportViewOnlyKeysSignal(); + void exportKeysSignal(); void restartDaemon(QPrivateSignal); void createWalletSignal(QWidget* parent); diff --git a/src/mainwindow.ui b/src/mainwindow.ui index 3e37bde..7856809 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -672,6 +672,8 @@ + + @@ -786,6 +788,16 @@ Wallet daemon &parameters + + + Export view only wallet + + + + + Export keys + + @@ -795,7 +807,7 @@ 1 copiedToClipboardSignal() - createProofSignal(QString) + createProofSignal(QString,bool) @@ -1079,9 +1091,9 @@ m_overviewFrame - createProofSignal(QString) + createProofSignal(QString,bool) MainWindow - createProof(QString) + createProof(QString,bool) 318 @@ -1125,6 +1137,38 @@ + + m_exportViewOnlyKeysAction + triggered() + MainWindow + exportViewOnlyKeys() + + + -1 + -1 + + + 636 + 411 + + + + + m_exportKeysAction + triggered() + MainWindow + exportKeys() + + + -1 + -1 + + + 636 + 411 + + + aboutQt() @@ -1143,9 +1187,11 @@ copiedToClipboard() openDataFolder() importKeys() - createProof(QString) + createProof(QString,bool) checkProof() showWalletdParams() + exportViewOnlyKeys() + exportKeys() diff --git a/src/overviewframe.cpp b/src/overviewframe.cpp index e7fc6f0..07027b1 100644 --- a/src/overviewframe.cpp +++ b/src/overviewframe.cpp @@ -171,7 +171,8 @@ bool OverviewFrame::eventFilter(QObject* object, QEvent* event) const bool copyableColumns = modelIndex.column() == WalletModel::COLUMN_HASH || (modelIndex.column() == WalletModel::COLUMN_BLOCK_HASH && !m_transactionsModel->data(modelIndex, WalletModel::ROLE_BLOCK_HASH).toString().isEmpty()); - const bool proofColumn = (modelIndex.column() == WalletModel::COLUMN_PROOF && m_transactionsModel->data(modelIndex, WalletModel::ROLE_PROOF).toBool()); + const bool proof = m_transactionsModel->data(modelIndex, WalletModel::ROLE_PROOF).toBool(); + const bool proofColumn = (modelIndex.column() == WalletModel::COLUMN_PROOF/* && proof*/); const bool valid = copyableColumns || proofColumn; if(!valid) return false; @@ -184,7 +185,7 @@ bool OverviewFrame::eventFilter(QObject* object, QEvent* event) if (proofColumn) { const QString txHash = m_transactionsModel->data(modelIndex, WalletModel::ROLE_HASH).toString(); - emit createProofSignal(txHash); + emit createProofSignal(txHash, !proof); } } else if (event->type() == QEvent::MouseMove) @@ -195,7 +196,7 @@ bool OverviewFrame::eventFilter(QObject* object, QEvent* event) const bool showHandCursor = modelIndex.column() == WalletModel::COLUMN_HASH || (modelIndex.column() == WalletModel::COLUMN_BLOCK_HASH && !m_transactionsModel->data(modelIndex, WalletModel::ROLE_BLOCK_HASH).toString().isEmpty()) || - (modelIndex.column() == WalletModel::COLUMN_PROOF && m_transactionsModel->data(modelIndex, WalletModel::ROLE_PROOF).toBool()); + (modelIndex.column() == WalletModel::COLUMN_PROOF/* && m_transactionsModel->data(modelIndex, WalletModel::ROLE_PROOF).toBool()*/); setCursor(showHandCursor ? Qt::PointingHandCursor : Qt::ArrowCursor); } diff --git a/src/overviewframe.h b/src/overviewframe.h index 58eccfa..50fe9e3 100644 --- a/src/overviewframe.h +++ b/src/overviewframe.h @@ -34,7 +34,7 @@ class OverviewFrame : public QFrame signals: void copiedToClipboardSignal(); - void createProofSignal(const QString& txHash); + void createProofSignal(const QString& txHash, bool needToFind); private: QScopedPointer m_ui; diff --git a/src/settings.cpp b/src/settings.cpp index 5f2dfc9..7cc9902 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -30,9 +30,9 @@ constexpr char OPTION_WALLETD_PARAMS[] = "walletdParams"; constexpr quint16 DEFAULT_LOCAL_RPC_PORT = 8070; constexpr char LOCAL_HOST[] = "127.0.0.1"; -constexpr char VERSION[] = "2.0.0"; +constexpr char VERSION[] = "2.0.1"; constexpr char VERSION_SUFFIX[] = "stable"; -constexpr char REVISION[] = "20180320"; +constexpr char REVISION[] = "20180329"; #if defined(Q_OS_LINUX) constexpr char DEFAULT_WORK_DIR[] = ".bytecoin"; diff --git a/src/walletd.cpp b/src/walletd.cpp index 6c432d2..09c93ad 100644 --- a/src/walletd.cpp +++ b/src/walletd.cpp @@ -6,17 +6,21 @@ #include #include #include +#include +#include #include #include "walletd.h" #include "JsonRpc/JsonRpcClient.h" #include "settings.h" #include "common.h" +#include "exportkeydialog.h" namespace { constexpr int RERUN_TIMER_MSEC = 3000; +constexpr int STATUS_TIMER_MSEC = 4000; constexpr int WAITING_TIMEOUT_MSEC = 10000; template @@ -117,10 +121,11 @@ RemoteWalletd::RemoteWalletd(const QString& endPoint, QObject* parent) : QObject(parent) , jsonClient_(new JsonRpc::WalletClient(endPoint, this)) , state_(State::STOPPED) - , rerunTimerId_(-1) +// , rerunTimerId_(-1) +// , statusTimerId_(-1) { connect(jsonClient_, &JsonRpc::WalletClient::addressesReceived, this, &RemoteWalletd::addressesReceived); -// connect(jsonClient_, &JsonRpc::WalletClient::statusReceived, this, &RemoteWalletd::statusReceived); + connect(jsonClient_, &JsonRpc::WalletClient::statusReceived, this, &RemoteWalletd::statusReceived); connect(jsonClient_, &JsonRpc::WalletClient::transfersReceived, this, &RemoteWalletd::transfersReceived); connect(jsonClient_, &JsonRpc::WalletClient::balanceReceived, this, &RemoteWalletd::balanceReceived); connect(jsonClient_, &JsonRpc::WalletClient::viewKeyReceived, this, &RemoteWalletd::viewKeyReceived); @@ -140,7 +145,14 @@ RemoteWalletd::RemoteWalletd(const QString& endPoint, QObject* parent) connect(jsonClient_, &JsonRpc::WalletClient::authRequiredSignal, this, &RemoteWalletd::authRequired); - connect(this, &RemoteWalletd::errorOccurred, this, &RemoteWalletd::rerun); + connect(this, &RemoteWalletd::errorOccurred, &rerunTimer_, static_cast(&QTimer::start)); + + rerunTimer_.setSingleShot(true); + rerunTimer_.setInterval(RERUN_TIMER_MSEC); + rerunTimer_.setSingleShot(false); + statusTimer_.setInterval(STATUS_TIMER_MSEC); + connect(&rerunTimer_, &QTimer::timeout, this, &RemoteWalletd::rerun); + connect(&statusTimer_, &QTimer::timeout, this, &RemoteWalletd::sendGetStatus); } /*virtual*/ @@ -149,6 +161,27 @@ RemoteWalletd::~RemoteWalletd() stop(); } +void RemoteWalletd::rerun() +{ +// rerunTimer_.stop(); + RemoteWalletd::run(); +} + +void RemoteWalletd::sendGetStatus() +{ + if (state_ == State::CONNECTED) + { + jsonClient_->sendGetStatus(RpcApi::GetStatus::Request{ + /*status.top_block_hash, + status.transaction_pool_version, + status.outgoing_peer_count, + status.incoming_peer_count, + status.lower_level_error*/}); + + jsonClient_->sendGetBalance(RpcApi::GetBalance::Request{QString{}, -1}); + } +} + /*virtual*/ void RemoteWalletd::run() { @@ -162,13 +195,14 @@ void RemoteWalletd::run() this, &RemoteWalletd::errorOccurred, [this]() { + statusTimer_.start(); jsonClient_->sendGetStatus(RpcApi::GetStatus::Request{}); }); - onceCallOrDieConnect( - jsonClient_, &JsonRpc::WalletClient::statusReceived, - this, &RemoteWalletd::errorOccurred, - this, &RemoteWalletd::statusReceived); +// onceCallOrDieConnect( +// jsonClient_, &JsonRpc::WalletClient::statusReceived, +// this, &RemoteWalletd::errorOccurred, +// this, &RemoteWalletd::statusReceived); jsonClient_->sendGetAddresses(); } @@ -176,11 +210,13 @@ void RemoteWalletd::run() /*virtual*/ void RemoteWalletd::stop() { - if (rerunTimerId_ != -1) - { - killTimer(rerunTimerId_); - rerunTimerId_ = -1; - } +// if (rerunTimerId_ != -1) +// { +// killTimer(rerunTimerId_); +// rerunTimerId_ = -1; +// } + rerunTimer_.stop(); + statusTimer_.stop(); setState(State::STOPPED); } @@ -191,40 +227,40 @@ void RemoteWalletd::statusReceived(const RpcApi::Status& status) emit statusReceivedSignal(status); if (state_ == State::CONNECTED) { - onceCallOrDieConnect( - jsonClient_, &JsonRpc::WalletClient::statusReceived, - this, &RemoteWalletd::errorOccurred, - this, &RemoteWalletd::statusReceived); +// onceCallOrDieConnect( +// jsonClient_, &JsonRpc::WalletClient::statusReceived, +// this, &RemoteWalletd::errorOccurred, +// this, &RemoteWalletd::statusReceived); - jsonClient_->sendGetStatus(RpcApi::GetStatus::Request{ + /*jsonClient_->sendGetStatus(RpcApi::GetStatus::Request{ status.top_block_hash, status.transaction_pool_version, status.outgoing_peer_count, status.incoming_peer_count, status.lower_level_error}); - jsonClient_->sendGetBalance(RpcApi::GetBalance::Request{QString{}, -1}); + jsonClient_->sendGetBalance(RpcApi::GetBalance::Request{QString{}, -1});*/ } } -void RemoteWalletd::rerun() -{ - if (rerunTimerId_ == -1) - rerunTimerId_ = startTimer(RERUN_TIMER_MSEC); -} +//void RemoteWalletd::startRerunTimer() +//{ +// if (rerunTimerId_ == -1) +// rerunTimerId_ = startTimer(RERUN_TIMER_MSEC); +//} -void RemoteWalletd::timerEvent(QTimerEvent* event) -{ - if (event->timerId() == rerunTimerId_) - { - killTimer(rerunTimerId_); - rerunTimerId_ = -1; - RemoteWalletd::run(); - return; - } +//void RemoteWalletd::timerEvent(QTimerEvent* event) +//{ +// if (event->timerId() == rerunTimerId_) +// { +// killTimer(rerunTimerId_); +// rerunTimerId_ = -1; +// RemoteWalletd::run(); +// return; +// } - QObject::timerEvent(event); -} +// QObject::timerEvent(event); +//} void RemoteWalletd::transfersReceived(const RpcApi::Transfers& history) @@ -443,7 +479,8 @@ void BuiltinWalletd::run(const QStringList& args) walletd_, &QProcess::errorOccurred, [this]() { - RemoteWalletd::run(); + if (state_ == State::RUNNING) + RemoteWalletd::run(); }); #else onceCallOrDieConnect( @@ -451,7 +488,8 @@ void BuiltinWalletd::run(const QStringList& args) walletd_, static_cast(&QProcess::error), [this]() { - RemoteWalletd::run(); + if (state_ == State::RUNNING) + RemoteWalletd::run(); }); #endif @@ -490,17 +528,10 @@ void BuiltinWalletd::changeWalletPassword(QString&& oldPassword, QString&& newPa QStringList args; args << QString("--wallet-file=%1").arg(pathToWallet_); args << QString("--set-password"); + changePassword_ = true; + password_ = std::move(oldPassword); + newPassword_ = std::move(newPassword); run(args); - walletd_->write((oldPassword + '\n').toUtf8()); - password_.fill('0', 200); - password_.clear(); - QByteArray pass = (newPassword + '\n').toUtf8(); - walletd_->write(pass); - walletd_->write(pass); // confirm password - newPassword.fill('0', 200); - newPassword.clear(); - pass.fill('0', 200); - pass.clear(); }); stop(); @@ -517,18 +548,35 @@ void BuiltinWalletd::daemonStarted() if (createNew_) emit requestPasswordWithConfirmationSignal(); - else + else if (!changePassword_) emit requestPasswordSignal(); const bool importKeys = !keys_.isEmpty(); if (importKeys) walletd_->write(keys_.toHex() + QString{'\n'}.toUtf8()); - walletd_->write((password_ + '\n').toUtf8()); - if (createNew_) - walletd_->write((password_ + '\n').toUtf8()); // write confirmation - password_.fill('0', 200); - password_.clear(); + if (changePassword_) + { + walletd_->write((password_ + '\n').toUtf8()); + password_.fill('0', 200); + password_.clear(); + QByteArray pass = (newPassword_ + '\n').toUtf8(); + walletd_->write(pass); + walletd_->write(pass); // confirm password + newPassword_.fill('0', 200); + newPassword_.clear(); + pass.fill('0', 200); + pass.clear(); + changePassword_ = false; + } + else + { + walletd_->write((password_ + '\n').toUtf8()); + if (createNew_) + walletd_->write((password_ + '\n').toUtf8()); // write confirmation + password_.fill('0', 200); + password_.clear(); + } walletd_->write((auth_.getConcatenated() + '\n').toUtf8()); @@ -611,6 +659,189 @@ void BuiltinWalletd::authRequired(QAuthenticator* authenticator) authenticator->setPassword(auth_.getPass()); } +void BuiltinWalletd::exportViewOnlyKeys(QWidget* parent/*, const QString& exportPath*/) +{ + QProcess walletd; + walletd.setProgram(Settings::getDefaultWalletdPath()); + + QString pass; + emit requestPasswordForExportSignal(&walletd, &pass); + + if (pass.isNull()) + return; + + const QString fileName = QFileDialog::getSaveFileName( + parent, + tr("Create wallet file"), + QDir::homePath(), + tr("Wallet files (*.wallet);;All files (*)")); + if (fileName.isEmpty()) + return; + + connect(&walletd, &QProcess::readyReadStandardOutput, this, &BuiltinWalletd::daemonStandardOutputReady); + connect(&walletd, &QProcess::readyReadStandardError, this, &BuiltinWalletd::daemonStandardErrorReady); +#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)) + connect( + walletd_, &QProcess::errorOccurred, + [&walletd, parent](QProcess::ProcessError error) + { + if (error != QProcess::FailedToStart) + return; + QMessageBox::critical(parent, QObject::tr("Error"), tr("Failed to export view only keys. ") + walletd.errorString()); + }); +#else + connect( + walletd_, static_cast(&QProcess::error), + [&walletd, parent](QProcess::ProcessError error) + { + if (error != QProcess::FailedToStart) + return; + QMessageBox::critical(parent, QObject::tr("Error"), tr("Failed to export view only keys. ") + walletd.errorString()); + }); +#endif + connect(&walletd, static_cast(&QProcess::finished), + [&walletd, parent](int exitCode, QProcess::ExitStatus /*exitStatus*/) + { + if (exitCode == 0) + return; + const QString walletdMsg = BuiltinWalletd::errorMessage(static_cast(exitCode)); + const QString msg = !walletdMsg.isEmpty() ? + walletdMsg : + tr("Failed to export view only keys. %1. Return code %2. ").arg(walletd.errorString()).arg(exitCode); + QMessageBox::critical(parent, QObject::tr("Error"), msg); + }); + + QStringList args; + args << QString("--wallet-file=%1").arg(pathToWallet_); + args << QString("--export-view-only=%1").arg(fileName); + walletd.setArguments(args); + walletd.start(); + + walletd.write((pass + '\n').toUtf8()); + pass.fill('0', 200); + pass.clear(); + + qDebug("[Walletd] Waiting for walletd finished..."); + if (walletd.waitForFinished(WAITING_TIMEOUT_MSEC)) + qDebug("[Walletd] Walletd terminated."); + else + qDebug("[Walletd] Walletd terminating is timed out."); +} + +void BuiltinWalletd::exportKeys(QWidget* parent) +{ + QProcess walletd; + walletd.setProgram(Settings::getDefaultWalletdPath()); + + QString pass; + emit requestPasswordForExportSignal(&walletd, &pass); + + if (pass.isNull()) + return; + + connect(&walletd, &QProcess::readyReadStandardError, this, &BuiltinWalletd::daemonStandardErrorReady); +#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)) + connect( + walletd_, &QProcess::errorOccurred, + [&walletd, parent](QProcess::ProcessError error) + { + if (error != QProcess::FailedToStart) + return; + QMessageBox::critical(parent, QObject::tr("Error"), tr("Failed to export keys. ") + walletd.errorString()); + }); +#else + connect( + walletd_, static_cast(&QProcess::error), + [&walletd, parent](QProcess::ProcessError error) + { + if (error != QProcess::FailedToStart) + return; + QMessageBox::critical(parent, QObject::tr("Error"), tr("Failed to export keys. ") + walletd.errorString()); + }); +#endif + connect(&walletd, static_cast(&QProcess::finished), + [&walletd, parent](int exitCode, QProcess::ExitStatus /*exitStatus*/) + { + if (exitCode == 0) + return; + const QString walletdMsg = BuiltinWalletd::errorMessage(static_cast(exitCode)); + const QString msg = !walletdMsg.isEmpty() ? + walletdMsg : + tr("Failed to export keys. %1. Return code %2. ").arg(walletd.errorString()).arg(exitCode); + QMessageBox::critical(parent, QObject::tr("Error"), msg); + }); + + QStringList args; + args << QString("--wallet-file=%1").arg(pathToWallet_); + args << QString("--export-keys"); + walletd.setArguments(args); + walletd.start(); + + walletd.write((pass + '\n').toUtf8()); + pass.fill('0', 200); + pass.clear(); + + qDebug("[Walletd] Waiting for walletd finished..."); + if (walletd.waitForFinished(WAITING_TIMEOUT_MSEC)) + qDebug("[Walletd] Walletd terminated."); + else + qDebug("[Walletd] Walletd terminating is timed out."); + + if (walletd.exitCode() != 0) + return; + const QByteArray data = walletd.readAllStandardOutput(); + const QString read{data}; + ExportKeyDialog dlg{QString{read.simplified().right(256)}}; + dlg.exec(); +} + +/*static*/ +QString BuiltinWalletd::errorMessage(ReturnCode err) +{ + QString msg; + switch(err) + { + case ReturnCode::BYTECOIND_DATABASE_ERROR: + msg = tr("Database write error. Disk is full or database is corrupted."); + break; + case ReturnCode::BYTECOIND_ALREADY_RUNNING: + msg = tr("Cannot run bytecoind. Another instance of bytecoind is running."); + break; + case ReturnCode::WALLETD_BIND_PORT_IN_USE: + msg = tr("Cannot run walletd. Walletd bind port in use."); + break; + case ReturnCode::BYTECOIND_BIND_PORT_IN_USE: + msg = tr("Cannot run bytecoind. Bytecoind bind port in use."); + break; + case ReturnCode::WALLET_FILE_READ_ERROR: + msg = tr("Cannot read the specified wallet file."); + break; + case ReturnCode::WALLET_FILE_UNKNOWN_VERSION: + msg = tr("Version of the specified wallet file is unknown."); + break; + case ReturnCode::WALLET_FILE_DECRYPT_ERROR: + msg = tr("Cannot decrypt the wallet file. The specified password is incorrect or the wallet file is corrupted."); + break; + case ReturnCode::WALLET_FILE_WRITE_ERROR: + msg = tr("Cannot write to the wallet file. Probably your file system is read only."); + break; + case ReturnCode::WALLET_FILE_EXISTS: + msg = tr("The specified wallet file already exists. Bytecoin wallet could not overwrite an existed file for safety reason. If you want to overwrite the file please remove it manually and try again."); + break; + case ReturnCode::WALLET_WITH_THE_SAME_VIEWKEY_IN_USE: + msg = tr("Another walletd instance is using the specified wallet file or another wallet file with the same view key."); + break; + case ReturnCode::WALLETD_WRONG_ARGS: + msg = tr("Wrong arguments passed to walletd."); + break; + case ReturnCode::WALLETD_EXPORTKEYS_MORETHANONE: + msg = tr("Walletd cannot export keys for more than one spend keypair"); + break; + } + return msg; +} + + static QString generatePass() { diff --git a/src/walletd.h b/src/walletd.h index 593ef71..8126caa 100644 --- a/src/walletd.h +++ b/src/walletd.h @@ -6,6 +6,7 @@ #include #include +#include #include "rpcapi.h" @@ -75,12 +76,17 @@ class RemoteWalletd : public QObject private: JsonRpc::WalletClient* jsonClient_; State state_; - int rerunTimerId_; +// int rerunTimerId_; +// int statusTimerId_; + QTimer rerunTimer_; + QTimer statusTimer_; void setState(State state); - void rerun(); - virtual void timerEvent(QTimerEvent* event) override; +// void startRerunTimer(); +// virtual void timerEvent(QTimerEvent* event) override; virtual void authRequired(QAuthenticator* authenticator); + void rerun(); + void sendGetStatus(); private slots: void statusReceived(const RpcApi::Status& status); @@ -141,6 +147,7 @@ class BuiltinWalletd : public RemoteWalletd WALLET_FILE_EXISTS = 209, // daemon never overwrites file during --generate-wallet WALLET_WITH_THE_SAME_VIEWKEY_IN_USE = 210, // another walletd instance is using the same wallet file or another wallet file with the same viewkey WALLETD_WRONG_ARGS = 211, + WALLETD_EXPORTKEYS_MORETHANONE = 212, // We can export keys only if wallet file contains exactly 1 spend keypair }; Q_ENUM(ReturnCode) @@ -148,6 +155,8 @@ class BuiltinWalletd : public RemoteWalletd BuiltinWalletd(const QString& pathToWallet, bool createNew, QByteArray&& keys, QObject* parent = nullptr); virtual ~BuiltinWalletd() override; + static QString errorMessage(ReturnCode err); + virtual void run() override; virtual void stop() override; @@ -160,6 +169,10 @@ class BuiltinWalletd : public RemoteWalletd QString errorString() const; QProcess::ProcessError error() const; + void exportViewOnlyKeys(QWidget* parent/*, const QString& exportPath*/); + void exportKeys(QWidget* parent); + + signals: void daemonStandardOutputSignal(const QString& data); void daemonStandardErrorSignal(const QString& data); @@ -172,12 +185,14 @@ class BuiltinWalletd : public RemoteWalletd void stateChangedSignal(State oldState, State newState); void requestPasswordSignal(); void requestPasswordWithConfirmationSignal(); + void requestPasswordForExportSignal(QProcess* walletd, QString* pass); private: QProcess* walletd_; State state_; const QString pathToWallet_; QString password_; + QString newPassword_; bool createNew_; bool changePassword_; QByteArray keys_; diff --git a/src/walletdparamsdialog.cpp b/src/walletdparamsdialog.cpp index a630088..66fdda2 100644 --- a/src/walletdparamsdialog.cpp +++ b/src/walletdparamsdialog.cpp @@ -11,9 +11,11 @@ namespace WalletGUI WalletdParamsDialog::WalletdParamsDialog(bool allowToRestart, QWidget *parent) : QDialog(parent) , ui(new Ui::WalletdParamsDialog) + , allowToRestart_(allowToRestart) { ui->setupUi(this); - ui->applyButton->setEnabled(allowToRestart); +// ui->applyButton->setEnabled(allowToRestart); + ui->applyButton->setText(allowToRestart_ ? tr("Save and restart walletd") : tr("Save")); ui->paramsEdit->setText(Settings::instance().getWalletdParams().join(QChar(' '))); } @@ -30,7 +32,8 @@ void WalletdParamsDialog::saveParams() void WalletdParamsDialog::applyParams() { saveParams(); - emit restartWalletd(); + if (allowToRestart_) + emit restartWalletd(); } } diff --git a/src/walletdparamsdialog.h b/src/walletdparamsdialog.h index 0dec060..69dd89e 100644 --- a/src/walletdparamsdialog.h +++ b/src/walletdparamsdialog.h @@ -30,6 +30,8 @@ public slots: private: Ui::WalletdParamsDialog *ui; + + bool allowToRestart_; }; } diff --git a/src/walletmodel.cpp b/src/walletmodel.cpp index fe07e8d..bdcc35b 100644 --- a/src/walletmodel.cpp +++ b/src/walletmodel.cpp @@ -22,6 +22,7 @@ struct WalletModelState RpcApi::Balance balance; QList txs; QList addresses; + bool viewOnly = false; RemoteWalletd::State walletdState = RemoteWalletd::State::STOPPED; int unconfimedSize = 0; @@ -173,16 +174,18 @@ void WalletModel::containerReceived(Container& oldContainer, const Container& ne void WalletModel::addressesReceived(const RpcApi::Addresses& response) { const QList& addresses = response.addresses; - if (pimpl_->addresses == addresses) + if (pimpl_->addresses == addresses && pimpl_->viewOnly == response.view_only) return; containerReceived(pimpl_->addresses, addresses, pimpl_->txs.size()); + pimpl_->viewOnly = response.view_only; QVector changedAddressRoles; changedAddressRoles << Qt::EditRole << Qt::DisplayRole - << ROLE_ADDRESS; + << ROLE_ADDRESS + << ROLE_VIEW_ONLY; - emit dataChanged(index(0, COLUMN_ADDRESS), index(pimpl_->addresses.size() - 1, COLUMN_ADDRESS), changedAddressRoles); + emit dataChanged(index(0, COLUMN_ADDRESS), index(pimpl_->addresses.size() - 1, COLUMN_VIEW_ONLY), changedAddressRoles); } void WalletModel::transfersReceived(const RpcApi::Transfers& history) @@ -379,7 +382,7 @@ QVariant WalletModel::getDisplayRoleData(const QModelIndex& index) const if (index.column() >= COLUMN_STATE && index.column() <= COLUMN_STATE) return getDisplayRoleState(index); - if (index.column() >= COLUMN_ADDRESS && index.column() <= COLUMN_ADDRESS) + if (index.column() >= COLUMN_ADDRESS && index.column() <= COLUMN_VIEW_ONLY) return getDisplayRoleAddresses(index); if (index.column() >= COLUMN_UNLOCK_TIME && index.column() <= COLUMN_PROOF) @@ -399,7 +402,7 @@ QVariant WalletModel::getUserRoleData(const QModelIndex& index, int role) const if (role >= ROLE_STATE && role <= ROLE_STATE) return getUserRoleState(index, role); - if (role >= ROLE_ADDRESS && role <= ROLE_ADDRESS) + if (role >= ROLE_ADDRESS && role <= ROLE_VIEW_ONLY) return getUserRoleAddresses(index, role); if (role >= ROLE_UNLOCK_TIME && role <= ROLE_PROOF) @@ -458,6 +461,8 @@ QVariant WalletModel::getDisplayRoleAddresses(const QModelIndex& index) const { case COLUMN_ADDRESS: return pimpl_->addresses[index.row()]; + case COLUMN_VIEW_ONLY: + return pimpl_->viewOnly ? tr("(View only)") : QString{}; } return QVariant(); @@ -472,6 +477,8 @@ QVariant WalletModel::getUserRoleAddresses(const QModelIndex& index, int role) c { case ROLE_ADDRESS: return pimpl_->addresses[index.row()]; + case ROLE_VIEW_ONLY: + return pimpl_->viewOnly; } return QVariant(); @@ -551,9 +558,12 @@ QVariant WalletModel::getDisplayRoleHistory(const QModelIndex& index) const for (const RpcApi::Transfer& tr : tx.transfers) { if (!tr.ours) + { proof = true; + break; + } } - return proof ? QVariant(tr("Proof")) : QVariant(/*tr("Try")*/); + return pimpl_->viewOnly ? QVariant{} : proof ? QVariant(tr("Proof")) : QVariant(tr("Try")); } } diff --git a/src/walletmodel.h b/src/walletmodel.h index f894f10..63998e8 100644 --- a/src/walletmodel.h +++ b/src/walletmodel.h @@ -25,6 +25,7 @@ class WalletModel : public QAbstractItemModel enum Columns { COLUMN_ADDRESS = 0, // getAddresses + COLUMN_VIEW_ONLY, COLUMN_UNLOCK_TIME, // listHistory (transactions) COLUMN_PAYMENT_ID, @@ -66,6 +67,7 @@ class WalletModel : public QAbstractItemModel enum Roles { ROLE_ADDRESS = Qt::UserRole, + ROLE_VIEW_ONLY, ROLE_UNLOCK_TIME, // listHistory (transactions) ROLE_PAYMENT_ID,