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

Add the ability to hold HTLCs before forwarding (FEAT 52/53) #989

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

TheBlueMatt
Copy link
Collaborator

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!

I didn't bother basing this on the onion messages PR, but its a somewhat implied dependency.

[1] https://lists.linuxfoundation.org/pipermail/lightning-dev/2021-October/003307.html

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
@TheBlueMatt TheBlueMatt changed the title Add the ability to hold HTLCs before forwarding Add the ability to hold HTLCs before forwarding (FEAT 52/53) May 13, 2022
Copy link

@thomash-acinq thomash-acinq left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For this to work, we must have Sender -> Hub A -> ... -> Hub B -> Recipient where Hub A and B are always online. Hub A would hold the HTLC.
You can't ask the recipient to tell Hub A when it gets online because for that you need the recipient to be online already to receive the instruction, it has to be Hub B that tells Hub A when recipient gets online.
So when you create the payment, you need to know that the recipient is behind Hub B and that Hub B supports this hold protocol. And in the message to Hub B (with a reply path to Hub A), you need to say who is the recipient.

Comment on lines +931 to +935
1. `tlv_stream`: `update_add_htlc_tlvs`
2. types:
1. type: 0 (`hold_htlc`)
2. data:
* [`32*bytes`:`payment_release_secret`]

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This conflicts with payments to blinded routes (https://github.com/lightning/bolts/pull/765/files), you can use 2.

@@ -43,6 +43,7 @@ The Context column decodes as follows:
| 26/27 | `option_shutdown_anysegwit` | Future segwit versions allowed in `shutdown` | IN | | [BOLT #2][bolt02-shutdown] |
| 44/45 | `option_channel_type` | Node supports the `channel_type` field in open/accept | IN | | [BOLT #2](02-peer-protocol.md#the-open_channel-message) |
| 48/49 | `option_payment_metadata` | Payment metadata in tlv record | 9 | | [BOLT #11](11-payment-encoding.md#tagged-fields)
| 52/53 | `option_htlc_hold` | Hold HTLCs and forward on receipt of an onion message | IN | `option_onion_messages` |

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to advertise this option to everyone? I can imagine that we would only accept to hold HTLCs for our customers but not for other nodes. I think it should be per channel.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see why you'd want such a restriction? The hold option can only be set by your counterparty, never a rando node, and if your counterparty wants to not use some of their channel balance...they can always do that?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe we do want to advertise this to everyone, because it's a good selling point for people to open channels with you: by just looking at your node_announcement they know that you offer this feature that will be useful to them if they want to receive payments and expect to be offline sometimes.

- MUST NOT include a `hold_htlc` TLV unless the sending node expects to be
offline for an extended duration starting soon.
- If the `hold_htlc` TLV is present:
- MUST immediately send at least two onion messages across at least two

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why 2? It seems like it should be an implementation decision.
Anyway, sending an onion message to a node that we expect to be offline is pointless, the message will never be delivered.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See PR text - this assumes store-and-forward mailbox support at the recipient's LSP.

Comment on lines +937 to +947
#### TLV fields for `held_htlc_available`
1. `tlv_stream`: `held_htlc_available`
2. types:

#### TLV fields for `release_held_htlc`

1. `tlv_stream`: `release_held_htlc`
2. types:
1. type: 0 (`payment_release_secret`)
2. data:
* [`32*bytes`:`payment_release_secret`]

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From the next section I get that these are onion messages. They should go in the onionmsg_payload in 04-onion-routing.md

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I kinda disagree? I mean not super strongly, I'm happy to put them anywhere, but generally I don't think we should be shoving every onion message into 04-onion-routing, that makes no sense, IMO. The BOLT 12 (somewhat obviously) PR puts its onion messages into BOLT 12, so I shoved these into the relevant place. We could also define a more general "13-onion-messages` BOLT and shove all the messages there, but I don't think that's super useful either - we generally group things by functionality, not type.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't mean that everything should go into 04-onion-routing but they need to be mentioned there as possible onion messages. Just like for BOLT 12, the details of the bolt 12 types are in there own file but they are referenced from 04-onion-routing. I'm saying this because for release_held_htlc, it's not a standard onion message TLV and it would be good to make it clear exactly where it needs to go.

@thomash-acinq
Copy link

Two more things that I think need more work:

  • CLTV: using this scheme would require some very large CLTV deltas which is not desirable. For the channel Sender -> Hub A it's fine because the assumption here is that relay happens on this channel but for other channels in the route HTLCs should be short-lived. We should have a system for using CLTV deltas in the payment onion instead of an absolute CLTV, I have already suggested such a scheme for payments to blinded routes: 9ca59ac
  • In addition to Hub A announcing support for this feature, Hub B must also support this. That should be advertised in the invoice.

If the recipient is online, this scheme adds an extra round trip for nothing. An alternative design would be try to relay the payment normally but add a reply path to Hub A in the payment onion, in the payload to Hub B. If the recipient is online, the payment goes through, if not then Hub B sends a hold_htlc to Hub A using the reply path and cancels the payment, the cancellation propagates back to Hub A and Hub A holds. Then when the recipient reconnects to Hub B, it sends a release_held_htlc to Hub A who retries the payment.
This eliminates an unnecessary round trip and falls back to a regular payment if Hub B does not support this scheme (we just need to put the reply path to Hub A in an odd TLV).

@TheBlueMatt
Copy link
Collaborator Author

For this to work, we must have Sender -> Hub A -> ... -> Hub B -> Recipient where Hub A and B are always online. Hub A would hold the HTLC.

Yes, not sure how else it'd work.

You can't ask the recipient to tell Hub A when it gets online because for that you need the recipient to be online already to receive the instruction, it has to be Hub B that tells Hub A when recipient gets online. So when you create the payment, you need to know that the recipient is behind Hub B and that Hub B supports this hold protocol. And in the message to Hub B (with a reply path to Hub A), you need to say who is the recipient.

Yes you can, you just have to assume Hub B supports "onion message mailbox" support - ie store-and-forward. I noted this in the PR description/commit text.

CLTV: using this scheme would require some very large CLTV deltas which is not desirable.

Only on the first hop - given its only useful/used if Sender is often-offline, there's not really any reason to care about a high CLTV on the first hop - that capital wasn't going to be useful for anything anyway.

You're right that we'll need a further extension to allow Hub A to send the HTLC onward with a lower CLTV than the one in the onion, add that to the list of things we need to flesh this out fully 🤷‍♂️ .

Hub B must also support this.

See above, I don't think so.

If the recipient is online, this scheme adds an extra round trip for nothing.

Correct, that's part of why its super explicit that "this shouldn't be used if you think the recipient is online", that's also why its not specified for BOLT 11 - see above, it only makes sense with a BOLT 12 extension where you indicate that "Hub B can provide PTLC-based invoices on my behalf".

@thomash-acinq
Copy link

Yes you can, you just have to assume Hub B supports "onion message mailbox" support - ie store-and-forward. I noted this in the PR description/commit text.

You should specify this "onion message mailbox" in more details, I don't think it is as obvious and simple at you imply.

You're right that we'll need a further extension to allow Hub A to send the HTLC onward with a lower CLTV than the one in the onion, add that to the list of things we need to flesh this out fully man_shrugging .

That's what I meant and as I said I have already suggested a solution for that in the context of payments to blinded routes : use CLTV deltas in payment onions instead of absolute CLTVs.

Hub B must also support this.

See above, I don't think so.

Hub B needs to support "onion message mailbox", it won't work without it. So you need a way to advertise this support.

it only makes sense with a BOLT 12 extension where you indicate that "Hub B can provide PTLC-based invoices on my behalf".

The main (only?) use case I can see for private wallet to private wallet payment is sending money to someone you trust (family or friends typically). And this does not require BOLT 12 or PTLC, it can be done today with keysend.

@yaslama
Copy link

yaslama commented May 18, 2022

The main (only?) use case I can see for private wallet to private wallet payment is sending money to someone you trust (family or friends typically).

With AMP, the payee can generate a static invoice and put it in an "always online" place (a QR in a website or can send an email or use any other asynchronous message mechanism). Without PTLC, the payer doesn't have any proof of payment, so she has to trust the payee. With PTLC no trust is needed.

@TheBlueMatt
Copy link
Collaborator Author

You should specify this "onion message mailbox" in more details, I don't think it is as obvious and simple at you imply.

Not sure why this is complicated? Just store-and-forward. There's DoS questions, but not a lot we can do about that. In any case, yes, it should be specified, I'm just taking this one small step at a time.

That's what I meant and as I said I have already suggested a solution for that in the context of payments to blinded routes : use CLTV deltas in payment onions instead of absolute CLTVs.

Ah! Okay apologies, I misread. Yes, that option would address the issue as well.

Hub B needs to support "onion message mailbox", it won't work without it. So you need a way to advertise this support.

Yes, to be clear, this PR as-is is maybe 1/5th of what we need. It's not useful on its own, but it's a first step towards something great.

The main (only?) use case I can see for private wallet to private wallet payment is sending money to someone you trust (family or friends typically). And this does not require BOLT 12 or PTLC, it can be done today with keysend.

Huh? Ability to generate a reusable invoice and receive tips is a substantial use-case that people generally expect to work when they receive a QR code, and which doesn't work almost at all today. This is how bitcoin works and is often how its used. More generally, here is the US, this is how Cash App and Venmo non-bitcoin QR codes work, and people share those as well.

Further, ability to release HTLCs on receipt of a message could shift the mobile failure rate substantially - today a ton of the payment failures seen are just mobile nodes that happen to be offline. If the sender had an indication of when the recipient was online they could avoid a lot of the pain of terrible mobile-node-sending UX.

With AMP, the payee can generate a static invoice and put it in an "always online" place (a QR in a website or can send an email or use any other asynchronous message mechanism). Without PTLC, the payer doesn't have any proof of payment, so she has to trust the payee. With PTLC no trust is needed.

Ah, good point, we can just use keysend to avoid needing PTLCs. Of course we see still have to define a number of invoice extensions either way, and I'd generally prefer to do it on BOLT12 (a keysend option on BOLT 12 may annoy @rustyrussell but....) given we need onion messages to make this work anyway.

@thomash-acinq
Copy link

thomash-acinq commented May 18, 2022

And this does not require BOLT 12 or PTLC, it can be done today with keysend.

Huh?
Ah, good point, we can just use keysend to avoid needing PTLCs.

That's exactly what I wrote. I understand perfectly well why this hold HTLC scheme is a good feature for sending money to people you trust (which includes tipping because you trust the person you tip not to pretend that you didn't pay them). I'm just saying that there is no need to wait for PTLC, it can be done today with a new invoice extension, the scheme described here and keysend. And even though I like BOLT 12, I don't see how it makes things better in this scenario.

@TheBlueMatt
Copy link
Collaborator Author

That's exactly what I wrote. I understand perfectly well why this hold HTLC scheme is a good feature for sending money to people you trust (which includes tipping because you trust the person you tip not to pretend that you didn't pay them)

Ah, okay, I totally misunderstood what you wrote there. Seems we're talking past each other a good bit here :(

I'm just saying that there is no need to wait for PTLC, it can be done today with a new invoice extension

Right, I think there are use-cases for proof-of-payment that make it useful to have PTLCs for this, though I agree its not required in most use-cases. Proof of donation is a valuable thing in some contexts, as is proof-of-payment as a scheme to improve security of offline/verifying signing in some cases.

And even though I like BOLT 12, I don't see how it makes things better in this scenario.

Right, I suggest it largely because it seems the obvious place to extend things. Given this work seeks to provide support for nodes which are behind an LSP, BOLT 12 is important for the same use cases - without BOLT 12, invoices for nodes behind LSPs are painfully large, with lots of readability issues. If this work didn't (a) already require new invoice extensions and (b) require onion messages anyway, I'd be considering BOLT 11 extensions or other invoice format extensions, but most of the work in implementing BOLT 12 is already required here (onion messages + blinded paths) and BOLT 12 is independently important for this use-case.

Comment on lines +984 to +985
- MUST NOT include a `hold_htlc` TLV unless the sending node expects the
final recipient of the HTLC to be offline at the time the HTLC would arrive
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be useful for the recipient to signal that they want the sender to make use of hold_htlc in their invoice, since the sender may not know they're paying to a mostly-offline user?

Downside of course being that it's bad for privacy and you generally don't want to tell people you're offline in LN. But without some indication, your options as a sender are:

  1. Use hold_htlc by default
    -> Unnescesary overhead for online destinations
    -> Won't work for offline users without LSPs (onion message fails quietly at offline node?)
  2. Try without first, fail and then retry with hold_htlc
    -> Bad UX / possible stuck payment

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be useful for the recipient to signal that they want the sender to make use of hold_htlc in their invoice, since the sender may not know they're paying to a mostly-offline user?

Yep! This isn't a fully-usable protocol on its own, its one of 3 or 4 parts you'd need to use this - invoice signaling being one part.

@moneyball
Copy link

I believe the latest thinking for the name that people can refer to this idea is "async payments."

@TheBlueMatt @cdecker

@remyers
Copy link

remyers commented Sep 15, 2022

It is worth exploring further how this proposal would work if it included support for the suggestion from @thomash-acinq to use keysend. Support for keysend would allow people to test much of the scheme before PTLCs become widely deployed by the network.

A few questions about using keysend:

  • would it be sufficient to use offer_node_id of the Recipient from the BOLT 12 offer itself ? This would reduce the need for the Recipient's hub to issue BOLT 12 invoices for the offline Recipient.

  • if the Recipient's hub DOES respond to an invoice_request onion message from the Sender with a BOLT 12 invoice for the Recipient, can the Sender still add a keysend TLV to their payment onion for the Recipient? even if the invoice uses route blinding? This would be a nice phase 2 that would give the Recipient privacy by not exposing their node ID. It would also be a step closer to a final PTLC based system.

An argument against keysend support as an intermediate solution is that it requires work that PTLCs will make obsolete, but if the effort is minimal and/or can be reused when PTLC support is available, it seems worth it.

@TheBlueMatt
Copy link
Collaborator Author

Yea, we could consider it definitely. First we do need onion messages to be broadly available, which is still a ways off, then we'll need to define the onion message format in a second PR. Once the OM stuff lands as BOLTs I'll take a look at it (if I remember).

@JssDWt
Copy link
Contributor

JssDWt commented Jul 8, 2023

We could make a more general way for recipients to deliver data to intermediate hops, without relying on the sender to support the feature. The hop hint in the invoice could contain an encrypted TLV payload for the intermediate hop. This way recipients would be able to encode hold_htlc into the payload for the intermediate hop. The sender can include this data without having to know about this feature. Because this feature is really something between the intermediate hop and the recipient (it would have to know it needs to include the payload obviously).

If in the future there are other schemes that require the recipient to communicate something to an intermediate hop, this structure could be reused, and the sender wouldn't have to implement anything new.

@TheBlueMatt
Copy link
Collaborator Author

That would still result in an HTLC getting sent a few hops to a blinded path introduction point and then holding liquidity on those hops into the recipient comes online.

@JssDWt
Copy link
Contributor

JssDWt commented Jul 8, 2023

That would still result in an HTLC getting sent a few hops to a blinded path introduction point and then holding liquidity on those hops into the recipient comes online.

It doesn't change this general flow at all (I think). I didn't mean blinded paths even. But it would provide a general way to let the recipient encode some data for an intermediate hop. So the recipient and the intermediate hop can make arbitrary agreements, without the sender having to know about it. The sender just puts the data in the payload for that hop. In this case, the recipient can encode that it wants the htlc to be held.

Another case (totally unrelated to this PR) could be a non-interactive lightning proxy. The recipient can encode the actual destination in the payload for the proxy.

There could be many different kinds of agreements between the recipient and the intermediate hop, that the sender doesn't need to know about.

@TheBlueMatt
Copy link
Collaborator Author

Even in that case I don't think its really acceptable - senders really need to be aware that their capital is about to be locked up for potentially-hours before they hit send on the HTLC. An intermediate node should never do that to someone unless they're aware (or being malicious).

@JssDWt
Copy link
Contributor

JssDWt commented Jul 9, 2023

Even in that case I don't think its really acceptable - senders really need to be aware that their capital is about to be locked up for potentially-hours before they hit send on the HTLC. An intermediate node should never do that to someone unless they're aware (or being malicious).

Point taken. Agreed.

2. types:
1. type: 0 (`hold_htlc`)
2. data:
* [`32*bytes`:`payment_release_secret`]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per our work in LDK (cc lightningdevkit/rust-lightning@6e27aec), this needs an update to remove the payment_release_secret and authenticate these messages via the blinded path only.

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.

10 participants