Skip to content

Commit 09b6e73

Browse files
authored
Merge pull request #4630 from wpaulino/avoid-splice-check-non-initiator-stfu
Avoid splice checks when responding to stfu
2 parents 4773cb8 + dbb1c96 commit 09b6e73

2 files changed

Lines changed: 71 additions & 20 deletions

File tree

lightning/src/ln/channel.rs

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -14669,7 +14669,24 @@ where
1466914669
return None;
1467014670
}
1467114671

14672-
if let Some(action) = self.quiescent_action.as_ref() {
14672+
if self.context.is_waiting_on_peer_pending_channel_update()
14673+
|| self.context.is_monitor_or_signer_pending_channel_update()
14674+
{
14675+
log_given_level!(
14676+
logger,
14677+
logger_level,
14678+
"Waiting for state machine pending changes to complete before sending stfu"
14679+
);
14680+
return None;
14681+
}
14682+
14683+
let initiator = if self.context.channel_state.is_remote_stfu_sent() {
14684+
// Since we may have also attempted to initiate quiescence but the counterparty
14685+
// initiated first, we'll retry after we're no longer quiescent.
14686+
self.context.channel_state.clear_remote_stfu_sent();
14687+
self.context.channel_state.set_quiescent();
14688+
false
14689+
} else if let Some(action) = self.quiescent_action.as_ref() {
1467314690
#[allow(irrefutable_let_patterns)]
1467414691
if let QuiescentAction::Splice { contribution, .. } = action {
1467514692
if self.pending_splice.is_some() {
@@ -14696,29 +14713,16 @@ where
1469614713
}
1469714714
}
1469814715
}
14699-
}
1470014716

14701-
if self.context.is_waiting_on_peer_pending_channel_update()
14702-
|| self.context.is_monitor_or_signer_pending_channel_update()
14703-
{
14704-
log_given_level!(
14705-
logger,
14706-
logger_level,
14707-
"Waiting for state machine pending changes to complete before sending stfu"
14708-
);
14709-
return None;
14710-
}
14711-
14712-
let initiator = if self.context.channel_state.is_remote_stfu_sent() {
14713-
// Since we may have also attempted to initiate quiescence but the counterparty
14714-
// initiated first, we'll retry after we're no longer quiescent.
14715-
self.context.channel_state.clear_remote_stfu_sent();
14716-
self.context.channel_state.set_quiescent();
14717-
false
14718-
} else {
1471914717
log_debug!(logger, "Sending stfu as quiescence initiator");
1472014718
self.context.channel_state.set_local_stfu_sent();
1472114719
true
14720+
} else {
14721+
debug_assert!(
14722+
false,
14723+
"Either we have a pending quiescent action or need to respond to the counterparty"
14724+
);
14725+
false
1472214726
};
1472314727

1472414728
Some(msgs::Stfu { channel_id: self.context.channel_id, initiator })

lightning/src/ln/splicing_tests.rs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8088,6 +8088,53 @@ fn test_funding_contributed_rbf_adjustment_exceeds_max_feerate() {
80888088
assert_eq!(splice_init.funding_feerate_per_kw, FEERATE_FLOOR_SATS_PER_KW);
80898089
}
80908090

8091+
#[test]
8092+
fn test_peer_initiated_stfu_skips_local_rbf_feerate_check() {
8093+
// Test that a local low-fee splice RBF attempt does not prevent us from responding to a
8094+
// counterparty-initiated quiescence attempt.
8095+
let chanmon_cfgs = create_chanmon_cfgs(2);
8096+
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
8097+
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
8098+
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
8099+
8100+
let node_id_0 = nodes[0].node.get_our_node_id();
8101+
let node_id_1 = nodes[1].node.get_our_node_id();
8102+
8103+
let initial_channel_value_sat = 100_000;
8104+
let (_, _, channel_id, _) =
8105+
create_announced_chan_between_nodes_with_value(&nodes, 0, 1, initial_channel_value_sat, 0);
8106+
8107+
let added_value = Amount::from_sat(50_000);
8108+
provide_utxo_reserves(&nodes, 4, added_value * 2);
8109+
8110+
let floor_feerate = FeeRate::from_sat_per_kwu(FEERATE_FLOOR_SATS_PER_KW as u64);
8111+
let node_0_template = nodes[0].node.splice_channel(&channel_id, &node_id_1).unwrap();
8112+
let wallet = WalletSync::new(Arc::clone(&nodes[0].wallet_source), nodes[0].logger);
8113+
let node_0_contribution =
8114+
node_0_template.splice_in_sync(added_value, floor_feerate, floor_feerate, &wallet).unwrap();
8115+
8116+
// Node 1 creates a pending splice before node 0 submits its contribution. Node 0's
8117+
// contribution cannot be adjusted up to the pending splice's minimum RBF feerate, so it must
8118+
// not send its own stfu yet.
8119+
let node_1_contribution = do_initiate_splice_in(&nodes[1], &nodes[0], channel_id, added_value);
8120+
let (_first_splice_tx, _) =
8121+
splice_channel(&nodes[1], &nodes[0], channel_id, node_1_contribution);
8122+
nodes[0].node.funding_contributed(&channel_id, &node_id_1, node_0_contribution, None).unwrap();
8123+
assert!(nodes[0].node.get_and_clear_pending_msg_events().is_empty());
8124+
8125+
// Node 1 can still initiate quiescence for its own RBF attempt. Node 0 should reply as the
8126+
// non-initiator instead of applying its local splice RBF feerate check to the response.
8127+
let min_rbf_feerate = FeeRate::from_sat_per_kwu(FEERATE_FLOOR_SATS_PER_KW as u64 + 25);
8128+
let _node_1_rbf_contribution =
8129+
do_initiate_rbf_splice_in(&nodes[1], &nodes[0], channel_id, min_rbf_feerate);
8130+
let stfu_init = get_event_msg!(nodes[1], MessageSendEvent::SendStfu, node_id_0);
8131+
assert!(stfu_init.initiator);
8132+
8133+
nodes[0].node.handle_stfu(node_id_1, &stfu_init);
8134+
let stfu_response = get_event_msg!(nodes[0], MessageSendEvent::SendStfu, node_id_1);
8135+
assert!(!stfu_response.initiator);
8136+
}
8137+
80918138
#[test]
80928139
fn test_funding_contributed_rbf_adjustment_insufficient_budget() {
80938140
// Test that when the change output can't absorb the fee increase needed for the minimum RBF feerate

0 commit comments

Comments
 (0)