qml: don't force-build address model from tx event handlers
What changed, and why it matters
This is a performance and responsiveness fix for the Electrum mobile/QML wallet. It stops the app from doing heavy work (building the address coin list) every time a new transaction arrives, which was causing the user interface to freeze. Instead, the list is only built when the user actually opens it. There is no security vulnerability being fixed here.
No security action required. Treat as a normal performance/responsiveness improvement. Users on mobile/QML builds may notice fewer UI freezes after updating.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The commit modifies qewallet.py so that addressCoinModel.setDirty() is only called if the model has already been instantiated. Previously, accessing self.addressCoinModel through its property getter would lazily construct QEAddressCoinListModel, whose init calls initModel() — a slow, synchronous operation. This construction was triggered from transaction event handlers (on_event_wallet_tx and on_event_history), causing UI blocking on every new or removed transaction. The change mirrors existing patterns for importAddresses/importPrivateKeys and defers initialization until the user navigates to the relevant view.
Changed components
electrum/gui/qml/qewallet.pyQEWallet transaction event handlersQEAddressCoinListModel lazy initializationInspect captured patch +4 / −2
diff --git a/electrum/gui/qml/qewallet.py b/electrum/gui/qml/qewallet.py
index 35aec4b..0842e79 100644
--- a/electrum/gui/qml/qewallet.py
+++ b/electrum/gui/qml/qewallet.py
@@ -202,7 +202,8 @@ class QEWallet(AuthMixin, QObject, QtEventListener):
if wallet == self.wallet:
self._logger.info(f'new transaction {tx.txid()}')
self.add_tx_notification(tx)
- self.addressCoinModel.setDirty()
+ if self._addressCoinModel is not None: # only setDirty if it was already initialized
+ self._addressCoinModel.setDirty()
self.historyModel.setDirty() # assuming wallet.is_up_to_date triggers after
if self.wallet.is_up_to_date():
# don't update during sync as this recomputes the balance on each new tx, blocking the UI thread.
@@ -221,7 +222,8 @@ class QEWallet(AuthMixin, QObject, QtEventListener):
# is deleted along with multiple associated txs
if wallet == self.wallet:
self._logger.info(f'removed transaction {tx.txid()}')
- self.addressCoinModel.setDirty()
+ if self._addressCoinModel is not None:
+ self._addressCoinModel.setDirty()
self.historyModel.setDirty()
self.balanceChanged.emit()
Why this scored 18/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.