feat(qt): refresh the whole wallet instead of processing individual updates for huge notification queues (#5453)

## Issue being fixed or feature implemented
It's super slow for wallets with 100.000s of txes to process lots of
notifications produced by rescan. Skip them all and simply refresh the
whole wallet instead. In my case (500k+ txes testnet wallet) gui update
after `rescanblockchain` time is down from _forever_ to ~30 seconds.
Same for `wipewallettxes true` (#5451 ). Gui update after
`wipewallettxes`/`wipewallettxes false` is instant (cause there are no
txes anymore) vs _forever_ before the patch.


## What was done?
refresh the whole wallet when notification queue is above 10K operations

actual changes (ignoring whitespaces):
d013cb4f5c

## How Has This Been Tested?
running on top of #5451 and #5452 , wiping and rescanning w/ and w/out
this patch.

## Breaking Changes
should be none


## Checklist:
- [x] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have added or updated relevant unit/integration/functional/e2e
tests
- [ ] I have made corresponding changes to the documentation
- [x] I have assigned this pull request to a milestone _(for repository
code-owners and collaborators only)_
This commit is contained in:
UdjinM6 2023-06-28 19:00:18 +03:00
parent ff60d10934
commit f3dc889e93
No known key found for this signature in database
GPG Key ID: 83592BD1400D58D9
2 changed files with 29 additions and 11 deletions

View File

@ -22,6 +22,7 @@
#include <QDebug>
#include <QIcon>
#include <QList>
#include <QMessageBox>
// Amount column is right-aligned it contains numbers
@ -73,14 +74,18 @@ public:
void refreshWallet(interfaces::Wallet& wallet)
{
qDebug() << "TransactionTablePriv::refreshWallet";
parent->beginResetModel();
try {
cachedWallet.clear();
{
for (const auto& wtx : wallet.getWalletTxs()) {
if (TransactionRecord::showTransaction()) {
cachedWallet.append(TransactionRecord::decomposeTransaction(wallet, wtx));
}
}
} catch(const std::exception& e) {
QMessageBox::critical(nullptr, PACKAGE_NAME, QString("Failed to refresh wallet table: ") + QString::fromStdString(e.what()));
}
parent->endResetModel();
}
/* Update our model of the wallet incrementally, to synchronize our model of the wallet
@ -242,6 +247,11 @@ TransactionTableModel::~TransactionTableModel()
delete priv;
}
void TransactionTableModel::refreshWallet()
{
priv->refreshWallet(walletModel->wallet());
}
/** Updates the column title to "Amount (DisplayUnit)" and emits headerDataChanged() signal for table headers to react. */
void TransactionTableModel::updateAmountColumnTitle()
{
@ -802,6 +812,7 @@ static void ShowProgress(TransactionTableModel *ttm, const std::string &title, i
if (nProgress == 100)
{
fQueueNotifications = false;
if (vQueueNotifications.size() < 10000) {
if (vQueueNotifications.size() > 10) { // prevent balloon spam, show maximum 10 balloons
bool invoked = QMetaObject::invokeMethod(ttm, "setProcessingQueuedTransactions", Qt::QueuedConnection, Q_ARG(bool, true));
assert(invoked);
@ -815,6 +826,11 @@ static void ShowProgress(TransactionTableModel *ttm, const std::string &title, i
vQueueNotifications[i].invoke(ttm);
}
} else {
// it's much faster to just refresh the whole thing instead
bool invoked = QMetaObject::invokeMethod(ttm, "refreshWallet", Qt::QueuedConnection);
assert(invoked);
}
std::vector<TransactionNotification >().swap(vQueueNotifications); // clear
}
}

View File

@ -113,6 +113,8 @@ private:
QVariant txAddressDecoration(const TransactionRecord *wtx) const;
public Q_SLOTS:
/* Refresh the whole wallet, helpful for huge notification queues */
void refreshWallet();
/* New transaction, or transaction changed status */
void updateTransaction(const QString &hash, int status, bool showTransaction);
void updateAddressBook(const QString &address, const QString &label,