- in lnurl.py, make request methods async
- in Qt GUI, lnurl network requests no longer block the GUI thread
- but they still do in the kivy GUI
- "lightning address" (LUD-16) support is removed for now as the
email addresses are indistinguishable from openalias email addresses
(both protocols should have added and enforced a prefix, or similar,
to remove this kind of ambiguity -- now we would need to make a
network request just to identify what kind of ID we were given)
- revert the logic of do_breach_remedy to what it was
before 0ca3d66d15,
but now calling self.maybe_redeem unconditionally.
- replace mempool transactions only if the fee increases
- do not notify the GUI if a local tx is replaced
- delete labels when replacing
- separate AddressSynchronizer from Wallet and LNWatcher
- the AddressSynchronizer class is referred to as 'adb' (address database)
- Use callbacks to replace overloaded methods
asyncio.get_event_loop() became deprecated in python3.10. (see https://github.com/python/cpython/issues/83710)
```
.../electrum/electrum/daemon.py:470: DeprecationWarning: There is no current event loop
self.asyncio_loop = asyncio.get_event_loop()
.../electrum/electrum/network.py:276: DeprecationWarning: There is no current event loop
self.asyncio_loop = asyncio.get_event_loop()
```
Also, according to that thread, "set_event_loop() [... is] not deprecated by oversight".
So, we stop using get_event_loop() and set_event_loop() in our own code.
Note that libraries we use (such as the stdlib for python <3.10), might call get_event_loop,
which then relies on us having called set_event_loop e.g. for the GUI thread. To work around
this, a custom event loop policy providing a get_event_loop implementation is used.
Previously, we have been using a single asyncio event loop, created with
util.create_and_start_event_loop, and code in many places got a reference to this loop
using asyncio.get_event_loop().
Now, we still use a single asyncio event loop, but it is now stored as a global in
util._asyncio_event_loop (access with util.get_asyncio_loop()).
I believe these changes also fix https://github.com/spesmilo/electrum/issues/5376
closes https://github.com/spesmilo/electrum/issues/7677
```
E/n | network | taskgroup died.
Traceback (most recent call last):
File "/opt/electrum/electrum/network.py", line 1204, in main
[await group.spawn(job) for job in self._jobs]
File "/home/voegtlin/.local/lib/python3.8/site-packages/aiorpcx/curio.py", line 297, in __aexit__
await self.join()
File "/opt/electrum/electrum/util.py", line 1255, in join
task.result()
File "/opt/electrum/electrum/network.py", line 1277, in _maintain_sessions
await maintain_main_interface()
File "/opt/electrum/electrum/network.py", line 1268, in maintain_main_interface
await self._ensure_there_is_a_main_interface()
File "/opt/electrum/electrum/network.py", line 1245, in _ensure_there_is_a_main_interface
await self._switch_to_random_interface()
File "/opt/electrum/electrum/network.py", line 648, in _switch_to_random_interface
await self.switch_to_interface(random.choice(servers))
File "/opt/electrum/electrum/network.py", line 714, in switch_to_interface
await i.taskgroup.spawn(self._request_server_info(i))
File "/home/voegtlin/.local/lib/python3.8/site-packages/aiorpcx/curio.py", line 204, in spawn
self._add_task(task)
File "/home/voegtlin/.local/lib/python3.8/site-packages/aiorpcx/curio.py", line 150, in _add_task
raise RuntimeError('task group terminated')
RuntimeError: task group terminated
```
I believe the "suppress spurious cancellations" block was added as SilentTaskGroup raised
CancelledError instead of RuntimeError for this scenario.
aiorpcx 0.20 changed the behaviour/API of TaskGroups.
When used as a context manager, TaskGroups no longer propagate
exceptions raised by their tasks. Instead, the calling code has
to explicitly check the results of tasks and decide whether to re-raise
any exceptions.
This is a significant change, and so this commit introduces "OldTaskGroup",
which should behave as the TaskGroup class of old aiorpcx. All existing
usages of TaskGroup are replaced with OldTaskGroup.
closes https://github.com/spesmilo/electrum/issues/7446
I think this was originally needed due to incorrect management of group lifecycles,
which our current code is doing better.
also note that if we needed this, in newer aiorpcx, the name of
the field was ~changed from `_closed` to `joined`:
239002689a
Adds liquidity hints for the sending capabilities of routing channels in the
graph. The channel blacklist is incorporated into liquidity hints.
Liquidity hints are updated when a payment fails with a temporary
channel failure or when it succeeds. Liquidity hints are used to give a
penalty in the _edge_cost heuristics used by the pathfinding algorithm.
The base penalty in (_edge_cost) is removed because it is now part of the
liquidity penalty. We don't return early from get_distances, as we want
to explore all channels.
It is not realistic to expect Electrum to be used as a watchtower
in GUI mode, and possibly counter-productive (may set wrong
expectations).
A proper watchtower should be configured as a daemon. The
documentation will be updated to reflect this change.
e.g. kivy GUI refreshes some fields based on this callback;
this should result in faster refreshes
(otherwise e.g. when switching servers, a callback might only come if
we successfully connect to the new server; or if an unrelated event
triggers it)
- trampoline is enabled by default in config, to prevent download of `gossip_db`.
(if disabled, `gossip_db` will be downloaded, regardless of the existence of channels)
- if trampoline is enabled:
- the wallet can only open channels with trampoline nodes
- already-existing channels with non-trampoline nodes are frozen for sending.
- there are two types of trampoline payments: legacy and end-to-end (e2e).
- we decide to perform legacy or e2e based on the invoice:
- we use trampoline_routing_opt in features to detect Eclair and Phoenix invoices
- we use trampoline_routing_hints to detect Electrum invoices
- when trying a legacy payment, we add a second trampoline to the path to preserve privacy.
(we fall back to a single trampoline if the payment fails for all trampolines)
- the trampoline list is hardcoded, it will remain so until `trampoline_routing_opt` feature flag is in INIT.
- there are currently only two nodes in the hardcoded list, it would be nice to have more.
- similar to Phoenix, we find the fee/cltv by trial-and-error.
- if there is a second trampoline in the path, we use the same fee for both.
- the final spec should add fee info in error messages, so we will be able to fine-tune fees
This was a regression from e83f0dd3fc,
introduced by the change in connection_down() there.
(if the initial connection to the main interface is not successful, the
network status will not be set to 'disconnected' - but it should be)
That change is now reverted here.
That change was somewhat independent of the rest of that commit,
except the rest highlighted that something of the sort was needed:
as it might sometimes take many seconds for an interface to close
and we might launch another interface for the same server while the
first one is still closing, the "server == self.default_server" test
is highly problematic.
To fix this second - original - issue, we now introduce a "closing" state
for interfaces (in the form of network._closing_ifaces).
The GUI blocks until network.set_parameters returns when switching servers,
which waits for switch_to_interface, which used to wait until interface.close()
returns. interface.close() tries to flush buffered writes to the wire, with a
30 sec timeout.
If the server or the network connection is slow, flushing the buffer can take
several seconds. In particular, servers running Fulcrum always seem to
timeout in this case, freezing the GUI for 30 seconds (when switching away).
The gossip db is loaded early when the network is started to save
time when the gui is locked and a wallet not yet loaded. Side effects
of the LNWallet to start peering when a channel db is loaded is
circumvented.
Enables lightning by creating a node private key and storing it in
the wallet. The gossiper is not launched at start up, only if there
are existing channels.
some basic sanity checks
Previously if the server sent back a malformed response, it could partially corrupt a wallet file.
(as sometimes the response would get persisted, and issues would only arise later when the values were used)
Previously this function would not switch to a different chain if the
current chain contained the preferred block. This was not the intended
behaviour: if there is a *stronger* chain that *also* contains the
preferred block, we should jump to that.
Note that with this commit there will now always be a preferred block
(defaults to genesis). Previously, it might seem that often there was none,
but actually in practice if the user used the GUI context menu to switch
servers even once, there was one (usually genesis).
Hence, with the old code, if an attacker mined a single header which
then got reorged, auto_connect clients which were connected to the
attacker's server would never switch servers (jump chains) even
without the user explicitly configuring preference for the stale branch.
Data returned by the main server for request "server.peers.subscribe"
is of course untrusted input. Previously if it contained e.g. invalid port numbers
or IP addresses, it could kill the whole network taskgroup.
(this might have only affected master and not released versions,
which would only raise exceptions once the client actually tried to connect to an invalid host/port)