- 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.
Fixes: after adding a payment request, if the process was killed,
the payreq might get lost. In case of using the GUI, neither the
callee nor the caller called wallet.save_db().
Unclear where wallet.save_db() should be called...
Now each method tries to persist their changes by default,
but as an optimisation, the caller can pass write_to_disk=False
e.g. when calling multiple such methods and then call wallet.save_db() itself.
If we had partial writes, which would either rm the need for wallet.save_db()
or at least make it cheaper, this code might get simpler...
related: https://github.com/spesmilo/electrum/pull/6435
related: https://github.com/spesmilo/electrum/issues/4823
see code comment.
While the balance in the channels might shift before the sender tries to
pay the invoice, as we are not a forwarding node, that seems unlikely to matter.
- better error handling: previously we stopped all attempts on any of
TRAMPOLINE_EXPIRY_TOO_SOON, UNKNOWN_NEXT_PEER, TEMPORARY_NODE_FAILURE.
Instead we should retry (but see code comments).
- previously payments failed if ALL of the following criteria applied:
- sender is paying via trampoline, but not via the ACINQ node (which is
special cased)
- receiver only has private channels and has put r_tags into invoice, along
with setting the trampoline feature bit in the invoice, however the receiver
is not connected to any trampoline forwarders directly
The sender would then assume that the private routing hints in the invoice
correspond to trampoline forwarders.
- also, previously if both the sender and the recipient used trampoline and
they shared a trampoline forwarder (that they were both connected to), the
private channels the recipient had (with nodes other than the shared TF)
would never be attempted.
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.
E | gui.qt.exception_window.Exception_Hook | exception caught by crash reporter
Traceback (most recent call last):
File "...\electrum\electrum\gui\qt\main_window.py", line 870, in timer_actions
self.update_wallet()
File "...\electrum\electrum\gui\qt\main_window.py", line 1003, in update_wallet
self.update_tabs()
File "...\electrum\electrum\gui\qt\main_window.py", line 1010, in update_tabs
self.history_model.refresh('update_tabs')
File "...\electrum\electrum\util.py", line 412, in <lambda>
return lambda *args, **kw_args: do_profile(args, kw_args)
File "...\electrum\electrum\util.py", line 408, in do_profile
o = func(*args, **kw_args)
File "...\electrum\electrum\gui\qt\history_list.py", line 329, in refresh
self.view.filter()
File "...\electrum\electrum\gui\qt\util.py", line 705, in filter
self.hide_rows()
File "...\electrum\electrum\gui\qt\util.py", line 709, in hide_rows
self.hide_row(row)
File "...\electrum\electrum\gui\qt\util.py", line 685, in hide_row
should_hide = self.should_hide(row_num)
File "...\electrum\electrum\gui\qt\history_list.py", line 445, in should_hide
date = tx_item['date']
KeyError: 'date'
(related to prev commit, but really another bug)
If we had two peers with the same pubkey (peer A in the process of teardown, peer B ~freshly connected),
peer A might remove peer B from lnworker.peers via close_and_cleanup().
rm `close_and_cleanup()` call from reestablish_channel - it was added
as a workaround for this bug (in 8b95b2127d)
before we understood the cause.
If a remote node tries to establish a transport with us but we already
have an open transport with such a node id, there are two sane ways to go, either:
- keep existing transport open, reject new transport
- close existing transport, establish new transport
We could do either; I chose to do the second option here, as that is what
lnd and eclair seem to be doing.
Previously we would get into an inconsistent state: both transports open,
but only one of them stored in lnworker.peers.
- use_recoverable_channel is a user setting, available
only in standard wallets with a 'segwit' seed_type
- if enabled, 'lightning_xprv' is derived from seed
- otherwise, wallets use the existing 'lightning_privkey2'
Recoverable channels:
- channel recovery data is added funding tx using an OP_RETURN
- recovery data = 4 magic bytes + node id[0:16]
- recovery data is chacha20 encrypted using funding_address as nonce.
(this will allow to fund multiple channels in the same tx)
GUI:
- whether channels are recoverable is shown in wallet info dialog.
- if the wallet can have recoverable channels but has an old node_id,
users are told to close their channels and restore from seed
to have that feature.
This is re the channel update for the incoming direction of our own channels.
This message can only come from the counterparty itself so maybe the sig check
is redundant... but for sanity I think we should check it anyway.