qml: QETransactionListModel: add txid->row index
What changed, and why it matters
This commit is a performance improvement for the Electrum mobile/QML wallet. It replaces repeated scanning of the transaction history list with a simple dictionary lookup (txid -> row index). There is no security-relevant change visible in the diff.
No security action required. Treat as a normal performance/refactoring commit.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch adds a _tx_positions dictionary mapping transaction IDs to their row index in tx_history. It updates that map whenever the model is populated or cleared, and uses it in on_event_adb_set_future_tx and on_tx_verified instead of linear searches. No cryptographic, network, input-validation, or access-control logic is modified.
Changed components
electrum/gui/qml/qetransactionlistmodel.pyInspect captured patch +19 / −16
diff --git a/electrum/gui/qml/qetransactionlistmodel.py b/electrum/gui/qml/qetransactionlistmodel.py
index 293e60e..62f1a16 100644
--- a/electrum/gui/qml/qetransactionlistmodel.py
+++ b/electrum/gui/qml/qetransactionlistmodel.py
@@ -35,7 +35,8 @@ class QETransactionListModel(QAbstractListModel, QtEventListener):
self.onchain_domain = onchain_domain
self.include_lightning = include_lightning
- self.tx_history = []
+ self.tx_history: list[dict] = []
+ self._tx_positions: dict[str, int] = {} # txid -> row index in tx_history
self.register_callbacks()
self.destroyed.connect(lambda: self.on_destroy())
@@ -58,10 +59,9 @@ class QETransactionListModel(QAbstractListModel, QtEventListener):
if adb != self.wallet.adb:
return
self._logger.debug(f'adb_set_future_tx event for txid {txid}')
- for i, item in enumerate(self.tx_history):
- if 'txid' in item and item['txid'] == txid:
- self._update_future_txitem(i)
- return
+ i = self._tx_positions.get(txid)
+ if i is not None:
+ self._update_future_txitem(i)
@qt_event_listener
def on_event_fee_histogram(self, histogram):
@@ -122,6 +122,7 @@ class QETransactionListModel(QAbstractListModel, QtEventListener):
def clear(self):
self.beginResetModel()
self.tx_history = []
+ self._tx_positions = {}
self.endResetModel()
def tx_to_model(self, tx_item):
@@ -224,6 +225,7 @@ class QETransactionListModel(QAbstractListModel, QtEventListener):
self.beginInsertRows(QModelIndex(), 0, len(txs) - 1)
self.tx_history = txs
self.tx_history.reverse()
+ self._tx_positions = {tx['txid']: i for i, tx in enumerate(self.tx_history) if 'txid' in tx}
self.endInsertRows()
self.countChanged.emit()
@@ -231,17 +233,18 @@ class QETransactionListModel(QAbstractListModel, QtEventListener):
self._dirty = False
def on_tx_verified(self, txid: str, info: TxMinedInfo):
- for i, tx in enumerate(self.tx_history):
- if 'txid' in tx and tx['txid'] == txid:
- tx['height'] = info.height()
- tx['confirmations'] = info.conf
- tx['timestamp'] = info.timestamp
- tx['section'] = self.get_section_by_timestamp(info.timestamp)
- tx['date'] = self.format_date_by_section(tx['section'], datetime.fromtimestamp(info.timestamp))
- index = self.index(i, 0)
- roles = [self._ROLE_RMAP[x] for x in ['section', 'height', 'confirmations', 'timestamp', 'date']]
- self.dataChanged.emit(index, index, roles)
- return
+ i = self._tx_positions.get(txid)
+ if i is None:
+ return
+ tx = self.tx_history[i]
+ tx['height'] = info.height()
+ tx['confirmations'] = info.conf
+ tx['timestamp'] = info.timestamp
+ tx['section'] = self.get_section_by_timestamp(info.timestamp)
+ tx['date'] = self.format_date_by_section(tx['section'], datetime.fromtimestamp(info.timestamp))
+ index = self.index(i, 0)
+ roles = [self._ROLE_RMAP[x] for x in ['section', 'height', 'confirmations', 'timestamp', 'date']]
+ self.dataChanged.emit(index, index, roles)
def _update_future_txitem(self, tx_item_idx: int):
tx_item = self.tx_history[tx_item_idx]
Why this scored 13/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.