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

draft: Upfront Fees to Mitigate Channel Jamming #1052

Closed
wants to merge 9 commits into from
12 changes: 12 additions & 0 deletions 02-peer-protocol.md
Original file line number Diff line number Diff line change
Expand Up @@ -990,6 +990,12 @@ is destined, is described in [BOLT #4](04-onion-routing.md).
* [`u32`:`cltv_expiry`]
* [`1366*byte`:`onion_routing_packet`]

1. `tlv_stream`: `update_add_htlc_tlvs`
2. types:
1. type: 2 (`upfront_fee_msat`)
2. data:
* [`tu64`:`upfront_fee_msat`]

#### Requirements

A sending node:
Expand All @@ -1002,6 +1008,12 @@ A sending node:
node is the funder:
- MUST be able to additionally pay for `to_local_anchor` and
`to_remote_anchor` above its reserve.
- if `upfront_fee_msat` is included in the HTLC
- MUST be able to additionally pay for the `upfront_fee_msat` above its
reserve.
- MUST push the `upfront_fee_msat` amount to the remote party's balance,
Copy link
Contributor

Choose a reason for hiding this comment

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

If the sender is the channel initiation and as such encumbering the responsibility for fees, I don't know if you have too sum up the upfront_fee_msat to the offered amount_msat to determinate you're still in the bounds of the "fee spike buffer".

by subtracting `upfront_fee_msat` from its expected `to_local` balance
and adding `upfront_fee_msat` to its expected `to_remote` balance.
- SHOULD NOT offer `amount_msat` if, after adding that HTLC to its commitment
transaction, its remaining balance doesn't allow it to pay the commitment
transaction fee when receiving or sending a future additional non-dust HTLC
Expand Down
8 changes: 8 additions & 0 deletions 03-transactions.md
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,14 @@ The base fee and anchor output values:
- MUST be subtracted from the `to_local` or `to_remote`
outputs, as specified in [Fee Calculation](#fee-calculation).

The sum of all `upfront_fee_msat` values for all offered HTLCs:
- before the commitment transaction outputs are determined:
- MUST be subtracted from the `to_local` and added to the `to_remote`

The sum of all `upfront_fee_msat` values for all received HTLCs:
- before the commitment transaction outputs are determined:
- MUST be added to the `to_local` and subtracted from the `to_remote`

The commitment transaction:
- if the amount of the commitment transaction `to_local` output would be
less than `dust_limit_satoshis` set by the transaction owner:
Expand Down
62 changes: 53 additions & 9 deletions 04-onion-routing.md
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,9 @@ This is formatted according to the Type-Length-Value format defined in [BOLT #1]
1. type: 16 (`payment_metadata`)
2. data:
* [`...*byte`:`payment_metadata`]
1. type: 2 (`upfront_fee_to_forward`)
2. data:
* [`tu64`:`upfront_fee_to_forward`]

`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.
Expand All @@ -227,11 +230,16 @@ 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.

`upfront_fee_to_forward` is the upfront fee value, in millisatoshis, that
should be pushed to the next receiving peer specified within the routing
information, or for the final destination.

### Requirements

The writer:
- For every node:
- MUST include `amt_to_forward` and `outgoing_cltv_value`.
- MUST include `upfront_fee_to_forward` if every hop advertises `option_upfront_fee`, otherwise MUST NOT include `upfront_fee_to_forward`.
- For every non-final node:
- MUST include `short_channel_id`
- MUST NOT include `payment_data`
Expand All @@ -247,19 +255,23 @@ The writer:

The reader:
- MUST return an error if `amt_to_forward` or `outgoing_cltv_value` are not present.
- MUST return an error if `upfront_fee_msat` is present and `upfront_fee_to_forward` is not.
- MUST return an error if `upfront_fee_msat` is not present and `upfront_fee_to_forward` is.
- if it is not the final node:
- MUST return an error if:
- `short_channel_id` is not present,
- it cannot forward the HTLC to the peer indicated by the channel `short_channel_id`.
- incoming `amount_msat` - `fee` < `amt_to_forward` (where `fee` is the advertised fee as described in [BOLT #7](07-routing-gossip.md#htlc-fees))
- `cltv_expiry` - `cltv_expiry_delta` < `outgoing_cltv_value`
- incoming `upfront_fee_msat` - `upfront_fee` < `upfront_fee_to_forward` (where `upfront_fee` is the advertised fee as described in [BOLT #7](07-routing-gossip.md#upfront-fees))
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this is where the spec is unclear to me.

upfront_fee_msat is unconditionally pushed on the to_remote balance from the viewpoint of the HTLC sender. At the same time, for this equality to hold incoming upfront_fee_msat must accumulate all the downstream upfront_fee to fulfil this equality. Otherwise you might have routing failures just due to hops setting their upfront_fee_base_sat and upfront_fee_proportional_ppm in an unequilibrated fashion.

E.g, you have Alice <-> Bob <-> Caroll <-> Dave. Let's say you have Bob requests 100 sat, Caroll requests 2000 sats and Dave requests 150 sats. The HTLC forward should fail at Bob, as 100 sat < 2000 sat, unless Alice sent an upfront_fee_msat= 2250 sats. However it also means Bob's balance is credited of 2250 sats, if understand the proposal correctly on this mechanism.

- if it is the final node:
- MUST treat `total_msat` as if it were equal to `amt_to_forward` if it
is not present.
- MUST return an error if:
- incoming `amount_msat` < `amt_to_forward`.
- incoming `cltv_expiry` < `outgoing_cltv_value`.
- incoming `cltv_expiry` < `current_block_height` + `min_final_cltv_expiry_delta`.
- incoming `upfront_fee_msat` < `upfront_fee_to_forward`

Additional requirements are specified [below](#basic-multi-part-payments).

Expand All @@ -273,7 +285,9 @@ 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".
an "HTLC set". The amount paid in `upfront_fee_to_forward` by every HTLC in
the set contributes to the `total_msat` paid by sender, as these amounts are
unconditionally pushed to the receiver.

`payment_metadata` is to be included in every payment part, so that
invalid payment details can be detected as early as possible.
Expand All @@ -292,10 +306,12 @@ The writer:
than or equal to twice `amount`.
- otherwise:
- MUST set `total_msat` to the amount it wishes to pay.
- MUST ensure that the total `amt_to_forward` of the HTLC set which arrives
at the payee is equal to or greater than `total_msat`.
- MUST NOT send another HTLC if the total `amt_to_forward` of the HTLC set
is already greater or equal to `total_msat`.
- MUST ensure that the total `amt_to_forward` + total
`upfront_fee_to_forward` of the HTLC set which arrives at the payee is
equal to or greater than `total_msat`.
- MUST NOT send another HTLC if the total `amt_to_forward` + total
`upfront_fee_to_forward` of the HTLC set is already greater or equal to
`total_msat`.
- MUST include `payment_secret`.
- otherwise:
- MUST set `total_msat` equal to `amt_to_forward`.
Expand All @@ -309,11 +325,11 @@ The final node:
- MUST add it to the HTLC set corresponding to that `payment_hash`.
- SHOULD fail the entire HTLC set if `total_msat` is not the same for
all HTLCs in the set.
- if the total `amt_to_forward` of this HTLC set is equal to or greater
than `total_msat`:
- if the total `amt_to_forward` + total `upfront_fee_to_forward` of this
HTLC set is equal to or greater than `total_msat`:
- SHOULD fulfill all HTLCs in the HTLC set
- otherwise, if the total `amt_to_forward` of this HTLC set is less than
`total_msat`:
- otherwise, if the total `amt_to_forward` + total `upfront_fee_to_forward`
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.
Expand Down Expand Up @@ -343,6 +359,10 @@ constrained in which paths they can take when retrying payments along specific
paths. However, no individual HTLC may be for less than the difference between
the total paid and `total_msat`.

The total `upfront_fee_to_forward` paid to the final node (across failed and
successful HTLC attempts) is included in the HTLC set total because these
amounts have been unconditionally pushed to the receiver from the sender.

The restriction on sending an HTLC once the set is over the agreed total prevents the preimage being released before all
the partial payments have arrived: that would allow any intermediate
node to immediately claim any outstanding partial payments.
Expand Down Expand Up @@ -1007,6 +1027,22 @@ the decrypted byte stream.
The complete amount of the multi-part payment was not received within a
reasonable time.

1. type: UPDATE|25 (`upfront_fee_insufficient`)
2. data:
* [`u64`:`upfront_fee`]
* [`u16`:`len`]
* [`len*byte`:`channel_update`]
Copy link
Collaborator

@joostjager joostjager Jan 18, 2023

Choose a reason for hiding this comment

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

We do have tlv failures now, so could make use of that. #1021


The upfront fee amount was below that required by the outgoing channel from the
processing node.

1. type: 27 (`final_incorrect_upfront_fee`)
2. data:
* [`u64`:`upfront_fee`]

The final hop's upfront fee in the HTLC doesn't match the value in the onion,
or does not meet the receiving node's expected upfront fee.

### Requirements

An _erring node_:
Expand Down Expand Up @@ -1069,6 +1105,10 @@ A _forwarding node_ MAY, but a _final node_ MUST NOT:
- if the channel is disabled:
- report the current channel setting for the outgoing channel.
- return a `channel_disabled` error.
- if the HTLC does NOT pay sufficient upfront fee:
- report the incoming upfront fee amounts and the current channel setting
for the outgoing chanel.
- return a `upfront_fee_insufficient` error.

An _intermediate hop_ MUST NOT, but the _final node_:
- if the payment hash has already been paid:
Expand Down Expand Up @@ -1098,6 +1138,10 @@ An _intermediate hop_ MUST NOT, but the _final node_:
- MUST return a `final_incorrect_htlc_amount` error.
- if it returns a `channel_update`:
- MUST set `short_channel_id` to the `short_channel_id` used by the incoming onion.
- if the `upfront_fee_msat` from the final node's HTLC is below `upfront_fee_to_forward`:
- MUST return `final_incorrect_upfront_fee` error.
- if the `upfront_fee_msat` does NOT pay sufficient fees:
- MUST return `final_incorrect_upfront_fee` error.

### Rationale

Expand Down
46 changes: 46 additions & 0 deletions 07-routing-gossip.md
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,13 @@ of *relaying* payments, not *sending* payments. When making a payment
* [`u32`:`fee_proportional_millionths`]
* [`u64`:`htlc_maximum_msat`]

1. `tlv_stream`: `channel_update_tlvs`
2. types:
1. type: 1 (`upfront_fee_policy`)
2. data:
* [`u32`:`upfront_fee_base_ppm`]
* [`u32`:`upfront_fee_proportional_ppm`]

The `channel_flags` bitfield is used to indicate the direction of the channel: it
identifies the node that this update originated from and signals various options
concerning the channel. The following table specifies the meaning of its
Expand Down Expand Up @@ -496,6 +503,20 @@ The origin node:
- SHOULD NOT create redundant `channel_update`s
- If it creates a new `channel_update` with updated channel parameters:
- SHOULD keep accepting the previous channel parameters for 10 minutes
- if it advertises `option_upfront_fee`:
- MAY set `upfront_fee_policy` to a fee policy that it will charge upfront
for HTLCs:
- `upfront_fee_base_ppm` is the parts per million of its `fee_base_msat`
that it will charge in upfront fees.
- `upfront_fee_proportional_ppm` is the parts per million of its
`fee_proportional_millionths` that it will charge in upfront fees.
- MUST NOT set `upfront_fee_base_ppm` > 100000 ppm.
- MUST NOT set `upfront_fee_proportional_ppm` > 100000 ppm.
- MUST accept the default values of `upfront_fee_base_ppm` = 10000 and
`upfront_fee_proportional_ppm` as values for `upfront_fee_policiy` if it
does not advertise a custom policy.
- otherwise:
- MUST NOT set `upfront_fee_policy`

The receiving node:
- if the `short_channel_id` does NOT match a previous `channel_announcement`,
Expand Down Expand Up @@ -533,6 +554,10 @@ The receiving node:
- SHOULD ignore this channel during route considerations.
- otherwise:
- SHOULD consider the `htlc_maximum_msat` when routing.
- if the `upfront_fee_policy`'s `upfront_fee_base_ppm` or
`upfront_fee_proportional_ppm` are greater than 100000 ppm:
- MAY blacklist this `node_id`.
- SHOULD ignore this channel during route considerations.

### Rationale

Expand Down Expand Up @@ -570,6 +595,14 @@ The `must_be_one` field in `message_flags` was previously used to indicate
the presence of the `htlc_maximum_msat` field. This field must now always
be present, so `must_be_one` is a constant value, and ignored by receivers.

Upfront fees compensate routing nodes in the case of payment failure for the
opportunity cost of fees that they could have otherwise earned, so they are
expressed as a proportion of the node's advertised routing fees. A maximum
proportion is enforced to ensure that nodes don't advertise upfront fees that
shift their economic incentive to failing rather than forwarding payments. A
default value is set to save network bandwidth on values that are likely to
remain unmodified for the majority of nodes.

## Query Messages

Negotiating the `gossip_queries` option via `init` enables a number
Expand Down Expand Up @@ -972,6 +1005,19 @@ The origin node:
sending `channel_update`.
- Note: this allows for any propagation delay.

## Upfront Fees

### Requirements
The origin nodes:
- SHOULD accept HTLCs that pay an upfront fee equal to or greater than:
- ( fee_base_msat * upfront_fee_base_ppm / 1000000 ) + ( amount_to_forward * (fee_proportional_millionths * upfront_fee_proportional_ppm / 1000000 ) / 1000000 )
- SHOULD accept HTLCs that pay a default of 10000 ppm upfront_fee_base_ppm
and upfront_fee_proportional_ppm if they did not advertise a custom policy.
- SHOULD accept HTLCs that pay an older fee, for some reasonable time after
sending `channel_update`.
- Note: this allows for any propagation delay.


## Pruning the Network View

### Requirements
Expand Down
1 change: 1 addition & 0 deletions 09-features.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ 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] |
| 56/57 | `option_upfront_fee` | Understands upfront fees | IN9 | | [BOLT #2][bolt02-adding-an-htlc-update_add_htlc] |

## Definitions

Expand Down
28 changes: 26 additions & 2 deletions 11-payment-encoding.md
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,9 @@ Currently defined tagged fields are:
* `9` (5): `data_length` variable. One or more 5-bit values containing features
supported or required for receiving this payment.
See [Feature Bits](#feature-bits).
* `u` (17): `data_length` 26. `upfront_fee_policy` to use for the last HTLC in the route:
* `upfront_base_msat` (32 bits, big-endian)
* `upfront_proportional_millionths` (32 bits, big-endian)

### Requirements

Expand Down Expand Up @@ -203,10 +206,15 @@ A writer:
- MUST pad field data to a multiple of 5 bits, using 0s.
- if a writer offers more than one of any field type, it:
- MUST specify the most-preferred field first, followed by less-preferred fields, in order.
- if `option_upfront_fee` is advertised in `9`:
- MUST set `u` to the `upfront_fee_policy` it will accept for the final HTLC in the route.
- SHOULD pad this value to obfuscate its location in the payment path.
- otherwise:
- MUST NOT include a `u` field.

A reader:
- 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.
- MUST skip over unknown fields, OR an `f` field with unknown `version`, OR `p`, `h`, `s`,
`n`, or `u` fields that do NOT have `data_length`s of 52, 52 52 or 53 or 26 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 @@ -222,6 +230,15 @@ A reader:
- MUST use an expiry delta of at least 18 when making the payment
- if an `m` field is provided:
- MUST use that as [`payment_metadata`](04-onion-routing.md#tlv_payload-payload-format)
- if `option_upfront_fee` is advertised in `9`:
- if a valid `u` field is provided:
- MUST use the `upfront_fee_policy` specified for the final hop's upfront fee payment.
- otherwise:
- MUST fail the payment.
- otherwise:
- if a valid `u` field is provided:
- MUST fail the payment.

### Rationale

The type-and-length format allows future extensions to be backward
Expand Down Expand Up @@ -268,6 +285,13 @@ The `r` field allows limited routing assistance: as specified, it only
allows minimum information to use private channels, however, it could also
assist in future partial-knowledge routing.

The `u` field allows the receiving party to set an upfront fee that provides
it with sufficient privacy from the second-to-last node which would otherwise
be able to identify the receiving node by a zero upfront fee (as there is no
outgoing channel upfront fee policy for the sender to use). This field is
only usable when paired with `option_upfront_fee` in the invoice's feature
vector, so invoices that do not set both should be considered invalid.

### Security Considerations for Payment Descriptions

Payment descriptions are user-defined and provide a potential avenue for
Expand Down
Loading