diff --git a/02-peer-protocol.md b/02-peer-protocol.md index 27b01fe04..3090f099b 100644 --- a/02-peer-protocol.md +++ b/02-peer-protocol.md @@ -1972,6 +1972,25 @@ is destined, is described in [BOLT #4](04-onion-routing.md). * [`sha256`:`payment_hash`] * [`u32`:`cltv_expiry`] * [`1366*byte`:`onion_routing_packet`] + * [`update_add_htlc_tlvs`:`tlvs`] + +1. `tlv_stream`: `update_add_htlc_tlvs` +2. types: + 1. type: 0 (`hold_htlc`) + 2. data: + * [`32*bytes`:`payment_release_secret`] + +#### 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`] 1. `tlv_stream`: `update_add_htlc_tlvs` 2. types: @@ -2016,6 +2035,19 @@ A sending node: - MUST increase the value of `id` by 1 for each successive offer. - if it is relaying a payment inside a blinded route: - MUST set `path_key` (see [Route Blinding](04-onion-routing.md#route-blinding)) + - 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 + - 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 + different paths to the final HTLC recipient. + - Each onion message MUST contain a `held_htlc_available` TLV. + - Each onion message MUST contain a unique `reply_path`s which terminates + at the reciever of the `update_add_htlc` message. + - Each `reply_path` MUST contain a `release_held_htlc` TLV for the + `update_add_htlc` recipient in the `encrypted_data_tlvs` with a + `payment_release_secret` matching that in the `hold_htlc` TLV. `id` MUST NOT be reset to 0 after the update is complete (i.e. after `revoke_and_ack` has been received). It MUST continue incrementing instead. @@ -2047,6 +2079,12 @@ A receiving node: - MUST respond with an error as detailed in [Failure Messages](04-onion-routing.md#failure-messages) - Otherwise: - MUST follow the requirements for the reader of `payload` in [Payload Format](04-onion-routing.md#payload-format) + - if the `hold_htlc` TLV is present: + - MUST NOT forward the HTLC until a corresponding `release_held_htlc` onion + message is received with a matching `payment_release_secret`. + - Upon receipt of a `release_held_htlc` onion message with a matching + `payment_release_secret` the HTLC SHOULD be treated as any HTLC without + the `hold_htlc` TLV and forwarded as usual. The `onion_routing_packet` contains an obfuscated list of hops and instructions for each hop along the path. It commits to the HTLC by setting the `payment_hash` as associated data, i.e. includes the `payment_hash` in the computation of HMACs. @@ -2082,6 +2120,19 @@ maintaining its channel reserve (because of the increased weight of the commitment transaction), resulting in a degraded channel. See [#728](https://github.com/lightningnetwork/lightning-rfc/issues/728) for more details. +For often-offline recipients, e.g. mobile clients, nodes can use the +`hold_htlc` TLV to prevent further forwarding of an HTLC until the recipient +comes online. As long as the final recipients' counterparty is online and +storing onion messages for the recipient, the recipient can reply to the onion +message when they come online, unblock the HTLC, and expect to receive it +quickly thereafter. + +Note that if the sender expects to be online when the recipient comes online, +they can utilize the `release_held_htlc` onion message without utilizing the +`hold_htlc` TLV - they can simply send a `held_htlc_available` onion message +to the final recipient and wait to send any HTLC at all until they receive a +`release_held_htlc` message back. + ### Removing an HTLC: `update_fulfill_htlc`, `update_fail_htlc`, and `update_fail_malformed_htlc` For simplicity, a node can only remove HTLCs added by the other node. diff --git a/04-onion-routing.md b/04-onion-routing.md index 7df5eb8aa..a9aaa74e0 100644 --- a/04-onion-routing.md +++ b/04-onion-routing.md @@ -189,6 +189,9 @@ This is formatted according to the Type-Length-Value format defined in [BOLT #1] 1. `tlv_stream`: `payload` 2. types: + 1. type: 1 (`invoice_request`) + 2. data: + * [`...*byte`:`invoice_request_tlv_stream`] 1. type: 2 (`amt_to_forward`) 2. data: * [`tu64`:`amt_to_forward`] @@ -214,6 +217,9 @@ This is formatted according to the Type-Length-Value format defined in [BOLT #1] 1. type: 18 (`total_amount_msat`) 2. data: * [`tu64`:`total_msat`] + 1. type: 5482373484 (`sender_provided_payment_preimage`) + 2. data: + * [`32*byte`:`payment_preimage`] `short_channel_id` is the ID of the outgoing channel used to route the message; the receiving peer should operate the other end of this channel. @@ -240,6 +246,11 @@ The requirements ensure consistency in responding to an unexpected `outgoing_cltv_value`, whether it is the final node or not, to avoid leaking its position in the route. +`sender_provided_payment_preimage` and `invoice_request` are set in the case +that the recipient is often-offline and another node provided a static BOLT 12 +invoice on their behalf, where `invoice_request` is the sender's originl +invoice request corresponding to this HTLC. + ### Requirements The creator of `encrypted_recipient_data` (usually, the recipient of payment): @@ -273,6 +284,14 @@ The writer of the TLV `payload`: - MUST use the current block height as a baseline value. - if a [random offset](07-routing-gossip.md#recommendations-for-routing) was added to improve privacy: - SHOULD add the offset to the baseline value. + - if paying to a static BOLT 12 invoice: + - MUST set `sender_provided_payment_preimage` to randomly generated unique bytes. + - MUST set `update_add_htlc.payment_hash` to match the SHA256 hash of + `sender_provided_payment_preimage`. + - MUST set `invoice_request` to the BOLT 12 invoice request + corresponding to this HTLC. + - otherwise: + - MUST NOT set `sender_provided_payment_preimage`. - MUST NOT include any other tlv field. - For every node outside of a blinded route: - MUST include `amt_to_forward` and `outgoing_cltv_value`. @@ -324,6 +343,7 @@ The reader: - MUST return an error if `amt_to_forward` is below what it expects for the payment. - MUST return an error if incoming `cltv_expiry` < `outgoing_cltv_value`. - MUST return an error if incoming `cltv_expiry` < `current_block_height` + `min_final_cltv_expiry_delta`. + - MUST use `sender_provided_payment_preimage` when claiming the HTLC, if present - Otherwise (it is not part of a blinded route): - MUST return an error if `path_key` is set in the incoming `update_add_htlc` or `current_path_key` is present. - MUST return an error if `amt_to_forward` or `outgoing_cltv_value` are not present. diff --git a/09-features.md b/09-features.md index 45be48465..e29dadbd1 100644 --- a/09-features.md +++ b/09-features.md @@ -29,6 +29,7 @@ The Context column decodes as follows: * `C+`: presented in the `channel_announcement` message, but always even (required). * `9`: presented in [BOLT 11](11-payment-encoding.md) invoices. * `B`: presented in the `allowed_features` field of a blinded path. +* `R`: presented in [BOLT 12](12-offers.md) invoice requests. | Bits | Name | Description | Context | Dependencies | Link | |-------|-----------------------------------|-----------------------------------------------------------|----------|---------------------------|-----------------------------------------------------------------------| @@ -51,8 +52,15 @@ The Context column decodes as follows: | 46/47 | `option_scid_alias` | Supply channel aliases for routing | IN | | [BOLT #2][bolt02-channel-ready] | | 48/49 | `option_payment_metadata` | Payment metadata in tlv record | 9 | | [BOLT #11](11-payment-encoding.md#tagged-fields) | | 50/51 | `option_zeroconf` | Understands zeroconf channel types | IN | `option_scid_alias` | [BOLT #2][bolt02-channel-ready] | +| 52/53 | `option_htlc_hold` | Hold HTLCs and forward on receipt of an onion message | IN | `option_onion_messages` | +| 56/57 | `option_om_mailbox` | Store-and-forward onion messages for often-offline peers | IN | `option_onion_messages` | [BOLT #12](bolt12-offers.md) | +| 59 | `static_invoice_pay` | Supports paying BOLT 12 static invoices | R | `option_onion_messages` | [BOLT #12](bolt12-offers.md) | +We define `option_om_mailbox` as the ability to store an onion message on behalf +of an offline peer, and forward it once the peer comes online (subject to rate +limiting). + ## Requirements The origin node: diff --git a/12-offer-encoding.md b/12-offer-encoding.md index 930d6442d..46ea52ceb 100644 --- a/12-offer-encoding.md +++ b/12-offer-encoding.md @@ -42,7 +42,7 @@ Here we use "user" as shorthand for the individual user's lightning node and "merchant" as the shorthand for the node of someone who is selling or has sold something. -There are two basic payment flows supported by BOLT 12: +There are three basic payment flows supported by BOLT 12: The general user-pays-merchant flow is: 1. A merchant publishes an *offer*, such as on a web page or a QR code. @@ -58,6 +58,19 @@ The merchant-pays-user flow (e.g. ATM or refund): 3. The merchant confirms the *invoice_node_id* to ensure it's about to pay the correct person, and makes a payment to the invoice. +The pay-mobile-user flow (e.g. paying a friend back to their mobile node): +1. The mobile user supplies some always-online node with a static (i.e. + `payment_hash`-less) invoice to return on its behalf. This always-online node may + be the mobile user's channel counterparty, wallet vendor, or another node on the + network that it has an out-of-band relationship with. +2. The mobile user publishes an offer that contains blinded paths that terminate + at the always-online node. +3. The payer sends an `invoice_request` to the always-online node, who replies + with the static invoice previously provided by the mobile user if the mobile user + is offline. If they are online, the `invoice_request` is forwarded to the mobile + user as usual. +4. The payer makes a payment to the mobile user as indicated by the invoice. + ## Payment Proofs and Payer Proofs Note that the normal lightning "proof of payment" can only demonstrate that an @@ -70,6 +83,9 @@ to request the invoice. In addition, the Merkle construction of the BOLT 12 invoice signature allows the user to reveal invoice fields in case of a dispute selectively. +Payers will not get proofs in the case that they received a static invoice from the +payee, see the pay-mobile-user flow above. + # Encoding Each of the forms documented here are in @@ -261,8 +277,9 @@ A writer of an offer: after midnight 1 January 1970, UTC that invoice_request should not be attempted. - if it is connected only by private channels: - - MUST include `offer_paths` containing one or more paths to the node from - publicly reachable nodes. + - MUST include `offer_paths` containing one or more paths to the node + that will reply to the `invoice_request`, using introduction nodes that are + publicly reachable. - otherwise: - MAY include `offer_paths`. - if it includes `offer_paths`: @@ -282,6 +299,8 @@ A writer of an offer: - MUST set `offer_quantity_max` to 0. - otherwise: - MUST NOT set `offer_quantity_max`. + - if it is often-offline and the invoice may be provided by another node on their behalf: + - MUST NOT include more than 1 chain in `offer_chains`. A reader of an offer: - if the offer contains any TLV fields outside the inclusive ranges: 1 to 79 and 1000000000 to 1999999999: @@ -441,6 +460,20 @@ while still allowing signature validation. 2. data: * [`bip340sig`:`sig`] +## Invoice Request Features + +| Bits | Description | Name | +|------|----------------------------------|-----------------------------| +| 59 | Supports paying static invoices | static_invoice_pay/optional | + +Setting `static_invoice_pay` indicates that the payer supports receiving a +`payment_hash`-less invoice in response to their `invoice_request`, and +subsequently setting `sender_provided_payment_preimage` in their payment onion. + +Useful if the payee is often offline and the invoice is being returned on +their behalf by another node, to avoid trusting that other node to not reuse a +`payment_hash`. + ## Requirements for Invoice Requests The writer: @@ -530,7 +563,14 @@ The reader: - MUST reject the invoice request if bitcoin is not a supported chain. - otherwise: - MUST reject the invoice request if `invreq_chain`.`chain` is not a supported chain. - + - if receiving the `invoice_request` on behalf of an often-offline payee: + - if the payee is online: + - MUST forward the `invoice_request` to the payee + - otherwise (payee is offline): + - if `invreq_features` supports `static_invoice_pay`: + - MUST reply with the static invoice previously provided by the payee + - otherwise: + - MUST reply with `invoice_error` ## Rationale @@ -561,10 +601,11 @@ The requirement to use `offer_paths` if present, ensures a node does not reveal # Invoices -Invoices are a payment request, and when the payment is made, -the payment preimage can be combined with the invoice to form a cryptographic receipt. +Invoices are a payment request. If `invoice_payment_hash` is set, then when the +payment is made, the payment preimage can be combined with the invoice to form a +cryptographic receipt. -The recipient sends an `invoice` in response to an `invoice_request` using +The recipient creates an `invoice` for responding to an `invoice_request` using the `onion_message` `invoice` field. 1. `tlv_stream`: `invoice` @@ -653,6 +694,9 @@ the `onion_message` `invoice` field. 1. type: 176 (`invoice_node_id`) 2. data: * [`point`:`node_id`] + 1. type: 178 (`invoice_message_paths`) + 2. data: + * [`...*blinded_path`:`paths`] 1. type: 240 (`signature`) 2. data: * [`bip340sig`:`sig`] @@ -691,17 +735,21 @@ may (due to capacity limits on a single channel) require it. A writer of an invoice: - MUST set `invoice_created_at` to the number of seconds since Midnight 1 January 1970, UTC when the invoice was created. - - MUST set `invoice_amount` to the minimum amount it will accept, in units of - the minimal lightning-payable unit (e.g. milli-satoshis for bitcoin) for - `invreq_chain`. - - if the invoice is in response to an `invoice_request`: + - if `invoice_payment_hash` is set and the invoice is in response to an `invoice_request`: - MUST copy all non-signature fields from the invoice request (including unknown fields). - if `invreq_amount` is present: - MUST set `invoice_amount` to `invreq_amount` - otherwise: - MUST set `invoice_amount` to the *expected amount*. - - MUST set `invoice_payment_hash` to the SHA256 hash of the - `payment_preimage` that will be given in return for payment. + - if the invoice is intended to be provided by a node other than the recipient: + - MUST NOT set `invoice_payment_hash`. + - MUST NOT set `invoice_amount`. + - MUST include `invoice_message_paths` containing at least two paths to + the recipient, where the penultimate hop supports `option_om_mailbox`. + - MUST NOT set any `invoice_request` TLV fields + - otherwise: + - MUST set `invoice_payment_hash` to the SHA256 hash of the + `payment_preimage` that will be given in return for payment. - if `offer_issuer_id` is present: - MUST set `invoice_node_id` to the `offer_issuer_id` - otherwise, if `offer_paths` is present: @@ -727,11 +775,14 @@ A writer of an invoice: - MUST include `invoice_blindedpay` with exactly one `blinded_payinfo` for each `blinded_path` in `paths`, in order. - MUST set `features` in each `blinded_payinfo` to match `encrypted_data_tlv`.`allowed_features` (or empty, if no `allowed_features`). - SHOULD ignore any payment which does not use one of the paths. + - if providing invoices on behalf of an often offline recipient: + - MAY reuse the previous invoice. A reader of an invoice: - - MUST reject the invoice if `invoice_amount` is not present. - MUST reject the invoice if `invoice_created_at` is not present. - - MUST reject the invoice if `invoice_payment_hash` is not present. + - if `static_invoice_pay` was not supported in `invreq_features`: + - MUST reject the invoice if `invoice_payment_hash` is not present. + - MUST reject the invoice if `invoice_amount` is not present. - MUST reject the invoice if `invoice_node_id` is not present. - if `invreq_chain` is not present: - MUST reject the invoice if bitcoin is not a supported chain. @@ -753,7 +804,8 @@ A reader of an invoice: - MUST NOT use the corresponding `invoice_paths`.`path` if `payinfo`.`features` has any unknown even bits set. - MUST reject the invoice if this leaves no usable paths. - if the invoice is a response to an `invoice_request`: - - MUST reject the invoice if all fields in ranges 0 to 159 and 1000000000 to 2999999999 (inclusive) do not exactly match the invoice request. + - if `invoice_payment_hash` is set: + - MUST reject the invoice if all fields in ranges 0 to 159 and 1000000000 to 2999999999 (inclusive) do not exactly match the invoice request. - if `offer_issuer_id` is present (invoice_request for an offer): - MUST reject the invoice if `invoice_node_id` is not equal to `offer_issuer_id` - otherwise, if `offer_paths` is present (invoice_request for an offer without id): @@ -782,6 +834,10 @@ A reader of an invoice: - MUST reject the invoice if it arrived via a blinded path. - otherwise (derived from an offer): - MUST reject the invoice if it did not arrive via invoice request `onionmsg_tlv` `reply_path`. + - if `invoice_payment_hash` is unset: + - MUST reject the invoice if `invoice_message_paths` is not present or is empty. + - MUST pay asynchronously using the `held_htlc_available` onion message + flow, where the onion message is sent over `invoice_message_paths`. ## Rationale