Conditionally advertise htlc_hold feature
What changed, and why it matters
This commit removes test-only restrictions on a feature called htlc_hold, allowing regular users to enable it. The feature lets an often-offline payer hold outbound payments temporarily at the next hop. It is a normal feature rollout, not a fix for an active attack or bug. There is no direct evidence in the commit that this change addresses a security vulnerability.
Review the htlc_hold logic for correctness and denial-of-service risks before enabling in production; no immediate security patch appears required based on this commit alone.
Security signals we found
Feature-gated code moved from test-only to production
Change in serialized config format (fuzz seed updates)
Feature bit advertisement now depends on user configuration
Evidence from the diff
The change removes #[cfg(test)] guards from UserConfig::enable_htlc_hold and from the code in channelmanager.rs that advertises the htlc_hold_optional init feature bit. It also adds enable_htlc_hold to the UserConfig deserialization path and updates fuzz test seeds to account for the changed serialized config size. The commit message frames this as enabling conditional advertisement of a feature bit now that the implementation supports often-offline senders/recipients.
Changed components
lightning/src/util/config.rslightning/src/ln/channelmanager.rsfuzz/src/full_stack.rsInspect captured patch +3 / −7
diff --git a/fuzz/src/full_stack.rs b/fuzz/src/full_stack.rs
index 0d6768e..ee5f457 100644
--- a/fuzz/src/full_stack.rs
+++ b/fuzz/src/full_stack.rs
@@ -1048,7 +1048,7 @@ fn two_peer_forwarding_seed() -> Vec<u8> {
// our network key
ext_from_hex("0100000000000000000000000000000000000000000000000000000000000000", &mut test);
// config
- ext_from_hex("000000000090000000000000000064000100000000000100ffff0000000000000000ffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff000000ffffffff00ffff1a000400010000020400000000040200000a08ffffffffffffffff00010000000000", &mut test);
+ ext_from_hex("000000000090000000000000000064000100000000000100ffff0000000000000000ffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff000000ffffffff00ffff1a000400010000020400000000040200000a08ffffffffffffffff0001000000000000", &mut test);
// new outbound connection with id 0
ext_from_hex("00", &mut test);
@@ -1502,7 +1502,7 @@ fn gossip_exchange_seed() -> Vec<u8> {
// our network key
ext_from_hex("0100000000000000000000000000000000000000000000000000000000000000", &mut test);
// config
- ext_from_hex("000000000090000000000000000064000100000000000100ffff0000000000000000ffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff000000ffffffff00ffff1a000400010000020400000000040200000a08ffffffffffffffff00010000000000", &mut test);
+ ext_from_hex("000000000090000000000000000064000100000000000100ffff0000000000000000ffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff000000ffffffff00ffff1a000400010000020400000000040200000a08ffffffffffffffff0001000000000000", &mut test);
// new outbound connection with id 0
ext_from_hex("00", &mut test);
diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs
index c1d38a0..dc51021 100644
--- a/lightning/src/ln/channelmanager.rs
+++ b/lightning/src/ln/channelmanager.rs
@@ -15203,9 +15203,6 @@ pub fn provided_init_features(config: &UserConfig) -> InitFeatures {
features.set_anchor_zero_fee_commitments_optional();
}
- // If we are configured to be an announced node, we are expected to be always-online and can
- // advertise the htlc_hold feature.
- #[cfg(test)]
if config.enable_htlc_hold {
features.set_htlc_hold_optional();
}
diff --git a/lightning/src/util/config.rs b/lightning/src/util/config.rs
index e52a9c3..079ed19 100644
--- a/lightning/src/util/config.rs
+++ b/lightning/src/util/config.rs
@@ -941,7 +941,6 @@ pub struct UserConfig {
/// Setting this to `true` may break backwards compatibility with LDK versions < 0.2.
///
/// Default value: `false`
- #[cfg(test)]
pub enable_htlc_hold: bool,
/// If this is set to true, then if we as an often-offline payer receive a [`StaticInvoice`] to
/// pay, we will attempt to hold the corresponding outbound HTLCs with our next-hop channel
@@ -971,7 +970,6 @@ impl Default for UserConfig {
accept_intercept_htlcs: false,
manually_handle_bolt12_invoices: false,
enable_dual_funded_channels: false,
- #[cfg(test)]
enable_htlc_hold: false,
hold_outbound_htlcs_at_next_hop: false,
}
@@ -995,6 +993,7 @@ impl Readable for UserConfig {
manually_handle_bolt12_invoices: Readable::read(reader)?,
enable_dual_funded_channels: Readable::read(reader)?,
hold_outbound_htlcs_at_next_hop: Readable::read(reader)?,
+ enable_htlc_hold: Readable::read(reader)?,
})
}
}
Why this scored 27/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.