Exit quiescence when splice_init is rejected with Abort
What changed, and why it matters
This commit fixes a state-handling bug in the Lightning Dev Kit's splicing feature. When a splice attempt is rejected because the proposed transaction fee rate is too high, the code now properly exits 'quiescence' (a temporary pause in normal channel activity) before returning the error. Previously, the channel could remain stuck in quiescence, which might disrupt normal channel operation and message flow.
Review related error paths in channelmanager.rs for similar failures to exit quiescence before returning abort errors. Ensure all splice/RBF error paths are covered by tests asserting quiescence cleanup.
Security signals we found
State inconsistency: channel remains in quiescence after abort
Denial-of-service-like symptom: disrupted channel message flow
Fix mirrors a prior similar fix for tx_init_rbf
Error path not exiting quiescence is a known bug class in this codebase
Test updated to assert correct post-abort behavior
Evidence from the diff
In channelmanager.rs, internal_splice_init previously allowed a ChannelError::Abort from resolve_queued_contribution (e.g., triggered by FeeRateTooHigh) to pass through try_channel_entry! without first calling exit_quiescence(). This left the channel in a quiescent state after aborting the splice. The patch intercepts ChannelError::Abort, calls funded_channel.exit_quiescence(), and returns the error with exited_quiescence set to true. A test in splicing_tests.rs is updated to verify that after rejection, the node sends both a TxAbort and a new Stfu (re-proposing quiescence due to a pending QuiescentAction).
Changed components
lightning/src/ln/channelmanager.rslightning/src/ln/splicing_tests.rsLDK splicing protocol implementationChannel quiescence state machineInspect captured patch +26 / −2
diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs
index 7a5d0b1..ae027da 100644
--- a/lightning/src/ln/channelmanager.rs
+++ b/lightning/src/ln/channelmanager.rs
@@ -13414,6 +13414,15 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
&self.get_our_node_id(),
&self.logger,
);
+ if let Err(ChannelError::Abort(_)) = &init_res {
+ funded_channel.exit_quiescence();
+ let chan_id = funded_channel.context.channel_id();
+ let res = MsgHandleErrInternal::from_chan_no_close(
+ init_res.unwrap_err(),
+ chan_id,
+ );
+ return Err(res.with_exited_quiescence(true));
+ }
let splice_ack_msg = try_channel_entry!(self, peer_state, init_res, chan_entry);
peer_state.pending_msg_events.push(MessageSendEvent::SendSpliceAck {
node_id: *counterparty_node_id,
diff --git a/lightning/src/ln/splicing_tests.rs b/lightning/src/ln/splicing_tests.rs
index 10f3434..1902df5 100644
--- a/lightning/src/ln/splicing_tests.rs
+++ b/lightning/src/ln/splicing_tests.rs
@@ -1709,10 +1709,25 @@ fn test_splice_tiebreak_feerate_too_high_rejected() {
let splice_init = get_event_msg!(nodes[0], MessageSendEvent::SendSpliceInit, node_id_1);
// Node 1 handles SpliceInit — TooHigh: target (100k) >> max (3k) and fair fee > budget.
+ // Node 1 exits quiescence upon rejecting with tx_abort, and since it has a pending
+ // QuiescentAction (from its own splice attempt), it immediately re-proposes quiescence.
nodes[1].node.handle_splice_init(node_id_0, &splice_init);
- let tx_abort = get_event_msg!(nodes[1], MessageSendEvent::SendTxAbort, node_id_0);
- assert_eq!(tx_abort.channel_id, channel_id);
+ let msg_events = nodes[1].node.get_and_clear_pending_msg_events();
+ assert_eq!(msg_events.len(), 2);
+ match &msg_events[0] {
+ MessageSendEvent::SendTxAbort { node_id, msg } => {
+ assert_eq!(*node_id, node_id_0);
+ assert_eq!(msg.channel_id, channel_id);
+ },
+ _ => panic!("Expected SendTxAbort, got {:?}", msg_events[0]),
+ };
+ match &msg_events[1] {
+ MessageSendEvent::SendStfu { node_id, .. } => {
+ assert_eq!(*node_id, node_id_0);
+ },
+ _ => panic!("Expected SendStfu, got {:?}", msg_events[1]),
+ };
}
#[cfg(test)]
Why this scored 53/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.