Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support async payments in BOLT 12 #1149

Draft
wants to merge 16 commits into
base: master
Choose a base branch
from

Conversation

valentinewallace
Copy link
Contributor

@valentinewallace valentinewallace commented Mar 19, 2024

This builds on #989 by adding the ability to fetch an invoice from an
always-online node on behalf of an often-offline recipient, e.g. a mobile node.

The idea is that often-offline recipients will supply some always-online node
such as their wallet vendor with a static keysend (i.e. payment_hash-less)
invoice to return on its behalf. The recipient will then publish an offer
containing blinded paths that terminate at this always-online node, who payers
can request the invoice from if the recipient is offline at the time. After
receiving the keysend invoice, payers will commence the protocol outlined in
1 to send the HTLC asynchronously.

Some context on the top commit where we include the invoice request in the payment onion:
This definitely warrants discussion, but the idea is that this field may be useful for often-offline recipients who did not receive the invoice request when it was originally sent. Recipients may want to verify the invreq or be provided some other relevant data about the payment, while keeping the payment stateless until an HTLC is actually received. For example, future extensions have been proposed 2 that require the recipient to know a unique token for a payment, and this field would provide that to them.

Seeking conceptual feedback! I'm also working on the implementation in LDK.

Based on #798 and #989.

TheBlueMatt and others added 13 commits February 23, 2024 16:21
This is an incredibly simple first start towards the protocol
sketched out at [1]. It adds the ability to have a counteraprty
hold an HTLC before forwarding it.

Specifically, the HTLC sender sets a required TLV on the
`update_add_htlc` message and sends an onion message to the final
recipient. From there, the final recipient uses the included
`reply_path` to notify the sender's counterparty that they're
online and ready to receive the HTLC.

In order to fully flesh out the protocol as sketched, we'll need
to add an onion message mailbox service (which should be as simple
as a new feature bit), add PTLCs, and extensions to BOLT 12 to
allow signaling that the final recipient is often-offline. While
we could add such signaling to BOLT 11, there's not a whole lot of
reason to - if the recipient is able to provide an invoice,
they're currently online!

[1] https://lists.linuxfoundation.org/pipermail/lightning-dev/2021-October/003307.html
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
It's far easier to validate these on parsing than to hand-validate them
elsewhere.

I didn't turn `alias` or `error` into this, though they're similar
(`alias` can have a nul terminator).

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
A BOLT11 "invoice" has proven too low-level for human use in many
scenarios.  Efforts like lnurl have covered the gap, but integrating
some of such higher layers into the lightning protocol itself has many
advantages.

This draft defines three new things:

1. A new invoice format.  I know, this is painful, but it maps almost
   1:1 to the current format (though signatures are very different),
   is easier to implement, and easier to send via the lightning
   network itself.

2. Formats for an "offer", which for all intents and purposes serves
   as the new, persistent invoice for users.

3. Format for an "invoice_request": this is a message sent via the
   lightning network itself to receive the real invoice, or can
   be used directly in a send-money scenario (e.g. ATM).

The offer (for accepting payments) or invoice_request (for sending
payments) are usually presented via a QR code or similar, the replies
are sent using onion messages.  Each copies fields from the prior so
it stands alone, to allow statelessness.

Features which have been deliberately omitted for the initial version:
- Recurrence.
- Invoice replacement ("don't accept that old payment!")
- Payer proof for refunds.

I need to thank everyone who gave detailed feedback, particularly:

1. Thomas H of ACINQ (https://github.com/thomash-acinq)
2. Joost Jager (https://github.com/joostjager)
3. Aditya Sharma (https://github.com/adi2011)
4. Rene Pickhardt (https://github.com/renepickhardt)
5. Bastien Teinturier (https://github.com/t-bast)
6. Valentine Wallace of LDK (https://github.com/valentinewallace)
7. Matt Corallo of LDK (https://github.com/BlueMatt)
8. Jeffrey Czyz of Square Crypto (https://github.com/jkczyz)

Also @bjarnemagnussen, @ellemouton, @animatedbarber, @617a7a,
@instagibbs, and @eupn.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Regenerated bolt12/signature-test.json; for some reason jq reordered a
few fields, but it now shows the complete signature.
bolt12/format-string-test.json is now a valid offer.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Offers may contain blinded paths to allow for greater recipient privacy.
However, they come at a cost of increased QR code size as each hop
requires a 33-byte `point` for the `next_node_id`. Allow using
`short_channel_id` instead, which only requires 8 bytes.

Still allow for use of `next_node_id` for cases where the blinded path
may not involve channel counterparties or for long-lived offers, which
may outlive the given channels.
Offers may contain blinded paths to allow for greater recipient privacy.
However, they come at a cost of increased QR code size as the
introduction node requires a 33-byte `point`.

Define a new `sciddir_or_pubkey` fundamental type such that either a point or a
reference to one in a `channel_announcement` can be used. This is
backwards compatible with `point`.

Use this new type for the `blinded_path` subtype's `first_node_id`.
This builds on prior commits by adding the ability to fetch an invoice from an
always-online node on behalf of an often-offline recipient, e.g. a mobile node.

The idea is that often-offline recipients will supply some always-online node
such as their wallet vendor with a static (i.e. `payment_hash`-less) invoice to
return on its behalf. The recipient will then publish an offer containing
blinded paths that terminate at this always-online node, who payers can request
the invoice from if the recipient is offline at the time. After receiving the
static invoice, payers will commence the protocol outlined in [1] to send the
HTLC asynchronously.

[1]: https://lists.linuxfoundation.org/pipermail/lightning-dev/2021-October/003307.html
This field may be useful for often-offline recipients who did not receive the
invreq when it was originally sent, due to another node providing a static
invoice on their behalf. Recipients may want to verify the invreq or be
provided some other relevant data about the payment while remaining stateless
until an HTLC is actually received.
@valentinewallace
Copy link
Contributor Author

Changed up the feature bits, required single-chain offers, and disallowed setting invoice_amount_msat for static invoices. Also moved away from the "keysend" language for clarity. These changes were based on implementing this in LDK in lightningdevkit/rust-lightning#3082, will take this out of draft once the design solidifies a bit more in that PR.

@valentinewallace
Copy link
Contributor Author

Added a fixup requiring the invreq to be included in the payment onion per spec meeting discussion a week ago!

valentinewallace added a commit to valentinewallace/rust-lightning that referenced this pull request Sep 18, 2024
Per <lightning/bolts#1149>, when paying a static
invoice we need to include our original invoice request in the HTLC onion since
the recipient wouldn't have received it previously.

We use an experimental TLV type for this new onion payload field, since the
spec is still not merged in the BOLTs.
valentinewallace added a commit to valentinewallace/rust-lightning that referenced this pull request Sep 18, 2024
Add a new invoice request parameter to onion_utils::build_onion_payloads.
As of this commit it will always be passed in as None, to be updated in future
commits.

Per <lightning/bolts#1149>, when paying a static
invoice we need to include our original invoice request in the HTLC onion since
the recipient wouldn't have received it previously.
valentinewallace added a commit to valentinewallace/rust-lightning that referenced this pull request Sep 18, 2024
Add a new invoice request parameter to onion_utils::create_payment_onion. As of
this commit it will always be passed in as None, to be updated in future
commits.

Per <lightning/bolts#1149>, when paying a static
invoice we need to include our original invoice request in the HTLC onion since
the recipient wouldn't have received it previously.
valentinewallace added a commit to valentinewallace/rust-lightning that referenced this pull request Sep 18, 2024
Add a new invoice request parameter to outbound_payments and channelmanager
send-to-route internal utils. As of this commit the invreq will always be
passed in as None, to be updated in future commits.

Per <lightning/bolts#1149>, when paying a static
invoice we need to include our original invoice request in the HTLC onion since
the recipient wouldn't have received it previously.
valentinewallace added a commit to valentinewallace/rust-lightning that referenced this pull request Sep 18, 2024
When transitioning outbound payments from AwaitingInvoice to
StaticInvoiceReceived, include the invreq in the new state's outbound payment
storage for future inclusion in an async payment onion.

Per <lightning/bolts#1149>, when paying a static
invoice we need to include our original invoice request in the HTLC onion since
the recipient wouldn't have received it previously.
valentinewallace added a commit to valentinewallace/rust-lightning that referenced this pull request Sep 18, 2024
Past commits have set us up to include invoice requests in outbound async
payment onions. Here we actually pull the invoice request from where it's
stored in outbound_payments and pass it into the correct utility for inclusion
in the onion.

Per <lightning/bolts#1149>, when paying a static
invoice we need to include our original invoice request in the HTLC onion since
the recipient wouldn't have received it previously.
valentinewallace added a commit to valentinewallace/rust-lightning that referenced this pull request Sep 18, 2024
While in the last commit we began including invoice requests in async payment
onions on initial send, further work is needed to include them on retry. Here
we begin storing invreqs in our retry data, and pass them along for inclusion
in the onion on payment retry.

Per <lightning/bolts#1149>, when paying a static
invoice we need to include our original invoice request in the HTLC onion since
the recipient wouldn't have received it previously.
valentinewallace added a commit to valentinewallace/rust-lightning that referenced this pull request Sep 18, 2024
Per <lightning/bolts#1149>, when paying a static
invoice we need to include our original invoice request in the HTLC onion since
the recipient wouldn't have received it previously.

We use an experimental TLV type for this new onion payload field, since the
spec is still not merged in the BOLTs.
valentinewallace added a commit to valentinewallace/rust-lightning that referenced this pull request Sep 18, 2024
Add a new invoice request parameter to onion_utils::build_onion_payloads.
As of this commit it will always be passed in as None, to be updated in future
commits.

Per <lightning/bolts#1149>, when paying a static
invoice we need to include our original invoice request in the HTLC onion since
the recipient wouldn't have received it previously.
valentinewallace added a commit to valentinewallace/rust-lightning that referenced this pull request Sep 18, 2024
Add a new invoice request parameter to onion_utils::create_payment_onion. As of
this commit it will always be passed in as None, to be updated in future
commits.

Per <lightning/bolts#1149>, when paying a static
invoice we need to include our original invoice request in the HTLC onion since
the recipient wouldn't have received it previously.
valentinewallace added a commit to valentinewallace/rust-lightning that referenced this pull request Sep 18, 2024
Add a new invoice request parameter to outbound_payments and channelmanager
send-to-route internal utils. As of this commit the invreq will always be
passed in as None, to be updated in future commits.

Per <lightning/bolts#1149>, when paying a static
invoice we need to include our original invoice request in the HTLC onion since
the recipient wouldn't have received it previously.
valentinewallace added a commit to valentinewallace/rust-lightning that referenced this pull request Sep 18, 2024
When transitioning outbound payments from AwaitingInvoice to
StaticInvoiceReceived, include the invreq in the new state's outbound payment
storage for future inclusion in an async payment onion.

Per <lightning/bolts#1149>, when paying a static
invoice we need to include our original invoice request in the HTLC onion since
the recipient wouldn't have received it previously.
valentinewallace added a commit to valentinewallace/rust-lightning that referenced this pull request Sep 18, 2024
Past commits have set us up to include invoice requests in outbound async
payment onions. Here we actually pull the invoice request from where it's
stored in outbound_payments and pass it into the correct utility for inclusion
in the onion on initial send.

Per <lightning/bolts#1149>, when paying a static
invoice we need to include our original invoice request in the HTLC onion since
the recipient wouldn't have received it previously.
valentinewallace added a commit to valentinewallace/rust-lightning that referenced this pull request Sep 18, 2024
While in the last commit we began including invoice requests in async payment
onions on initial send, further work is needed to include them on retry. Here
we begin storing invreqs in our retry data, and pass them along for inclusion
in the onion on payment retry.

Per <lightning/bolts#1149>, when paying a static
invoice we need to include our original invoice request in the HTLC onion since
the recipient wouldn't have received it previously.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants