Testing with a wallet with a ~1000 unpaid/expired payment requests,
with the Qt gui, the python process saturates one of my CPU cores to 100%.
This is because main_window.timer_actions() calls request_list.refresh_all()
every 0.5 seconds, which iterates over all unpaid payreqs, and does a
scriptpubkey->address->scriptpubkey conversion.
Trace of the hot path:
```
File "/home/user/wspace/electrum/./run_electrum", line 510, in <module>
main()
File "/home/user/wspace/electrum/./run_electrum", line 421, in main
handle_cmd(
File "/home/user/wspace/electrum/./run_electrum", line 439, in handle_cmd
d.run_gui(config, plugins)
File "/home/user/wspace/electrum/electrum/daemon.py", line 581, in run_gui
self.gui_object.main()
File "/home/user/wspace/electrum/electrum/gui/qt/__init__.py", line 469, in main
self.app.exec_()
File "/home/user/wspace/electrum/electrum/gui/qt/main_window.py", line 861, in timer_actions
self.receive_tab.request_list.refresh_all()
File "/home/user/wspace/electrum/electrum/gui/qt/util.py", line 821, in refresh_all
self.refresh_row(key, row)
File "/home/user/wspace/electrum/electrum/gui/qt/request_list.py", line 126, in refresh_row
status = self.wallet.get_invoice_status(request)
File "/home/user/wspace/electrum/electrum/wallet.py", line 2330, in get_invoice_status
paid, conf = self.is_onchain_invoice_paid(invoice)
File "/home/user/wspace/electrum/electrum/wallet.py", line 1118, in is_onchain_invoice_paid
is_paid, conf_needed, relevant_txs = self._is_onchain_invoice_paid(invoice)
File "/home/user/wspace/electrum/electrum/wallet.py", line 1085, in _is_onchain_invoice_paid
outputs = invoice.get_outputs()
File "/home/user/wspace/electrum/electrum/invoices.py", line 130, in get_outputs
traceback.print_stack()
```
These commits drastically reduce the CPU utilisation.
This commit is contained in:
@@ -813,6 +813,8 @@ class MyTreeView(QTreeView):
|
|||||||
return row
|
return row
|
||||||
|
|
||||||
def refresh_all(self):
|
def refresh_all(self):
|
||||||
|
if self.maybe_defer_update():
|
||||||
|
return
|
||||||
for row in range(0, self.std_model.rowCount()):
|
for row in range(0, self.std_model.rowCount()):
|
||||||
item = self.std_model.item(row, 0)
|
item = self.std_model.item(row, 0)
|
||||||
key = item.data(self.key_role)
|
key = item.data(self.key_role)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import time
|
import time
|
||||||
from typing import TYPE_CHECKING, List, Optional, Union, Dict, Any
|
from typing import TYPE_CHECKING, List, Optional, Union, Dict, Any, Sequence
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
|
||||||
import attr
|
import attr
|
||||||
@@ -126,16 +126,13 @@ class Invoice(StoredObject):
|
|||||||
address = self._lnaddr.get_fallback_address() or None
|
address = self._lnaddr.get_fallback_address() or None
|
||||||
return address
|
return address
|
||||||
|
|
||||||
def get_outputs(self):
|
def get_outputs(self) -> Sequence[PartialTxOutput]:
|
||||||
if self.is_lightning():
|
outputs = self.outputs or []
|
||||||
|
if not outputs:
|
||||||
address = self.get_address()
|
address = self.get_address()
|
||||||
amount = self.get_amount_sat()
|
amount = self.get_amount_sat()
|
||||||
if address and amount is not None:
|
if address and amount is not None:
|
||||||
outputs = [PartialTxOutput.from_address_and_value(address, int(amount))]
|
outputs = [PartialTxOutput.from_address_and_value(address, int(amount))]
|
||||||
else:
|
|
||||||
outputs = []
|
|
||||||
else:
|
|
||||||
outputs = self.outputs
|
|
||||||
return outputs
|
return outputs
|
||||||
|
|
||||||
def can_be_paid_onchain(self) -> bool:
|
def can_be_paid_onchain(self) -> bool:
|
||||||
|
|||||||
@@ -148,9 +148,18 @@ class TxOutput:
|
|||||||
return cls(scriptpubkey=bfh(addr), value=val)
|
return cls(scriptpubkey=bfh(addr), value=val)
|
||||||
raise Exception(f"unexpected legacy address type: {_type}")
|
raise Exception(f"unexpected legacy address type: {_type}")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def scriptpubkey(self) -> bytes:
|
||||||
|
return self._scriptpubkey
|
||||||
|
|
||||||
|
@scriptpubkey.setter
|
||||||
|
def scriptpubkey(self, scriptpubkey: bytes):
|
||||||
|
self._scriptpubkey = scriptpubkey
|
||||||
|
self._address = get_address_from_output_script(scriptpubkey)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def address(self) -> Optional[str]:
|
def address(self) -> Optional[str]:
|
||||||
return get_address_from_output_script(self.scriptpubkey) # TODO cache this?
|
return self._address
|
||||||
|
|
||||||
def get_ui_address_str(self) -> str:
|
def get_ui_address_str(self) -> str:
|
||||||
addr = self.address
|
addr = self.address
|
||||||
|
|||||||
Reference in New Issue
Block a user