diff --git a/02-peer-protocol.md b/02-peer-protocol.md index 009555d0c..0c1a8a059 100644 --- a/02-peer-protocol.md +++ b/02-peer-protocol.md @@ -2222,6 +2222,17 @@ is destined, is described in [BOLT #4](04-onion-routing.md). 1. type: 0 (`blinded_path`) 2. data: * [`point`:`path_key`] + 3. type: 2 (`hold_htlc`) + 4. data: + +#### 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: #### Requirements @@ -2260,6 +2271,10 @@ 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. `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. @@ -2291,6 +2306,11 @@ 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. + - Upon receipt of a corresponding `release_held_htlc` onion message 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. @@ -2326,6 +2346,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. @@ -2511,6 +2544,13 @@ The description of key derivation is in [BOLT #3](03-transactions.md#key-derivat * [`channel_id`:`channel_id`] * [`32*byte`:`per_commitment_secret`] * [`point`:`next_per_commitment_point`] + * [`revoke_and_ack_tlvs`:`tlvs`] + +1. `tlv_stream`: `revoke_and_ack_tlvs` +2. types: + 1. type: 0 (`release_held_htlc_message_paths`) + 2. data: + * [`...blinded_path`:`paths`] #### Requirements @@ -2519,6 +2559,10 @@ A sending node: the previous commitment transaction. - MUST set `next_per_commitment_point` to the values for its next commitment transaction. + - If `hold_htlc` was set in the preceding `update_add_htlc` and `option_htlc_hold` was advertised + by this node: + - MUST set `release_held_htlc_message_paths` to at least 1 blinded path that can be used for + the ultimate payment recipient to eventually send `release_held_htlc` onion messages over A receiving node: - if `per_commitment_secret` is not a valid secret key or does not generate the previous `per_commitment_point`: @@ -2526,6 +2570,14 @@ A receiving node: - if the `per_commitment_secret` was not generated by the protocol in [BOLT #3](03-transactions.md#per-commitment-secret-requirements): - MAY send a `warning` and close the connection, or send an `error` and fail the channel. + - If `release_held_htlc_message_paths` are present and `hold_htlc` was set in the preceding `update_add_htlc`: + - 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 receiver of the preceding `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` A node: - MUST NOT broadcast old (revoked) commitment transactions, diff --git a/04-onion-routing.md b/04-onion-routing.md index d61542c6f..6876513a1 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. @@ -1519,6 +1539,9 @@ even, of course!). 1. type: 68 (`invoice_error`) 2. data: * [`tlv_invoice_error`:`inverr`] + 1. type: 70 (`static_invoice`) + 2. data: + * [`tlv_static_invoice`:`static_inv`] #### Requirements diff --git a/09-features.md b/09-features.md index e7a8cbed6..e9e57728c 100644 --- a/09-features.md +++ b/09-features.md @@ -53,6 +53,7 @@ The Context column decodes as follows: | 46/47 | `option_scid_alias` | Supply channel aliases for routing | INT | | [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 | INT | `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` | | 60/61 | `option_simple_close` | Simplified closing negotiation | IN | `option_shutdown_anysegwit` | [BOLT #2][bolt02-simple-close] | ## Requirements diff --git a/12-offer-encoding.md b/12-offer-encoding.md index db920f5a1..612845a56 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,18 @@ 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 and forwards the `invoice_request` to the mobile + user in case they happen to be online. +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 +82,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 @@ -126,7 +141,7 @@ Each form is signed using one or more *signature TLV elements*: TLV types 240 through 1000 (inclusive). For these, the tag is "lightning" || `messagename` || `fieldname`, and `msg` is the Merkle-root; "lightning" is the literal 9-byte ASCII string, -`messagename` is the name of the TLV stream being signed (i.e. "invoice_request" or "invoice") and the `fieldname` is the TLV field containing the +`messagename` is the name of the TLV stream being signed (i.e. "invoice_request", "invoice", or "static_invoice") and the `fieldname` is the TLV field containing the signature (e.g. "signature"). The formulation of the Merkle tree is similar to that proposed in @@ -261,8 +276,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 +298,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: @@ -543,6 +561,9 @@ The reader: - if `invreq_bip_353_name` is present: - MUST reject the invoice request if `name` or `domain` contain any bytes which are not `0`-`9`, `a`-`z`, `A`-`Z`, `-`, `_` or `.`. + - if receiving the `invoice_request` on behalf of an often-offline payee: + - SHOULD forward the `invoice_request` to the payee + - SHOULD reply with the static invoice previously provided by the payee ## Rationale @@ -573,10 +594,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` @@ -671,6 +693,9 @@ the `onion_message` `invoice` field. 1. type: 176 (`invoice_node_id`) 2. data: * [`point`:`node_id`] + 1. type: 178 (`static_invoice_message_paths`) + 2. data: + * [`...*blinded_path`:`paths`] 1. type: 240 (`signature`) 2. data: * [`bip340sig`:`sig`] @@ -709,17 +734,28 @@ 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 expiry for accepting payment is not 7200 seconds after `invoice_created_at`: + - MUST set `invoice_relative_expiry`.`seconds_from_creation` to the number of + seconds after `invoice_created_at` that payment of this invoice should not be attempted. + - if the invoice is intended to be provided by a node other than the recipient (i.e. a static + invoice): + - MUST NOT set `invoice_payment_hash`. + - MUST NOT set `invoice_amount`. + - MUST include `static_invoice_message_paths` containing at least two paths to + the recipient. + - MUST NOT set any `invoice_request` TLV fields + - if the expiry for accepting payment is not 2 weeks after `invoice_created_at`: + - MUST set `invoice_relative_expiry`.`seconds_from_creation` to the number of + seconds after `invoice_created_at` that payment of this invoice should not be attempted. + - 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: @@ -730,9 +766,6 @@ A writer of an invoice: - MUST set `invoice_features`.`features` bit `MPP/compulsory` - or if it allows multiple parts to pay the invoice: - MUST set `invoice_features`.`features` bit `MPP/optional` - - if the expiry for accepting payment is not 7200 seconds after `invoice_created_at`: - - MUST set `invoice_relative_expiry`.`seconds_from_creation` to the number of - seconds after `invoice_created_at` that payment of this invoice should not be attempted. - if it accepts onchain payments: - MAY specify `invoice_fallbacks` - SHOULD specify `invoice_fallbacks` in order of most-preferred to least-preferred @@ -745,11 +778,11 @@ 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. - 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. @@ -771,7 +804,9 @@ 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 `invoice_amount` is not present. + - 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): @@ -800,6 +835,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 `static_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 `static_invoice_message_paths`. ## Rationale