diff options
| author | Riccardo Spagni <ric@spagni.net> | 2017-02-04 17:46:57 +0200 |
|---|---|---|
| committer | Riccardo Spagni <ric@spagni.net> | 2017-02-04 17:46:57 +0200 |
| commit | 739d24efb4864a84f9b6bfac34dc804e26bde77b (patch) | |
| tree | f71030206a20ca93981aa51bdeade495920c6304 | |
| parent | f2a583fd49f6070b8a641e749704b8b958e20537 (diff) | |
| parent | 0b41fbc858a95b99a6a6f5ab203368cfd4870044 (diff) | |
| download | monzero-gui-739d24efb4864a84f9b6bfac34dc804e26bde77b.tar.gz monzero-gui-739d24efb4864a84f9b6bfac34dc804e26bde77b.tar.xz monzero-gui-739d24efb4864a84f9b6bfac34dc804e26bde77b.zip | |
Merge pull request #442
0b41fbc Don't close/reopen when changing daemon requires #1655 (Jaquee)
2586404 sync progress improvements (Jaquee)
eb909e1 async connectionStatus and init (Jaquee)
cb3281d WalletManager: fix possible race (Jaquee)
9dbbd4c WalletManager: check connection before isMining() (Jaquee)
| -rw-r--r-- | components/ProgressBar.qml | 2 | ||||
| -rw-r--r-- | main.qml | 33 | ||||
| -rw-r--r-- | pages/Settings.qml | 4 | ||||
| -rw-r--r-- | pages/Transfer.qml | 1 | ||||
| -rw-r--r-- | src/libwalletqt/Wallet.cpp | 79 | ||||
| -rw-r--r-- | src/libwalletqt/Wallet.h | 15 | ||||
| -rw-r--r-- | src/libwalletqt/WalletManager.cpp | 7 |
7 files changed, 96 insertions, 45 deletions
diff --git a/components/ProgressBar.qml b/components/ProgressBar.qml index 33f2c585..ec53ec61 100644 --- a/components/ProgressBar.qml +++ b/components/ProgressBar.qml @@ -42,7 +42,7 @@ Item { var progressLevel = ((currentBlock/targetBlock) * 100).toFixed(0); fillLevel = progressLevel progressText.text = qsTr("Synchronizing blocks %1/%2").arg(currentBlock.toFixed(0)).arg(targetBlock.toFixed(0)); - item.visible = (currentWallet.connected !== Wallet.ConnectionStatus_Disconnected) && (currentBlock < targetBlock) + progressBar.visible = currentBlock < targetBlock } } @@ -55,7 +55,6 @@ ApplicationWindow { property var transaction; property var transactionDescription; property alias password : passwordDialog.password - property int splashCounter: 0 property bool isNewWallet: false property int restoreHeight:0 property bool daemonSynced: false @@ -265,10 +264,12 @@ ApplicationWindow { return path.replace(/.*[\/\\]/, '').replace(/\.keys$/, '') } - function onWalletConnectionStatusChanged(){ + function onWalletConnectionStatusChanged(status){ console.log("Wallet connection status changed") middlePanel.updateStatus(); - } + leftPanel.networkStatus.connected = status + leftPanel.progressBar.visible = (status === Wallet.ConnectionStatus_Connected) && !daemonSynced + } function onWalletOpened(wallet) { walletName = usefulName(wallet.path) @@ -310,7 +311,6 @@ ApplicationWindow { console.log(">>> wallet updated") middlePanel.unlockedBalanceText = leftPanel.unlockedBalanceText = walletManager.displayAmount(currentWallet.unlockedBalance); middlePanel.balanceText = leftPanel.balanceText = walletManager.displayAmount(currentWallet.balance); - console.log("time to unlock: ", currentWallet.history.minutesToUnlock); // Update history if new block found since last update and balance is locked. if(foundNewBlock && currentWallet.history.locked) { foundNewBlock = false; @@ -336,11 +336,16 @@ ApplicationWindow { // Daemon fully synced // TODO: implement onDaemonSynced or similar in wallet API and don't start refresh thread before daemon is synced - daemonSynced = (currentWallet.connected != Wallet.ConnectionStatus_Disconnected && dCurrentBlock >= dTargetBlock) + daemonSynced = dCurrentBlock >= dTargetBlock + // Update daemon sync progress leftPanel.progressBar.updateProgress(dCurrentBlock,dTargetBlock); - updateSyncing((currentWallet.connected !== Wallet.ConnectionStatus_Disconnected) && (dCurrentBlock < dTargetBlock)) + leftPanel.progressBar.visible = !daemonSynced && currentWallet.connected !== Wallet.ConnectionStatus_Disconnected + // Update wallet sync progress + updateSyncing((currentWallet.connected !== Wallet.ConnectionStatus_Disconnected) && !daemonSynced) + // Update transfer page status middlePanel.updateStatus(); + // If wallet isnt connected and no daemon is running - Ask if(currentWallet.connected === Wallet.ConnectionStatus_Disconnected && !daemonManager.running() && !walletInitialized){ daemonManagerDialog.open(); @@ -392,17 +397,10 @@ ApplicationWindow { daemonRunning = false; } - function onWalletNewBlock(blockHeight) { - // Update progress bar - var currHeight = blockHeight - //fast refresh until restoreHeight is reached - var increment = ((restoreHeight == 0) || currHeight < restoreHeight)? 1000 : 10 - - if(currHeight > splashCounter + increment){ - splashCounter = currHeight - leftPanel.progressBar.updateProgress(currHeight,currentWallet.daemonBlockChainTargetHeight()); - } - foundNewBlock = true; + function onWalletNewBlock(blockHeight, targetHeight) { + // Update progress bar + leftPanel.progressBar.updateProgress(blockHeight,targetHeight); + foundNewBlock = true; } function onWalletMoneyReceived(txId, amount) { @@ -712,7 +710,6 @@ ApplicationWindow { // close wallet and show wizard function showWizard(){ walletInitialized = false; - splashCounter = 0; closeWallet(); currentWallet = undefined; wizard.restart(); diff --git a/pages/Settings.qml b/pages/Settings.qml index e6088722..9bbb0ee3 100644 --- a/pages/Settings.qml +++ b/pages/Settings.qml @@ -324,8 +324,8 @@ Rectangle { var newDaemon = daemonAddr.text + ":" + daemonPort.text if(persistentSettings.daemon_address != newDaemon) { persistentSettings.daemon_address = newDaemon - //reconnect wallet - appWindow.initialize(); + //Reinit wallet + currentWallet.initAsync(newDaemon) } } } diff --git a/pages/Transfer.qml b/pages/Transfer.qml index 28eebc22..79efc28d 100644 --- a/pages/Transfer.qml +++ b/pages/Transfer.qml @@ -682,7 +682,6 @@ Rectangle { //TODO: enable send page when we're connected and daemon is synced function updateStatus() { - console.log("updated transfer page status") if(typeof currentWallet === "undefined") { statusText.text = qsTr("Wallet is not connected to daemon.") + "<br>" + root.startLinkText return; diff --git a/src/libwalletqt/Wallet.cpp b/src/libwalletqt/Wallet.cpp index 2ade69bb..56121370 100644 --- a/src/libwalletqt/Wallet.cpp +++ b/src/libwalletqt/Wallet.cpp @@ -16,6 +16,8 @@ #include <QtConcurrent/QtConcurrent> #include <QList> #include <QVector> +#include <QMutex> +#include <QMutexLocker> namespace { static const int DAEMON_BLOCKCHAIN_HEIGHT_CACHE_TTL_SECONDS = 10; @@ -54,7 +56,7 @@ public: virtual void newBlock(uint64_t height) { // qDebug() << __FUNCTION__; - emit m_wallet->newBlock(height); + emit m_wallet->newBlock(height, m_wallet->daemonBlockChainTargetHeight()); } virtual void updated() @@ -103,17 +105,35 @@ bool Wallet::testnet() const return m_walletImpl->testnet(); } -Wallet::ConnectionStatus Wallet::connected() const + +void Wallet::updateConnectionStatusAsync() { - // cache connection status - if (!m_initialized || m_connectionStatusTime.elapsed() / 1000 > m_connectionStatusTtl) { - m_initialized = true; - ConnectionStatus newStatus = static_cast<ConnectionStatus>(m_walletImpl->connected()); + QFuture<Monero::Wallet::ConnectionStatus> future = QtConcurrent::run(m_walletImpl, &Monero::Wallet::connected); + QFutureWatcher<Monero::Wallet::ConnectionStatus> *connectionWatcher = new QFutureWatcher<Monero::Wallet::ConnectionStatus>(); + + connect(connectionWatcher, &QFutureWatcher<Monero::Wallet::ConnectionStatus>::finished, [=]() { + QFuture<Monero::Wallet::ConnectionStatus> future = connectionWatcher->future(); + connectionWatcher->deleteLater(); + ConnectionStatus newStatus = static_cast<ConnectionStatus>(future.result()); if (newStatus != m_connectionStatus) { m_connectionStatus = newStatus; - emit connectionStatusChanged(); + emit connectionStatusChanged(newStatus); } + // Release lock + m_connectionStatusRunning = false; + }); + connectionWatcher->setFuture(future); +} + +Wallet::ConnectionStatus Wallet::connected(bool forceCheck) +{ + // cache connection status + if (forceCheck || !m_initialized || (m_connectionStatusTime.elapsed() / 1000 > m_connectionStatusTtl && !m_connectionStatusRunning) || m_connectionStatusTime.elapsed() > 30000) { + qDebug() << "Checking connection status"; + m_connectionStatusRunning = true; + m_initialized = true; m_connectionStatusTime.restart(); + updateConnectionStatusAsync(); } return m_connectionStatus; @@ -151,17 +171,38 @@ bool Wallet::store(const QString &path) bool Wallet::init(const QString &daemonAddress, quint64 upperTransactionLimit, bool isRecovering, quint64 restoreHeight) { - return m_walletImpl->init(daemonAddress.toStdString(), upperTransactionLimit); -} - -void Wallet::initAsync(const QString &daemonAddress, quint64 upperTransactionLimit, bool isRecovering, quint64 restoreHeight) -{ + qDebug() << "init non async"; if (isRecovering){ qDebug() << "RESTORING"; m_walletImpl->setRecoveringFromSeed(true); m_walletImpl->setRefreshFromBlockHeight(restoreHeight); } - m_walletImpl->initAsync(daemonAddress.toStdString(), upperTransactionLimit); + m_walletImpl->init(daemonAddress.toStdString(), upperTransactionLimit); + return true; +} + +void Wallet::initAsync(const QString &daemonAddress, quint64 upperTransactionLimit, bool isRecovering, quint64 restoreHeight) +{ + qDebug() << "initAsync: " + daemonAddress; + m_connectionStatus = Wallet::ConnectionStatus_Disconnected; + emit connectionStatusChanged(m_connectionStatus); + + QFuture<bool> future = QtConcurrent::run(this, &Wallet::init, + daemonAddress, upperTransactionLimit, isRecovering, restoreHeight); + QFutureWatcher<bool> * watcher = new QFutureWatcher<bool>(); + + connect(watcher, &QFutureWatcher<bool>::finished, + this, [this, watcher, daemonAddress, upperTransactionLimit, isRecovering, restoreHeight]() { + QFuture<bool> future = watcher->future(); + watcher->deleteLater(); + if(future.result()){ + qDebug() << "init async finished - starting refresh"; + connected(true); + m_walletImpl->startRefresh(); + + } + }); + watcher->setFuture(future); } //! create a view only wallet @@ -220,6 +261,7 @@ quint64 Wallet::daemonBlockChainTargetHeight() const if (m_daemonBlockChainTargetHeight == 0 || m_daemonBlockChainTargetHeightTime.elapsed() / 1000 > m_daemonBlockChainTargetHeightTtl) { m_daemonBlockChainTargetHeight = m_walletImpl->daemonBlockChainTargetHeight(); + // Target height is set to 0 if daemon is synced. // Use current height from daemon when target height < current height if (m_daemonBlockChainTargetHeight < m_daemonBlockChainHeight){ @@ -242,6 +284,7 @@ bool Wallet::refresh() void Wallet::refreshAsync() { + qDebug() << "refresh async"; m_walletImpl->refreshAsync(); } @@ -273,13 +316,14 @@ void Wallet::createTransactionAsync(const QString &dst_addr, const QString &paym QFuture<PendingTransaction*> future = QtConcurrent::run(this, &Wallet::createTransaction, dst_addr, payment_id,amount, mixin_count, priority); QFutureWatcher<PendingTransaction*> * watcher = new QFutureWatcher<PendingTransaction*>(); - watcher->setFuture(future); + connect(watcher, &QFutureWatcher<PendingTransaction*>::finished, this, [this, watcher,dst_addr,payment_id,mixin_count]() { QFuture<PendingTransaction*> future = watcher->future(); watcher->deleteLater(); emit transactionCreated(future.result(),dst_addr,payment_id,mixin_count); }); + watcher->setFuture(future); } PendingTransaction *Wallet::createTransactionAll(const QString &dst_addr, const QString &payment_id, @@ -299,13 +343,14 @@ void Wallet::createTransactionAllAsync(const QString &dst_addr, const QString &p QFuture<PendingTransaction*> future = QtConcurrent::run(this, &Wallet::createTransactionAll, dst_addr, payment_id, mixin_count, priority); QFutureWatcher<PendingTransaction*> * watcher = new QFutureWatcher<PendingTransaction*>(); - watcher->setFuture(future); + connect(watcher, &QFutureWatcher<PendingTransaction*>::finished, this, [this, watcher,dst_addr,payment_id,mixin_count]() { QFuture<PendingTransaction*> future = watcher->future(); watcher->deleteLater(); emit transactionCreated(future.result(),dst_addr,payment_id,mixin_count); }); + watcher->setFuture(future); } PendingTransaction *Wallet::createSweepUnmixableTransaction() @@ -319,13 +364,14 @@ void Wallet::createSweepUnmixableTransactionAsync() { QFuture<PendingTransaction*> future = QtConcurrent::run(this, &Wallet::createSweepUnmixableTransaction); QFutureWatcher<PendingTransaction*> * watcher = new QFutureWatcher<PendingTransaction*>(); - watcher->setFuture(future); + connect(watcher, &QFutureWatcher<PendingTransaction*>::finished, this, [this, watcher]() { QFuture<PendingTransaction*> future = watcher->future(); watcher->deleteLater(); emit transactionCreated(future.result(),"","",0); }); + watcher->setFuture(future); } UnsignedTransaction * Wallet::loadTxFile(const QString &fileName) @@ -542,6 +588,7 @@ Wallet::Wallet(Monero::Wallet *w, QObject *parent) m_daemonBlockChainHeightTime.restart(); m_daemonBlockChainTargetHeightTime.restart(); m_initialized = false; + m_connectionStatusRunning = false; } Wallet::~Wallet() diff --git a/src/libwalletqt/Wallet.h b/src/libwalletqt/Wallet.h index 9aec45fc..7e9651e4 100644 --- a/src/libwalletqt/Wallet.h +++ b/src/libwalletqt/Wallet.h @@ -3,6 +3,8 @@ #include <QObject> #include <QTime> +#include <QMutex> +#include <QtConcurrent/QtConcurrent> #include "wallet/wallet2_api.h" // we need to have an access to the Monero::Wallet::Status enum here; #include "PendingTransaction.h" // we need to have an access to the PendingTransaction::Priority enum here; @@ -75,7 +77,8 @@ public: bool testnet() const; //! returns whether the wallet is connected, and version status - ConnectionStatus connected() const; + ConnectionStatus connected(bool forceCheck = false); + void updateConnectionStatusAsync(); //! returns true if wallet was ever synchronized bool synchronized() const; @@ -98,10 +101,10 @@ public: Q_INVOKABLE bool store(const QString &path = ""); //! initializes wallet - Q_INVOKABLE bool init(const QString &daemonAddress, quint64 upperTransactionLimit, bool isRecovering = false, quint64 restoreHeight = 0); + Q_INVOKABLE bool init(const QString &daemonAddress, quint64 upperTransactionLimit = 0, bool isRecovering = false, quint64 restoreHeight = 0); //! initializes wallet asynchronously - Q_INVOKABLE void initAsync(const QString &daemonAddress, quint64 upperTransactionLimit, bool isRecovering = false, quint64 restoreHeight = 0); + Q_INVOKABLE void initAsync(const QString &daemonAddress, quint64 upperTransactionLimit = 0, bool isRecovering = false, quint64 restoreHeight = 0); //! create a view only wallet Q_INVOKABLE bool createViewOnly(const QString &path, const QString &password) const; @@ -231,13 +234,13 @@ signals: void moneySpent(const QString &txId, quint64 amount); void moneyReceived(const QString &txId, quint64 amount); void unconfirmedMoneyReceived(const QString &txId, quint64 amount); - void newBlock(quint64 height); + void newBlock(quint64 height, quint64 targetHeight); void historyModelChanged() const; // emitted when transaction is created async void transactionCreated(PendingTransaction * transaction, QString address, QString paymentId, quint32 mixinCount); - void connectionStatusChanged() const; + void connectionStatusChanged(ConnectionStatus status) const; private: Wallet(QObject * parent = nullptr); @@ -266,6 +269,8 @@ private: mutable bool m_initialized; AddressBook * m_addressBook; mutable AddressBookModel * m_addressBookModel; + QMutex m_connectionStatusMutex; + bool m_connectionStatusRunning; }; diff --git a/src/libwalletqt/WalletManager.cpp b/src/libwalletqt/WalletManager.cpp index 1db216cf..df0ffdbd 100644 --- a/src/libwalletqt/WalletManager.cpp +++ b/src/libwalletqt/WalletManager.cpp @@ -64,13 +64,14 @@ void WalletManager::openWalletAsync(const QString &path, const QString &password QFuture<Wallet*> future = QtConcurrent::run(this, &WalletManager::openWallet, path, password, testnet); QFutureWatcher<Wallet*> * watcher = new QFutureWatcher<Wallet*>(); - watcher->setFuture(future); + connect(watcher, &QFutureWatcher<Wallet*>::finished, this, [this, watcher]() { QFuture<Wallet*> future = watcher->future(); watcher->deleteLater(); emit walletOpened(future.result()); }); + watcher->setFuture(future); } @@ -121,7 +122,6 @@ void WalletManager::closeWalletAsync() { QFuture<QString> future = QtConcurrent::run(this, &WalletManager::closeWallet); QFutureWatcher<QString> * watcher = new QFutureWatcher<QString>(); - watcher->setFuture(future); connect(watcher, &QFutureWatcher<QString>::finished, this, [this, watcher]() { @@ -129,6 +129,7 @@ void WalletManager::closeWalletAsync() watcher->deleteLater(); emit walletClosed(future.result()); }); + watcher->setFuture(future); } bool WalletManager::walletExists(const QString &path) const @@ -256,6 +257,8 @@ double WalletManager::miningHashRate() const bool WalletManager::isMining() const { + if(!m_currentWallet->connected()) + return false; return m_pimpl->isMining(); } |
