These methods return a list of channels that can be rebalanced,
in order to receive or send a given amount.
Also add 'channels' parameter to submarine swaps.
Previously, swaps were not considering which channel to use.
When we do not have liquidity to pay an invoice:
- add 'rebalance' option in order to pay an invoice
- use the suggested channel in the 'swap' option
When we do not have the liquidity to receive an invoice:
- add 'Rebalance' and 'Swap' buttons to the receive tab
I believe lightning requests created before https://github.com/spesmilo/electrum/pull/7730
can have an amount of None - ones created after have amount 0 instead.
We could do a wallet db upgrade potentially.
Regardless, the type hint is `get_amount_sat(self) -> Union[int, str, None]`,
so None should be handled. (well, arguably "!" should be handled too...)
```
E | gui.qt.exception_window.Exception_Hook | exception caught by crash reporter
Traceback (most recent call last):
File "...\electrum\electrum\gui\qt\request_list.py", line 101, in item_changed
self.parent.show_receive_request(req)
File "...\electrum\electrum\gui\qt\main_window.py", line 1279, in show_receive_request
URI = req.get_bip21_URI(lightning=bip21_lightning)
File "...\electrum\electrum\invoices.py", line 164, in get_bip21_URI
amount = int(self.get_amount_sat())
TypeError: int() argument must be a string, a bytes-like object or a real number, not 'NoneType'
```
```
E | gui.qt.exception_window.Exception_Hook | exception caught by crash reporter
Traceback (most recent call last):
File "...\electrum\electrum\gui\qt\request_list.py", line 101, in item_changed
self.parent.show_receive_request(req)
File "...\electrum\electrum\gui\qt\main_window.py", line 1281, in show_receive_request
can_receive_lightning = self.wallet.lnworker and req.get_amount_sat() <= self.wallet.lnworker.num_sats_can_receive()
TypeError: '<=' not supported between instances of 'NoneType' and 'decimal.Decimal'
```
follow-up https://github.com/spesmilo/electrum/pull/7818
- note it matters whether a sender pays us end-to-end-trampoline or just via legacy
- consider: Alice has 0.1 BTC recv cap in chan1 and 1 BTC recv cap in chan2, both with border-node T1
- if sender is paying e2e trampoline, it can realistically pay even ~1.1 BTC, as T1 can resplit the HTLCs
- if sender is paying legacy, it will have a hard time trying to pay more than 1 BTC, in practice
- although note if T1 has implemented non-strict-forwarding (see BOLT-04), achieving 1 BTC is easy,
as T1 can redirect HTLCs (but cannot split them, in this case)
- to make num_sats_can_receive realistic, it assumes the legacy case
- To calc num_sats_can_receive, we sort our channels in decreasing order of receive-capacities, iterate over them
and calculate a running sum - we stop adding channels when the next chan's recv cap is small compared to
the running total.
- When putting routing hints in an invoice, we do the same, with the added condition that we keep adding channels
if their recv cap is larger than the invoice amount.
- consider: Alice has 0.1 BTC recv cap in chan1 with Bob, and 1 BTC recv cap in chan2 with Carol
- if Alice wants to recv 100 sats, it is useful to add hints for both channels into the invoice, for redundancy
- if Alice wants to recv 0.9 BTC, it is questionable whether adding the smaller chan is useful - the code here won't add it
- increase MPP_RECEIVE_CUTOFF from 5 to 20 percent
- filter channels by node_id, not channel_id
- make num_sats_can_receive consistent with routing hints
return the max value allowed for legacy payments.
(that is, do not assume we can do MPP involving two trampolines)
This reverts fb6047ec46
Reason: num_sats_can_send may be used to decide the amount
we put in a new channel.
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
The call to super was removed in https://github.com/spesmilo/electrum/commit/4efcb53d24d5f1040556d5fb4194eb8007943602 ,
so that LNWallet's taskgroup would not run _maintain_connectivity, AFAICT.
The way it was done meant that "main_loop" itself would not run for LNWallet, only for LNGossip - very confusing.
It is only due to a quirk in the behaviour of TaskGroups that the group "started" at all.
```
Traceback (most recent call last):
File "...\electrum\electrum\gui\qt\main_window.py", line 898, in timer_actions
self.update_wallet()
File "...\electrum\electrum\gui\qt\main_window.py", line 1040, in update_wallet
self.update_tabs()
File "...\electrum\electrum\gui\qt\main_window.py", line 1047, in update_tabs
self.history_model.refresh('update_tabs')
File "...\electrum\electrum\util.py", line 439, in <lambda>
return lambda *args, **kw_args: do_profile(args, kw_args)
File "...\electrum\electrum\util.py", line 435, in do_profile
o = func(*args, **kw_args)
File "...\electrum\electrum\gui\qt\history_list.py", line 275, in refresh
transactions = wallet.get_full_history(
File "...\electrum\electrum\util.py", line 439, in <lambda>
return lambda *args, **kw_args: do_profile(args, kw_args)
File "...\electrum\electrum\util.py", line 435, in do_profile
o = func(*args, **kw_args)
File "...\electrum\electrum\wallet.py", line 947, in get_full_history
lnworker_history = self.lnworker.get_onchain_history() if self.lnworker and include_lightning else {}
File "...\electrum\electrum\lnworker.py", line 911, in get_onchain_history
tx_height = self.lnwatcher.get_tx_height(swap.funding_txid)
AttributeError: 'NoneType' object has no attribute 'get_tx_height'
```
fixes https://github.com/spesmilo/electrum/issues/7750
Each task we schedule on `TaskThread` can provide an optional `cancel` method.
When stopping `TaskThread`, we call this `cancel` method on all tasks in the queue.
If the currently running task does not implement `cancel`, `TaskThread.stop` will block
until that task finishes.
Note that there is a significant change in behaviour here:
`ElectrumWindow.run_coroutine_from_thread` and `ElectrumWindow.pay_lightning_invoice`
previously serialised the execution of their coroutines via wallet.thread.
This is no longer the case: they will now schedule coroutines immediately.
So for example, the GUI now allows trying to pay multiple LN invoices "concurrently".
Messages are sent in reestablish_channel (async)
Message checks and force_close are performed in on_channel_reestablish (not async).
That task should not be cancelled if the connection is closed.
Revert 57583c05cf
It is not safe to keep using the channel after we attempted to broadcast a force-close,
even if the broadcast errored: the server cannot be trusted wrt to errors.
Note that if there is a network-error, due to the state-transition, the GUI won't offer
the force-close option to the user again. However, LNWallet will periodically rebroadcast
the tx automatically (in on_channel_update); and we also save the tx as local into the
wallet.
* Refactor `create_trampoline_route`.
* Enables end-to-end multi-trampoline multipart payments.
Trampoline-to-legacy payments are still not enabled, as this is
currently not supported by Eclair.
* Reverts to a global trampoline fee level, as trampoline failures
are currently not handled properly, see (#7648), which doubles
fee rates.
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
- Separates the trampoline and local routing multi-part payment cases.
- Ask only for splits that don't send over a single channel (those have
been tried already in the single-part case).
- Makes sure that create_routes_for_payment only yields partial routes
that belong to a single split configuration.
- Tracks trampoline fee levels on a per node basis, previously, in the
case of having two channels with a trampoline forwarder, the global
fee level would have increased by two levels upon first try.
- The splitting algorithm is redesigned to use random distribution of
subsplittings over channels.
- Splittings can include multiple subamounts within a channel.
- The single-channel splittings are implicitly activated once the
liquidity hints don't support payments of large size.