Commit Graph

971 Commits

Author SHA1 Message Date
ThomasV 7a6a39d1aa add comments about xpub encryption 2026-04-02 14:46:50 +02:00
f321x 609a274661 LNWallet: set trampoline invoice feature independently
Make the trampoline signaling in bolt11 invoices dependent upon all
unfrozen channels being with trampoline peers instead of the trampoline
config.
Stops automatically freezing non-trampoline channels for receiving if
trampoline is enabled.

One effect of this change is that now we don't signal trampoline support
anymore in the invoice even if trampoline is enabled, if one of the
channels is with a non trampoline peer.
2026-03-26 12:10:22 +01:00
f321x 0265c70766 LNWallet: only include tramp r_tags if tramp feature
Only include r_tags for trampoline nodes in a bolt11 invoice
if its invoice_features signal trampoline support.
2026-03-26 12:10:19 +01:00
ThomasV 31c2ffbf64 Merge pull request #10532 from spesmilo/variable_trampoline_onions
trampoline: allow trampoline onion packets of arbitrary size
2026-03-24 12:11:56 +01:00
ThomasV 01d017cd97 follow-up #10442
this assert fails if we do not have the preimage
2026-03-19 11:45:40 +01:00
ThomasV 558f85296c trampoline: allow trampoline onion packets of arbitrary size 2026-03-19 08:47:07 +01:00
SomberNight fe5cb09e05 wallet_db: convert PaymentInfo amounts from 0 to None
When creating a "zero-amount" payment request, currently we save a PaymentInfo with a "None" amount.
I think there were a few releases in 2023 that saved PaymentInfos with a `0` amount instead. This was changed in #8659 [0], but as said there [1], a DB upgrade was not done.
Now an assert added in [2] is failing due to this inconsistency, for affected old wallets.
- I think to trigger that, one needs a wallet that has a payment request (with a `0` amount) created around that time, which is still unpaid.

This patch tries to restore consistency by enforcing None amounts.

fixes https://github.com/spesmilo/electrum/issues/10501

[0]: https://github.com/spesmilo/electrum/pull/8659
[1]: https://github.com/spesmilo/electrum/pull/8659#issuecomment-1777101285
[2]: https://github.com/spesmilo/electrum/commit/286fc4b86e4d23cb9af15b9061b3d709e7592bcb
2026-03-02 17:12:07 +00:00
SomberNight 10274c1cd7 simplify prev 2026-02-24 17:57:58 +00:00
SomberNight 0b2c7a8a38 lnsweep: safer maybe_reveal_preimage_for_htlc, add "is_preimage_public"
"When should we reveal preimages onchain?"
This commit tries to simplify the thinking by making the observation:
- we can reveal preimages (actually in any context) if they are already public
- a preimage is public if any other lightning node knows it besides us
  - if we learn the preimage from another LN node, it is public
  - if we send update_fulfill_htlc, it becomes public
  - if we see a preimage onchain, it is public

- in lnsweep._maybe_reveal_preimage_for_htlc:
  - partial mpp check is not relevant if preimage is already public
  - let's just always do KeepWatchingTXO, for sanity/safety

Co-authored-by: ThomasV <thomasv@electrum.org>
2026-02-24 17:49:15 +00:00
ghost43 aefc4aa5b3 Merge pull request #10459 from SomberNight/202602_lnaddr_format_rtags
lnwallet.pay_to_node: log r_tags from invoice
2026-02-09 17:06:21 +00:00
ThomasV b2a3e08ac8 ignore exceptions in process_gossip
A failing signature verification should not kill the taskgroup
2026-02-09 10:58:24 +01:00
SomberNight 4d4cff7840 lnwallet.pay_to_node: log r_tags from invoice
and add helper "format_bolt11_routing_info_as_human_readable"
2026-02-03 07:36:20 +00:00
f321x 79ef429b3c lnworker: don't connect to onion peers if no proxy
When gossip is enabled we waste a lot of time trying to connect
to onion peers if we don't have a proxy enabled. We should just skip
them and try to connect to clearnet peers instead.
2026-01-27 13:14:31 +01:00
f321x db6b6a16f8 lnpeermgr: add_peer: fix check if proxy enabled
LNPeerManager.add_peer would only check if self.network.proxy is set,
which it is always as Network is initialized with self.proxy =
ProxySettings(). Instead it should check if proxy is set and enabled.
2026-01-27 12:49:19 +01:00
SomberNight 0ae10b2a7b lnpeer: log name of wallet file in each line
- if multiple LN-enabled wallets are open, need to know which peer is for which wallet
- note: LNGossip is a singleton
  - if a wallet is named LNGossip, can't distinguish. I think that's ok.

compare log lines:
before:
```
84.82 | I | lnpeer.Peer.[LNWallet, 034cc6216f-f8dcaa6e] | Disconnecting: GracefulDisconnect('Failed to initialize: TimeoutError()')
17.97 | D | lnpeer.Peer.[LNGossip, 0259d4116d-1618547b] | Sending INIT
```
after:
```
 5.80 | D | lnpeer.Peer.[test_segwit_2, 038863cf8a-fd53ef9c] | Sending CHANNEL_READY
 5.92 | D | lnpeer.Peer.[LNGossip, 038863cf8a-6286ffd4] | Received INIT
```
2026-01-19 16:03:42 +00:00
SomberNight c37b844f66 lnutil: change ReceivedMPPStatus.htlcs to frozenset, i.e. immutable
As ThomasV says:

> ReceivedMPPStatus is a Namedtuple, which is immutable, but it contains
> a mutable field. Since ReceivedMPPStatus is not a StoredObject,
> no patch will be created when the htlcs list is modified, and we may
> end up not saving the change to disk if partial writes are enabled.

patch taken from https://github.com/spesmilo/electrum/pull/10395#pullrequestreview-3634244541
closes https://github.com/spesmilo/electrum/pull/10395

Co-authored-by: f321x <f@f321x.com>
2026-01-15 15:59:14 +00:00
ThomasV 1845143786 lnpeer: wait_for_received_pending_htlcs_to_get_removed: wait only if peer has been initialized 2026-01-13 17:16:10 +01:00
SomberNight dfeb9918d8 tests: lnchannel: rewrite create_test_channels to use LNWallet 2026-01-05 15:56:04 +00:00
SomberNight b292c027c3 lnpeer: move make_local_config to LNWallet
no functional changes
2026-01-05 15:55:41 +00:00
SomberNight 1006e8092f lnworker: split LNWallet and LNWorker: LNWallet "has an" LNWorker
- LNWallet no longer "is-an" LNWorker, instead LNWallet "has-an" LNWorker
- the motivation is to make the unit tests nicer, and allow writing unit tests for more things
  - I hope this makes it possible to e.g. test lnsweep in the unit tests
  - some stuff we would previously have to write a regtest for, maybe we can write a unit test for, now
- in unit tests, MockLNWallet now
  - inherits LNWallet
  - the Wallet is no longer being mocked
2026-01-05 15:55:31 +00:00
SomberNight aab22a237b ln: require LnFeatures.OPTION_CHANNEL_TYPE as bolts now mandate it
This simplifies some code.

following https://github.com/lightning/bolts/commit/9d456b1c4a6c8e05a6b5b5edbc6c10f7b4b8e4de
2025-12-18 16:43:19 +00:00
f321x 2f2340d69f lnworker: prevent creation of PaymentInfo with 0 exp
In some parts of the application 0 (sec) == no expiry, however we
use `LN_EXPIRY_NEVER` (100 years) instead of 0 for lightning invoices.

This replaces a 0 second expiry with `LN_EXPIRY_NEVER` in
`LNWallet.create_payment_info()` to prevent htlcs for no-expiry invoices
from getting failed incorrectly (which the assert prevented)
and fix the assertion error in #10350.

Fixes #10350.

# Conflicts:
#	electrum/lnworker.py
2025-12-12 09:58:22 +01:00
SomberNight c465f7c3e0 lnworker/lnpeer: don't use lnworker.channels.get(chan_id)
- lnworker.channels takes a copy of the whole dict, to make it thread-safe
- in LNWallet class, can just use self._channels.get(chan_id)
- otherwise there is lnworker.get_channel_by_id
- same for lnpeer.channels.get and lnpeer.get_channel_by_id
2025-12-10 16:14:31 +00:00
f321x 125a921cc4 lnworker: add invoice features to PaymentInfo class
Adds the invoice features to the `PaymentInfo` class so we can check if
the sender respects our requested features (e.g. if they tried to send
mpp if we requested no mpp).
2025-12-10 10:36:31 +01:00
f321x 5be598b808 lnworker: use channel_id instead of scid in ReceivedMPPHtlc
Store the channel id instead of the scid in ReceivedMPPHtlc.
The scid can be None, in theory even for multiple channels at the same
time. Using the channel_id which is always available and unique seems
less error prone at the cost of temporarily higher storage requirements
in the db for the duration of the pending htlcs.

Alternatively we could use the local scid alias however using the
channel_id seems less complex and leaves less room for ambiguity.
2025-12-09 14:44:11 +01:00
f321x 8a88ebe6bc lnworker: add type assert to get_channel_by_short_id
Prevents accidentally passing None if channel.short_id is not set yet
2025-12-09 14:44:09 +01:00
SomberNight 6d1e8e8619 lnworker: write rationale for PaymentInfo class in docstring
ref https://github.com/spesmilo/electrum/commit/4ad9caddab3fe5d3b25fc53d7ffa7ccf5cbd3b6c
ref https://github.com/spesmilo/electrum/commit/f08e5541aeda9524eb456477f93732de7357c792
2025-12-08 15:54:37 +00:00
ghost43 f8fc2b63e3 Merge pull request #10271 from f321x/fix_save_payment_info
lightning: fix self payments (e.g. rebalance)
2025-12-05 17:19:39 +00:00
Sander van Grieken 3e4f80aa06 electrum refuses to exchange gossip with CLN nodes, due to missing feature OPTION_CHANNEL_TYPE_OPT.
moving OPTIONAL_CHANNEL_TYPE_OPT to BASE_FEATURES
2025-12-05 15:51:16 +01:00
f321x df612fa010 lnworker: allow overwriting amount of sent payment info
Allows replacing a saved `PaymentInfo` of `SENT` direction if the old
one is not yet paid.
This allows the user to retry paying a 0 amount invoice with different
amount if the previous attempt failed.
2025-12-01 18:39:59 +01:00
f321x 923d48f9db lnworker: differentiate PaymentInfo by direction
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.
2025-12-01 18:39:56 +01:00
f321x af4dc24d87 lnworker: use config lightning fee for estimate
I was unable to do a "Max" amount submarine swap because the
`fee_estimate` method used by `LNWallet.num_sats_can_send()` uses a
hardcoded `fee_proportional_millionths` to estimate the fee for the
lightning payment.
When the actual fee determined later is higher
than the estimated fee the payment fails as the channel is unable to add
the htlc sum including the real fees as the amount exceeds the balance of
the channel.
Using the fees the maximum fees user has configured and estimate the
potential fee as inverse of PaymentFeeBudget is more
reliable/conservative as we definitely aren't going to pay more fees
than this amount.
2025-11-28 16:25:34 +01:00
f321x abc469c846 lnworker: split dont_settle_htlcs
Splits `LNWallet.dont_settle_htlcs` into `LNWallet.dont_settle_htlcs`
and `LNWallet.dont_expire_htlcs`.

Registering a payment hash in dont_settle_htlcs will prevent it from
getting fulfilled if we have the preimage stored. The preimage will not
be released before the the payment hash gets removed from
dont_settle_htlcs. Htlcs can still get expired as usual or failed if no
preimage is known.
This is only used by Just-in-time channel openings.

Registering a payment hash in dont_expire_htlcs allows to overwrite the
minimum final cltv delta value after which htlcs would usually get
expired. This allows to delay expiry of htlcs or, if the value in the
dont_settle_htlcs dict is None, completely prevent expiry and let the
htlc get expired onchain.

Splitting this up in two different dicts makes it more explicit and
easier to reason about what they are actually doing.

 Please enter the commit message for your changes. Lines starting
2025-11-27 17:58:44 +01:00
f321x 0f314d1dd9 lnpeer/lnworker: refactor htlc_switch
refactor `htlc_switch` to new architecture to make it more robust
against partial settlement of htlc sets and increase maintainability.
Htlcs are now processed in two steps, first the htlcs are collected into
sets from the channels, and potentially failed on their own already.
Then a second loop iterates over the htlc sets and finalizes only on
whole sets.

# Conflicts:
#	electrum/lnpeer.py
2025-11-27 17:57:14 +01:00
f321x 196cc33c1c ln: fix race when doing concurrent ln payments
There is a race when initiating multiple lightning payments concurrently
(e.g. when doing a reverse swap with prepayment + swap payment).
suggest_splits might overallocate
split amounts for a channel as the splitting of both invoice amounts runs
concurrently and before acutal htlcs that reduce the channels balance
have been added to the channel yet. This results in a "not
enough balance" PaymentFailure once we try to send the htlcs and the
other payment attempt already reduced the available balance of the
channel.

This fix takes a lock from splitting the amount until the htlcs are
put on the channel, so suggest_splits always acts on the correct channel
balance.
2025-11-27 16:43:40 +01:00
f321x a6e103b63c lnonion:
add helper properties
 minor refactoring
2025-11-25 13:14:57 +01:00
SomberNight c288656dc0 trampoline: when sending payment, log "is_legacy" (e2e vs pay2legacy) 2025-11-21 15:45:33 +00:00
SomberNight 1b600b49e9 lnmsg/lnonion: follow-up prev: "hide" MappingProxyType usage 2025-11-18 14:54:33 +00:00
f321x 936e7fd1c2 lnonion: immutable OnionPacket and OnionHopsDataSingle
Make OnionHopsDataSingle and OnionPacket immutable for safer caching and
handling.

# Conflicts:
#	electrum/onion_message.py
2025-11-11 14:37:37 +01:00
SomberNight e53666ac86 lnworker: follow-up prev: split pay_to_node 2025-11-07 15:37:49 +00:00
f321x f5aa82d4f0 lnworker: fix todo, collect failed htlcs in payment
This makes `LNWallet.pay_to_node()` wait
`PaySession.TIMEOUT_WAIT_FOR_NEXT_RESOLVED_HTLC` (0.5 sec) for another
htlc to get resolved after receiving a htlc failure during a payment
attempt.
This seems to make payments more reliable in scenarios where we receive
multiple htlc failures closely after each other as
`create_route_for_payment` then has access to the failed routes/failure
information of all these htlcs when trying to re-split the outstanding
amount.
2025-10-21 13:19:12 +02:00
SomberNight 6e45d6e690 lnworker: (trivial) add a few missing type-hints 2025-10-09 15:06:23 +00:00
ThomasV f4e7ffd5f3 lnworker: set OPTION_ONION_MESSAGE_OPT feature if we are forwarding. 2025-10-07 11:19:37 +02:00
SomberNight 7d0ac64d06 Merge remote-tracking branch 'spesmilo/pr/9993': lnurl-withdraw
ref https://github.com/spesmilo/electrum/pull/9993
2025-10-02 23:34:40 +00:00
f321x 286fc4b86e lnworker: enforce creation of PaymentInfo for b11
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.
2025-09-30 09:54:35 +02:00
f321x d62b627a0b lnpeer: move htlc forwarding funcs to lnworker
forwarding happens independent of the peer that received the htlc to
forward and fits better in lnworker.
2025-09-30 09:54:24 +02:00
f321x 32aa6ab20c lnutil: rename RecvMPPResolution.ACCEPTED
Renames RecvMPPResolution.ACCEPTED to .COMPLETE as .ACCEPTED is somewhat
misleading. Accepted could imply that the preimage for this set has been
revealed or that the set has been settled, however it only means that we
have received the full set (it is complete), but the set still can be
failed (e.g. through cltv timeout) and has not been claimed yet.
2025-09-29 16:11:26 +00:00
f321x fcc3796079 lnworker: move RecvMPPResolution and status to lnutil
it is required both in lnpeer and lnworker, moving it to lnutil seems to
make more sense.

# Conflicts:
#	electrum/lnworker.py
2025-09-29 16:11:17 +00:00
f321x 4c0155c072 lnworker: make PaymentInfo dataclass
Move PaymentInfo from NamedTuple to dataclass to allow for easier
handling e.g. using dataclasses.astuple etc.
2025-09-29 16:11:03 +00:00
SomberNight b944371ffd adb: change API of util.TxMinedInfo: height() is now always SPV-ed 2025-09-24 13:46:24 +00:00