From 2867d5c1a4d2c931f11cc0e713e8878419ca481b Mon Sep 17 00:00:00 2001 From: Leo Nash Date: Wed, 1 Apr 2026 01:01:58 +0000 Subject: [PATCH] Add `unannounced_channel_max_inbound_htlc_value_in_flight_percentage` Users can now configure two different max percentages for the channel value that can be allocated to inbound HTLCs, one for announced channels, and another for unannounced channels. We also bump the default maximums to 25% for announced channels, and 100% for unannounced channels, to bring them closer to what people would expect. --- lightning/src/ln/async_payments_tests.rs | 7 ++ lightning/src/ln/blinded_payment_tests.rs | 12 +- lightning/src/ln/chanmon_update_fail_tests.rs | 7 +- lightning/src/ln/channel.rs | 104 +++++++++++++----- lightning/src/ln/channel_open_tests.rs | 6 +- lightning/src/ln/functional_tests.rs | 28 +++-- lightning/src/ln/htlc_reserve_unit_tests.rs | 21 ++-- lightning/src/ln/monitor_tests.rs | 2 + lightning/src/ln/payment_tests.rs | 82 +++++++++----- lightning/src/ln/reload_tests.rs | 12 +- lightning/src/ln/splicing_tests.rs | 24 ++-- lightning/src/ln/update_fee_tests.rs | 7 +- lightning/src/util/config.rs | 77 ++++++++++--- 13 files changed, 288 insertions(+), 101 deletions(-) diff --git a/lightning/src/ln/async_payments_tests.rs b/lightning/src/ln/async_payments_tests.rs index 25522346d9c..341bd5d7269 100644 --- a/lightning/src/ln/async_payments_tests.rs +++ b/lightning/src/ln/async_payments_tests.rs @@ -504,6 +504,9 @@ fn often_offline_node_cfg() -> UserConfig { cfg.channel_handshake_config.announce_for_forwarding = false; cfg.channel_handshake_limits.force_announced_channel_preference = true; cfg.hold_outbound_htlcs_at_next_hop = true; + // Use the setting that matches the default at the time these tests were written + cfg.channel_handshake_config.unannounced_channel_max_inbound_htlc_value_in_flight_percentage = + 10; cfg } @@ -1310,6 +1313,10 @@ fn async_receive_mpp() { let mut allow_priv_chan_fwds_cfg = test_default_channel_config(); allow_priv_chan_fwds_cfg.accept_forwards_to_priv_channels = true; + // Set the percentage to the default value at the time this test was written + allow_priv_chan_fwds_cfg + .channel_handshake_config + .announced_channel_max_inbound_htlc_value_in_flight_percentage = 10; let node_chanmgrs = create_node_chanmgrs( 4, diff --git a/lightning/src/ln/blinded_payment_tests.rs b/lightning/src/ln/blinded_payment_tests.rs index e148ce2c474..d62f79957eb 100644 --- a/lightning/src/ln/blinded_payment_tests.rs +++ b/lightning/src/ln/blinded_payment_tests.rs @@ -269,7 +269,11 @@ fn one_hop_blinded_path_with_dummy_hops() { fn mpp_to_one_hop_blinded_path() { let chanmon_cfgs = create_chanmon_cfgs(4); let node_cfgs = create_node_cfgs(4, &chanmon_cfgs); - let node_chanmgrs = create_node_chanmgrs(4, &node_cfgs, &[None, None, None, None]); + let mut config = test_default_channel_config(); + // Set the percentage to the default value at the time this test was written + config.channel_handshake_config.announced_channel_max_inbound_htlc_value_in_flight_percentage = 10; + let configs: [Option; 4] = core::array::from_fn(|_| Some(config.clone())); + let node_chanmgrs = create_node_chanmgrs(4, &node_cfgs, &configs); let nodes = create_network(4, &node_cfgs, &node_chanmgrs); let mut secp_ctx = Secp256k1::new(); @@ -349,7 +353,11 @@ fn mpp_to_one_hop_blinded_path() { fn mpp_to_three_hop_blinded_paths() { let chanmon_cfgs = create_chanmon_cfgs(6); let node_cfgs = create_node_cfgs(6, &chanmon_cfgs); - let node_chanmgrs = create_node_chanmgrs(6, &node_cfgs, &[None, None, None, None, None, None]); + let mut config = test_default_channel_config(); + // Set the percentage to the default value at the time this test was written + config.channel_handshake_config.announced_channel_max_inbound_htlc_value_in_flight_percentage = 10; + let configs: [Option; 6] = core::array::from_fn(|_| Some(config.clone())); + let node_chanmgrs = create_node_chanmgrs(6, &node_cfgs, &configs); let nodes = create_network(6, &node_cfgs, &node_chanmgrs); // Create this network topology so node 0 MPP's over 2 3-hop blinded paths: diff --git a/lightning/src/ln/chanmon_update_fail_tests.rs b/lightning/src/ln/chanmon_update_fail_tests.rs index dd799c2c27c..af4d1569d0c 100644 --- a/lightning/src/ln/chanmon_update_fail_tests.rs +++ b/lightning/src/ln/chanmon_update_fail_tests.rs @@ -4656,6 +4656,7 @@ fn test_claim_to_closed_channel_blocks_claimed_event() { #[test] #[cfg(all(feature = "std", not(target_os = "windows")))] fn test_single_channel_multiple_mpp() { + use crate::util::config::UserConfig; use std::sync::atomic::{AtomicBool, Ordering}; // Test what happens when we attempt to claim an MPP with many parts that came to us through @@ -4667,7 +4668,11 @@ fn test_single_channel_multiple_mpp() { // for more info. let chanmon_cfgs = create_chanmon_cfgs(9); let node_cfgs = create_node_cfgs(9, &chanmon_cfgs); - let configs = [None, None, None, None, None, None, None, None, None]; + let mut config = test_default_channel_config(); + // Set the percentage to the default value at the time this test was written + config.channel_handshake_config.announced_channel_max_inbound_htlc_value_in_flight_percentage = + 10; + let configs: [Option; 9] = core::array::from_fn(|_| Some(config.clone())); let node_chanmgrs = create_node_chanmgrs(9, &node_cfgs, &configs); let mut nodes = create_network(9, &node_cfgs, &node_chanmgrs); diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index 03f78dc82b4..5579c119e05 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -4102,6 +4102,7 @@ impl ChannelContext { ), holder_max_htlc_value_in_flight_msat: get_holder_max_htlc_value_in_flight_msat( channel_value_satoshis, + announce_for_forwarding, &config.channel_handshake_config, ), counterparty_htlc_minimum_msat: open_channel_fields.htlc_minimum_msat, @@ -4405,6 +4406,7 @@ impl ChannelContext { // receive `accept_channel2`. holder_max_htlc_value_in_flight_msat: get_holder_max_htlc_value_in_flight_msat( channel_value_satoshis, + config.channel_handshake_config.announce_for_forwarding, &config.channel_handshake_config, ), counterparty_htlc_minimum_msat: 0, @@ -6678,24 +6680,41 @@ impl ChannelContext { /// 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`] +/// [`ChannelHandshakeConfig::announced_channel_max_inbound_htlc_value_in_flight_percentage`] +/// or [`ChannelHandshakeConfig::unannounced_channel_max_inbound_htlc_value_in_flight_percentage`] +/// depending on the value of [`ChannelHandshakeConfig::announce_for_forwarding`]. /// /// 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 +/// [`ChannelHandshakeConfig::announced_channel_max_inbound_htlc_value_in_flight_percentage`]: crate::util::config::ChannelHandshakeConfig::announced_channel_max_inbound_htlc_value_in_flight_percentage +/// [`ChannelHandshakeConfig::unannounced_channel_max_inbound_htlc_value_in_flight_percentage`]: crate::util::config::ChannelHandshakeConfig::unannounced_channel_max_inbound_htlc_value_in_flight_percentage +/// [`ChannelHandshakeConfig::announce_for_forwarding`]: crate::util::config::ChannelHandshakeConfig::announce_for_forwarding fn get_holder_max_htlc_value_in_flight_msat( - channel_value_satoshis: u64, config: &ChannelHandshakeConfig, + channel_value_satoshis: u64, is_announced_channel: bool, config: &ChannelHandshakeConfig, ) -> u64 { - let configured_percent = if config.max_inbound_htlc_value_in_flight_percent_of_channel < 1 { + let config_setting = if is_announced_channel { + config.announced_channel_max_inbound_htlc_value_in_flight_percentage + } else { + config.unannounced_channel_max_inbound_htlc_value_in_flight_percentage + }; + let configured_percent = if config_setting < 1 { 1 - } else if config.max_inbound_htlc_value_in_flight_percent_of_channel > 100 { + } else if config_setting > 100 { 100 } else { - config.max_inbound_htlc_value_in_flight_percent_of_channel as u64 + config_setting as u64 }; channel_value_satoshis * 10 * configured_percent } +/// This is for legacy reasons, present for forward-compatibility. +/// LDK versions older than 0.0.104 don't know how read/handle values other than the legacy +/// percentage from storage. Hence, we use this function to not persist legacy values of +/// `holder_max_htlc_value_in_flight_msat` for channels into storage. +fn get_legacy_default_holder_max_htlc_value_in_flight_msat(channel_value_satoshis: u64) -> u64 { + channel_value_satoshis * 10 * MAX_IN_FLIGHT_PERCENT_LEGACY as u64 +} + /// Returns a minimum channel reserve value the remote needs to maintain, /// required by us according to the configured or default /// [`ChannelHandshakeConfig::their_channel_reserve_proportional_millionths`] @@ -15691,15 +15710,11 @@ impl Writeable for FundedChannel { None }; - let mut old_max_in_flight_percent_config = UserConfig::default().channel_handshake_config; - old_max_in_flight_percent_config.max_inbound_htlc_value_in_flight_percent_of_channel = - MAX_IN_FLIGHT_PERCENT_LEGACY; - let max_in_flight_msat = get_holder_max_htlc_value_in_flight_msat( + let legacy_max_in_flight_msat = get_legacy_default_holder_max_htlc_value_in_flight_msat( self.funding.get_value_satoshis(), - &old_max_in_flight_percent_config, ); let serialized_holder_htlc_max_in_flight = - if self.context.holder_max_htlc_value_in_flight_msat != max_in_flight_msat { + if self.context.holder_max_htlc_value_in_flight_msat != legacy_max_in_flight_msat { Some(self.context.holder_max_htlc_value_in_flight_msat) } else { None @@ -16131,11 +16146,9 @@ impl<'a, 'b, 'c, ES: EntropySource, SP: SignerProvider> let mut holder_selected_channel_reserve_satoshis = Some( get_legacy_default_holder_selected_channel_reserve_satoshis(channel_value_satoshis), ); + let mut holder_max_htlc_value_in_flight_msat = - Some(get_holder_max_htlc_value_in_flight_msat( - channel_value_satoshis, - &UserConfig::default().channel_handshake_config, - )); + Some(get_legacy_default_holder_max_htlc_value_in_flight_msat(channel_value_satoshis)); // 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()); @@ -17141,8 +17154,13 @@ mod tests { } #[test] - #[rustfmt::skip] fn test_configured_holder_max_htlc_value_in_flight() { + do_test_configured_holder_max_htlc_value_in_flight(true); + do_test_configured_holder_max_htlc_value_in_flight(false); + } + + #[rustfmt::skip] + fn do_test_configured_holder_max_htlc_value_in_flight(announce_channel: bool) { let test_est = TestFeeEstimator::new(15000); let feeest = LowerBoundedFeeEstimator::new(&test_est); let logger = TestLogger::new(); @@ -17154,13 +17172,49 @@ mod tests { let inbound_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[7; 32]).unwrap()); let mut config_2_percent = UserConfig::default(); - config_2_percent.channel_handshake_config.max_inbound_htlc_value_in_flight_percent_of_channel = 2; + config_2_percent.channel_handshake_config.announce_for_forwarding = announce_channel; + if announce_channel { + config_2_percent + .channel_handshake_config + .announced_channel_max_inbound_htlc_value_in_flight_percentage = 2; + } else { + config_2_percent + .channel_handshake_config + .unannounced_channel_max_inbound_htlc_value_in_flight_percentage = 2; + } let mut config_99_percent = UserConfig::default(); - config_99_percent.channel_handshake_config.max_inbound_htlc_value_in_flight_percent_of_channel = 99; + config_99_percent.channel_handshake_config.announce_for_forwarding = announce_channel; + if announce_channel { + config_99_percent + .channel_handshake_config + .announced_channel_max_inbound_htlc_value_in_flight_percentage = 99; + } else { + config_99_percent + .channel_handshake_config + .unannounced_channel_max_inbound_htlc_value_in_flight_percentage = 99; + } let mut config_0_percent = UserConfig::default(); - config_0_percent.channel_handshake_config.max_inbound_htlc_value_in_flight_percent_of_channel = 0; + config_0_percent.channel_handshake_config.announce_for_forwarding = announce_channel; + if announce_channel { + config_0_percent + .channel_handshake_config + .announced_channel_max_inbound_htlc_value_in_flight_percentage = 0; + } else { + config_0_percent + .channel_handshake_config + .unannounced_channel_max_inbound_htlc_value_in_flight_percentage = 0; + } let mut config_101_percent = UserConfig::default(); - config_101_percent.channel_handshake_config.max_inbound_htlc_value_in_flight_percent_of_channel = 101; + config_101_percent.channel_handshake_config.announce_for_forwarding = announce_channel; + if announce_channel { + config_101_percent + .channel_handshake_config + .announced_channel_max_inbound_htlc_value_in_flight_percentage = 101; + } else { + config_101_percent + .channel_handshake_config + .unannounced_channel_max_inbound_htlc_value_in_flight_percentage = 101; + } // Test that `OutboundV1Channel::new` creates a channel with the correct value for // `holder_max_htlc_value_in_flight_msat`, when configured with a valid percentage value, @@ -17189,26 +17243,26 @@ mod tests { assert_eq!(chan_4.context.holder_max_htlc_value_in_flight_msat, (chan_4_value_msat as f64 * 0.99) as u64); // Test that `OutboundV1Channel::new` uses the lower bound of the configurable percentage values (1%) - // if `max_inbound_htlc_value_in_flight_percent_of_channel` is set to a value less than 1. + // if `(un)announced_channel_max_inbound_htlc_value_in_flight_percentage` is set to a value less than 1. let chan_5 = OutboundV1Channel::<&TestKeysInterface>::new(&feeest, &&keys_provider, &&keys_provider, outbound_node_id, &channelmanager::provided_init_features(&config_0_percent), 10000000, 100000, 42, &config_0_percent, 0, 42, None, &logger, None).unwrap(); let chan_5_value_msat = chan_5.funding.get_value_satoshis() * 1000; assert_eq!(chan_5.context.holder_max_htlc_value_in_flight_msat, (chan_5_value_msat as f64 * 0.01) as u64); // Test that `OutboundV1Channel::new` uses the upper bound of the configurable percentage values - // (100%) if `max_inbound_htlc_value_in_flight_percent_of_channel` is set to a larger value + // (100%) if `(un)announced_channel_max_inbound_htlc_value_in_flight_percentage` is set to a larger value // than 100. let chan_6 = OutboundV1Channel::<&TestKeysInterface>::new(&feeest, &&keys_provider, &&keys_provider, outbound_node_id, &channelmanager::provided_init_features(&config_101_percent), 10000000, 100000, 42, &config_101_percent, 0, 42, None, &logger, None).unwrap(); let chan_6_value_msat = chan_6.funding.get_value_satoshis() * 1000; assert_eq!(chan_6.context.holder_max_htlc_value_in_flight_msat, chan_6_value_msat); // Test that `InboundV1Channel::new` uses the lower bound of the configurable percentage values (1%) - // if `max_inbound_htlc_value_in_flight_percent_of_channel` is set to a value less than 1. + // if `(un)announced_channel_max_inbound_htlc_value_in_flight_percentage` is set to a value less than 1. let chan_7 = InboundV1Channel::<&TestKeysInterface>::new(&feeest, &&keys_provider, &&keys_provider, inbound_node_id, &channelmanager::provided_channel_type_features(&config_0_percent), &channelmanager::provided_init_features(&config_0_percent), &chan_1_open_channel_msg, 7, &config_0_percent, 0, &&logger, None).unwrap(); let chan_7_value_msat = chan_7.funding.get_value_satoshis() * 1000; assert_eq!(chan_7.context.holder_max_htlc_value_in_flight_msat, (chan_7_value_msat as f64 * 0.01) as u64); // Test that `InboundV1Channel::new` uses the upper bound of the configurable percentage values - // (100%) if `max_inbound_htlc_value_in_flight_percent_of_channel` is set to a larger value + // (100%) if `(un)announced_channel_max_inbound_htlc_value_in_flight_percentage` is set to a larger value // than 100. let chan_8 = InboundV1Channel::<&TestKeysInterface>::new(&feeest, &&keys_provider, &&keys_provider, inbound_node_id, &channelmanager::provided_channel_type_features(&config_101_percent), &channelmanager::provided_init_features(&config_101_percent), &chan_1_open_channel_msg, 7, &config_101_percent, 0, &&logger, None).unwrap(); let chan_8_value_msat = chan_8.funding.get_value_satoshis() * 1000; diff --git a/lightning/src/ln/channel_open_tests.rs b/lightning/src/ln/channel_open_tests.rs index d28d157488d..ac4a1b67994 100644 --- a/lightning/src/ln/channel_open_tests.rs +++ b/lightning/src/ln/channel_open_tests.rs @@ -182,7 +182,8 @@ fn test_inbound_anchors_manual_acceptance() { fn test_inbound_anchors_config_overridden() { let overrides = ChannelConfigOverrides { handshake_overrides: Some(ChannelHandshakeConfigUpdate { - max_inbound_htlc_value_in_flight_percent_of_channel: Some(5), + announced_channel_max_inbound_htlc_value_in_flight_percentage: Some(5), + unannounced_channel_max_inbound_htlc_value_in_flight_percentage: None, htlc_minimum_msat: Some(1000), minimum_depth: Some(2), to_self_delay: Some(200), @@ -1070,7 +1071,8 @@ pub fn test_accept_inbound_channel_config_override() { let config_overrides = ChannelConfigOverrides { handshake_overrides: Some(ChannelHandshakeConfigUpdate { - max_inbound_htlc_value_in_flight_percent_of_channel: None, + announced_channel_max_inbound_htlc_value_in_flight_percentage: None, + unannounced_channel_max_inbound_htlc_value_in_flight_percentage: None, htlc_minimum_msat: None, minimum_depth: None, to_self_delay: None, diff --git a/lightning/src/ln/functional_tests.rs b/lightning/src/ln/functional_tests.rs index 7ed46922d8a..32a07be4d2b 100644 --- a/lightning/src/ln/functional_tests.rs +++ b/lightning/src/ln/functional_tests.rs @@ -6903,22 +6903,22 @@ pub fn test_channel_update_has_correct_htlc_maximum_msat() { config_30_percent.channel_handshake_config.announce_for_forwarding = true; config_30_percent .channel_handshake_config - .max_inbound_htlc_value_in_flight_percent_of_channel = 30; + .announced_channel_max_inbound_htlc_value_in_flight_percentage = 30; let mut config_50_percent = UserConfig::default(); config_50_percent.channel_handshake_config.announce_for_forwarding = true; config_50_percent .channel_handshake_config - .max_inbound_htlc_value_in_flight_percent_of_channel = 50; + .announced_channel_max_inbound_htlc_value_in_flight_percentage = 50; let mut config_95_percent = UserConfig::default(); config_95_percent.channel_handshake_config.announce_for_forwarding = true; config_95_percent .channel_handshake_config - .max_inbound_htlc_value_in_flight_percent_of_channel = 95; + .announced_channel_max_inbound_htlc_value_in_flight_percentage = 95; let mut config_100_percent = UserConfig::default(); config_100_percent.channel_handshake_config.announce_for_forwarding = true; config_100_percent .channel_handshake_config - .max_inbound_htlc_value_in_flight_percent_of_channel = 100; + .announced_channel_max_inbound_htlc_value_in_flight_percentage = 100; let chanmon_cfgs = create_chanmon_cfgs(4); let node_cfgs = create_node_cfgs(4, &chanmon_cfgs); @@ -8436,7 +8436,12 @@ pub fn test_inconsistent_mpp_params() { // such HTLC and allow the second to stay. let chanmon_cfgs = create_chanmon_cfgs(4); let node_cfgs = create_node_cfgs(4, &chanmon_cfgs); - let node_chanmgrs = create_node_chanmgrs(4, &node_cfgs, &[None, None, None, None]); + let mut config = test_default_channel_config(); + // Set the percentage to the default value at the time this test was written + config.channel_handshake_config.announced_channel_max_inbound_htlc_value_in_flight_percentage = + 10; + let configs: [Option; 4] = core::array::from_fn(|_| Some(config.clone())); + let node_chanmgrs = create_node_chanmgrs(4, &node_cfgs, &configs); let nodes = create_network(4, &node_cfgs, &node_chanmgrs); let node_a_id = nodes[0].node.get_our_node_id(); @@ -8580,7 +8585,12 @@ pub fn test_double_partial_claim() { // amount. let chanmon_cfgs = create_chanmon_cfgs(4); let node_cfgs = create_node_cfgs(4, &chanmon_cfgs); - let node_chanmgrs = create_node_chanmgrs(4, &node_cfgs, &[None, None, None, None]); + let mut config = test_default_channel_config(); + // Set the percentage to the default value at the time this test was written + config.channel_handshake_config.announced_channel_max_inbound_htlc_value_in_flight_percentage = + 10; + let configs: [Option; 4] = core::array::from_fn(|_| Some(config.clone())); + let node_chanmgrs = create_node_chanmgrs(4, &node_cfgs, &configs); let nodes = create_network(4, &node_cfgs, &node_chanmgrs); let node_b_id = nodes[1].node.get_our_node_id(); @@ -9067,7 +9077,8 @@ pub fn test_nondust_htlc_excess_fees_are_dust() { config.channel_handshake_limits.min_max_accepted_htlcs = chan_utils::max_htlcs(&chan_ty); config.channel_handshake_config.our_max_accepted_htlcs = chan_utils::max_htlcs(&chan_ty); config.channel_handshake_config.our_htlc_minimum_msat = 1; - config.channel_handshake_config.max_inbound_htlc_value_in_flight_percent_of_channel = 100; + config.channel_handshake_config.announced_channel_max_inbound_htlc_value_in_flight_percentage = + 100; let node_chanmgrs = create_node_chanmgrs( 3, @@ -10039,7 +10050,8 @@ pub fn test_dust_exposure_holding_cell_assertion() { // Use a fixed dust exposure limit to make the test simpler const DUST_HTLC_VALUE_MSAT: u64 = 500_000; config.channel_config.max_dust_htlc_exposure = MaxDustHTLCExposure::FixedLimitMsat(5_000_000); - config.channel_handshake_config.max_inbound_htlc_value_in_flight_percent_of_channel = 100; + config.channel_handshake_config.announced_channel_max_inbound_htlc_value_in_flight_percentage = + 100; let configs = [Some(config.clone()), Some(config.clone()), Some(config.clone())]; let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &configs); diff --git a/lightning/src/ln/htlc_reserve_unit_tests.rs b/lightning/src/ln/htlc_reserve_unit_tests.rs index 608ac143c8d..aaf81b87be7 100644 --- a/lightning/src/ln/htlc_reserve_unit_tests.rs +++ b/lightning/src/ln/htlc_reserve_unit_tests.rs @@ -2376,7 +2376,8 @@ fn test_create_channel_to_trusted_peer_0reserve() { fn do_test_create_channel_to_trusted_peer_0reserve(mut config: UserConfig) -> ChannelTypeFeatures { let chanmon_cfgs = create_chanmon_cfgs(2); let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); - config.channel_handshake_config.max_inbound_htlc_value_in_flight_percent_of_channel = 100; + config.channel_handshake_config.announced_channel_max_inbound_htlc_value_in_flight_percentage = + 100; let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[Some(config.clone()), Some(config)]); let nodes = create_network(2, &node_cfgs, &node_chanmgrs); @@ -2465,7 +2466,8 @@ fn do_test_accept_inbound_channel_from_trusted_peer_0reserve( ) -> ChannelTypeFeatures { let chanmon_cfgs = create_chanmon_cfgs(2); let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); - config.channel_handshake_config.max_inbound_htlc_value_in_flight_percent_of_channel = 100; + config.channel_handshake_config.announced_channel_max_inbound_htlc_value_in_flight_percentage = + 100; let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[Some(config.clone()), Some(config)]); let nodes = create_network(2, &node_cfgs, &node_chanmgrs); @@ -2679,7 +2681,8 @@ fn do_test_0reserve_no_outputs_legacy(no_outputs_case: LegacyChannelsNoOutputs) let chanmon_cfgs = create_chanmon_cfgs(2); let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); - config.channel_handshake_config.max_inbound_htlc_value_in_flight_percent_of_channel = 100; + config.channel_handshake_config.announced_channel_max_inbound_htlc_value_in_flight_percentage = + 100; let channel_type = ChannelTypeFeatures::only_static_remote_key(); @@ -2979,7 +2982,8 @@ fn do_test_0reserve_no_outputs_keyed_anchors(payment_success: bool) { let chanmon_cfgs = create_chanmon_cfgs(2); let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); - config.channel_handshake_config.max_inbound_htlc_value_in_flight_percent_of_channel = 100; + config.channel_handshake_config.announced_channel_max_inbound_htlc_value_in_flight_percentage = + 100; let channel_type = ChannelTypeFeatures::anchors_zero_htlc_fee_and_dependencies(); @@ -3112,7 +3116,8 @@ fn do_test_0reserve_no_outputs_p2a_anchor() { let chanmon_cfgs = create_chanmon_cfgs(2); let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); - config.channel_handshake_config.max_inbound_htlc_value_in_flight_percent_of_channel = 100; + config.channel_handshake_config.announced_channel_max_inbound_htlc_value_in_flight_percentage = + 100; let channel_type = ChannelTypeFeatures::anchors_zero_fee_commitments(); @@ -3170,7 +3175,8 @@ fn do_test_0reserve_force_close_with_single_p2a_output(high_feerate: bool) { *feerate_lock = 2500; } let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); - config.channel_handshake_config.max_inbound_htlc_value_in_flight_percent_of_channel = 100; + config.channel_handshake_config.announced_channel_max_inbound_htlc_value_in_flight_percentage = + 100; let channel_type = ChannelTypeFeatures::anchors_zero_fee_commitments(); @@ -3276,7 +3282,8 @@ fn test_0reserve_zero_conf_combined() { let chanmon_cfgs = create_chanmon_cfgs(2); let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); let mut config = test_default_channel_config(); - config.channel_handshake_config.max_inbound_htlc_value_in_flight_percent_of_channel = 100; + config.channel_handshake_config.announced_channel_max_inbound_htlc_value_in_flight_percentage = + 100; let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[Some(config.clone()), Some(config)]); let nodes = create_network(2, &node_cfgs, &node_chanmgrs); diff --git a/lightning/src/ln/monitor_tests.rs b/lightning/src/ln/monitor_tests.rs index efd2084a38e..f52f093917b 100644 --- a/lightning/src/ln/monitor_tests.rs +++ b/lightning/src/ln/monitor_tests.rs @@ -2724,6 +2724,8 @@ fn do_test_anchors_aggregated_revoked_htlc_tx(p2a_anchor: bool) { anchors_config.channel_handshake_config.announce_for_forwarding = true; anchors_config.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx = true; anchors_config.channel_handshake_config.negotiate_anchor_zero_fee_commitments = p2a_anchor; + // Set the percentage to the default value at the time this test was written + anchors_config.channel_handshake_config.announced_channel_max_inbound_htlc_value_in_flight_percentage = 10; let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[Some(anchors_config.clone()), Some(anchors_config.clone())]); let bob_deserialized; diff --git a/lightning/src/ln/payment_tests.rs b/lightning/src/ln/payment_tests.rs index be52459a872..807d1a1af39 100644 --- a/lightning/src/ln/payment_tests.rs +++ b/lightning/src/ln/payment_tests.rs @@ -45,7 +45,7 @@ use crate::sign::EntropySource; use crate::types::features::{Bolt11InvoiceFeatures, ChannelTypeFeatures}; use crate::types::payment::{PaymentHash, PaymentPreimage, PaymentSecret}; use crate::types::string::UntrustedString; -use crate::util::config::HTLCInterceptionFlags; +use crate::util::config::{HTLCInterceptionFlags, UserConfig}; use crate::util::errors::APIError; use crate::util::ser::Writeable; use bitcoin::hashes::sha256::Hash as Sha256; @@ -212,7 +212,9 @@ fn mpp_retry_overpay() { let node_cfgs = create_node_cfgs(4, &chanmon_cfgs); let mut user_config = test_legacy_channel_config(); - user_config.channel_handshake_config.max_inbound_htlc_value_in_flight_percent_of_channel = 100; + user_config + .channel_handshake_config + .announced_channel_max_inbound_htlc_value_in_flight_percentage = 100; let mut limited_1 = user_config.clone(); limited_1.channel_handshake_config.our_htlc_minimum_msat = 35_000_000; let mut limited_2 = user_config.clone(); @@ -487,7 +489,12 @@ fn do_test_keysend_payments(public_node: bool) { fn test_mpp_keysend() { let chanmon_cfgs = create_chanmon_cfgs(4); let node_cfgs = create_node_cfgs(4, &chanmon_cfgs); - let node_chanmgrs = create_node_chanmgrs(4, &node_cfgs, &[None, None, None, None]); + let mut config = test_default_channel_config(); + // Set the percentage to the default value at the time this test was written + config.channel_handshake_config.announced_channel_max_inbound_htlc_value_in_flight_percentage = + 10; + let configs: [Option; 4] = core::array::from_fn(|_| Some(config.clone())); + let node_chanmgrs = create_node_chanmgrs(4, &node_cfgs, &configs); let nodes = create_network(4, &node_cfgs, &node_chanmgrs); let node_b_id = nodes[1].node.get_our_node_id(); @@ -1702,7 +1709,8 @@ fn preflight_probes_yield_event_skip_private_hop() { // We alleviate the HTLC max-in-flight limit, as otherwise we'd always be limited through that. let mut config = test_default_channel_config(); - config.channel_handshake_config.max_inbound_htlc_value_in_flight_percent_of_channel = 100; + config.channel_handshake_config.announced_channel_max_inbound_htlc_value_in_flight_percentage = + 100; let config = Some(config); let configs = [config.clone(), config.clone(), config.clone(), config.clone(), config]; @@ -1749,7 +1757,8 @@ fn preflight_probes_yield_event() { // We alleviate the HTLC max-in-flight limit, as otherwise we'd always be limited through that. let mut config = test_default_channel_config(); - config.channel_handshake_config.max_inbound_htlc_value_in_flight_percent_of_channel = 100; + config.channel_handshake_config.announced_channel_max_inbound_htlc_value_in_flight_percentage = + 100; let config = Some(config); let configs = [config.clone(), config.clone(), config.clone(), config]; @@ -1800,7 +1809,8 @@ fn preflight_probes_yield_event_and_skip() { // We alleviate the HTLC max-in-flight limit, as otherwise we'd always be limited through that. let mut config = test_default_channel_config(); - config.channel_handshake_config.max_inbound_htlc_value_in_flight_percent_of_channel = 100; + config.channel_handshake_config.announced_channel_max_inbound_htlc_value_in_flight_percentage = + 100; let config = Some(config); let configs = @@ -2429,11 +2439,12 @@ fn do_accept_underpaying_htlcs_config(num_mpp_parts: usize) { HTLCInterceptionFlags::ToInterceptSCIDs as u8; intercept_forwards_config .channel_handshake_config - .max_inbound_htlc_value_in_flight_percent_of_channel = max_in_flight_percent; + .announced_channel_max_inbound_htlc_value_in_flight_percentage = max_in_flight_percent; let mut underpay_config = test_default_channel_config(); underpay_config.channel_config.accept_underpaying_htlcs = true; - underpay_config.channel_handshake_config.max_inbound_htlc_value_in_flight_percent_of_channel = - max_in_flight_percent; + underpay_config + .channel_handshake_config + .unannounced_channel_max_inbound_htlc_value_in_flight_percentage = max_in_flight_percent; let configs = [None, Some(intercept_forwards_config), Some(underpay_config)]; let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &configs); @@ -3220,7 +3231,12 @@ fn retry_multi_path_single_failed_payment() { // Tests that we can/will retry after a single path of an MPP payment failed immediately let chanmon_cfgs = create_chanmon_cfgs(2); let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); - let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None, None]); + let mut config = test_default_channel_config(); + // Set the percentage to the default value at the time this test was written + config.channel_handshake_config.announced_channel_max_inbound_htlc_value_in_flight_percentage = + 10; + let node_chanmgrs = + create_node_chanmgrs(2, &node_cfgs, &[Some(config.clone()), Some(config.clone())]); let nodes = create_network(2, &node_cfgs, &node_chanmgrs); let node_b_id = nodes[1].node.get_our_node_id(); @@ -3339,7 +3355,12 @@ fn immediate_retry_on_failure() { // Tests that we can/will retry immediately after a failure let chanmon_cfgs = create_chanmon_cfgs(2); let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); - let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None, None]); + let mut config = test_default_channel_config(); + // Set the percentage to the default value at the time this test was written + config.channel_handshake_config.announced_channel_max_inbound_htlc_value_in_flight_percentage = + 10; + let node_chanmgrs = + create_node_chanmgrs(2, &node_cfgs, &[Some(config.clone()), Some(config.clone())]); let nodes = create_network(2, &node_cfgs, &node_chanmgrs); let node_b_id = nodes[1].node.get_our_node_id(); @@ -4240,17 +4261,13 @@ fn do_claim_from_closed_chan(fail_payment: bool) { // CLTVs on the paths to different value resulting in a different claim deadline. let chanmon_cfgs = create_chanmon_cfgs(4); let node_cfgs = create_node_cfgs(4, &chanmon_cfgs); - let legacy_cfg = test_legacy_channel_config(); - let node_chanmgrs = create_node_chanmgrs( - 4, - &node_cfgs, - &[ - Some(legacy_cfg.clone()), - Some(legacy_cfg.clone()), - Some(legacy_cfg.clone()), - Some(legacy_cfg), - ], - ); + let mut legacy_cfg = test_legacy_channel_config(); + // Set the percentage to the default value at the time this test was written + legacy_cfg + .channel_handshake_config + .announced_channel_max_inbound_htlc_value_in_flight_percentage = 10; + let configs: [Option; 4] = core::array::from_fn(|_| Some(legacy_cfg.clone())); + let node_chanmgrs = create_node_chanmgrs(4, &node_cfgs, &configs); let mut nodes = create_network(4, &node_cfgs, &node_chanmgrs); let node_a_id = nodes[0].node.get_our_node_id(); @@ -4635,7 +4652,12 @@ fn do_test_custom_tlvs_consistency( ) { let chanmon_cfgs = create_chanmon_cfgs(4); let node_cfgs = create_node_cfgs(4, &chanmon_cfgs); - let node_chanmgrs = create_node_chanmgrs(4, &node_cfgs, &[None, None, None, None]); + let mut config = test_default_channel_config(); + // Set the percentage to the default value at the time this test was written + config.channel_handshake_config.announced_channel_max_inbound_htlc_value_in_flight_percentage = + 10; + let configs: [Option; 4] = core::array::from_fn(|_| Some(config.clone())); + let node_chanmgrs = create_node_chanmgrs(4, &node_cfgs, &configs); let nodes = create_network(4, &node_cfgs, &node_chanmgrs); let node_a_id = nodes[0].node.get_our_node_id(); @@ -4788,7 +4810,8 @@ fn do_test_payment_metadata_consistency(do_reload: bool, do_modify: bool) { let chain_mon; let mut config = test_default_channel_config(); - config.channel_handshake_config.max_inbound_htlc_value_in_flight_percent_of_channel = 50; + config.channel_handshake_config.announced_channel_max_inbound_htlc_value_in_flight_percentage = + 50; let configs = [None, Some(config.clone()), Some(config.clone()), Some(config.clone())]; let node_chanmgrs = create_node_chanmgrs(4, &node_cfgs, &configs); let node_d_reload; @@ -5147,7 +5170,8 @@ fn test_non_strict_forwarding() { let node_cfgs = create_node_cfgs(3, &chanmon_cfgs); let mut config = test_legacy_channel_config(); - config.channel_handshake_config.max_inbound_htlc_value_in_flight_percent_of_channel = 100; + config.channel_handshake_config.announced_channel_max_inbound_htlc_value_in_flight_percentage = + 100; let configs = [Some(config.clone()), Some(config.clone()), Some(config)]; let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &configs); @@ -5386,11 +5410,15 @@ fn max_out_mpp_path() { let mut user_cfg = test_default_channel_config(); user_cfg.channel_config.forwarding_fee_base_msat = 0; - user_cfg.channel_handshake_config.max_inbound_htlc_value_in_flight_percent_of_channel = 100; + user_cfg + .channel_handshake_config + .unannounced_channel_max_inbound_htlc_value_in_flight_percentage = 100; let mut lsp_cfg = test_default_channel_config(); lsp_cfg.channel_config.forwarding_fee_base_msat = 0; lsp_cfg.channel_config.forwarding_fee_proportional_millionths = 3000; - lsp_cfg.channel_handshake_config.max_inbound_htlc_value_in_flight_percent_of_channel = 100; + lsp_cfg + .channel_handshake_config + .unannounced_channel_max_inbound_htlc_value_in_flight_percentage = 100; let chanmon_cfgs = create_chanmon_cfgs(3); let node_cfgs = create_node_cfgs(3, &chanmon_cfgs); diff --git a/lightning/src/ln/reload_tests.rs b/lightning/src/ln/reload_tests.rs index 892a6c62d8f..9e992467ecd 100644 --- a/lightning/src/ln/reload_tests.rs +++ b/lightning/src/ln/reload_tests.rs @@ -745,7 +745,11 @@ fn do_test_partial_claim_before_restart(persist_both_monitors: bool, double_rest let (persist_d_1, persist_d_2); let (chain_d_1, chain_d_2); - let node_chanmgrs = create_node_chanmgrs(4, &node_cfgs, &[None, None, None, None]); + let mut config = test_default_channel_config(); + // Set the percentage to the default value at the time this test was written + config.channel_handshake_config.announced_channel_max_inbound_htlc_value_in_flight_percentage = 10; + let configs: [Option; 4] = core::array::from_fn(|_| Some(config.clone())); + let node_chanmgrs = create_node_chanmgrs(4, &node_cfgs, &configs); let (node_d_1, node_d_2); let mut nodes = create_network(4, &node_cfgs, &node_chanmgrs); @@ -2107,7 +2111,11 @@ fn test_reload_with_mpp_claims_on_same_channel() { let node_cfgs = create_node_cfgs(3, &chanmon_cfgs); let persister; let new_chain_monitor; - let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]); + let mut config = test_default_channel_config(); + // Set the percentage to the default value at the time this test was written + config.channel_handshake_config.announced_channel_max_inbound_htlc_value_in_flight_percentage = 10; + let configs: [Option; 3] = core::array::from_fn(|_| Some(config.clone())); + let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &configs); let nodes_1_deserialized; let mut nodes = create_network(3, &node_cfgs, &node_chanmgrs); diff --git a/lightning/src/ln/splicing_tests.rs b/lightning/src/ln/splicing_tests.rs index 5279f2dfcc0..e4c4c10dbbd 100644 --- a/lightning/src/ln/splicing_tests.rs +++ b/lightning/src/ln/splicing_tests.rs @@ -1122,7 +1122,8 @@ fn test_splice_in() { let chanmon_cfgs = create_chanmon_cfgs(2); let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); let mut config = test_default_channel_config(); - config.channel_handshake_config.max_inbound_htlc_value_in_flight_percent_of_channel = 100; + config.channel_handshake_config.announced_channel_max_inbound_htlc_value_in_flight_percentage = + 100; let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, Some(config)]); let nodes = create_network(2, &node_cfgs, &node_chanmgrs); @@ -1172,7 +1173,8 @@ fn test_splice_out() { let chanmon_cfgs = create_chanmon_cfgs(2); let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); let mut config = test_default_channel_config(); - config.channel_handshake_config.max_inbound_htlc_value_in_flight_percent_of_channel = 100; + config.channel_handshake_config.announced_channel_max_inbound_htlc_value_in_flight_percentage = + 100; let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, Some(config)]); let nodes = create_network(2, &node_cfgs, &node_chanmgrs); @@ -1215,7 +1217,8 @@ fn test_splice_in_and_out() { let chanmon_cfgs = create_chanmon_cfgs(2); let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); let mut config = test_default_channel_config(); - config.channel_handshake_config.max_inbound_htlc_value_in_flight_percent_of_channel = 100; + config.channel_handshake_config.announced_channel_max_inbound_htlc_value_in_flight_percentage = + 100; let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, Some(config)]); let nodes = create_network(2, &node_cfgs, &node_chanmgrs); @@ -3546,7 +3549,8 @@ fn test_splice_balance_falls_below_reserve() { let chanmon_cfgs = create_chanmon_cfgs(2); let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); let mut config = test_default_channel_config(); - config.channel_handshake_config.max_inbound_htlc_value_in_flight_percent_of_channel = 100; + config.channel_handshake_config.announced_channel_max_inbound_htlc_value_in_flight_percentage = + 100; let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[Some(config.clone()), Some(config)]); let nodes = create_network(2, &node_cfgs, &node_chanmgrs); @@ -4066,19 +4070,22 @@ fn test_funding_contributed_unfunded_channel() { #[test] fn test_splice_pending_htlcs() { let mut config = test_default_channel_config(); - config.channel_handshake_config.max_inbound_htlc_value_in_flight_percent_of_channel = 100; + config.channel_handshake_config.announced_channel_max_inbound_htlc_value_in_flight_percentage = + 100; config.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx = false; config.channel_handshake_config.negotiate_anchor_zero_fee_commitments = false; do_test_splice_pending_htlcs(config); let mut config = test_default_channel_config(); - config.channel_handshake_config.max_inbound_htlc_value_in_flight_percent_of_channel = 100; + config.channel_handshake_config.announced_channel_max_inbound_htlc_value_in_flight_percentage = + 100; config.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx = true; config.channel_handshake_config.negotiate_anchor_zero_fee_commitments = false; do_test_splice_pending_htlcs(config); let mut config = test_default_channel_config(); - config.channel_handshake_config.max_inbound_htlc_value_in_flight_percent_of_channel = 100; + config.channel_handshake_config.announced_channel_max_inbound_htlc_value_in_flight_percentage = + 100; config.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx = false; config.channel_handshake_config.negotiate_anchor_zero_fee_commitments = true; do_test_splice_pending_htlcs(config); @@ -6298,7 +6305,8 @@ fn test_splice_revalidation_at_quiescence() { let chanmon_cfgs = create_chanmon_cfgs(2); let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); let mut config = test_default_channel_config(); - config.channel_handshake_config.max_inbound_htlc_value_in_flight_percent_of_channel = 100; + config.channel_handshake_config.announced_channel_max_inbound_htlc_value_in_flight_percentage = + 100; let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[Some(config.clone()), Some(config)]); let nodes = create_network(2, &node_cfgs, &node_chanmgrs); diff --git a/lightning/src/ln/update_fee_tests.rs b/lightning/src/ln/update_fee_tests.rs index fc80059bbd3..b1f8257088e 100644 --- a/lightning/src/ln/update_fee_tests.rs +++ b/lightning/src/ln/update_fee_tests.rs @@ -1031,7 +1031,8 @@ pub fn do_cannot_afford_on_holding_cell_release( let chanmon_cfgs = create_chanmon_cfgs(2); let mut cfg = test_legacy_channel_config(); - cfg.channel_handshake_config.max_inbound_htlc_value_in_flight_percent_of_channel = 100; + cfg.channel_handshake_config.announced_channel_max_inbound_htlc_value_in_flight_percentage = + 100; if channel_type_features.supports_anchors_zero_fee_htlc_tx() { cfg.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx = true; } @@ -1225,7 +1226,9 @@ pub fn do_can_afford_given_trimmed_htlcs(inequality_regions: core::cmp::Ordering let chanmon_cfgs = create_chanmon_cfgs(2); let mut legacy_cfg = test_legacy_channel_config(); - legacy_cfg.channel_handshake_config.max_inbound_htlc_value_in_flight_percent_of_channel = 100; + legacy_cfg + .channel_handshake_config + .announced_channel_max_inbound_htlc_value_in_flight_percentage = 100; let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); let node_chanmgrs = diff --git a/lightning/src/util/config.rs b/lightning/src/util/config.rs index 14c507184ac..ebef8c27bca 100644 --- a/lightning/src/util/config.rs +++ b/lightning/src/util/config.rs @@ -62,17 +62,35 @@ 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. + /// Sets the maximum percentage of the total channel value that can be allocated to inbound + /// HTLCs in announced channels. /// /// 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: `25` /// + /// Minimum value: `1` (Any values less will be treated as `1` instead.) + /// + /// Maximum value: `100` (Any values larger will be treated as `100` instead.) + pub announced_channel_max_inbound_htlc_value_in_flight_percentage: u8, + /// Sets the maximum percentage of the total channel value that can be allocated to inbound + /// HTLCs in unannounced channels. + /// + /// 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: /// * 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. /// @@ -82,12 +100,12 @@ pub struct ChannelHandshakeConfig { /// See [`ChannelHandshakeConfig::our_to_self_delay`] and [`ChannelConfig::cltv_expiry_delta`] /// for more information. /// - /// Default value: `10` + /// Default value: `100` /// /// Minimum value: `1` (Any values less will be treated as `1` instead.) /// /// Maximum value: `100` (Any values larger will be treated as `100` instead.) - pub max_inbound_htlc_value_in_flight_percent_of_channel: u8, + pub unannounced_channel_max_inbound_htlc_value_in_flight_percentage: 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 @@ -246,7 +264,8 @@ 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, + announced_channel_max_inbound_htlc_value_in_flight_percentage: 25, + unannounced_channel_max_inbound_htlc_value_in_flight_percentage: 100, negotiate_scid_privacy: false, announce_for_forwarding: false, commit_upfront_shutdown_pubkey: true, @@ -264,11 +283,21 @@ impl Default for ChannelHandshakeConfig { #[cfg(fuzzing)] impl Readable for ChannelHandshakeConfig { fn read(reader: &mut R) -> Result { + let minimum_depth = Readable::read(reader)?; + let our_to_self_delay = Readable::read(reader)?; + let our_htlc_minimum_msat = Readable::read(reader)?; + // Apply the same byte to both the announced and the unannounced maximums so as to + // not invalidate the existing fuzz corpus + let max_inbound_htlc_value_in_flight_percentage = Readable::read(reader)?; + Ok(Self { - minimum_depth: Readable::read(reader)?, - our_to_self_delay: Readable::read(reader)?, - our_htlc_minimum_msat: Readable::read(reader)?, - max_inbound_htlc_value_in_flight_percent_of_channel: Readable::read(reader)?, + minimum_depth, + our_to_self_delay, + our_htlc_minimum_msat, + announced_channel_max_inbound_htlc_value_in_flight_percentage: + max_inbound_htlc_value_in_flight_percentage, + unannounced_channel_max_inbound_htlc_value_in_flight_percentage: + max_inbound_htlc_value_in_flight_percentage, negotiate_scid_privacy: Readable::read(reader)?, announce_for_forwarding: Readable::read(reader)?, commit_upfront_shutdown_pubkey: Readable::read(reader)?, @@ -1171,9 +1200,15 @@ impl UserConfig { /// Config structure for overriding channel handshake parameters. #[derive(Default)] pub struct ChannelHandshakeConfigUpdate { - /// Overrides the percentage of the channel value we will cap the total value of outstanding inbound HTLCs to. See - /// [`ChannelHandshakeConfig::max_inbound_htlc_value_in_flight_percent_of_channel`]. - pub max_inbound_htlc_value_in_flight_percent_of_channel: Option, + /// Overrides the maximum percentage of the total channel value that can be allocated to inbound + /// HTLCs in announced channels. See + /// [`ChannelHandshakeConfig::announced_channel_max_inbound_htlc_value_in_flight_percentage`]. + pub announced_channel_max_inbound_htlc_value_in_flight_percentage: Option, + + /// Overrides the maximum percentage of the total channel value that can be allocated to inbound + /// HTLCs in unannounced channels. See + /// [`ChannelHandshakeConfig::unannounced_channel_max_inbound_htlc_value_in_flight_percentage`]. + pub unannounced_channel_max_inbound_htlc_value_in_flight_percentage: Option, /// Overrides the smallest value HTLC we will accept to process. See [`ChannelHandshakeConfig::our_htlc_minimum_msat`]. pub htlc_minimum_msat: Option, @@ -1199,9 +1234,17 @@ impl ChannelHandshakeConfig { /// Applies the provided handshake config update. pub fn apply(&mut self, config: &ChannelHandshakeConfigUpdate) { if let Some(max_in_flight_percent) = - config.max_inbound_htlc_value_in_flight_percent_of_channel + config.announced_channel_max_inbound_htlc_value_in_flight_percentage + { + self.announced_channel_max_inbound_htlc_value_in_flight_percentage = + max_in_flight_percent; + } + + if let Some(max_in_flight_percent) = + config.unannounced_channel_max_inbound_htlc_value_in_flight_percentage { - self.max_inbound_htlc_value_in_flight_percent_of_channel = max_in_flight_percent; + self.unannounced_channel_max_inbound_htlc_value_in_flight_percentage = + max_in_flight_percent; } if let Some(htlc_minimum_msat) = config.htlc_minimum_msat {