Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .aspell.en.pws
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,8 @@ fips
rfc
varint
CompactSize
multipath
mpp
tlvs
snprintf
GitHub
Expand Down
119 changes: 112 additions & 7 deletions 04-onion-routing.md
Original file line number Diff line number Diff line change
Expand Up @@ -248,18 +248,111 @@ This is a more flexible format, which avoids the redundant `short_channel_id` fi
1. type: 6 (`short_channel_id`)
2. data:
* [`short_channel_id`:`short_channel_id`]
1. type: 8 (`payment_data`)
2. data:
* [`32*byte`:`payment_secret`]
* [`tu64`:`total_msat`]
Comment thread
t-bast marked this conversation as resolved.

### Requirements

The writer:
- MUST include `amt_to_forward` and `outgoing_cltv_value` for every node.
- MUST include `short_channel_id` for every non-final node.
- MUST NOT include `short_channel_id` for the final node.
- Unless `node_announcement`, `init` message or the [BOLT #11](11-payment-encoding.md#tagged-fields) offers feature `var_onion_optin`:
- MUST use the legacy payload format instead.
- For every node:
- MUST include `amt_to_forward` and `outgoing_cltv_value`.
- For every non-final node:
- MUST include `short_channel_id`
- MUST NOT include `payment_data`
- For the final node:
- MUST NOT include `short_channel_id`
- if the recipient provided `payment_secret`:
Comment thread
cfromknecht marked this conversation as resolved.
- MUST include `payment_data`
- MUST set `payment_secret` to the one provided
- MUST set `total_msat` to the total amount it will send

The reader:
- MUST return an error if `amt_to_forward` or `outgoing_cltv_value` are not present.
- if it is the final node:
- MUST treat `total_msat` as if it were equal to `amt_to_forward` if it
Comment thread
cfromknecht marked this conversation as resolved.
is not present.

The requirements for the contents of these fields are specified [above](#legacy-hop_data-payload-format)
and [below](#basic-multi-part-payments).

### Basic Multi-Part Payments
Comment thread
t-bast marked this conversation as resolved.

An HTLC may be part of a larger "multi-part" payment: such
"base" atomic multipath payments will use the same `payment_hash` for
all paths.

Note that `amt_to_forward` is the amount for this HTLC only: a
`total_msat` field containing a greater value is a promise by the
ultimate sender that the rest of the payment will follow in succeeding
HTLCs; we call these outstanding HTLCs which have the same preimage,
an "HTLC set".

#### Requirements

The requirements for the contents of these fields are specified [above](#legacy-hop_data-payload-format).
The writer:

This comment was marked as abuse.

Copy link
Copy Markdown
Collaborator Author

@rustyrussell rustyrussell Sep 17, 2019

Choose a reason for hiding this comment

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

These are routed through multiple nodes though, so it's best to be clear. Maybe we should change to be "origin node" instead of writer, but reader can't always be replaced with "final node"....?

This comment was marked as abuse.

- if the invoice offers the `basic_mpp` feature:
- MAY send more than one HTLC to pay the invoice.
- MUST use the same `payment_hash` on all HTLCs in the set.
- SHOULD send all payments at approximately the same time.
- SHOULD try to use diverse paths to the recipient for each HTLC.
- SHOULD retry and/or re-divide HTLCs which fail.
- if the invoice specifies an `amount`:
- MUST set `total_msat` to at least that `amount`, and less
than or equal to twice `amount`.
- otherwise:
- MUST set `total_msat` to the amount it wishes to pay.
- MUST ensure that the total `amount_msat` of the HTLC set which arrives at the payee
is equal to `total_msat`.
- MUST NOT send another HTLC if the total `amount_msat` of the HTLC set is already greater or equal to `total_msat`.
- otherwise:
- MUST set `total_msat` equal to `amt_to_forward`.
Comment thread
rustyrussell marked this conversation as resolved.

The final node:
- MUST fail the HTLC if dictated by Requirements under [Failure Messages](#failure-messages)
- Note: "amount paid" specified there is the `total_msat` field.
- if it does not support `basic_mpp`:
- MUST fail the HTLC if `total_msat` is not exactly equal to `amt_to_forward`.
- otherwise, if it supports `basic_mpp`:
- MUST add it to the HTLC set corresponding to that `payment_hash`.
Comment thread
cfromknecht marked this conversation as resolved.
- SHOULD fail the entire HTLC set if `total_msat` is not the same for
Comment thread
cfromknecht marked this conversation as resolved.
all HTLCs in the set.
- if the total `amount_msat` of this HTLC set equals `total_msat`:
- SHOULD fulfill all HTLCs in the HTLC set
- otherwise, if the total `amount_msat` of this HTLC set is less than
`total_msat`:
- MUST NOT fulfill any HTLCs in the HTLC set
- MUST fail all HTLCs in the HTLC set after some reasonable timeout.
- SHOULD wait for at least 60 seconds after the initial HTLC.
- SHOULD use `mpp_timeout` for the failure message.
- if it fulfills any HTLCs in the HTLC set:
- MUST fulfill the entire HTLC set.

#### Rationale

If `basic_mpp` is present it causes a delay to allow other partial
payments to combine. The total amount must be sufficient for the
desired payment, just as it must be for single payments. But this must
be reasonably bounded to avoid a denial-of-service.

Because invoices do not necessarily specify an amount, and because
payers can add noise to the final amount, the total amount must be
sent explicitly. The requirements allow exceeding this slightly, as
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

If we don't add a mandatory random identifier along the way, then we should discourage sending more than the invoice amount.

it simplifies adding noise to the amount when splitting, as well as
scenarios in which the senders are genuinely independent (friends
splitting a bill, for example).

The restriction on sending an HTLC once the set is over the agreed total prevents the preimage being released before all
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

nit: long line

the partial payments have arrived: that would allow any intermediate
node to immediately claim any outstanding partial payments.

An implementation may choose not to fulfill an HTLC set which
otherwise meets the amount criterion (eg. some other failure, or
invoice timeout), however if it were to fulfill only some of them,

This comment was marked as abuse.

Copy link
Copy Markdown
Collaborator Author

@rustyrussell rustyrussell Sep 17, 2019

Choose a reason for hiding this comment

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

Agree better to specify in terms of block height. If CLTV height is shared between all HTLCs, you should be able to wait until it minus some block height delta to land an unilateral closing.

No, you're tying up channels across the network. We're not going to hold things for many minutes before this becomes a spam attack. Certainly not waiting for blocks!

Also with current wording it's not clear what receiving node should do after delay expiration, back to step upper ("SHOULD fulfill ...") or go to the one below ("MUST fail ...")

Both apply. You SHOULD wait 60 seconds, you MUST have a some timeout.

In the same way, if you try to pull some HTLCs of the set before all of them are locked on final_hop channels it may be a risk? Let's say if you pick up different paths and some nodes share the same operator, if you provide preimage for HTLC#1 but HTLC#3 isn't locked yet, preimage could be replay on HTLC#3 first links without payment being forwarded until payee. This point should be better underscored.

Yes, we need to add "MUST NOT fulfill a set if the total is not sufficient".

intermediary nodes could simply claim the remaining ones.

# Accepting and Forwarding a Payment

Expand Down Expand Up @@ -313,6 +406,8 @@ using an alternate channel.
When building the route, the origin node MUST use a payload for
the final node with the following values:

* `payment_secret`: set to the payment secret specified by the recipient (e.g.
`payment_secret` from a [BOLT #11](11-payment-encoding.md) payment invoice)
* `outgoing_cltv_value`: set to the final expiry specified by the recipient (e.g.
`min_final_cltv_expiry` from a [BOLT #11](11-payment-encoding.md) payment invoice)
* `amt_to_forward`: set to the final amount specified by the recipient (e.g. `amount`
Expand Down Expand Up @@ -827,9 +922,10 @@ handling by the processing node.
* [`u64`:`htlc_msat`]
* [`u32`:`height`]

The `payment_hash` is unknown to the final node, the amount for that
`payment_hash` is incorrect or the CLTV expiry of the htlc is too close to the
current block height for safe handling.
The `payment_hash` is unknown to the final node, the `payment_secret` doesn't
match the `payment_hash`, the amount for that `payment_hash` is incorrect or
the CLTV expiry of the htlc is too close to the current block height for safe
handling.

The `htlc_msat` parameter is superfluous, but left in for backwards
compatibility. The value of `htlc_msat` always matches the amount specified in
Expand Down Expand Up @@ -885,6 +981,11 @@ or is incomplete. If the failure can be narrowed down to a specific tlv type in
the payload, the erring node may include that `type` and its byte `offset` in
the decrypted byte stream.

1. type: 23 (`mpp_timeout`)

The complete amount of the multi-part payment was not received within a
reasonable time.

### Requirements

An _erring node_:
Expand Down Expand Up @@ -952,6 +1053,10 @@ An _intermediate hop_ MUST NOT, but the _final node_:
- if the payment hash has already been paid:
- MAY treat the payment hash as unknown.
- MAY succeed in accepting the HTLC.
- if the `payment_secret` doesn't match the expected value for that `payment_hash`,
or the `payment_secret` is required and is not present:
- MUST fail the HTLC.
- MUST return an `incorrect_or_unknown_payment_details` error.
- if the amount paid is less than the amount expected:
- MUST fail the HTLC.
- MUST return an `incorrect_or_unknown_payment_details` error.
Expand Down
3 changes: 3 additions & 0 deletions 09-features.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ The Context column decodes as follows:
| 8/9 | `var_onion_optin` | Requires/supports variable-length routing onion payloads | IN | [Routing Onion Specification][bolt04] |
| 10/11 | `gossip_queries_ex` | Gossip queries can include additional information | IN | [BOLT #7][bolt07-query] |
| 12/13| `option_static_remotekey` | Static key for remote output | IN | [BOLT #3](03-transactions.md) |
| 14/15 | `payment_secret` | Node supports `payment_secret` field | IN9 | [Routing Onion Specification][bolt04] |
| 16/17 | `basic_mpp` | Node can receive basic multi-part payments | IN9 | [BOLT #3][bolt04-mpp] |
Comment thread
cfromknecht marked this conversation as resolved.

## Requirements

Expand Down Expand Up @@ -67,3 +69,4 @@ This work is licensed under a [Creative Commons Attribution 4.0 International Li
[bolt04]: 04-onion-routing.md
[bolt07-sync]: 07-routing-gossip.md#initial-sync
[bolt07-query]: 07-routing-gossip.md#query-messages
[bolt04-mpp]: 04-onion-routing.md#basic-multi-part-payments
67 changes: 52 additions & 15 deletions 11-payment-encoding.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ Each Tagged Field is of the form:
Currently defined tagged fields are:

* `p` (1): `data_length` 52. 256-bit SHA256 payment_hash. Preimage of this provides proof of payment.
* `s` (16): `data_length` 52. This 256-bit secret prevents forwarding nodes from probing the payment recipient.
* `d` (13): `data_length` variable. Short description of purpose of payment (UTF-8), e.g. '1 cup of coffee' or 'ナンセンス 1杯'
* `n` (19): `data_length` 53. 33-byte public key of the payee node
* `h` (23): `data_length` 52. 256-bit description of purpose of payment (SHA256). This is used to commit to an associated description that is over 639 bytes, but the transport mechanism for the description in that case is transport specific and not defined here.
Expand All @@ -148,7 +149,7 @@ Currently defined tagged fields are:
### Requirements

A writer:
- MUST include exactly one `p` field.
- MUST include exactly one `p` and `s` fields.
- MUST set `payment_hash` to the SHA2 256-bit hash of the `payment_preimage`
that will be given in return for payment.
- MUST include either exactly one `d` or exactly one `h` field.
Expand Down Expand Up @@ -191,8 +192,8 @@ A writer:
- MUST specify the most-preferred field first, followed by less-preferred fields, in order.

A reader:
- MUST skip over unknown fields, OR an `f` field with unknown `version`, OR `p`, `h`, or
`n` fields that do NOT have `data_length`s of 52, 52, or 53, respectively.
- MUST skip over unknown fields, OR an `f` field with unknown `version`, OR `p`, `h`, `s` or
`n` fields that do NOT have `data_length`s of 52, 52, 52 or 53, respectively.
- if the `9` field contains unknown _odd_ bits that are non-zero:
- MUST ignore the bit.
- if the `9` field contains unknown _even_ bits that are non-zero:
Expand All @@ -202,6 +203,8 @@ A reader:
description.
- if a valid `n` field is provided:
- MUST use the `n` field to validate the signature instead of performing signature recovery.
- if there is a valid `s` field:
Comment thread
cfromknecht marked this conversation as resolved.
- MUST use that as [`payment_secret`](04-onion-routing.md#tlv_payload-payload-format)

### Rationale

Expand Down Expand Up @@ -279,6 +282,34 @@ The field is big-endian. The least-significant bit is numbered 0,
which is _even_, and the next most significant bit is numbered 1,
which is _odd_.

Note that the `payment_secret` feature prevents probing attacks from nodes
along the path, but only if made compulsory: yet doing so will break
older clients which do not understand the feature.

### Requirements

A writer:
- if `payment_secret` feature is set:
- MUST include an `s` field.
- otherwise:
- MUST NOT include an `s` field.
- if the `payment_secret` field is required in the onion:
- MUST set the even feature `payment_secret`.
- If the final node supports [Basic multi-part payments](04-onion-routing.md#basic-multi-part-payments):
- MUST set the `basic_mpp` feature.
- Otherwise:
- MUST NOT set the `basic_mpp` feature.
- if it sets either `payment_secret` or `basic_mpp` features:
- MUST set the `var_onion_optin` feature.
- MUST set `var_onion_optin` if and only if it supports that feature.

A reader:
- if the `basic_mpp` feature is offered in the invoice:
- MAY pay using [Basic multi-part payments](04-onion-routing.md#basic-multi-part-payments).
- otherwise:
- MUST NOT use [Basic multi-part payments](04-onion-routing.md#basic-multi-part-payments).


# Payer / Payee Interactions

These are generally defined by the rest of the Lightning BOLT series,
Expand Down Expand Up @@ -318,7 +349,7 @@ https://github.com/rustyrussell/lightning-payencode

# Examples

NB: all the following examples are signed with `priv_key`=`e126f68f7eafcc8b74f54d269fe206be715000f94dac067d1c04a8ca3b2db734`.
NB: all the following examples are signed with `priv_key`=`e126f68f7eafcc8b74f54d269fe206be715000f94dac067d1c04a8ca3b2db734`. Also, the first 9 examples are legacy: modern invoices have an `s` field.

> ### Please make a donation of any amount using payment_hash 0001020304050607080900010203040506070809000102030405060708090102 to me @03e7156ae33b0a208d0744199163177e909e80176e55d97a2f221ede0f934dd9ad
> lnbc1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpl2pkx2ctnv5sxxmmwwd5kgetjypeh2ursdae8g6twvus8g6rfwvs8qun0dfjkxaq8rkx3yf5tcsyz3d73gafnh3cax9rn449d9p5uxz9ezhhypd0elx87sjle52x86fux2ypatgddc6k63n7erqz25le42c4u4ecky03ylcqca784w
Expand Down Expand Up @@ -535,8 +566,8 @@ Breakdown:
* `6c6e626332306d0b25fe64570d0e496dbd9f8b0d000dbb44824f751380da37c6dba89b14f6f92047d63f576e304021a00008101820283038404800081018202830384048000810182028303840480810243500c318a1e0a628b34025e8c9019ab6d09b64c2b3c66a693d0dc63194b02481931000` hex of data for signing (prefix + data after separator up to the start of the signature)
* `399a8b167029fda8564fd2e99912236b0b8017e7d17e416ae17307812c92cf42` hex of SHA256 of the preimage

> ### Please send $30 for coffee beans to the same peer, which supports features 1 and 9
> lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5vdhkven9v5sxyetpdees9qzsze992adudgku8p05pstl6zh7av6rx2f297pv89gu5q93a0hf3g7lynl3xq56t23dpvah6u7y9qey9lccrdml3gaqwc6nxsl5ktzm464sq73t7cl
> ### Please send $30 for coffee beans to the same peer, which supports features 15 and 99, using secret 0x1111111111111111111111111111111111111111111111111111111111111111
> lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5vdhkven9v5sxyetpdeessp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9q5sqqqqqqqqqqqqqqqpqqq4u9s93jtgysm3mrwll70zr697y3mf902hvxwej0v7c62rsltw83ng0pu8w3j230sluc5gxkdmm9dvpy9y6ggtjd2w544mzdrcs42t7sqdkcy8h

Breakdown:

Expand All @@ -548,14 +579,17 @@ Breakdown:
* `d`: short description
* `q5`: `data_length` (`q` = 0, `5` = 20; 0 * 32 + 20 == 20)
* `vdhkven9v5sxyetpdees`: 'coffee beans'
* `s`: payment secret
* `p5`: `data_length` (`p` = 1, `5` = 20; 1 * 32 + 20 == 52)
* `zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs`: 0x1111111111111111111111111111111111111111111111111111111111111111
* `9`: features
* `qz`: `data_length` (`q` = 0, `z` = 2; 0 * 32 + 2 == 2)
* `sz`: b1000000010
* `e992adudgku8p05pstl6zh7av6rx2f297pv89gu5q93a0hf3g7lynl3xq56t23dpvah6u7y9qey9lccrdml3gaqwc6nxsl5ktzm464sq`: signature
* `73t7cl`: Bech32 checksum
* `q5`: `data_length` (`q` = 0, `5` = 20; 0 * 32 + 20 == 20) 4
* `sqqqqqqqqqqqqqqqpqqq`: b1000....00001000000000000000
* `pqqq4u9s93jtgysm3mrwll70zr697y3mf902hvxwej0v7c62rsltw83ng0pu8w3j230sluc5gxkdmm9dvpy9y6ggtjd2w544mzdrcs42t7sq`: signature
* `dkcy8h`: Bech32 checksum

> # Same, but using invalid unknown feature 100
> lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5vdhkven9v5sxyetpdees9q4pqqqqqqqqqqqqqqqqqqszk3ed62snp73037h4py4gry05eltlp0uezm2w9ajnerhmxzhzhsu40g9mgyx5v3ad4aqwkmvyftzk4k9zenz90mhjcy9hcevc7r3lx2sphzfxz7
> # Same, but adding invalid unknown feature 100
> lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5vdhkven9v5sxyetpdeessp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9q4psqqqqqqqqqqqqqqqpqqqqu7fz6pjqczdm3jp3qps7xntj2w2mm70e0ckhw3c5xk9p36pvk3sewn7ncaex6uzfq0vtqzy28se6pcwn790vxex7xystzumhg55p6qq9wq7td

Breakdown:

Expand All @@ -567,11 +601,14 @@ Breakdown:
* `d`: short description
* `q5`: `data_length` (`q` = 0, `5` = 20; 0 * 32 + 20 == 20)
* `vdhkven9v5sxyetpdees`: 'coffee beans'
* `s`: payment secret
* `p5`: `data_length` (`p` = 1, `5` = 20; 1 * 32 + 20 == 52)
* `zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs`: 0x1111111111111111111111111111111111111111111111111111111111111111
* `9`: features
* `q4`: `data_length` (`q` = 0, `4` = 21; 0 * 32 + 21 == 21)
* `pqqqqqqqqqqqqqqqqqqsz`: b00001...(90 zeroes)...1000000010
* `k3ed62snp73037h4py4gry05eltlp0uezm2w9ajnerhmxzhzhsu40g9mgyx5v3ad4aqwkmvyftzk4k9zenz90mhjcy9hcevc7r3lx2sp`: signature
* `hzfxz7`: Bech32 checksum
* `psqqqqqqqqqqqqqqqpqqqq`: b000011000....00001000000000000000
* `u7fz6pjqczdm3jp3qps7xntj2w2mm70e0ckhw3c5xk9p36pvk3sewn7ncaex6uzfq0vtqzy28se6pcwn790vxex7xystzumhg55p6qq`: signature
* `9wq7td`: Bech32 checksum

# Authors

Expand Down