Skip to content

Commit 5fffe77

Browse files
committed
ln/refactor: use get_initial_channel_type for channel downgrade
Rather than duplicating our channel type preference ordering in downgrade logic, make a modified version of the remote peer's supported features and remove our current channel type from it to get the next preferred channel type.
1 parent 588f490 commit 5fffe77

File tree

2 files changed

+110
-19
lines changed

2 files changed

+110
-19
lines changed

lightning/src/ln/channel.rs

Lines changed: 45 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1557,6 +1557,7 @@ impl<SP: Deref> Channel<SP> where
15571557

15581558
pub fn maybe_handle_error_without_close<F: Deref, L: Deref>(
15591559
&mut self, chain_hash: ChainHash, fee_estimator: &LowerBoundedFeeEstimator<F>, logger: &L,
1560+
user_config: &UserConfig, their_features: &InitFeatures,
15601561
) -> Result<Option<OpenChannelMessage>, ()>
15611562
where
15621563
F::Target: FeeEstimator,
@@ -1567,13 +1568,17 @@ impl<SP: Deref> Channel<SP> where
15671568
ChannelPhase::Funded(_) => Ok(None),
15681569
ChannelPhase::UnfundedOutboundV1(chan) => {
15691570
let logger = WithChannelContext::from(logger, &chan.context, None);
1570-
chan.maybe_handle_error_without_close(chain_hash, fee_estimator, &&logger)
1571+
chan.maybe_handle_error_without_close(
1572+
chain_hash, fee_estimator, &&logger, user_config, their_features,
1573+
)
15711574
.map(|msg| Some(OpenChannelMessage::V1(msg)))
15721575
},
15731576
ChannelPhase::UnfundedInboundV1(_) => Ok(None),
15741577
ChannelPhase::UnfundedV2(chan) => {
15751578
if chan.funding.is_outbound() {
1576-
chan.maybe_handle_error_without_close(chain_hash, fee_estimator)
1579+
chan.maybe_handle_error_without_close(
1580+
chain_hash, fee_estimator, user_config, their_features,
1581+
)
15771582
.map(|msg| Some(OpenChannelMessage::V2(msg)))
15781583
} else {
15791584
Ok(None)
@@ -4868,7 +4873,8 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
48684873
/// of the channel type we tried, not of our ability to open any channel at all. We can see if a
48694874
/// downgrade of channel features would be possible so that we can still open the channel.
48704875
pub(crate) fn maybe_downgrade_channel_features<F: Deref>(
4871-
&mut self, funding: &mut FundingScope, fee_estimator: &LowerBoundedFeeEstimator<F>
4876+
&mut self, funding: &mut FundingScope, fee_estimator: &LowerBoundedFeeEstimator<F>,
4877+
user_config: &UserConfig, their_features: &InitFeatures,
48724878
) -> Result<(), ()>
48734879
where
48744880
F::Target: FeeEstimator
@@ -4889,21 +4895,35 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
48894895
// features one by one until we've either arrived at our default or the counterparty has
48904896
// accepted one.
48914897
//
4892-
// Due to the order below, we may not negotiate `option_anchors_zero_fee_htlc_tx` if the
4893-
// counterparty doesn't support `option_scid_privacy`. Since `get_initial_channel_type`
4894-
// checks whether the counterparty supports every feature, this would only happen if the
4895-
// counterparty is advertising the feature, but rejecting channels proposing the feature for
4896-
// whatever reason.
4897-
let channel_type = &mut funding.channel_transaction_parameters.channel_type_features;
4898+
// To downgrade the current channel type, we start with the remote party's full set of
4899+
// feature bits and un-set any features that are set for the current channel type or any
4900+
// channel types that come before it in our order of preference. This will allow us to
4901+
// negotiate the "next best" channel type per our ranking in `get_initial_channel_type`.
4902+
let channel_type = &funding.channel_transaction_parameters.channel_type_features;
4903+
let mut eligible_features = their_features.clone();
4904+
48984905
if channel_type.supports_anchors_zero_fee_htlc_tx() {
4899-
channel_type.clear_anchors_zero_fee_htlc_tx();
4900-
self.feerate_per_kw = fee_estimator.bounded_sat_per_1000_weight(ConfirmationTarget::NonAnchorChannelFee);
4901-
assert!(!channel_type.supports_anchors_nonzero_fee_htlc_tx());
4906+
eligible_features.clear_anchors_zero_fee_htlc_tx();
4907+
assert!(!eligible_features.supports_anchors_nonzero_fee_htlc_tx());
4908+
assert!(!eligible_features.supports_anchors_zero_fee_htlc_tx());
49024909
} else if channel_type.supports_scid_privacy() {
4903-
channel_type.clear_scid_privacy();
4904-
} else {
4905-
*channel_type = ChannelTypeFeatures::only_static_remote_key();
4910+
eligible_features.clear_scid_privacy();
4911+
eligible_features.clear_anchors_zero_fee_htlc_tx();
4912+
assert!(!eligible_features.supports_scid_privacy());
4913+
assert!(!eligible_features.supports_anchors_nonzero_fee_htlc_tx());
4914+
assert!(!eligible_features.supports_anchors_zero_fee_htlc_tx());
49064915
}
4916+
4917+
let next_channel_type = get_initial_channel_type(user_config, &eligible_features);
4918+
4919+
let conf_target = if next_channel_type.supports_anchors_zero_fee_htlc_tx() {
4920+
ConfirmationTarget::AnchorChannelFee
4921+
} else {
4922+
ConfirmationTarget::NonAnchorChannelFee
4923+
};
4924+
self.feerate_per_kw = fee_estimator.bounded_sat_per_1000_weight(conf_target);
4925+
funding.channel_transaction_parameters.channel_type_features = next_channel_type;
4926+
49074927
Ok(())
49084928
}
49094929

@@ -9893,13 +9913,16 @@ impl<SP: Deref> OutboundV1Channel<SP> where SP::Target: SignerProvider {
98939913
/// not of our ability to open any channel at all. Thus, on error, we should first call this
98949914
/// and see if we get a new `OpenChannel` message, otherwise the channel is failed.
98959915
pub(crate) fn maybe_handle_error_without_close<F: Deref, L: Deref>(
9896-
&mut self, chain_hash: ChainHash, fee_estimator: &LowerBoundedFeeEstimator<F>, logger: &L
9916+
&mut self, chain_hash: ChainHash, fee_estimator: &LowerBoundedFeeEstimator<F>, logger: &L,
9917+
user_config: &UserConfig, their_features: &InitFeatures,
98979918
) -> Result<msgs::OpenChannel, ()>
98989919
where
98999920
F::Target: FeeEstimator,
99009921
L::Target: Logger,
99019922
{
9902-
self.context.maybe_downgrade_channel_features(&mut self.funding, fee_estimator)?;
9923+
self.context.maybe_downgrade_channel_features(
9924+
&mut self.funding, fee_estimator, user_config, their_features,
9925+
)?;
99039926
self.get_open_channel(chain_hash, logger).ok_or(())
99049927
}
99059928

@@ -10405,12 +10428,15 @@ impl<SP: Deref> PendingV2Channel<SP> where SP::Target: SignerProvider {
1040510428
/// not of our ability to open any channel at all. Thus, on error, we should first call this
1040610429
/// and see if we get a new `OpenChannelV2` message, otherwise the channel is failed.
1040710430
pub(crate) fn maybe_handle_error_without_close<F: Deref>(
10408-
&mut self, chain_hash: ChainHash, fee_estimator: &LowerBoundedFeeEstimator<F>
10431+
&mut self, chain_hash: ChainHash, fee_estimator: &LowerBoundedFeeEstimator<F>,
10432+
user_config: &UserConfig, their_features: &InitFeatures,
1040910433
) -> Result<msgs::OpenChannelV2, ()>
1041010434
where
1041110435
F::Target: FeeEstimator
1041210436
{
10413-
self.context.maybe_downgrade_channel_features(&mut self.funding, fee_estimator)?;
10437+
self.context.maybe_downgrade_channel_features(
10438+
&mut self.funding, fee_estimator, user_config, their_features,
10439+
)?;
1041410440
Ok(self.get_open_channel_v2(chain_hash))
1041510441
}
1041610442

lightning/src/ln/channelmanager.rs

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12472,6 +12472,7 @@ where
1247212472
match peer_state.channel_by_id.get_mut(&msg.channel_id) {
1247312473
Some(chan) => match chan.maybe_handle_error_without_close(
1247412474
self.chain_hash, &self.fee_estimator, &self.logger,
12475+
&self.default_configuration, &peer_state.latest_features,
1247512476
) {
1247612477
Ok(Some(OpenChannelMessage::V1(msg))) => {
1247712478
peer_state.pending_msg_events.push(MessageSendEvent::SendOpenChannel {
@@ -16368,6 +16369,31 @@ mod tests {
1636816369
do_test_channel_type_downgrade(initiator_cfg, receiver_cfg, start_type, vec![end_type]);
1636916370
}
1637016371

16372+
#[test]
16373+
fn test_scid_privacy_downgrade() {
16374+
// Tests downgrade from `anchors_zero_fee_htlc_tx` with `option_scid_alias` when the
16375+
// remote node advertises the features but does not accept the channel, asserting that
16376+
// `option_scid_alias` is the last feature to be downgraded.
16377+
let mut initiator_cfg = test_default_channel_config();
16378+
initiator_cfg.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx = true;
16379+
initiator_cfg.channel_handshake_config.negotiate_scid_privacy = true;
16380+
initiator_cfg.channel_handshake_config.announce_for_forwarding = false;
16381+
16382+
let mut receiver_cfg = test_default_channel_config();
16383+
receiver_cfg.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx = true;
16384+
receiver_cfg.channel_handshake_config.negotiate_scid_privacy = true;
16385+
receiver_cfg.manually_accept_inbound_channels = true;
16386+
16387+
let mut start_type = ChannelTypeFeatures::anchors_zero_htlc_fee_and_dependencies();
16388+
start_type.set_scid_privacy_required();
16389+
let mut with_scid_privacy = ChannelTypeFeatures::only_static_remote_key();
16390+
with_scid_privacy.set_scid_privacy_required();
16391+
let static_remote = ChannelTypeFeatures::only_static_remote_key();
16392+
let downgrade_types = vec![with_scid_privacy, static_remote];
16393+
16394+
do_test_channel_type_downgrade(initiator_cfg, receiver_cfg, start_type, downgrade_types);
16395+
}
16396+
1637116397
#[rustfmt::skip]
1637216398
fn do_test_channel_type_downgrade(initiator_cfg: UserConfig, acceptor_cfg: UserConfig,
1637316399
start_type: ChannelTypeFeatures, downgrade_types: Vec<ChannelTypeFeatures>) {
@@ -16404,6 +16430,45 @@ mod tests {
1640416430
}
1640516431
}
1640616432

16433+
#[test]
16434+
#[rustfmt::skip]
16435+
fn test_no_channel_downgrade() {
16436+
// Tests that the local node will not retry when a `option_static_remote` channel is
16437+
// rejected by a peer that advertises support for the feature.
16438+
let initiator_cfg = test_default_channel_config();
16439+
let mut receiver_cfg = test_default_channel_config();
16440+
receiver_cfg.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx = true;
16441+
receiver_cfg.manually_accept_inbound_channels = true;
16442+
16443+
let chanmon_cfgs = create_chanmon_cfgs(2);
16444+
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
16445+
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[Some(initiator_cfg), Some(receiver_cfg)]);
16446+
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
16447+
let error_message = "Channel force-closed";
16448+
16449+
nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100_000, 0, 0, None, None).unwrap();
16450+
let open_channel_msg = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
16451+
let start_type = ChannelTypeFeatures::only_static_remote_key();
16452+
assert_eq!(open_channel_msg.common_fields.channel_type.as_ref().unwrap(), &start_type);
16453+
16454+
nodes[1].node.handle_open_channel(nodes[0].node.get_our_node_id(), &open_channel_msg);
16455+
let events = nodes[1].node.get_and_clear_pending_events();
16456+
match events[0] {
16457+
Event::OpenChannelRequest { temporary_channel_id, .. } => {
16458+
nodes[1].node.force_close_broadcasting_latest_txn(&temporary_channel_id, &nodes[0].node.get_our_node_id(), error_message.to_string()).unwrap();
16459+
}
16460+
_ => panic!("Unexpected event"),
16461+
}
16462+
16463+
let error_msg = get_err_msg(&nodes[1], &nodes[0].node.get_our_node_id());
16464+
nodes[0].node.handle_error(nodes[1].node.get_our_node_id(), &error_msg);
16465+
16466+
// Since nodes[0] could not retry the channel with a different type, it should close it.
16467+
let chan_closed_events = nodes[0].node.get_and_clear_pending_events();
16468+
assert_eq!(chan_closed_events.len(), 1);
16469+
if let Event::ChannelClosed { .. } = chan_closed_events[0] { } else { panic!(); }
16470+
}
16471+
1640716472
#[test]
1640816473
#[rustfmt::skip]
1640916474
fn test_update_channel_config() {

0 commit comments

Comments
 (0)