When the user has already loaded a wallet in QML and tries to restore a
new wallet `WCHaveSeed.qml` incorrectly shows a `Finish` button instead
of a `Next` button and raises a KeyError if the user clicks on Finish
instead of resolving the passphrase input view (regression from
https://github.com/spesmilo/electrum/pull/10016).
This happens because `last` of `have_seed` depends on
`NewWalletWizard.is_single_password()` and NewWalletWizard.wants_ext(wizard_data).
`is_single_password()` is true if a wallet is already loaded,
while `wants_ext(wizard_data)` is false as `wants_ext()` depends on `seed_extend: True` in
`wizard_data` which only gets set after `apply()` of `WCHaveSeed` gets
called, however the evaluation of `WCHaveSeed` being the last view
happens before the view is shown.
By calling `checkIsLast()` in the validation timer of `WCHaveSeed` the
`last` property gets set again after `apply()` has been called, so
the view is guaranteed to correctly show either the `Finish` or `Next` button
after a seed has been entered.
Handles exceptions thrown by `shutil.copyfile()` in the
`add_plugin_dialog`.
In issue #10101 an user tried to access an onedrive vault directory which
made shutil fail to copy the file with:
```
OSError: [Errno 22] Invalid argument: 'odopen://unlockvault/?accounttype=personal'
```
Adapts the gui(s) to detect if an existing reserve input has not been
used as input for the transaction even though the user tried to spend
max. This allows to show the lightning reserve warning not only for
reserve change outputs but also for existing reserve inputs that have
been ignored for this max spend transaction.
Still keeps the `is_utxo_reserve` flag on `PartialTxOutput` as it is
used in the qml gui.
qml: add signals for QEQRScanner and fallbacks, add QEBytes container type
so we can pass along byte arrays between QML and python, port qr scan
occurrences to new signals.
Removes the '.desktop' suffix from the
`QGuiApplication.setDesktopFileName` argument to prevent the following
warning on startup of Electrum:
```
QGuiApplication::setDesktopFileName: the specified desktop file name ends with .desktop.
For compatibility reasons, the .desktop suffix will be removed.
Please specify a desktop file name without .desktop suffix
```
The [qt
docs](https://doc.qt.io/qtforpython-6/PySide6/QtGui/QGuiApplication.html#PySide6.QtGui.QGuiApplication.desktopFileName)
say that `desktopFileName` is "... is the file name, without the full
path or the trailing “.desktop” extension of the desktop entry that
represents this application according to the freedesktop desktop entry
specification."
When putting app to background with qr scanner active, then moved to foreground again,
SimpleScannerActivity instance is not destroyed, but the local mScannerView was re-initialized
with a new instance (through startCamera()) regardless of pre-existing instance, and added to
the contentFrame. This leaves the previous mScannerView instance in limbo, potentially getting
garbage collected at unpredictable times.
Adds an on_done_callback to the QESwapHelper.transport_task future
to prevent the task from swallowing exceptions by retrieving exceptions
and calling `util.send_exception_to_crash_reporter` with them.
Do some validation if the user input in `NewChannelDialog` before
allowing to click the `Ok` button. This is done to make the UI a bit
more intuitive and prevent issues like #10053 in which the user was able
to click `Ok` with a empty trampoline node list which raised an
`IndexError` (probably on testnet4).
- don't show crash reporter multiple times for the "same" exception
- at least until the user restart the program (there is no persistence)
- this is a ~replacement for the removed "Never show crash reporter" option
- in case there e.g. a thread with timer spamming an exception erroneously,
this ensures we only offer to send the crash report once (per process lifecycle)
exc triggered when switching from same server to same server:
```
9.43 | D | gui.qml.qenetwork | server_status updated: Connecting
9.43 | E | network | Exception in _run_new_interface: Exception('diagnostic name not yet available?')
Traceback (most recent call last):
File "/home/user/wspace/electrum/electrum/logging.py", line 241, in __get_logger_for_obj
diag_name = self.diagnostic_name()
File "/home/user/wspace/electrum/electrum/interface.py", line 555, in diagnostic_name
return self.server.net_addr_str()
AttributeError: 'str' object has no attribute 'net_addr_str'
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/home/user/wspace/electrum/electrum/util.py", line 1218, in wrapper
return await func(*args, **kwargs)
File "/home/user/wspace/electrum/electrum/network.py", line 986, in _run_new_interface
interface = Interface(network=self, server=server)
File "/home/user/wspace/electrum/electrum/interface.py", line 502, in __init__
Logger.__init__(self)
File "/home/user/wspace/electrum/electrum/logging.py", line 232, in __init__
self.logger = self.__get_logger_for_obj()
File "/home/user/wspace/electrum/electrum/logging.py", line 243, in __get_logger_for_obj
raise Exception("diagnostic name not yet available?") from e
Exception: diagnostic name not yet available?
```
`TxDialog` may has to fetch tx information from the network on
construction (`self.set_tx()`) and is showing a `RunCoroutineDialog`.
If the user cancels this dialog the `UserCancelled` exception is not
caught in `show_transaction()` and can even lead to Electrum crashing.
Fixes#10041
Fixes exception occuring when `wallet.lnworker` is `None` and the user
clicks on `New Channel` in the channels list tab. The `New Channel`
button is enabled when the wallet *can* have lightning, not the wallet
actually having lightning enabled.
With this patch the `init_lightning_dialog` will show up if the user
clicks on `New Channel` but lightning is not yet enabled.
I noticed this by restoring from a funded vpub and then
loading the keystore from seed afterwards.
```
319.55 | E | gui.qml.qeapp.Exception_Hook | exception caught by crash reporter
Traceback (most recent call last):
File "...\electrum\electrum\util.py", line 1130, in run_with_except_hook
run_original(*args2, **kwargs2)
File "...\Python310\lib\threading.py", line 953, in run
self._target(*self._args, **self._kwargs)
File "...\plyer\platforms\win\libs\balloontip.py", line 206, in balloon_tip
WindowsBalloonTip(**kwargs)
File "...\plyer\platforms\win\libs\balloontip.py", line 130, in __init__
raise Exception('Could not load icon {}'.format(app_icon))
Exception: Could not load icon ...\electrum\electrum\gui\icons\electrum.png
```
When closing Electrum with open `ConfirmTxDialog` the following
exception is raised:
```
1319.20 | E | gui.qt.exception_window.Exception_Hook | exception caught by crash reporter
Traceback (most recent call last):
File "/home/user/code/electrum-fork/electrum/gui/qt/send_tab.py", line 575, in do_pay_or_get_invoice
self.do_pay_invoice(self.pending_invoice)
~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^
File "/home/user/code/electrum-fork/electrum/gui/qt/send_tab.py", line 602, in do_pay_invoice
self.pay_onchain_dialog(invoice.outputs, invoice=invoice)
~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/user/code/electrum-fork/electrum/gui/qt/send_tab.py", line 328, in pay_onchain_dialog
tx, is_preview = self.window.confirm_tx_dialog(make_tx, output_value, batching_candidates=candidates)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/user/code/electrum-fork/electrum/gui/qt/main_window.py", line 1502, in confirm_tx_dialog
return d.run(), d.is_preview
~~~~~^^
File "/home/user/code/electrum-fork/electrum/gui/qt/confirm_tx_dialog.py", line 477, in run
self.stop_editor_updates()
~~~~~~~~~~~~~~~~~~~~~~~~^^
File "/home/user/code/electrum-fork/electrum/gui/qt/confirm_tx_dialog.py", line 133, in stop_editor_updates
self.main_window.gui_object.timer.timeout.disconnect(self.timer_actions)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'timeout'
```
This can be prevented by checking if `main_window.gui_object.timer` is
None before trying to disconnect it.
- save custom fixed feerate fee_policies, not just slider-restricted ones
- dynamically update fee_target text, to follow feerate_e
- otherwise when the slider is set to "feerate", users would be shown two conflicting values
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
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.