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

Add a channel congestion control mechanism #2330

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft

Conversation

t-bast
Copy link
Member

@t-bast t-bast commented Jun 24, 2022

Channels have a limited number of HTLCs that can be in-flight at a given time, because the commitment transaction cannot have an unbounded number of outputs. Malicious actors can exploit this by filling our channels with HTLCs and waiting as long as possible before failing them (also known as a channel jamming attack).

To increase the cost of this attack, we don't let our channels be filled with low-value HTLCs. When we already have many low-value HTLCs in-flight, we only accept higher value HTLCs. Attackers will have to lock non-negligible amounts to carry out the attack.

I chose to use hard-coded buckets for now that encode the following constraints:

  • Allow at most 50% of htlcs with an amount below 1% of our max-htlc-value-in-flight
  • Allow at most 80% of htlcs with an amount below 5% of our max-htlc-value-in-flight
  • Allow at most 90% of htlcs with an amount below 10% of our max-htlc-value-in-flight
  • The remaining 10% of our channel is left for HTLCs bigger than 10% of our max-htlc-value-in-flight

I don't know if we should make it configurable. It's quite hard to reason about the effectiveness of a specific configuration, it really needs to be plotted against various channel configurations, as the reject htlcs when buckets are full unit test does.

When channels are very big, we probably never expect HTLCs bigger than 1% to be relayed: instead of using a percentage of max-in-flight, should we use something non-linear here, such as a percentage of f(max-in-flight) with a carefully chosen non-linear function f?

Assuming anchor_outputs_zero_fee_htlc_txs and a dust limit of 330 sat, the current configuration offers the following guarantees:

  • For a channel using max-htlc-value-in-flight = 500_000 sat and max-accepted-htlcs = 30:
    • The attacker must use 4_950 sat to block HTLCs below 5_000 sat`
    • The attacker must use 49_950 sat to block HTLCs below 25_000 sat`
    • The attacker must use 124_950 sat to block HTLCs below 50_000 sat`
    • The attacker must use 274_950 sat to jam the channel entirely
  • For a channel using max-htlc-value-in-flight = 1_000_000 sat and max-accepted-htlcs = 30:
    • The attacker must use 4_950 sat to block HTLCs below 10_000 sat`
    • The attacker must use 94_950 sat to block HTLCs below 50_000 sat`
    • The attacker must use 244_950 sat to block HTLCs below 100_000 sat`
    • The attacker must use 544_950 sat to jam the channel entirely
  • For a channel using max-htlc-value-in-flight = 5_000_000 sat and max-accepted-htlcs = 30:
    • The attacker must use 4_950 sat to block HTLCs below 50_000 sat`
    • The attacker must use 454_950 sat to block HTLCs below 250_000 sat`
    • The attacker must use 1_204_950 sat to block HTLCs below 500_000 sat`
    • The attacker must use 2_704_950 sat to jam the channel entirely
  • For a channel using max-htlc-value-in-flight = 500_000 sat and max-accepted-htlcs = 50:
    • The attacker must use 8_250 sat to block HTLCs below 5_000 sat`
    • The attacker must use 83_250 sat to block HTLCs below 25_000 sat`
    • The attacker must use 208_250 sat to block HTLCs below 50_000 sat`
    • The attacker must use 458_250 sat to jam the channel entirely
  • For a channel using max-htlc-value-in-flight = 1_000_000 sat and max-accepted-htlcs = 50:
    • The attacker must use 8_250 sat to block HTLCs below 10_000 sat`
    • The attacker must use 158_250 sat to block HTLCs below 50_000 sat`
    • The attacker must use 408_250 sat to block HTLCs below 100_000 sat`
    • The attacker must use 908_250 sat to jam the channel entirely
  • For a channel using max-htlc-value-in-flight = 5_000_000 sat and max-accepted-htlcs = 50:
    • The attacker must use 8_250 sat to block HTLCs below 50_000 sat`
    • The attacker must use 758_250 sat to block HTLCs below 250_000 sat`
    • The attacker must use 2_008_250 sat to block HTLCs below 500_000 sat`
    • The attacker must use 4_508_250 sat to jam the channel entirely

I'm not sure how we could plot this to make it easier to analyze, there are quite a lot of moving parameters to take into account...

An important caveat of this bucketing strategy is how it interacts with balance estimation. If our first bucket is full, a sender may think our balance is low and will avoid sending large HTLCs through the channel, while this large HTLC could be forwarded. This means that the balance estimation feature would actually defeat the congestion control mechanism...

We may need to return a dedicated onion error when applying such congestion control to ensure that senders don't misinterpret it as a liquidity failure, but then every relaying node has an incentive to use that new error to avoid revealing that they have a liquidity failure ¯_(ツ)_/¯

NB: this PR builds on top of #2299

We previously set the `htlc_maximum_msat` inside `channel_update` to the
channel's capacity, but that didn't make any sense: we will reject htlcs
that are above the local or remote `max_htlc_value_in_flight_msat`.

We now set this value to match the lowest `max_htlc_value_in_flight_msat`
of the channel, and properly type our local value to be a millisatoshi
amount instead of a more generic UInt64.
We introduce a new parameter to set `max-htlc-value-in-flight` based on
the channel capacity, when it provides a lower value than the existing
`max-htlc-value-in-flight-msat` static value.
Channels have a limited number of HTLCs that can be in-flight at a given
time, because the commitment transaction cannot have an unbounded number
of outputs. Malicious actors can exploit this by filling our channels with
HTLCs and waiting as long as possible before failing them (also known as
a channel jamming attack).

To increase the cost of this attack, we don't let our channels be filled
with low-value HTLCs. When we already have many low-value HTLCs in-flight,
we only accept higher value HTLCs. Attackers will have to lock non-negligible
amounts to carry out the attack.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

1 participant