Add `unannounced_channel_max_inbound_htlc_value_in_flight_percentage`
What changed, and why it matters
This commit is a feature change, not a security bug fix. It splits one setting into two: the maximum share of a channel's value that can be tied up in incoming payments (HTLCs). Announced channels now default to 25% and unannounced (private) channels default to 100%. The change also updates many tests to keep their old behavior by explicitly setting the previous 10% default. There is no direct vulnerability in the diff, but the higher defaults slightly increase funds-at-risk if a node goes offline while many HTLCs are pending.
Review whether the new 100% default for unannounced channels matches your risk model; explicitly configure lower limits if you operate private channels and want to limit offline-exposure risk. No immediate patch or incident response is required.
Security signals we found
Configuration change that increases default inbound HTLC exposure limits
No input validation bypass or unsafe arithmetic introduced
Legacy serialization path maintained for backward compatibility
No attribution of a security report in commit or vendor material
Evidence from the diff
The patch replaces the single max_inbound_htlc_value_in_flight_percent_of_channel config field with two fields: announced_channel_max_inbound_htlc_value_in_flight_percentage and unannounced_channel_max_inbound_htlc_value_in_flight_percentage. get_holder_max_htlc_value_in_flight_msat now selects the appropriate percentage based on announce_for_forwarding. Defaults changed from 10% to 25% for announced channels and 100% for unannounced channels. Serialization compatibility is preserved by writing the legacy default when the value matches the old default, and a dedicated get_legacy_default_holder_max_htlc_value_in_flight_msat helper is added. Tests are updated to pin the old 10% value where needed. No memory-safety, cryptographic, or protocol-integrity flaw is visible in the diff.
Changed components
lightning/src/util/config.rslightning/src/ln/channel.rslightning/src/ln/*_tests.rsInspect captured patch +288 / −101
diff --git a/lightning/src/ln/async_payments_tests.rs b/lightning/src/ln/async_payments_tests.rs
index 2552234..341bd5d 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 e148ce2..d62f799 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<UserConfig>; 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<UserConfig>; 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 dd799c2..af4d156 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<UserConfig>; 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 03f78dc..5579c11 100644
--- a/lightning/src/ln/channel.rs
+++ b/lightning/src/ln/channel.rs
@@ -4102,6 +4102,7 @@ impl<SP: SignerProvider> ChannelContext<SP> {
),
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<SP: SignerProvider> ChannelContext<SP> {
// 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<SP: SignerProvider> ChannelContext<SP> {
/// 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<SP: SignerProvider> Writeable for FundedChannel<SP> {
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 d28d157..ac4a1b6 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 7ed4692..32a07be 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<UserConfig>; 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<UserConfig>; 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 608ac14..aaf81b8 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 efd2084..f52f093 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 be52459..807d1a1 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<UserConfig>; 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<UserConfig>; 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<UserConfig>; 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 892a6c6..9e99246 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<UserConfig>; 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<UserConfig>; 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 5279f2d..e4c4c10 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 fc80059..b1f8257 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 14c5071..ebef8c2 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<R: crate::io::Read>(reader: &mut R) -> Result<Self, crate::ln::msgs::DecodeError> {
+ 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<u8>,
+ /// 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<u8>,
+
+ /// 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<u8>,
/// Overrides the smallest value HTLC we will accept to process. See [`ChannelHandshakeConfig::our_htlc_minimum_msat`].
pub htlc_minimum_msat: Option<u64>,
@@ -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 {
Why this scored 30/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.