Skip to content

Commit c1594a0

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 e4b1c6b commit c1594a0

File tree

2 files changed

+35
-70
lines changed

2 files changed

+35
-70
lines changed

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]
@@ -14250,13 +14236,11 @@ where
1425014236
}
1425114237

1425214238
fn quiescent_negotiation_err(&mut self, err: ChannelError) -> InteractiveTxMsgError {
14253-
let exited_quiescence = if matches!(err, ChannelError::Abort(_)) {
14239+
if matches!(err, ChannelError::Abort(_)) {
1425414240
debug_assert!(self.context.channel_state.is_quiescent());
14255-
self.exit_quiescence()
14256-
} else {
14257-
false
14258-
};
14259-
InteractiveTxMsgError { err, splice_funding_failed: None, exited_quiescence }
14241+
self.exit_quiescence();
14242+
}
14243+
InteractiveTxMsgError { err, splice_funding_failed: None }
1426014244
}
1426114245

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

lightning/src/ln/channelmanager.rs

Lines changed: 19 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1027,7 +1027,6 @@ struct MsgHandleErrInternal {
10271027
closes_channel: bool,
10281028
shutdown_finish: Option<(ShutdownResult, Option<(msgs::ChannelUpdate, NodeId, NodeId)>)>,
10291029
tx_abort: Option<msgs::TxAbort>,
1030-
exited_quiescence: bool,
10311030
}
10321031

10331032
impl MsgHandleErrInternal {
@@ -1042,7 +1041,6 @@ impl MsgHandleErrInternal {
10421041
closes_channel: false,
10431042
shutdown_finish: None,
10441043
tx_abort: None,
1045-
exited_quiescence: false,
10461044
}
10471045
}
10481046

@@ -1062,13 +1060,7 @@ impl MsgHandleErrInternal {
10621060
}
10631061

10641062
fn from_no_close(err: msgs::LightningError) -> Self {
1065-
Self {
1066-
err,
1067-
closes_channel: false,
1068-
shutdown_finish: None,
1069-
tx_abort: None,
1070-
exited_quiescence: false,
1071-
}
1063+
Self { err, closes_channel: false, shutdown_finish: None, tx_abort: None }
10721064
}
10731065

10741066
fn from_finish_shutdown(
@@ -1089,7 +1081,6 @@ impl MsgHandleErrInternal {
10891081
closes_channel: true,
10901082
shutdown_finish: Some((shutdown_res, channel_update)),
10911083
tx_abort: None,
1092-
exited_quiescence: false,
10931084
}
10941085
}
10951086

@@ -1125,13 +1116,7 @@ impl MsgHandleErrInternal {
11251116
},
11261117
},
11271118
};
1128-
Self {
1129-
err,
1130-
closes_channel: false,
1131-
shutdown_finish: None,
1132-
tx_abort,
1133-
exited_quiescence: false,
1134-
}
1119+
Self { err, closes_channel: false, shutdown_finish: None, tx_abort }
11351120
}
11361121

11371122
fn dont_send_error_message(&mut self) {
@@ -1148,9 +1133,11 @@ impl MsgHandleErrInternal {
11481133
self.closes_channel
11491134
}
11501135

1151-
fn with_exited_quiescence(mut self, exited_quiescence: bool) -> Self {
1152-
self.exited_quiescence = exited_quiescence;
1153-
self
1136+
/// Whether the holding cell should be released after handling this error. This is inferred
1137+
/// from the presence of a `tx_abort`, which is sent when aborting an interactive transaction
1138+
/// negotiation that was conducted during quiescence.
1139+
fn needs_holding_cell_release(&self) -> bool {
1140+
self.tx_abort.is_some()
11541141
}
11551142
}
11561143

@@ -4569,6 +4556,7 @@ impl<
45694556

45704557
internal.map_err(|err_internal| {
45714558
let mut msg_event = None;
4559+
let needs_holding_cell_release = err_internal.needs_holding_cell_release();
45724560

45734561
if let Some((shutdown_res, update_option)) = err_internal.shutdown_finish {
45744562
let counterparty_node_id = shutdown_res.counterparty_node_id;
@@ -4610,7 +4598,7 @@ impl<
46104598
}
46114599

46124600
let mut holding_cell_res = None;
4613-
if msg_event.is_some() || err_internal.exited_quiescence {
4601+
if msg_event.is_some() || needs_holding_cell_release {
46144602
let per_peer_state = self.per_peer_state.read().unwrap();
46154603
if let Some(peer_state_mutex) = per_peer_state.get(&counterparty_node_id) {
46164604
let mut peer_state = peer_state_mutex.lock().unwrap();
@@ -4621,8 +4609,7 @@ impl<
46214609
}
46224610
// We need to enqueue the `tx_abort` in `pending_msg_events` above before we
46234611
// enqueue any commitment updates generated by freeing holding cell HTLCs.
4624-
holding_cell_res = err_internal
4625-
.exited_quiescence
4612+
holding_cell_res = needs_holding_cell_release
46264613
.then(|| self.check_free_peer_holding_cells(&mut peer_state));
46274614
}
46284615
}
@@ -11850,10 +11837,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1185011837
None,
1185111838
));
1185211839
}
11853-
debug_assert!(!err.exited_quiescence || matches!(err.err, ChannelError::Abort(_)));
11854-
1185511840
MsgHandleErrInternal::from_chan_no_close(err.err, channel_id)
11856-
.with_exited_quiescence(err.exited_quiescence)
1185711841
}
1185811842

1185911843
fn internal_tx_msg<
@@ -12012,11 +11996,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1201211996

1201311997
Ok(())
1201411998
},
12015-
Err(InteractiveTxMsgError {
12016-
err,
12017-
splice_funding_failed,
12018-
exited_quiescence,
12019-
}) => {
11999+
Err(InteractiveTxMsgError { err, splice_funding_failed }) => {
1202012000
if let Some(splice_funding_failed) = splice_funding_failed {
1202112001
let pending_events = &mut self.pending_events.lock().unwrap();
1202212002
pending_events.push_back((
@@ -12040,10 +12020,8 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1204012020
None,
1204112021
));
1204212022
}
12043-
debug_assert!(!exited_quiescence || matches!(err, ChannelError::Abort(_)));
1204412023

12045-
Err(MsgHandleErrInternal::from_chan_no_close(err, msg.channel_id)
12046-
.with_exited_quiescence(exited_quiescence))
12024+
Err(MsgHandleErrInternal::from_chan_no_close(err, msg.channel_id))
1204712025
},
1204812026
}
1204912027
},
@@ -12114,7 +12092,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1211412092
}
1211512093
// We consider a splice negotiated when we exchange `tx_signatures`,
1211612094
// which also terminates quiescence.
12117-
let exited_quiescence = splice_negotiated.is_some();
12095+
let needs_holding_cell_release = splice_negotiated.is_some();
1211812096
if let Some(splice_negotiated) = splice_negotiated {
1211912097
self.pending_events.lock().unwrap().push_back((
1212012098
events::Event::SplicePending {
@@ -12129,7 +12107,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1212912107
None,
1213012108
));
1213112109
}
12132-
let holding_cell_res = if exited_quiescence {
12110+
let holding_cell_res = if needs_holding_cell_release {
1213312111
self.check_free_peer_holding_cells(peer_state)
1213412112
} else {
1213512113
Vec::new()
@@ -12171,7 +12149,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1217112149
match peer_state.channel_by_id.entry(msg.channel_id) {
1217212150
hash_map::Entry::Occupied(mut chan_entry) => {
1217312151
let res = chan_entry.get_mut().tx_abort(msg, &self.logger);
12174-
let (tx_abort, splice_failed, exited_quiescence) =
12152+
let (tx_abort, splice_failed) =
1217512153
try_channel_entry!(self, peer_state, res, chan_entry);
1217612154

1217712155
let persist = if tx_abort.is_some() || splice_failed.is_some() {
@@ -12180,6 +12158,9 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1218012158
NotifyOption::SkipPersistNoEvents
1218112159
};
1218212160

12161+
// Release any HTLCs held during quiescence now that we're
12162+
// exiting via tx_abort.
12163+
let needs_holding_cell_release = tx_abort.is_some();
1218312164
if let Some(tx_abort_msg) = tx_abort {
1218412165
peer_state.pending_msg_events.push(MessageSendEvent::SendTxAbort {
1218512166
node_id: *counterparty_node_id,
@@ -12211,7 +12192,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1221112192
));
1221212193
}
1221312194

12214-
let holding_cell_res = if exited_quiescence {
12195+
let holding_cell_res = if needs_holding_cell_release {
1221512196
self.check_free_peer_holding_cells(peer_state)
1221612197
} else {
1221712198
Vec::new()

0 commit comments

Comments
 (0)