Set max channel dust limit to 10,000 sats for all zero-fee-htlc-tx chans
What changed, and why it matters
This change loosens the maximum 'dust limit' that rust-lightning will accept from a channel peer, but only for modern channel types that use zero-fee HTLC transactions (keyed-anchor and 0FC channels). For older channel types the old, stricter 546-satoshi limit remains. The patch is a protocol-compliance/robustness fix rather than a clear vulnerability fix, and it includes a test update.
Treat as a normal protocol-compliance update. Review issue #4225 and any related BOLT/discussion context to confirm the 10,000-satoshi bound is well-justified and does not introduce HTLC pinning or fee-griefing risks. Run the updated channel_open_tests.
Security signals we found
Dust-limit validation change in channel handshake
Different trust boundary for modern vs legacy channel types
Referenced issue #4225 (content not supplied)
No explicit security framing in commit message or diff
Evidence from the diff
The commit raises MAX_CHAN_DUST_LIMIT_SATOSHIS from 546 to 10,000 sats and introduces a separate MAX_LEGACY_CHAN_DUST_LIMIT_SATOSHIS kept at 546. During channel open and accept validation, the effective cap is chosen based on whether the channel type supports anchors_zero_fee_htlc_tx or anchor_zero_fee_commitments. The rationale in the commit message is that in zero-fee-HTLC-tx channels the HTLC dust limit is independent of the negotiated feerate, so a higher counterparty dust limit is acceptable. A test is updated to exercise the new 10,001-satoshi rejection threshold for the new channel types.
Changed components
lightning/src/ln/channel.rslightning/src/ln/channel_open_tests.rsInspect captured patch +22 / −8
diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs
index 704039b..ab36272 100644
--- a/lightning/src/ln/channel.rs
+++ b/lightning/src/ln/channel.rs
@@ -982,8 +982,11 @@ pub const TOTAL_BITCOIN_SUPPLY_SATOSHIS: u64 = 21_000_000 * 1_0000_0000;
/// implementations use this value for their dust limit today.
pub const MAX_STD_OUTPUT_DUST_LIMIT_SATOSHIS: u64 = 546;
+/// The maximum channel dust limit we will accept from our counterparty for non-anchor channels.
+pub const MAX_LEGACY_CHAN_DUST_LIMIT_SATOSHIS: u64 = MAX_STD_OUTPUT_DUST_LIMIT_SATOSHIS;
+
/// The maximum channel dust limit we will accept from our counterparty.
-pub const MAX_CHAN_DUST_LIMIT_SATOSHIS: u64 = MAX_STD_OUTPUT_DUST_LIMIT_SATOSHIS;
+pub const MAX_CHAN_DUST_LIMIT_SATOSHIS: u64 = 10_000;
/// The dust limit is used for both the commitment transaction outputs as well as the closing
/// transactions. For cooperative closing transactions, we require segwit outputs, though accept
@@ -3644,8 +3647,14 @@ impl<SP: SignerProvider> ChannelContext<SP> {
if open_channel_fields.dust_limit_satoshis < MIN_CHAN_DUST_LIMIT_SATOSHIS {
return Err(ChannelError::close(format!("dust_limit_satoshis ({}) is less than the implementation limit ({})", open_channel_fields.dust_limit_satoshis, MIN_CHAN_DUST_LIMIT_SATOSHIS)));
}
- if open_channel_fields.dust_limit_satoshis > MAX_CHAN_DUST_LIMIT_SATOSHIS {
- return Err(ChannelError::close(format!("dust_limit_satoshis ({}) is greater than the implementation limit ({})", open_channel_fields.dust_limit_satoshis, MAX_CHAN_DUST_LIMIT_SATOSHIS)));
+
+ let max_chan_dust_limit_satoshis = if channel_type.supports_anchors_zero_fee_htlc_tx() || channel_type.supports_anchor_zero_fee_commitments() {
+ MAX_CHAN_DUST_LIMIT_SATOSHIS
+ } else {
+ MAX_LEGACY_CHAN_DUST_LIMIT_SATOSHIS
+ };
+ if open_channel_fields.dust_limit_satoshis > max_chan_dust_limit_satoshis {
+ return Err(ChannelError::close(format!("dust_limit_satoshis ({}) is greater than the implementation limit ({})", open_channel_fields.dust_limit_satoshis, max_chan_dust_limit_satoshis)));
}
// Convert things into internal flags and prep our state:
@@ -4426,8 +4435,14 @@ impl<SP: SignerProvider> ChannelContext<SP> {
if common_fields.dust_limit_satoshis < MIN_CHAN_DUST_LIMIT_SATOSHIS {
return Err(ChannelError::close(format!("dust_limit_satoshis ({}) is less than the implementation limit ({})", common_fields.dust_limit_satoshis, MIN_CHAN_DUST_LIMIT_SATOSHIS)));
}
- if common_fields.dust_limit_satoshis > MAX_CHAN_DUST_LIMIT_SATOSHIS {
- return Err(ChannelError::close(format!("dust_limit_satoshis ({}) is greater than the implementation limit ({})", common_fields.dust_limit_satoshis, MAX_CHAN_DUST_LIMIT_SATOSHIS)));
+
+ let max_chan_dust_limit_satoshis = if channel_type.supports_anchors_zero_fee_htlc_tx() || channel_type.supports_anchor_zero_fee_commitments() {
+ MAX_CHAN_DUST_LIMIT_SATOSHIS
+ } else {
+ MAX_LEGACY_CHAN_DUST_LIMIT_SATOSHIS
+ };
+ if common_fields.dust_limit_satoshis > max_chan_dust_limit_satoshis {
+ return Err(ChannelError::close(format!("dust_limit_satoshis ({}) is greater than the implementation limit ({})", common_fields.dust_limit_satoshis, max_chan_dust_limit_satoshis)));
}
if common_fields.minimum_depth > peer_limits.max_minimum_depth {
return Err(ChannelError::close(format!("We consider the minimum depth to be unreasonably large. Expected minimum: ({}). Actual: ({})", peer_limits.max_minimum_depth, common_fields.minimum_depth)));
diff --git a/lightning/src/ln/channel_open_tests.rs b/lightning/src/ln/channel_open_tests.rs
index 9a65e34..e13343a 100644
--- a/lightning/src/ln/channel_open_tests.rs
+++ b/lightning/src/ln/channel_open_tests.rs
@@ -880,8 +880,7 @@ pub fn bolt2_open_channel_sane_dust_limit() {
nodes[0].node.create_channel(node_b_id, value_sats, push_msat, 42, None, None).unwrap();
let mut node0_to_1_send_open_channel =
get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, node_b_id);
- node0_to_1_send_open_channel.common_fields.dust_limit_satoshis = 547;
- node0_to_1_send_open_channel.channel_reserve_satoshis = 100001;
+ node0_to_1_send_open_channel.common_fields.dust_limit_satoshis = 10_001;
nodes[1].node.handle_open_channel(node_a_id, &node0_to_1_send_open_channel);
let events = nodes[1].node.get_and_clear_pending_events();
@@ -893,7 +892,7 @@ pub fn bolt2_open_channel_sane_dust_limit() {
{
Err(APIError::ChannelUnavailable { err }) => assert_eq!(
err,
- "dust_limit_satoshis (547) is greater than the implementation limit (546)"
+ "dust_limit_satoshis (10001) is greater than the implementation limit (10000)"
),
_ => panic!(),
},
Why this scored 47/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.