Skip to content

wip: bolt 12#10671

Draft
f321x wants to merge 43 commits into
spesmilo:masterfrom
f321x:bolt12_2
Draft

wip: bolt 12#10671
f321x wants to merge 43 commits into
spesmilo:masterfrom
f321x:bolt12_2

Conversation

@f321x
Copy link
Copy Markdown
Member

@f321x f321x commented May 27, 2026

Supersedes #10110
Still WIP, I will cherry-pick commits into separate, focused PRs for review over time.

accumulator and others added 30 commits May 22, 2026 15:09
…ation and schnorr-sign over tlvs,

implicit en/decode utf8 fields, schnorr signature verification.

Co-Authored-By: f321x <f@f321x.com>
Validate points to be valid ECPubkeys in lnmsg._read_primitive_field.
There are failing bolt12 test vectors that contain offers with invalid
points.
Separates the payinfo creation from get_blinded_paths_to_me into a separate
function.
Handle missing remote channel_update when creating payinfo
for blinded path by skipping the affected channel.
Ignore channel amount constraints when doing pathfinding for an
onion message. Onion messages don't need to move funds so pathfinding
shouldn't penalize channels based on fake payment amounts.
Filter channels/peers in `get_blinded_paths_to_me` depending on
the context (onion message or blinded payment path). Raise
according exceptions when no channel/peer is available.
move decryption of recipient_data to process_onion_packet,
add handling of blinding in peer msgs,
handle properties in ProcessedOnionPacket in case of path blinding,
move repeated next blinding key derivation to func lnonion.next_blinding_from_shared_secret()

Co-Authored-By: f321x <f@f321x.com>
…EATURES

... and lnutil.LN_FEATURES_IMPLEMENTED
when we have tried all blinded paths and for none of them we could find a route
and we have a network address available for the destination (either node_id
or blinded path introduction point).
Adds a separate method to `Peer` specifically for sending
onion messages.

This allows to 'enqueue' a (onion) message send before the peer
is initialized without having to externalize waiting for init from `Peer`.
This way we can establish a peer connection in `OnionMessageManager` and
immediately fire an onion message on the `Peer`.
Using the Queue also prevents the timing/retry logic in `OnionMessageManager` from
breaking down if a single peer (of multiple available ones) takes a long time
to send for whatever reason.

Also creates a simpler API for callers (they don't have to pass
a message_name and packet len).
Only catch UserFacingException. The scope of Exception is way too large,
this caught all kinds of exceptions from LNWallet etc.
It is not useful to show the user an error popup with e.g. "KeyError".
Introduce dataclasses for blinded path related structures.
This allows safer and cleaner handling.

- BlindedPathHop
- BlindedPath
- BlindedPayInfo
- BlindedPathInfo
Introduce typed dataclass hierarchy for BOLT12 objects:
- BOLT12Offer, BOLT12InvoiceRequest, BOLT12Invoice
- validation in __post_init__() methods
- helper functions
- unittests (test_bolt12.py)

Co-Authored-By: Sander van Grieken <sander@outrightsolutions.nl>
Adds unittest to check if we handle malformed bolt12 strings according
to the specification using the format-string-test.json test vector.
https://github.com/lightning/bolts/blob/5f31faa0b6e2cdbe32171d79464305f90bda9585/bolt12/format-string-test.json
Tests BOLT12Offer validation against the test vector json from the
bolts repository.
Co-Authored-By: f321x <f@f321x.com>
Implements methods in LNWallet to create and send invoice_requests,
handles incoming invoices. Supports both offerless and offer based
invreqs
Add unittests for the invoice_request creation and invoice handling.
Store BOLT12 invoices as bech32-encoded strings (lni...) in the
lightning_invoice field of the persisted Invoice class.
Decode on demand and cache instance via cached_property.

The `Invoice` can act as sort of abstraction over bolt11 and bolt12
invoices for the GUI.

Co-Authored-By: Sander van Grieken <sander@outrightsolutions.nl>
Add unnittests for bolt12 payment identifier.
Implement `calc_hops_data_for_blinded_payment`, which takes
a route to the introduction point of a blinded payment as well as
the blinded path and assembles the hop payloads for the whole payment
(unblinded path + blinded path).

Co-Authored-By: f321x <f@f321x.com>
Introduce RoutingInfo class to make the lightning payment
flow (LNWallet.pay_invoice and following) less specific to bolt11
but act on generic `RoutingInfo`.
Adapt the LNWallet payment flow to handle blinded/bolt12 payments.
Paying via Trampoline is added in a future commit.

Co-Authored-By: Sander van Grieken <sander@outrightsolutions.nl>
accumulator and others added 13 commits May 22, 2026 15:15
Implement initial LNWallet method `create_offer`
to create bolt12 offer for sharing with external parties.
Add CLI command `add_offer` to use this method.
Co-Authored-By: Sander van Grieken <sander@outrightsolutions.nl>
Add method to substract fees required for blinded path from a
PaymentFeeBudget to calculate the remaining budget for the unblinded
path.
Eclair interprets the invoice_features tlv for legacy trampoline
payments as bytes, potentially this u64 conversion is outdated?
This changes the invoice_features tlv to bytes type.

See eclair source (grep "invoiceFeatures").
https://github.com/ACINQ/eclair/blob/a4d66adce2ec180c94532d1d0014f86f6e74f607/eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/PaymentOnion.scala#L638
Update the trampoline payment logic in LNWallet to handle payments
to/through blinded paths.
This allows for bolt 12 trampoline payments.

Also stops including a trampoline onion layer for the recipient of
a legacy trampoline payment. A non-trampoline aware (legacy) receiver
cannot read this onion and it is not required for Eclair compatibility
anymore.
Co-Authored-By: f321x <f@f321x.com>
Co-Authored-By: f321x <f@f321x.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants