diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index 80f399bd0328..ebb8b3d70257 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -168,8 +168,6 @@ OverviewPage::OverviewPage(QWidget* parent) : GUIUtil::updateFonts(); - m_balances.balance = -1; - // Recent transactions ui->listTransactions->setItemDelegate(txdelegate); // Note: minimum height of listTransactions will be set later in updateAdvancedCJUI() to reflect actual settings @@ -206,8 +204,9 @@ void OverviewPage::handleTransactionClicked(const QModelIndex &index) void OverviewPage::setPrivacy(bool privacy) { m_privacy = privacy; - if (m_balances.balance != -1) { - setBalance(m_balances); + const auto& balances = walletModel->getCachedBalance(); + if (balances.balance != -1) { + setBalance(balances); coinJoinStatus(true); } @@ -230,7 +229,6 @@ OverviewPage::~OverviewPage() void OverviewPage::setBalance(const interfaces::WalletBalances& balances) { BitcoinUnit unit = walletModel->getOptionsModel()->getDisplayUnit(); - m_balances = balances; if (walletModel->wallet().isLegacy()) { if (walletModel->wallet().privateKeysDisabled()) { ui->labelBalance->setText(BitcoinUnits::floorHtmlWithPrivacy(unit, balances.watch_only_balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy)); @@ -316,14 +314,13 @@ void OverviewPage::setWalletModel(WalletModel *model) // update the display unit, to not use the default ("DASH") updateDisplayUnit(); // Keep up to date with wallet - interfaces::Wallet& wallet = model->wallet(); - interfaces::WalletBalances balances = wallet.getBalances(); - setBalance(balances); + setBalance(model->getCachedBalance()); connect(model, &WalletModel::balanceChanged, this, &OverviewPage::setBalance); connect(model->getOptionsModel(), &OptionsModel::displayUnitChanged, this, &OverviewPage::updateDisplayUnit); - updateWatchOnlyLabels((wallet.haveWatchOnly() && !model->wallet().privateKeysDisabled()) || gArgs.GetBoolArg("-debug-ui", false)); + interfaces::Wallet& wallet = model->wallet(); + updateWatchOnlyLabels((wallet.haveWatchOnly() && !wallet.privateKeysDisabled()) || gArgs.GetBoolArg("-debug-ui", false)); connect(model, &WalletModel::notifyWatchonlyChanged, [this](bool showWatchOnly) { updateWatchOnlyLabels(showWatchOnly && !walletModel->wallet().privateKeysDisabled()); }); @@ -348,11 +345,11 @@ void OverviewPage::setWalletModel(WalletModel *model) void OverviewPage::updateDisplayUnit() { - if(walletModel && walletModel->getOptionsModel()) - { + if (walletModel && walletModel->getOptionsModel()) { m_display_bitcoin_unit = walletModel->getOptionsModel()->getDisplayUnit(); - if (m_balances.balance != -1) { - setBalance(m_balances); + const auto& balances = walletModel->getCachedBalance(); + if (balances.balance != -1) { + setBalance(balances); } // Update txdelegate->unit with the current unit @@ -379,10 +376,11 @@ void OverviewPage::updateCoinJoinProgress() { if (!walletModel || !clientModel || clientModel->node().shutdownRequested() || !clientModel->masternodeSync().isBlockchainSynced()) return; + const auto& cached_balances = walletModel->getCachedBalance(); QString strAmountAndRounds; QString strCoinJoinAmount = BitcoinUnits::formatHtmlWithUnit(m_display_bitcoin_unit, clientModel->coinJoinOptions().getAmount() * COIN, false, BitcoinUnits::SeparatorStyle::ALWAYS); - if(m_balances.balance == 0) + if (cached_balances.balance == 0) { ui->coinJoinProgress->setValue(0); ui->coinJoinProgress->setToolTip(tr("No inputs detected")); @@ -398,7 +396,7 @@ void OverviewPage::updateCoinJoinProgress() CAmount nAnonymizableBalance = walletModel->wallet().getAnonymizableBalance(false, false); - CAmount nMaxToAnonymize = nAnonymizableBalance + m_balances.anonymized_balance; + CAmount nMaxToAnonymize = nAnonymizableBalance + cached_balances.anonymized_balance; // If it's more than the anon threshold, limit to that. if (nMaxToAnonymize > clientModel->coinJoinOptions().getAmount() * COIN) nMaxToAnonymize = clientModel->coinJoinOptions().getAmount() * COIN; @@ -455,7 +453,7 @@ void OverviewPage::updateCoinJoinProgress() anonNormPart = anonNormPart > 1 ? 1 : anonNormPart; anonNormPart *= 100; - anonFullPart = (float)m_balances.anonymized_balance / nMaxToAnonymize; + anonFullPart = (float)cached_balances.anonymized_balance / nMaxToAnonymize; anonFullPart = anonFullPart > 1 ? 1 : anonFullPart; anonFullPart *= 100; @@ -683,7 +681,7 @@ void OverviewPage::toggleCoinJoin(){ if (!walletModel->coinJoin()->isMixing()) { auto& options = walletModel->node().coinJoinOptions(); const CAmount nMinAmount = options.getSmallestDenomination() + options.getMaxCollateralAmount(); - if(m_balances.balance < nMinAmount) { + if (walletModel->getCachedBalance().balance < nMinAmount) { QString strMinAmount(BitcoinUnits::formatWithUnit(m_display_bitcoin_unit, nMinAmount)); QMessageBox::warning(this, strCoinJoinName, tr("%1 requires at least %2 to use.").arg(strCoinJoinName).arg(strMinAmount), diff --git a/src/qt/overviewpage.h b/src/qt/overviewpage.h index 5f1789f27d7a..29a9172644d4 100644 --- a/src/qt/overviewpage.h +++ b/src/qt/overviewpage.h @@ -51,7 +51,6 @@ public Q_SLOTS: Ui::OverviewPage *ui; ClientModel *clientModel; WalletModel *walletModel; - interfaces::WalletBalances m_balances; bool m_privacy{false}; BitcoinUnit m_display_bitcoin_unit; bool fShowAdvancedCJUI; diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index 146ed5cefe8c..07a68eddbe36 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -180,11 +180,9 @@ void SendCoinsDialog::setModel(WalletModel *_model) } } - interfaces::WalletBalances balances = _model->wallet().getBalances(); - setBalance(balances); connect(_model, &WalletModel::balanceChanged, this, &SendCoinsDialog::setBalance); - connect(_model->getOptionsModel(), &OptionsModel::displayUnitChanged, this, &SendCoinsDialog::updateDisplayUnit); - updateDisplayUnit(); + connect(_model->getOptionsModel(), &OptionsModel::displayUnitChanged, this, &SendCoinsDialog::refreshBalance); + refreshBalance(); // Coin Control connect(_model->getOptionsModel(), &OptionsModel::displayUnitChanged, this, &SendCoinsDialog::coinControlUpdateLabels); @@ -782,9 +780,9 @@ void SendCoinsDialog::setBalance(const interfaces::WalletBalances& balances) } } -void SendCoinsDialog::updateDisplayUnit() +void SendCoinsDialog::refreshBalance() { - setBalance(model->wallet().getBalances()); + setBalance(model->getCachedBalance()); coinControlUpdateLabels(); ui->customFee->setDisplayUnit(model->getOptionsModel()->getDisplayUnit()); updateSmartFeeLabel(); @@ -858,7 +856,7 @@ void SendCoinsDialog::useAvailableBalance(SendCoinsEntry* entry) m_coin_control->fAllowWatchOnly = model->wallet().privateKeysDisabled() && !model->wallet().hasExternalSigner(); // Calculate available amount to send. - CAmount amount = model->wallet().getAvailableBalance(*m_coin_control); + CAmount amount = model->getAvailableBalance(m_coin_control.get()); for (int i = 0; i < ui->entries->count(); ++i) { SendCoinsEntry* e = qobject_cast(ui->entries->itemAt(i)->widget()); if (e && !e->isHidden() && e != entry) { diff --git a/src/qt/sendcoinsdialog.h b/src/qt/sendcoinsdialog.h index 22aa578be639..cbd286f7c39b 100644 --- a/src/qt/sendcoinsdialog.h +++ b/src/qt/sendcoinsdialog.h @@ -88,7 +88,7 @@ private Q_SLOTS: void on_buttonMinimizeFee_clicked(); void removeEntry(SendCoinsEntry* entry); void useAvailableBalance(SendCoinsEntry* entry); - void updateDisplayUnit(); + void refreshBalance(); void coinControlFeatureChanged(bool); void coinControlButtonClicked(); void coinControlChangeChecked(int); diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp index 9cd8d1ceb885..ae68c851c694 100644 --- a/src/qt/test/wallettests.cpp +++ b/src/qt/test/wallettests.cpp @@ -159,6 +159,8 @@ void TestGUI(interfaces::Node& node) sendCoinsDialog.setModel(&walletModel); transactionView.setModel(&walletModel); + // Update walletModel cached balance which will trigger an update for the 'labelBalance' QLabel. + walletModel.pollBalanceChanged(); { // Check balance in send dialog QLabel* balanceLabel = sendCoinsDialog.findChild("labelBalance"); @@ -184,6 +186,7 @@ void TestGUI(interfaces::Node& node) OverviewPage overviewPage; overviewPage.setClientModel(&clientModel); overviewPage.setWalletModel(&walletModel); + walletModel.pollBalanceChanged(); // Manual balance polling update QLabel* balanceLabel = overviewPage.findChild("labelBalance"); QString balanceText = balanceLabel->text().trimmed(); BitcoinUnit unit = walletModel.getOptionsModel()->getDisplayUnit(); diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 9b03c9cf9d5c..fbcbdc3fbae2 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -73,6 +73,10 @@ WalletModel::~WalletModel() void WalletModel::startPollBalance() { + // Update the cached balance right away, so every view can make use of it, + // so them don't need to waste resources recalculating it. + pollBalanceChanged(); + // This timer will be fired repeatedly to update the balance // Since the QTimer::timeout is a private signal, it cannot be used // in the GUIUtil::ExceptionSafeConnect directly. @@ -137,12 +141,17 @@ void WalletModel::pollBalanceChanged() void WalletModel::checkBalanceChanged(const interfaces::WalletBalances& new_balances) { - if(new_balances.balanceChanged(m_cached_balances)) { + if (new_balances.balanceChanged(m_cached_balances)) { m_cached_balances = new_balances; Q_EMIT balanceChanged(new_balances); } } +interfaces::WalletBalances WalletModel::getCachedBalance() const +{ + return m_cached_balances; +} + void WalletModel::updateTransaction() { // Balance and number of transactions might have changed @@ -244,7 +253,9 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact return DuplicateAddress; } - CAmount nBalance = m_wallet->getAvailableBalance(coinControl); + // If no coin was manually selected, use the cached balance + // Future: can merge this call with 'createTransaction'. + CAmount nBalance = getAvailableBalance(&coinControl); if(total > nBalance) { @@ -616,3 +627,8 @@ uint256 WalletModel::getLastBlockProcessed() const { return m_client_model ? m_client_model->getBestBlockHash() : uint256{}; } + +CAmount WalletModel::getAvailableBalance(const CCoinControl* control) +{ + return control && control->HasSelected() ? wallet().getAvailableBalance(*control) : getCachedBalance().balance; +} diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index b33e74a43ada..c248acaa5a41 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -162,6 +162,13 @@ class WalletModel : public QObject uint256 getLastBlockProcessed() const; + // Retrieve the cached wallet balance + interfaces::WalletBalances getCachedBalance() const; + + // If coin control has selected outputs, searches the total amount inside the wallet. + // Otherwise, uses the wallet's cached available balance. + CAmount getAvailableBalance(const wallet::CCoinControl* control); + private: std::unique_ptr m_wallet; std::unique_ptr m_handler_unload;