Skip to content

Commit

Permalink
BugFix: fix not updating GUI balance race condition.
Browse files Browse the repository at this point in the history
The problem arises when we trigger the balance update worker task and the chain tip changes (due a reorg) before one of the threadpool's threads start executing the update task. As the tip in this situation has the same height that the one cached inside the model, the `processBalanceChangeInternal` returns true without setting the processing flag to false again. Blocking every future balance update.

Github-Pull: #2379
Rebased-From: fbda4d2
  • Loading branch information
furszy committed Jun 18, 2021
1 parent 2c923ed commit 18f4b4a
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 18 deletions.
38 changes: 20 additions & 18 deletions src/qt/walletmodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -205,24 +205,26 @@ static bool processBalanceChangeInternal(WalletModel* walletModel)
int chainHeight = walletModel->getLastBlockProcessedNum();
const uint256& blockHash = walletModel->getLastBlockProcessed();

if (walletModel->hasForceCheckBalance() || chainHeight != walletModel->getCacheNumBLocks()) {
// Try to get lock only if needed
TRY_LOCK(pwalletMain->cs_wallet, lockWallet);
if (!lockWallet)
return false;

walletModel->setfForceCheckBalanceChanged(false);

// Balance and number of transactions might have changed
walletModel->setCacheNumBlocks(chainHeight);
walletModel->setCacheBlockHash(blockHash);
walletModel->checkBalanceChanged(walletModel->getBalances());
QMetaObject::invokeMethod(walletModel, "updateTxModelData", Qt::QueuedConnection);
QMetaObject::invokeMethod(walletModel, "pollFinished", Qt::QueuedConnection);

// Address in receive tab may have been used
Q_EMIT walletModel->notifyReceiveAddressChanged();
}
// Avoid recomputing wallet balances unless a tx changed or BlockTip notification was received.
// Extra note: This needs to be done before and after the update task trigger and execution because, as it runs concurrently,
// there is no guarantee that the threadpool will execute the task right away.
if (!walletModel->hasForceCheckBalance() && walletModel->getCacheBlockHash() == blockHash) return false;

// Try to get lock only if needed
TRY_LOCK(pwalletMain->cs_wallet, lockWallet);
if (!lockWallet) return false;

walletModel->setfForceCheckBalanceChanged(false);

// Balance and number of transactions might have changed
walletModel->setCacheNumBlocks(chainHeight);
walletModel->setCacheBlockHash(blockHash);
walletModel->checkBalanceChanged(walletModel->getBalances());
QMetaObject::invokeMethod(walletModel, "updateTxModelData", Qt::QueuedConnection);
QMetaObject::invokeMethod(walletModel, "pollFinished", Qt::QueuedConnection);

// Address in receive tab may have been used
Q_EMIT walletModel->notifyReceiveAddressChanged();
return true;
}

Expand Down
1 change: 1 addition & 0 deletions src/qt/walletmodel.h
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,7 @@ class WalletModel : public QObject
void setCacheNumBlocks(int _cachedNumBlocks) { cachedNumBlocks = _cachedNumBlocks; }
int getCacheNumBLocks() { return cachedNumBlocks; }
void setCacheBlockHash(const uint256& _blockHash) { m_cached_best_block_hash = _blockHash; }
uint256 getCacheBlockHash() { return m_cached_best_block_hash; }
void setfForceCheckBalanceChanged(bool _fForceCheckBalanceChanged) { fForceCheckBalanceChanged = _fForceCheckBalanceChanged; }
Q_INVOKABLE void checkBalanceChanged(const interfaces::WalletBalances& new_balances);

Expand Down

0 comments on commit 18f4b4a

Please sign in to comment.