Skip to content

Commit c929248

Browse files
jkczyzclaude
andcommitted
Remove exited_quiescence from error handling
The `exited_quiescence` field on `MsgHandleErrInternal` and `InteractiveTxMsgError` is a leaky abstraction -- the channelmanager error handling shouldn't know about quiescence, only whether the holding cell needs to be released. Infer this from the presence of a `tx_abort` instead, since exiting quiescence via an error always produces one. Remove `exited_quiescence` from `InteractiveTxMsgError`, `MsgHandleErrInternal`, and the return type of `Channel::tx_abort`, along with the `with_exited_quiescence` builder. For unfunded v2 channels, `tx_abort` may be present without quiescence having been exited, but the holding cell release is a no-op since an unfunded channel won't have any HTLCs. Similarly, the unreachable `debug_assert!(false)` branch in `fail_interactive_tx_negotiation` for funded channels produces a `tx_abort` without exiting quiescence, but the holding cell release is a no-op since the channel is still quiescent. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 98ec3e4 commit c929248

2 files changed

Lines changed: 33 additions & 62 deletions

File tree

lightning/src/ln/channel.rs

Lines changed: 16 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1172,9 +1172,6 @@ pub(super) struct InteractiveTxMsgError {
11721172
/// If a splice was in progress when processing the message, this contains the splice funding
11731173
/// information for emitting a `SpliceFailed` event.
11741174
pub(super) splice_funding_failed: Option<SpliceFundingFailed>,
1175-
/// Whether we were quiescent when we received the message, and are no longer due to aborting
1176-
/// the session.
1177-
pub(super) exited_quiescence: bool,
11781175
}
11791176

11801177
/// The return value of `monitor_updating_restored`
@@ -1818,30 +1815,24 @@ where
18181815
let logger = WithChannelContext::from(logger, &self.context(), None);
18191816
log_info!(logger, "Failed interactive transaction negotiation: {reason}");
18201817

1821-
let (splice_funding_failed, exited_quiescence) = match &mut self.phase {
1818+
let splice_funding_failed = match &mut self.phase {
18221819
ChannelPhase::Undefined => unreachable!(),
1823-
ChannelPhase::UnfundedOutboundV1(_) | ChannelPhase::UnfundedInboundV1(_) => {
1824-
(None, false)
1825-
},
1820+
ChannelPhase::UnfundedOutboundV1(_) | ChannelPhase::UnfundedInboundV1(_) => None,
18261821
ChannelPhase::UnfundedV2(pending_v2_channel) => {
18271822
pending_v2_channel.interactive_tx_constructor.take();
1828-
(None, false)
1823+
None
18291824
},
18301825
ChannelPhase::Funded(funded_channel) => {
18311826
if funded_channel.should_reset_pending_splice_state(false) {
1832-
(funded_channel.reset_pending_splice_state(), true)
1827+
funded_channel.reset_pending_splice_state()
18331828
} else {
18341829
debug_assert!(false, "We should never fail an interactive funding negotiation once we're exchanging tx_signatures");
1835-
(None, false)
1830+
None
18361831
}
18371832
},
18381833
};
18391834

1840-
InteractiveTxMsgError {
1841-
err: ChannelError::Abort(reason),
1842-
splice_funding_failed,
1843-
exited_quiescence,
1844-
}
1835+
InteractiveTxMsgError { err: ChannelError::Abort(reason), splice_funding_failed }
18451836
}
18461837

18471838
pub fn tx_add_input<L: Logger>(
@@ -1856,7 +1847,6 @@ where
18561847
"Received unexpected interactive transaction negotiation message".to_owned(),
18571848
),
18581849
splice_funding_failed: None,
1859-
exited_quiescence: false,
18601850
}),
18611851
}
18621852
}
@@ -1873,7 +1863,6 @@ where
18731863
"Received unexpected interactive transaction negotiation message".to_owned(),
18741864
),
18751865
splice_funding_failed: None,
1876-
exited_quiescence: false,
18771866
}),
18781867
}
18791868
}
@@ -1890,7 +1879,6 @@ where
18901879
"Received unexpected interactive transaction negotiation message".to_owned(),
18911880
),
18921881
splice_funding_failed: None,
1893-
exited_quiescence: false,
18941882
}),
18951883
}
18961884
}
@@ -1907,7 +1895,6 @@ where
19071895
"Received unexpected interactive transaction negotiation message".to_owned(),
19081896
),
19091897
splice_funding_failed: None,
1910-
exited_quiescence: false,
19111898
}),
19121899
}
19131900
}
@@ -1924,7 +1911,6 @@ where
19241911
return Err(InteractiveTxMsgError {
19251912
err: ChannelError::WarnAndDisconnect(err.to_owned()),
19261913
splice_funding_failed: None,
1927-
exited_quiescence: false,
19281914
});
19291915
},
19301916
};
@@ -1985,13 +1971,13 @@ where
19851971

19861972
pub fn tx_abort<L: Logger>(
19871973
&mut self, msg: &msgs::TxAbort, logger: &L,
1988-
) -> Result<(Option<msgs::TxAbort>, Option<SpliceFundingFailed>, bool), ChannelError> {
1974+
) -> Result<(Option<msgs::TxAbort>, Option<SpliceFundingFailed>), ChannelError> {
19891975
// If we have not sent a `tx_abort` message for this negotiation previously, we need to echo
19901976
// back a tx_abort message according to the spec:
19911977
// https://github.com/lightning/bolts/blob/247e83d/02-peer-protocol.md?plain=1#L560-L561
19921978
// For rationale why we echo back `tx_abort`:
19931979
// https://github.com/lightning/bolts/blob/247e83d/02-peer-protocol.md?plain=1#L578-L580
1994-
let (should_ack, splice_funding_failed, exited_quiescence) = match &mut self.phase {
1980+
let (should_ack, splice_funding_failed) = match &mut self.phase {
19951981
ChannelPhase::Undefined => unreachable!(),
19961982
ChannelPhase::UnfundedOutboundV1(_) | ChannelPhase::UnfundedInboundV1(_) => {
19971983
let err = "Got an unexpected tx_abort message: This is an unfunded channel created with V1 channel establishment";
@@ -2000,7 +1986,7 @@ where
20001986
ChannelPhase::UnfundedV2(pending_v2_channel) => {
20011987
let had_constructor =
20021988
pending_v2_channel.interactive_tx_constructor.take().is_some();
2003-
(had_constructor, None, false)
1989+
(had_constructor, None)
20041990
},
20051991
ChannelPhase::Funded(funded_channel) => {
20061992
if funded_channel.has_pending_splice_awaiting_signatures()
@@ -2028,11 +2014,11 @@ where
20282014
.unwrap_or(false);
20292015
debug_assert!(has_funding_negotiation);
20302016
let splice_funding_failed = funded_channel.reset_pending_splice_state();
2031-
(true, splice_funding_failed, true)
2017+
(true, splice_funding_failed)
20322018
} else {
20332019
// We were not tracking the pending funding negotiation state anymore, likely
20342020
// due to a disconnection or already having sent our own `tx_abort`.
2035-
(false, None, false)
2021+
(false, None)
20362022
}
20372023
},
20382024
};
@@ -2048,7 +2034,7 @@ where
20482034
}
20492035
});
20502036

2051-
Ok((tx_abort, splice_funding_failed, exited_quiescence))
2037+
Ok((tx_abort, splice_funding_failed))
20522038
}
20532039

20542040
#[rustfmt::skip]
@@ -14286,13 +14272,11 @@ where
1428614272
}
1428714273

1428814274
fn quiescent_negotiation_err(&mut self, err: ChannelError) -> InteractiveTxMsgError {
14289-
let exited_quiescence = if matches!(err, ChannelError::Abort(_)) {
14275+
if matches!(err, ChannelError::Abort(_)) {
1429014276
debug_assert!(self.context.channel_state.is_quiescent());
14291-
self.exit_quiescence()
14292-
} else {
14293-
false
14294-
};
14295-
InteractiveTxMsgError { err, splice_funding_failed: None, exited_quiescence }
14277+
self.exit_quiescence();
14278+
}
14279+
InteractiveTxMsgError { err, splice_funding_failed: None }
1429614280
}
1429714281

1429814282
pub fn remove_legacy_scids_before_block(&mut self, height: u32) -> alloc::vec::Drain<'_, u64> {

lightning/src/ln/channelmanager.rs

Lines changed: 17 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1073,7 +1073,6 @@ struct MsgHandleErrInternal {
10731073
closes_channel: bool,
10741074
shutdown_finish: Option<(ShutdownResult, Option<(msgs::ChannelUpdate, NodeId, NodeId)>)>,
10751075
tx_abort: Option<msgs::TxAbort>,
1076-
exited_quiescence: bool,
10771076
}
10781077

10791078
impl MsgHandleErrInternal {
@@ -1088,7 +1087,6 @@ impl MsgHandleErrInternal {
10881087
closes_channel: false,
10891088
shutdown_finish: None,
10901089
tx_abort: None,
1091-
exited_quiescence: false,
10921090
}
10931091
}
10941092

@@ -1108,13 +1106,7 @@ impl MsgHandleErrInternal {
11081106
}
11091107

11101108
fn from_no_close(err: msgs::LightningError) -> Self {
1111-
Self {
1112-
err,
1113-
closes_channel: false,
1114-
shutdown_finish: None,
1115-
tx_abort: None,
1116-
exited_quiescence: false,
1117-
}
1109+
Self { err, closes_channel: false, shutdown_finish: None, tx_abort: None }
11181110
}
11191111

11201112
fn from_finish_shutdown(
@@ -1135,7 +1127,6 @@ impl MsgHandleErrInternal {
11351127
closes_channel: true,
11361128
shutdown_finish: Some((shutdown_res, channel_update)),
11371129
tx_abort: None,
1138-
exited_quiescence: false,
11391130
}
11401131
}
11411132

@@ -1171,13 +1162,7 @@ impl MsgHandleErrInternal {
11711162
},
11721163
},
11731164
};
1174-
Self {
1175-
err,
1176-
closes_channel: false,
1177-
shutdown_finish: None,
1178-
tx_abort,
1179-
exited_quiescence: false,
1180-
}
1165+
Self { err, closes_channel: false, shutdown_finish: None, tx_abort }
11811166
}
11821167

11831168
fn dont_send_error_message(&mut self) {
@@ -1194,9 +1179,11 @@ impl MsgHandleErrInternal {
11941179
self.closes_channel
11951180
}
11961181

1197-
fn with_exited_quiescence(mut self, exited_quiescence: bool) -> Self {
1198-
self.exited_quiescence = exited_quiescence;
1199-
self
1182+
/// Whether the holding cell should be released after handling this error. This is inferred
1183+
/// from the presence of a `tx_abort`, which is sent when aborting an interactive transaction
1184+
/// negotiation that was conducted during quiescence.
1185+
fn needs_holding_cell_release(&self) -> bool {
1186+
self.tx_abort.is_some()
12001187
}
12011188
}
12021189

@@ -4635,6 +4622,7 @@ impl<
46354622

46364623
internal.map_err(|err_internal| {
46374624
let mut msg_event = None;
4625+
let needs_holding_cell_release = err_internal.needs_holding_cell_release();
46384626

46394627
if let Some((shutdown_res, update_option)) = err_internal.shutdown_finish {
46404628
let counterparty_node_id = shutdown_res.counterparty_node_id;
@@ -4676,7 +4664,7 @@ impl<
46764664
}
46774665

46784666
let mut holding_cell_res = None;
4679-
if msg_event.is_some() || err_internal.exited_quiescence {
4667+
if msg_event.is_some() || needs_holding_cell_release {
46804668
let per_peer_state = self.per_peer_state.read().unwrap();
46814669
if let Some(peer_state_mutex) = per_peer_state.get(&counterparty_node_id) {
46824670
let mut peer_state = peer_state_mutex.lock().unwrap();
@@ -4687,8 +4675,7 @@ impl<
46874675
}
46884676
// We need to enqueue the `tx_abort` in `pending_msg_events` above before we
46894677
// enqueue any commitment updates generated by freeing holding cell HTLCs.
4690-
holding_cell_res = err_internal
4691-
.exited_quiescence
4678+
holding_cell_res = needs_holding_cell_release
46924679
.then(|| self.check_free_peer_holding_cells(&mut peer_state));
46934680
}
46944681
}
@@ -12007,10 +11994,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1200711994
None,
1200811995
));
1200911996
}
12010-
debug_assert!(!err.exited_quiescence || matches!(err.err, ChannelError::Abort(_)));
12011-
1201211997
MsgHandleErrInternal::from_chan_no_close(err.err, channel_id)
12013-
.with_exited_quiescence(err.exited_quiescence)
1201411998
}
1201511999

1201612000
fn internal_tx_msg<
@@ -12247,7 +12231,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1224712231
}
1224812232
// We consider a splice negotiated when we exchange `tx_signatures`,
1224912233
// which also terminates quiescence.
12250-
let exited_quiescence = splice_negotiated.is_some();
12234+
let needs_holding_cell_release = splice_negotiated.is_some();
1225112235
if let Some(splice_negotiated) = splice_negotiated {
1225212236
self.pending_events.lock().unwrap().push_back((
1225312237
events::Event::SplicePending {
@@ -12262,7 +12246,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1226212246
None,
1226312247
));
1226412248
}
12265-
let holding_cell_res = if exited_quiescence {
12249+
let holding_cell_res = if needs_holding_cell_release {
1226612250
self.check_free_peer_holding_cells(peer_state)
1226712251
} else {
1226812252
Vec::new()
@@ -12304,7 +12288,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1230412288
match peer_state.channel_by_id.entry(msg.channel_id) {
1230512289
hash_map::Entry::Occupied(mut chan_entry) => {
1230612290
let res = chan_entry.get_mut().tx_abort(msg, &self.logger);
12307-
let (tx_abort, splice_failed, exited_quiescence) =
12291+
let (tx_abort, splice_failed) =
1230812292
try_channel_entry!(self, peer_state, res, chan_entry);
1230912293

1231012294
let persist = if tx_abort.is_some() || splice_failed.is_some() {
@@ -12313,6 +12297,9 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1231312297
NotifyOption::SkipPersistNoEvents
1231412298
};
1231512299

12300+
// Release any HTLCs held during quiescence now that we're
12301+
// exiting via tx_abort.
12302+
let needs_holding_cell_release = tx_abort.is_some();
1231612303
if let Some(tx_abort_msg) = tx_abort {
1231712304
peer_state.pending_msg_events.push(MessageSendEvent::SendTxAbort {
1231812305
node_id: *counterparty_node_id,
@@ -12344,7 +12331,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1234412331
));
1234512332
}
1234612333

12347-
let holding_cell_res = if exited_quiescence {
12334+
let holding_cell_res = if needs_holding_cell_release {
1234812335
self.check_free_peer_holding_cells(peer_state)
1234912336
} else {
1235012337
Vec::new()

0 commit comments

Comments
 (0)