Skip to content

Add option to generate outbound scid alias using intercept namespace #3839

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 22 additions & 7 deletions lightning/src/ln/channelmanager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3771,19 +3771,21 @@ where

#[cfg(test)]
pub fn create_and_insert_outbound_scid_alias_for_test(&self) -> u64 {
self.create_and_insert_outbound_scid_alias()
self.create_and_insert_outbound_scid_alias_with_namespace(
fake_scid::Namespace::OutboundAlias
)
}

#[rustfmt::skip]
fn create_and_insert_outbound_scid_alias(&self) -> u64 {
fn create_and_insert_outbound_scid_alias_with_namespace(&self, namespace: fake_scid::Namespace) -> u64 {
let height = self.best_block.read().unwrap().height;
let mut outbound_scid_alias = 0;
let mut i = 0;
loop {
if cfg!(fuzzing) { // fuzzing chacha20 doesn't use the key at all so we always get the same alias
outbound_scid_alias += 1;
} else {
outbound_scid_alias = fake_scid::Namespace::OutboundAlias.get_fake_scid(height, &self.chain_hash, &self.fake_scid_rand_bytes, &self.entropy_source);
outbound_scid_alias = namespace.get_fake_scid(height, &self.chain_hash, &self.fake_scid_rand_bytes, &self.entropy_source);
}
if outbound_scid_alias != 0 && self.outbound_scid_aliases.lock().unwrap().insert(outbound_scid_alias) {
break;
Expand All @@ -3794,6 +3796,15 @@ where
outbound_scid_alias
}

/// Determines the appropriate outbound SCID namespace based on the intercept_htlcs_on_channel configuration.
fn get_outbound_scid_namespace(intercept_htlcs_on_channel: bool) -> fake_scid::Namespace {
if intercept_htlcs_on_channel {
fake_scid::Namespace::Intercept
} else {
fake_scid::Namespace::OutboundAlias
}
}

/// Creates a new outbound channel to the given remote node and with the given value.
///
/// `user_channel_id` will be provided back as in
Expand Down Expand Up @@ -3850,9 +3861,10 @@ where
}

let mut channel = {
let outbound_scid_alias = self.create_and_insert_outbound_scid_alias();
let their_features = &peer_state.latest_features;
let config = if override_config.is_some() { override_config.as_ref().unwrap() } else { &self.default_configuration };
let outbound_scid_namespace = Self::get_outbound_scid_namespace(config.channel_handshake_config.intercept_htlcs_on_channel);
let outbound_scid_alias = self.create_and_insert_outbound_scid_alias_with_namespace(outbound_scid_namespace);
let their_features = &peer_state.latest_features;
match OutboundV1Channel::new(&self.fee_estimator, &self.entropy_source, &self.signer_provider, their_network_key,
their_features, channel_value_satoshis, push_msat, user_channel_id, config,
self.best_block.read().unwrap().height, outbound_scid_alias, temporary_channel_id, &*self.logger)
Expand Down Expand Up @@ -8191,7 +8203,8 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
}

// Now that we know we have a channel, assign an outbound SCID alias.
let outbound_scid_alias = self.create_and_insert_outbound_scid_alias();
let outbound_scid_namespace = Self::get_outbound_scid_namespace(config.channel_handshake_config.intercept_htlcs_on_channel);
let outbound_scid_alias = self.create_and_insert_outbound_scid_alias_with_namespace(outbound_scid_namespace);
channel.context_mut().set_outbound_scid_alias(outbound_scid_alias);

if let Some(message_send_event) = message_send_event {
Expand Down Expand Up @@ -8407,7 +8420,8 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
},
};

let outbound_scid_alias = self.create_and_insert_outbound_scid_alias();
let outbound_scid_namespace = Self::get_outbound_scid_namespace(self.default_configuration.channel_handshake_config.intercept_htlcs_on_channel);
let outbound_scid_alias = self.create_and_insert_outbound_scid_alias_with_namespace(outbound_scid_namespace);
channel.context_mut().set_outbound_scid_alias(outbound_scid_alias);

if let Some(message_send_event) = message_send_event {
Expand Down Expand Up @@ -16303,6 +16317,7 @@ mod tests {
to_self_delay: Some(200),
max_accepted_htlcs: Some(5),
channel_reserve_proportional_millionths: Some(20000),
intercept_htlcs_on_channel: None,
}),
update_overrides: None,
};
Expand Down
1 change: 1 addition & 0 deletions lightning/src/ln/functional_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7474,6 +7474,7 @@ pub fn test_manually_accept_inbound_channel_request() {
to_self_delay: None,
max_accepted_htlcs: Some(3),
channel_reserve_proportional_millionths: None,
intercept_htlcs_on_channel: None,
}),
update_overrides: Some(ChannelConfigUpdate {
forwarding_fee_proportional_millionths: None,
Expand Down
21 changes: 21 additions & 0 deletions lightning/src/util/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,18 @@ pub struct ChannelHandshakeConfig {
///
/// [`max_htlcs`]: crate::ln::chan_utils::max_htlcs
pub our_max_accepted_htlcs: u16,
/// If set, this channel's SCID alias will be generated in the intercept namespace, causing
/// all HTLCs sent to this channel to trigger [`Event::HTLCIntercepted`] events instead of
/// being automatically forwarded. This enables manual control over all payments to the channel.
///
/// Requires [`UserConfig::accept_intercept_htlcs`] to be `true`. Useful for scenarios like
/// fee-taking or conditional forwarding.
///
/// Default value: `false`
///
/// [`Event::HTLCIntercepted`]: crate::events::Event::HTLCIntercepted
/// [`UserConfig::accept_intercept_htlcs`]: crate::util::config::UserConfig::accept_intercept_htlcs
pub intercept_htlcs_on_channel: bool,
}

impl Default for ChannelHandshakeConfig {
Expand All @@ -250,6 +262,7 @@ impl Default for ChannelHandshakeConfig {
#[cfg(test)]
negotiate_anchor_zero_fee_commitments: false,
our_max_accepted_htlcs: 50,
intercept_htlcs_on_channel: false,
}
}
}
Expand All @@ -273,6 +286,7 @@ impl Readable for ChannelHandshakeConfig {
#[cfg(test)]
negotiate_anchor_zero_fee_commitments: Readable::read(reader)?,
our_max_accepted_htlcs: Readable::read(reader)?,
intercept_htlcs_on_channel: Readable::read(reader)?,
})
}
}
Expand Down Expand Up @@ -1009,6 +1023,9 @@ pub struct ChannelHandshakeConfigUpdate {
/// The Proportion of the channel value to configure as counterparty's channel reserve. See
/// [`ChannelHandshakeConfig::their_channel_reserve_proportional_millionths`].
pub channel_reserve_proportional_millionths: Option<u32>,
/// If set, allows this channel's SCID alias to be generated in the intercept namespace. See
/// [`ChannelHandshakeConfig::intercept_htlcs_on_channel`].
pub intercept_htlcs_on_channel: Option<bool>,
}

impl ChannelHandshakeConfig {
Expand Down Expand Up @@ -1039,5 +1056,9 @@ impl ChannelHandshakeConfig {
if let Some(channel_reserve) = config.channel_reserve_proportional_millionths {
self.their_channel_reserve_proportional_millionths = channel_reserve;
}

if let Some(intercept_htlcs) = config.intercept_htlcs_on_channel {
self.intercept_htlcs_on_channel = intercept_htlcs;
}
}
}
Loading