When clicking the "close_button" button (labelled "Not Now"), the whole app state got bugged:
none of the existing windows (e.g. ElectrumWindow) could get focus anymore.
The signature of PushButton.clicked is:
`void QAbstractButton::clicked(bool checked = false)`
https://doc.qt.io/qt-6/qabstractbutton.html#clicked
and pyqt is probably doing some polymorphism, dynamically deciding if the qt slot wants the "checked" arg or not.
The extremely weird part is that the bug is triggered on clicking "close_button" (probably pyqt is passing "checked" to self.close)
but instead of the current commit, the following diff, touching a completely different button, would also "fix" the issue:
```
diff --git a/electrum/gui/qt/exception_window.py b/electrum/gui/qt/exception_window.py
index eceab89de6..e0162e5827 100644
--- a/electrum/gui/qt/exception_window.py
+++ b/electrum/gui/qt/exception_window.py
@@ -67,7 +67,7 @@ class Exception_Window(BaseCrashReporter, QWidget, MessageBoxMixin, Logger):
self._report_contents_dlg = None # type: Optional[ReportContentsDialog]
collapse_info = QPushButton(_("Show report contents"))
- collapse_info.clicked.connect(self.show_report_contents_dlg)
+ collapse_info.clicked.connect(lambda: self.show_report_contents_dlg())
main_box.addWidget(collapse_info)
```
No idea why.
deletes the `seed_type` key from `wizard_data` in `WCWalletType` if it
is not explicitly set to prevent a stale value from a previous wizard
flow if the user goes back in the wizard and selects a different wallet
type instead of completing the wizard with the previously selected
wallet type.
This happens as the `apply()` function gets called with the
previously set radio button (e.g. 2fa) if the user goes back, if he then
selects multisig the `2fa_segwit` `seed_type` won't get cleared and
cause the exception later.
Example exception when first selecting 2fa, then going back and creating
a multisig wallet:
```
32.77 | E | gui.qml.qeapp.Exception_Hook | exception caught by crash reporter
Traceback (most recent call last):
File "/home/vagrant/electrum/electrum/gui/qml/qewizard.py", line 40, in submit
view = self.resolve_next(self._current.view, wdata)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/vagrant/electrum/electrum/wizard.py", line 78, in resolve_next
view_accept(wizard_data)
File "/home/vagrant/electrum/electrum/wizard.py", line 501, in maybe_master_pubkey
wizard_data['multisig_master_pubkey'] = self.keystore_from_data(wizard_data['wallet_type'], wizard_data).get_master_public_key()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/vagrant/electrum/electrum/wizard.py", line 339, in keystore_from_data
return keystore.from_seed(data['seed'], passphrase=seed_extension, for_multisig=for_multisig)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/vagrant/electrum/electrum/keystore.py", line 1197, in from_seed
raise BitcoinException('Unexpected seed type {}'.format(repr(t)))
electrum.util.BitcoinException: Unexpected seed type '2fa_segwit'
```
Triggered by the following wizard stack:
```
30.94 | D | wizard | view=create_seed
30.94 | D | wizard | resolve_next view is confirm_seed
30.94 | D | wizard | wizard stack:
0: 0x7fdc6804ae80 - {}
1: 0x7fdc6ac61400 - {'wallet_name': 'wallet_1'}
2: 0x7fdc680d8a80 - {'seed_type': '2fa_segwit', 'wallet_name': 'wallet_1', 'wallet_type': 'multisig'}
3: 0x7fdc6804ab00 - {'multisig_cosigner_data': {}, 'multisig_participants': 2, 'multisig_signatures': 2, 'seed_type': '2fa_segwit', 'wallet_name': 'wallet_1', 'wallet_type': 'multisig'}
4: 0x7fdc6807f0c0 - {'keystore_type': 'createseed', 'multisig_cosigner_data': {}, 'multisig_participants': 2, 'multisig_signatures': 2, 'seed_type': '2fa_segwit', 'wallet_name': 'wallet_1', 'wallet_type': 'multisig'}
c: 0x7fdc6807c380 - {'keystore_type': 'createseed', 'multisig_cosigner_data': {}, 'multisig_participants': 2, 'multisig_signatures': 2, 'seed': '<redacted>', 'seed_extend': False, 'seed_extra_words': '<redacted>', 'seed_type': '2fa_segwit', 'seed_variant': 'electrum', 'wallet_name': 'wallet_1', 'wallet_type': 'multisig'}
30.94 | W | gui.qml.qeapp | next view: confirm_seed
```
- the msg_box did not allow neither vertical nor horizontal scrolling
- long lines were not word-wrapped, but were effectively truncated
- long reports could only be inspected if the user somehow selected
the full text and pasted it into a text editor
- new dialog allows vertical and horizontal scrolling
- we could maybe word-wrap instead of horizontal scrolling,
but this is already a strict improvement for long reports
- if fee estimates are high atm, some outputs are not worth to sweep
- however, fee estimates might be only-temporarily very high
- previously in such a case lnwatcher would just discard outputs as dust,
and mark the channel REDEEMED (and hence never watch it or try again)
- now, instead, if the outputs would not be dust if fee estimates were lower,
lnwatcher will keep watching the channel
- and if estimates go down, lnwatcher will sweep them then
- relatedly, previously txbatcher.is_dust() used allow_fallback_to_static_rates=True,
and it erroneously almost always fell back to the static rates (150 s/b) during
startup (race: lnwatcher was faster than the network managed to get estimates)
- now, instead, txbatcher.is_dust() does not fallback to static rates,
and the callers are supposed to handle NoDynamicFeeEstimates.
- I think this makes much more sense. The previous meaning of "is_dust"
with the fallback was weird. Now it means: "is dust at current feerates".
fixes https://github.com/spesmilo/electrum/issues/9980
when setting a transaction label in the qml
`LightningPaymentDetails` or `TxDetails` dialogs which get opened
directly by the `ReceiveDialog` (`onRequestPaid`) the label is not applied on the main
transaction list as no callback for `detailsChanged` is registered which
gets called when the label changes. As a result the label is only
visible after the main list gets reloaded (e.g. restart).
This commit adds callbacks for `detailsChanged` to fix this.
We often call str.format() on translated strings.
E.g. `_("time left: {} seconds").format(t1)`
If the translated string has a different format syntax, this can raise at runtime.
This PR adds some runtime checks that try to ensure the source string and the translated string
have a similar format syntax. If the checks fail, `_()` will "reject" the translation by
returning the source string.
fixes https://github.com/spesmilo/electrum/issues/10010
ref https://github.com/spesmilo/electrum/issues/10007#issue-3203378250
Only try to get wallet from daemon in the `command` decorator if the
wallet_path is available to prevent raising `TypeError` when
`daemon.get_wallet(path=None)` gets called.
Fixes https://github.com/spesmilo/electrum/issues/10012
There could be flows where sign_transaction
will return without actually
signing the transaction.
We also want to add the ability to sign
the transactions externally, so here we check
if they are already signed.
Long Term recovery transactions should have
a high fee policy, because we don't know when
we will broadcast them.
On the other hand, they won't need to be urgent
when broadcasted either.
The implementation is just
bool QAbstractItemModel::hasIndex(int row, int column, const QModelIndex &parent) const
{
if (row < 0 || column < 0)
return false;
return row < rowCount(parent) && column < columnCount(parent);
}
and yet it features as the most prominent part of the profile,
encompassing up to 25% of refresh()
Open-coding it makes refresh() 40% faster. Measurements from between
after wallet.get_full_history() and return from refresh()
Before:
1.8637257907539606
1.8563996930606663
1.7696567592211068
1.8933695629239082
After:
1.3133591176010668
1.3686819169670343
1.2470976510085166
1.2455544411204755
endInsertRows() triggers a sort, the history sort/filter proxy model
then launders the comparison requests through get_data_for_role()
with a custom key, which is then especially looked up in there,
but custom-flattened in the proxy model. This is OO hell
Measuring refresh() from after if transactions == self.transactions: return
to the final return, sorting the wallet from #9958/#6625 takes ~3.5s
and 132348 get_data_for_role() calls
Beside that get_data_for_role() is called maybe 10 times per on-hover?
It's immaterial
Thus: compute the sorting keys when constructing the HistoryNode
and use them directly in the comparison.
This decouples get_data_for_role() from the sorter
and speeds the sort up by ~2x,
now being mostly made up of the python interpreter overhead(?)
for upcalls to lessThan()
A dict wins with a list for the lookup a tiny bit
(and is 100x better code-wise):
1.896097298245877s list
1.840533264912665s list
1.757185084745288s list
1.8990754359401762s list
1.914668960031122s list
1.9349112827330828s list
2.432649422902614s list
1.929884395096451s list
1.9610795709304512s list
1.8694845158606768s list
1.9600030612200499s list
1.9199693519622087s dict
2.0466488380916417s dict
1.8510140180587769s dict
1.8978681536391377s dict
2.0079748439602554s dict
1.9111531740054488s dict
1.9525738609954715s dict
1.850804285146296s dict
1.860573346260935s dict
1.95173170696944s dict
1.8481200002133846s dict
Benchmark 1: dict
Time (mean ± σ): 1918.039234 ms ± 63.688609 ms
Range (min … max): 1848.120000 ms … 2046.648838 ms 11 runs
Benchmark 2: list
Time (mean ± σ): 1945.052027 ms ± 164.019588 ms
Range (min … max): 1757.185085 ms … 2432.649423 ms 11 runs
Summary
'dict' ran
1.014084 ± 0.090082 times faster than 'list'
- if Electrum cannot do a graceful shutdown, the daemon lockfile won't get cleaned up
- the daemon lockfile contains the creation time of the daemon
- then, especially for an always offline phone/laptop, if the battery dies, the clock
might go back to the past
- the bug: next time Electrum starts, the program will wait until create_time + 1.0
before giving up on the daemon and creating a new one
closes https://github.com/spesmilo/electrum/issues/9802
- certainly fixes at least https://github.com/spesmilo/electrum/issues/9802#issuecomment-3020220593
- the OP there might or might not be the same issue
closes https://github.com/spesmilo/electrum/issues/9529
- same here, might or might not be the same issue
the logic bug is quite old, from e6020975a5