diff --git a/02-peer-protocol.md b/02-peer-protocol.md index f43c68611..b0a1d3c48 100644 --- a/02-peer-protocol.md +++ b/02-peer-protocol.md @@ -995,7 +995,10 @@ is destined, is described in [BOLT #4](04-onion-routing.md). 1. type: 0 (`blinding_point`) 2. data: * [`point`:`blinding`] - + 1. type: 1 (`endorsed`) + 2. data: + * [`byte`:`endorsed`] + #### Requirements A sending node: @@ -1033,6 +1036,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 `blinding_point` (see [Route Blinding](04-onion-routing.md#route-blinding)) + - if it is the original source of the HTLC: + - SHOULD set `endorsed` to `1`. + - otherwise: + - SHOULD set `endorsed` as described in [Bolt 4](04-onion-routing.md#resource-bucketing). `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. @@ -1059,6 +1066,8 @@ A receiving node: `error` and fail the channel. - if `blinding_point` is provided: - MUST use the corresponding blinded private key to decrypt the `onion_routing_packet` (see [Route Blinding](04-onion-routing.md#route-blinding)) + - if `endorsed` is provided: + - SHOULD interpret `endorsed` as described in [Bolt 4](04-onion-routing.md#resource-bucketing). 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. diff --git a/04-onion-routing.md b/04-onion-routing.md index 700c2bb0a..6886e1aa0 100644 --- a/04-onion-routing.md +++ b/04-onion-routing.md @@ -53,6 +53,7 @@ A node: * [Route Blinding](#route-blinding) * [Accepting and Forwarding a Payment](#accepting-and-forwarding-a-payment) * [Non-strict Forwarding](#non-strict-forwarding) + * [Resource Bucketing](#resource-bucketing) * [Payload for the Last Node](#payload-for-the-last-node) * [Shared Secret](#shared-secret) * [Blinding Ephemeral Keys](#blinding-ephemeral-keys) @@ -62,6 +63,7 @@ A node: * [Returning Errors](#returning-errors) * [Failure Messages](#failure-messages) * [Receiving Failure Codes](#receiving-failure-codes) + * [Recommendations for Reputation](#recommendations-for-reputation) * [Test Vector](#test-vector) * [Returning Errors](#returning-errors) * [References](#references) @@ -635,6 +637,35 @@ Alternatively, implementations may choose to apply non-strict forwarding only to like-policy channels to ensure their expected fee revenue does not deviate by using an alternate channel. +## Resource Bucketing + +When making the decision to forward a payment on its outgoing channel, a node +MAY choose to limit its exposure to HTLCs that put it at risk of a denial of +service attack. +* `unknown_allocation_slots`: defines the number of HTLC slots allocated to + unknown traffic (default: 50% of remote peer's `max_accepted_htlcs`). +* `unknown_allocation_liquidity`: defines the amount of the channel balance + that is allocated to unknown traffic (default: 50% of remote peer's + `max_htlc_value_in_flight_msat`. + +A node implementing resource bucketing limits exposure on its outgoing channel: +- MUST choose `unknown_allocation_slots` <= the remote channel peer's + `max_accepted_htlcs`. +- MUST choose `unknown_allocation_liquidity` <= the remote channel peer's + `max_htlc_value_in_flight_msat`. +- If `endorsed` is set to 1 in the incoming `update_add_htlc` AND the HTLC + is from a node that the forwarding node considers to have good local + reputation (see [Recommendations for Reputation](#recommendations-for-reputation)): + - SHOULD proceed with forwarding the HTLC. + - SHOULD set `endorsed` to 1 in the outgoing `update_add_htlc`. +- Otherwise, the HTLC is classified as `unknown`: + - If `unknown_allocation_slots` HTLC slots are occupied by other `unknown` HTLCs: + - SHOULD return `temporary_channel_failure` as specified in [Failure Messages](#failure-messages). + - If `unknown_allocation_liquidity` satoshis of liquidity are locked in + other `unknown` HTLCs: + - SHOULD return `temporary_channel_failure` as specified in [Failure Messages](#failure-messages). + - SHOULD set `endorsed` to 0 in the outgoing `update_add_htlc`. + ## Payload for the Last Node When building the route, the origin node MUST use a payload for @@ -1407,6 +1438,60 @@ The _origin node_: - MAY use the data specified in the various failure types for debugging purposes. +## Recommendations for Reputation + +Local reputation is used by forwarding nodes to decide whether to endorse a HTLC +on their outgoing link. Nodes MAY use any metric of their choosing to classify +a peer as having "good" reputation, though a poor choice of reputation scoring +metric will affect their downstream reputation. + +- `resolution_time`: the time elapsed between `update_add_htlc` and its + resolution (`update_fulfill_hltc` / `update_fail_hltc` / + `update_fail_malformed_htlc`). +- `resolution_threshold`: the resolution time threshold that is considered + "good" behavior (default: 10 seconds). +- `fees`: the fees paid by a forwarded HTLC (as described in [BOLT #7](07-routing-gossip.md#htlc-fees), + equal to 0 if the HTLC was failed). + +For every incoming HLTC a peer has forwarded through a node, its `effective_fees` +are calculated as follows: +- if `endorsed` = 1 in `update_add_htlc`: + - if the HTLC was settled with `update_fulfill_hltc`: + - `effective_fees` = `fees` - ceil( (`resolution_time` - `resolution_threshold`) / `resolution_threshold`) * `fees` + - otherwise: + - `effective_fees` = - ceil( (`resolution_time` - `resolution_threshold`) / `resolution_threshold`) * `fees` +- otherwise: + - if successfully resolved AND `resolution_time` <= `resolution_threshold` + - `effective_fees` = `fees` + - otherwise: + - `effective_fees` = 0 + +The sum of the `effective_fees` for each HTLC that a peer has forwarded over +a sliding window of time is used to assess local reputation. + +- `maximum_hold`: the maximum amount of time that a HTLC can be locked in a + node's commitment. +- `reputation_window`: the period of time over which we assess revenue + (recommended default = 10 * `maximum_hold`) +- `revenue`: the total routing revenue generated by the node over `maximum_hold` +- `reputation_revenue`: the total `effective_fees` of HTLCs forwarded by the peer + and resolved within `reputation_window`. + +The local reputation that a peer has earned is compared to total revenue to +classify reputation as good or neutral. + +- if `reputation_revenue` over `reputation_window` >= `revenue` over `maximum_hold` + - a peer should be considered to have good local reputation. +- otherwise, the peer should be considered to have neutral local reputation. + +### Rationale +If a HTLC is endorsed by a peer they have signaled that they expect the HTLC +to resolve honestly, so will be held accountable for the manner in which they +resolve. By contrast, if a HTLC was not endorsed by the upstream peer, it +should not have a negative impact on reputation. In the case where one of +these "unknown" HTLCs succeeds within the reasonable resolution threshold, the +peer is still credited with fees because the HTLC resolved desirably. + # Test Vector ## Returning Errors