Fixes:
```
Traceback (most recent call last):
File "/home/user/code/electrum-fork/electrum/plugins/psbt_nostr/qt.py", line 149, in on_receive
self.mark_pending_event_rcvd(event_id)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^
File "/home/user/code/electrum-fork/electrum/plugins/psbt_nostr/psbt_nostr.py", line 254, in mark_pending_event_rcvd
self.pending.set()
~~~~~~~~~~~~~~~~^^
File "/usr/lib64/python3.14/asyncio/locks.py", line 192, in set
fut.set_result(True)
~~~~~~~~~~~~~~^^^^^^
File "/usr/lib64/python3.14/asyncio/base_events.py", line 829, in call_soon
self._check_thread()
~~~~~~~~~~~~~~~~~~^^
File "/usr/lib64/python3.14/asyncio/base_events.py", line 866, in _check_thread
raise RuntimeError(
"Non-thread-safe operation invoked on an event loop other "
"than the current one")
RuntimeError: Non-thread-safe operation invoked on an event loop other than the current one
```
Throws UserFacingException if the communication with the ledger fails
due to an OSError. This happens e.g. if the Bitcoin app has been closed.
We shouldn't get crash reports for errors due to disconnection.
Allows storing two different payment info of the same payment hash by
including the direction into the db key.
We create and store PaymentInfo for sending attempts and for requests (receiving),
if we try to pay ourself (e.g. through a channel rebalance) the checks
in `save_payment_info` would prevent this and throw an exception.
By storing the PaymentInfos of outgoing and incoming payments separately in
the db this collision is avoided and it makes it easier to reason about
which PaymentInfo belongs where.
Launch `WatchtowerPlugin.watchtower.start_watching()` through
asyncio.run_coroutine_threadsafe instead of ensure_future to prevent the
following exception from happening when running python with
`PYTHONASYNCIODEBUG=1`.
```
20251103T165007.087746Z | ERROR | plugin.Plugins | cannot initialize plugin watchtower: Error loading watchtower plugin: RuntimeError('Non-thread-safe operation invoked on an event loop other than the current one')
Traceback (most recent call last):
File "/home/user/code/electrum-fork/electrum/plugin.py", line 629, in load_plugin_by_name
plugin = module.Plugin(self, self.config, name)
File "/home/user/code/electrum-fork/electrum/plugins/watchtower/watchtower.py", line 59, in __init__
asyncio.ensure_future(self.watchtower.start_watching())
~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib64/python3.14/asyncio/tasks.py", line 732, in ensure_future
return loop.create_task(coro_or_future)
~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^
File "/usr/lib64/python3.14/asyncio/base_events.py", line 468, in create_task
return self._task_factory(self, coro, **kwargs)
~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^
File "/home/user/code/electrum-fork/electrum/util.py", line 1773, in factory
task = asyncio.Task(coro, loop=loop_, **kwargs)
File "/usr/lib64/python3.14/asyncio/base_events.py", line 829, in call_soon
self._check_thread()
~~~~~~~~~~~~~~~~~~^^
File "/usr/lib64/python3.14/asyncio/base_events.py", line 866, in _check_thread
raise RuntimeError(
"Non-thread-safe operation invoked on an event loop other "
"than the current one")
RuntimeError: Non-thread-safe operation invoked on an event loop other than the current one
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/home/user/code/electrum-fork/electrum/plugin.py", line 184, in load_plugins
self.load_plugin_by_name(name)
~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^
File "/home/user/code/electrum-fork/electrum/plugin.py", line 631, in load_plugin_by_name
raise Exception(f"Error loading {name} plugin: {repr(e)}") from e
Exception: Error loading watchtower plugin: RuntimeError('Non-thread-safe operation invoked on an event loop other than the current one')
```
The default minimumHeight for wizard components is a bit small for the
2fa confirmation component as it only shows the QR code but not the
input field. This seems to confuse users as its not intuitive to scroll
down if there is no large text shown (as for example in the ToS component).
This change increases the minimumHeight and restores it to the previous
height once the user leaves the component again.
Enforce that the information used to create a bolt11 invoice using
`get_bolt11_invoice()` is similar to the related instance of PaymentInfo
by requiring a PaymentInfo as argument for `get_bolt11_invoice()`.
This way the invoice cannot differ from the created PaymentInfo.
This allows to use the information in PaymentInfo for validation of
incoming htlcs more reliably.
To cover all required information for the creation of a b11 invoice the
PaymentInfo class has to be extended with a expiry and
min_final_cltv_expiry. This requires a db upgrade.
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.