Make our in-flight limit percentage configurable
authorViktor Tigerström <11711198+ViktorTigerstrom@users.noreply.github.com>
Tue, 26 Apr 2022 22:37:45 +0000 (00:37 +0200)
committerViktor Tigerström <11711198+ViktorTigerstrom@users.noreply.github.com>
Tue, 3 May 2022 20:35:43 +0000 (22:35 +0200)
Add a config field
`ChannelHandshakeConfig::max_inbound_htlc_value_in_flight_percent_of_channel`
which sets the percentage of the channel value we cap the total value of
outstanding inbound HTLCs to.

This field can be set to a value between 1-100, where the value
corresponds to the percent of the channel value in whole percentages.

Note that:
* If configured to another value than the default value 10, any new
channels created with the non default value will cause versions of LDK
prior to 0.0.104 to refuse to read the `ChannelManager`.

* This caps the total value for inbound HTLCs in-flight only, and
there's currently no way to configure the cap for the total value of
outbound HTLCs in-flight.

* The requirements for your node being online to ensure the safety of
HTLC-encumbered funds are different from the non-HTLC-encumbered funds.
This makes this an important knob to restrict exposure to loss due to
being offline for too long. See
`ChannelHandshakeConfig::our_to_self_delay` and
`ChannelConfig::cltv_expiry_delta` for more information.

Default value: 10.
Minimum value: 1, any values less than 1 will be treated as 1 instead.
Maximum value: 100, any values larger than 100 will be treated as 100
instead.

lightning/src/ln/channel.rs
lightning/src/util/config.rs

index 1cb7a689a21a1b710413e93afbba8e1881d48e90..f6767e8a7d46555cecb48592ee52200aa4b53ded 100644 (file)
@@ -39,7 +39,7 @@ use util::events::ClosureReason;
 use util::ser::{Readable, ReadableArgs, Writeable, Writer, VecWriter};
 use util::logger::Logger;
 use util::errors::APIError;
-use util::config::{UserConfig, ChannelConfig, ChannelHandshakeLimits};
+use util::config::{UserConfig, ChannelConfig, ChannelHandshakeConfig, ChannelHandshakeLimits};
 use util::scid_utils::scid_from_parts;
 
 use io;
@@ -745,6 +745,12 @@ pub const COMMITMENT_TX_WEIGHT_PER_HTLC: u64 = 172;
 
 pub const ANCHOR_OUTPUT_VALUE_SATOSHI: u64 = 330;
 
+/// The percentage of the channel value `holder_max_htlc_value_in_flight_msat` used to be set to,
+/// before this was made configurable. The percentage was made configurable in LDK 0.0.107,
+/// although LDK 0.0.104+ enabled serialization of channels with a different value set for
+/// `holder_max_htlc_value_in_flight_msat`.
+pub const MAX_IN_FLIGHT_PERCENT_LEGACY: u8 = 10;
+
 /// Maximum `funding_satoshis` value according to the BOLT #2 specification, if
 /// `option_support_large_channel` (aka wumbo channels) is not supported.
 /// It's 2^24 - 1.
@@ -803,9 +809,22 @@ macro_rules! secp_check {
 }
 
 impl<Signer: Sign> Channel<Signer> {
-       // Convert constants + channel value to limits:
-       fn get_holder_max_htlc_value_in_flight_msat(channel_value_satoshis: u64) -> u64 {
-               channel_value_satoshis * 1000 / 10 //TODO
+       /// Returns the value to use for `holder_max_htlc_value_in_flight_msat` as a percentage of the
+       /// `channel_value_satoshis` in msat, set through
+       /// [`ChannelHandshakeConfig::max_inbound_htlc_value_in_flight_percent_of_channel`]
+       ///
+       /// The effective percentage is lower bounded by 1% and upper bounded by 100%.
+       ///
+       /// [`ChannelHandshakeConfig::max_inbound_htlc_value_in_flight_percent_of_channel`]: crate::util::config::ChannelHandshakeConfig::max_inbound_htlc_value_in_flight_percent_of_channel
+       fn get_holder_max_htlc_value_in_flight_msat(channel_value_satoshis: u64, config: &ChannelHandshakeConfig) -> u64 {
+               let configured_percent = if config.max_inbound_htlc_value_in_flight_percent_of_channel < 1 {
+                       1
+               } else if config.max_inbound_htlc_value_in_flight_percent_of_channel > 100 {
+                       100
+               } else {
+                       config.max_inbound_htlc_value_in_flight_percent_of_channel as u64
+               };
+               channel_value_satoshis * 10 * configured_percent
        }
 
        /// Returns a minimum channel reserve value the remote needs to maintain,
@@ -964,7 +983,7 @@ impl<Signer: Sign> Channel<Signer> {
                        counterparty_dust_limit_satoshis: 0,
                        holder_dust_limit_satoshis: MIN_CHAN_DUST_LIMIT_SATOSHIS,
                        counterparty_max_htlc_value_in_flight_msat: 0,
-                       holder_max_htlc_value_in_flight_msat: Self::get_holder_max_htlc_value_in_flight_msat(channel_value_satoshis),
+                       holder_max_htlc_value_in_flight_msat: Self::get_holder_max_htlc_value_in_flight_msat(channel_value_satoshis, &config.own_channel_config),
                        counterparty_selected_channel_reserve_satoshis: None, // Filled in in accept_channel
                        holder_selected_channel_reserve_satoshis,
                        counterparty_htlc_minimum_msat: 0,
@@ -1282,7 +1301,7 @@ impl<Signer: Sign> Channel<Signer> {
                        counterparty_dust_limit_satoshis: msg.dust_limit_satoshis,
                        holder_dust_limit_satoshis: MIN_CHAN_DUST_LIMIT_SATOSHIS,
                        counterparty_max_htlc_value_in_flight_msat: cmp::min(msg.max_htlc_value_in_flight_msat, msg.funding_satoshis * 1000),
-                       holder_max_htlc_value_in_flight_msat: Self::get_holder_max_htlc_value_in_flight_msat(msg.funding_satoshis),
+                       holder_max_htlc_value_in_flight_msat: Self::get_holder_max_htlc_value_in_flight_msat(msg.funding_satoshis, &config.own_channel_config),
                        counterparty_selected_channel_reserve_satoshis: Some(msg.channel_reserve_satoshis),
                        holder_selected_channel_reserve_satoshis,
                        counterparty_htlc_minimum_msat: msg.htlc_minimum_msat,
@@ -5877,13 +5896,18 @@ impl<Signer: Sign> Writeable for Channel<Signer> {
                let chan_type = if self.channel_type != ChannelTypeFeatures::only_static_remote_key() {
                        Some(&self.channel_type) } else { None };
 
-               // The same logic applies for `holder_selected_channel_reserve_satoshis` and
-               // `holder_max_htlc_value_in_flight_msat` values other than the defaults.
+               // The same logic applies for `holder_selected_channel_reserve_satoshis` values other than
+               // the default, and when `holder_max_htlc_value_in_flight_msat` is configured to be set to
+               // a different percentage of the channel value then 10%, which older versions of LDK used
+               // to set it to before the percentage was made configurable.
                let serialized_holder_selected_reserve =
                        if self.holder_selected_channel_reserve_satoshis != Self::get_holder_selected_channel_reserve_satoshis(self.channel_value_satoshis)
                        { Some(self.holder_selected_channel_reserve_satoshis) } else { None };
+
+               let mut old_max_in_flight_percent_config = UserConfig::default().own_channel_config;
+               old_max_in_flight_percent_config.max_inbound_htlc_value_in_flight_percent_of_channel = MAX_IN_FLIGHT_PERCENT_LEGACY;
                let serialized_holder_htlc_max_in_flight =
-                       if self.holder_max_htlc_value_in_flight_msat != Self::get_holder_max_htlc_value_in_flight_msat(self.channel_value_satoshis)
+                       if self.holder_max_htlc_value_in_flight_msat != Self::get_holder_max_htlc_value_in_flight_msat(self.channel_value_satoshis, &old_max_in_flight_percent_config)
                        { Some(self.holder_max_htlc_value_in_flight_msat) } else { None };
 
                write_tlv_fields!(writer, {
@@ -6153,7 +6177,7 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<(&'a K, u32)> for Channel<Signer>
                let mut target_closing_feerate_sats_per_kw = None;
                let mut monitor_pending_finalized_fulfills = Some(Vec::new());
                let mut holder_selected_channel_reserve_satoshis = Some(Self::get_holder_selected_channel_reserve_satoshis(channel_value_satoshis));
-               let mut holder_max_htlc_value_in_flight_msat = Some(Self::get_holder_max_htlc_value_in_flight_msat(channel_value_satoshis));
+               let mut holder_max_htlc_value_in_flight_msat = Some(Self::get_holder_max_htlc_value_in_flight_msat(channel_value_satoshis, &UserConfig::default().own_channel_config));
                // Prior to supporting channel type negotiation, all of our channels were static_remotekey
                // only, so we default to that if none was written.
                let mut channel_type = Some(ChannelTypeFeatures::only_static_remote_key());
index 0f625098f79f9030ae25ddc1979cc6b5fcba30ae..3868d29aab49f66789c49c970a662cba19000e2e 100644 (file)
@@ -48,6 +48,30 @@ pub struct ChannelHandshakeConfig {
        /// Default value: 1. If the value is less than 1, it is ignored and set to 1, as is required
        /// by the protocol.
        pub our_htlc_minimum_msat: u64,
+       /// Sets the percentage of the channel value we will cap the total value of outstanding inbound
+       /// HTLCs to.
+       ///
+       /// This can be set to a value between 1-100, where the value corresponds to the percent of the
+       /// channel value in whole percentages.
+       ///
+       /// Note that:
+       /// * If configured to another value than the default value 10, any new channels created with
+       /// the non default value will cause versions of LDK prior to 0.0.104 to refuse to read the
+       /// `ChannelManager`.
+       ///
+       /// * This caps the total value for inbound HTLCs in-flight only, and there's currently
+       /// no way to configure the cap for the total value of outbound HTLCs in-flight.
+       ///
+       /// * The requirements for your node being online to ensure the safety of HTLC-encumbered funds
+       /// are different from the non-HTLC-encumbered funds. This makes this an important knob to
+       /// restrict exposure to loss due to being offline for too long.
+       /// See [`ChannelHandshakeConfig::our_to_self_delay`] and [`ChannelConfig::cltv_expiry_delta`]
+       /// for more information.
+       ///
+       /// Default value: 10.
+       /// Minimum value: 1, any values less than 1 will be treated as 1 instead.
+       /// Maximum value: 100, any values larger than 100 will be treated as 100 instead.
+       pub max_inbound_htlc_value_in_flight_percent_of_channel: u8,
        /// If set, we attempt to negotiate the `scid_privacy` (referred to as `scid_alias` in the
        /// BOLTs) option for outbound private channels. This provides better privacy by not including
        /// our real on-chain channel UTXO in each invoice and requiring that our counterparty only
@@ -78,6 +102,7 @@ impl Default for ChannelHandshakeConfig {
                        minimum_depth: 6,
                        our_to_self_delay: BREAKDOWN_TIMEOUT,
                        our_htlc_minimum_msat: 1,
+                       max_inbound_htlc_value_in_flight_percent_of_channel: 10,
                        negotiate_scid_privacy: false,
                }
        }