Skip to content

Commit 3e9a10d

Browse files
committed
Free holding cell upon handling an invalid interactive-tx message
After cad88af, a few code paths that also lead to a quiescence exit were not accounted for. This commit addresses the path where we exit quiescence due to a processing error on a counterparty's `tx_add_input/output`, `tx_remove_input/output`, or `tx_complete` message.
1 parent 0b45bfd commit 3e9a10d

3 files changed

Lines changed: 216 additions & 45 deletions

File tree

lightning/src/ln/channel.rs

Lines changed: 55 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1176,6 +1176,18 @@ pub enum UpdateFulfillCommitFetch {
11761176
DuplicateClaim {},
11771177
}
11781178

1179+
/// Error returned when processing an invalid interactive-tx message from our counterparty.
1180+
pub(super) struct InteractiveTxMsgError {
1181+
/// The underlying error.
1182+
pub(super) err: ChannelError,
1183+
/// If a splice was in progress when processing the message, this contains the splice funding
1184+
/// information for emitting a `SpliceFailed` event.
1185+
pub(super) splice_funding_failed: Option<SpliceFundingFailed>,
1186+
/// Whether we were quiescent when we received the message, and are no longer due to aborting
1187+
/// the session.
1188+
pub(super) exited_quiescence: bool,
1189+
}
1190+
11791191
/// The return value of `monitor_updating_restored`
11801192
pub(super) struct MonitorRestoreUpdates {
11811193
pub raa: Option<msgs::RevokeAndACK>,
@@ -1818,104 +1830,118 @@ where
18181830

18191831
fn fail_interactive_tx_negotiation<L: Logger>(
18201832
&mut self, reason: AbortReason, logger: &L,
1821-
) -> (ChannelError, Option<SpliceFundingFailed>) {
1833+
) -> InteractiveTxMsgError {
18221834
let logger = WithChannelContext::from(logger, &self.context(), None);
18231835
log_info!(logger, "Failed interactive transaction negotiation: {reason}");
18241836

1825-
let splice_funding_failed = match &mut self.phase {
1837+
let (splice_funding_failed, exited_quiescence) = match &mut self.phase {
18261838
ChannelPhase::Undefined => unreachable!(),
1827-
ChannelPhase::UnfundedOutboundV1(_) | ChannelPhase::UnfundedInboundV1(_) => None,
1839+
ChannelPhase::UnfundedOutboundV1(_) | ChannelPhase::UnfundedInboundV1(_) => {
1840+
(None, false)
1841+
},
18281842
ChannelPhase::UnfundedV2(pending_v2_channel) => {
18291843
pending_v2_channel.interactive_tx_constructor.take();
1830-
None
1844+
(None, false)
18311845
},
18321846
ChannelPhase::Funded(funded_channel) => {
18331847
if funded_channel.should_reset_pending_splice_state(false) {
1834-
funded_channel.reset_pending_splice_state()
1848+
(funded_channel.reset_pending_splice_state(), true)
18351849
} else {
18361850
debug_assert!(false, "We should never fail an interactive funding negotiation once we're exchanging tx_signatures");
1837-
None
1851+
(None, false)
18381852
}
18391853
},
18401854
};
18411855

1842-
(ChannelError::Abort(reason), splice_funding_failed)
1856+
InteractiveTxMsgError {
1857+
err: ChannelError::Abort(reason),
1858+
splice_funding_failed,
1859+
exited_quiescence,
1860+
}
18431861
}
18441862

18451863
pub fn tx_add_input<L: Logger>(
18461864
&mut self, msg: &msgs::TxAddInput, logger: &L,
1847-
) -> Result<InteractiveTxMessageSend, (ChannelError, Option<SpliceFundingFailed>)> {
1865+
) -> Result<InteractiveTxMessageSend, InteractiveTxMsgError> {
18481866
match self.interactive_tx_constructor_mut() {
18491867
Some(interactive_tx_constructor) => interactive_tx_constructor
18501868
.handle_tx_add_input(msg)
18511869
.map_err(|reason| self.fail_interactive_tx_negotiation(reason, logger)),
1852-
None => Err((
1853-
ChannelError::WarnAndDisconnect(
1870+
None => Err(InteractiveTxMsgError {
1871+
err: ChannelError::WarnAndDisconnect(
18541872
"Received unexpected interactive transaction negotiation message".to_owned(),
18551873
),
1856-
None,
1857-
)),
1874+
splice_funding_failed: None,
1875+
exited_quiescence: false,
1876+
}),
18581877
}
18591878
}
18601879

18611880
pub fn tx_add_output<L: Logger>(
18621881
&mut self, msg: &msgs::TxAddOutput, logger: &L,
1863-
) -> Result<InteractiveTxMessageSend, (ChannelError, Option<SpliceFundingFailed>)> {
1882+
) -> Result<InteractiveTxMessageSend, InteractiveTxMsgError> {
18641883
match self.interactive_tx_constructor_mut() {
18651884
Some(interactive_tx_constructor) => interactive_tx_constructor
18661885
.handle_tx_add_output(msg)
18671886
.map_err(|reason| self.fail_interactive_tx_negotiation(reason, logger)),
1868-
None => Err((
1869-
ChannelError::WarnAndDisconnect(
1887+
None => Err(InteractiveTxMsgError {
1888+
err: ChannelError::WarnAndDisconnect(
18701889
"Received unexpected interactive transaction negotiation message".to_owned(),
18711890
),
1872-
None,
1873-
)),
1891+
splice_funding_failed: None,
1892+
exited_quiescence: false,
1893+
}),
18741894
}
18751895
}
18761896

18771897
pub fn tx_remove_input<L: Logger>(
18781898
&mut self, msg: &msgs::TxRemoveInput, logger: &L,
1879-
) -> Result<InteractiveTxMessageSend, (ChannelError, Option<SpliceFundingFailed>)> {
1899+
) -> Result<InteractiveTxMessageSend, InteractiveTxMsgError> {
18801900
match self.interactive_tx_constructor_mut() {
18811901
Some(interactive_tx_constructor) => interactive_tx_constructor
18821902
.handle_tx_remove_input(msg)
18831903
.map_err(|reason| self.fail_interactive_tx_negotiation(reason, logger)),
1884-
None => Err((
1885-
ChannelError::WarnAndDisconnect(
1904+
None => Err(InteractiveTxMsgError {
1905+
err: ChannelError::WarnAndDisconnect(
18861906
"Received unexpected interactive transaction negotiation message".to_owned(),
18871907
),
1888-
None,
1889-
)),
1908+
splice_funding_failed: None,
1909+
exited_quiescence: false,
1910+
}),
18901911
}
18911912
}
18921913

18931914
pub fn tx_remove_output<L: Logger>(
18941915
&mut self, msg: &msgs::TxRemoveOutput, logger: &L,
1895-
) -> Result<InteractiveTxMessageSend, (ChannelError, Option<SpliceFundingFailed>)> {
1916+
) -> Result<InteractiveTxMessageSend, InteractiveTxMsgError> {
18961917
match self.interactive_tx_constructor_mut() {
18971918
Some(interactive_tx_constructor) => interactive_tx_constructor
18981919
.handle_tx_remove_output(msg)
18991920
.map_err(|reason| self.fail_interactive_tx_negotiation(reason, logger)),
1900-
None => Err((
1901-
ChannelError::WarnAndDisconnect(
1921+
None => Err(InteractiveTxMsgError {
1922+
err: ChannelError::WarnAndDisconnect(
19021923
"Received unexpected interactive transaction negotiation message".to_owned(),
19031924
),
1904-
None,
1905-
)),
1925+
splice_funding_failed: None,
1926+
exited_quiescence: false,
1927+
}),
19061928
}
19071929
}
19081930

19091931
pub fn tx_complete<F: FeeEstimator, L: Logger>(
19101932
&mut self, msg: &msgs::TxComplete, fee_estimator: &LowerBoundedFeeEstimator<F>, logger: &L,
1911-
) -> Result<TxCompleteResult, (ChannelError, Option<SpliceFundingFailed>)> {
1933+
) -> Result<TxCompleteResult, InteractiveTxMsgError> {
19121934
let tx_complete_action = match self.interactive_tx_constructor_mut() {
19131935
Some(interactive_tx_constructor) => interactive_tx_constructor
19141936
.handle_tx_complete(msg)
19151937
.map_err(|reason| self.fail_interactive_tx_negotiation(reason, logger))?,
19161938
None => {
19171939
let err = "Received unexpected interactive transaction negotiation message";
1918-
return Err((ChannelError::WarnAndDisconnect(err.to_owned()), None));
1940+
return Err(InteractiveTxMsgError {
1941+
err: ChannelError::WarnAndDisconnect(err.to_owned()),
1942+
splice_funding_failed: None,
1943+
exited_quiescence: false,
1944+
});
19191945
},
19201946
};
19211947

lightning/src/ln/channelmanager.rs

Lines changed: 57 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,8 @@ use crate::ln::chan_utils::selected_commitment_sat_per_1000_weight;
5959
use crate::ln::channel::QuiescentAction;
6060
use crate::ln::channel::{
6161
self, hold_time_since, Channel, ChannelError, ChannelUpdateStatus, DisconnectResult,
62-
FundedChannel, FundingTxSigned, InboundUpdateAdd, InboundV1Channel, OutboundV1Channel,
63-
PendingV2Channel, ReconnectionMsg, ShutdownResult, SpliceFundingFailed, StfuResponse,
62+
FundedChannel, FundingTxSigned, InboundUpdateAdd, InboundV1Channel, InteractiveTxMsgError,
63+
OutboundV1Channel, PendingV2Channel, ReconnectionMsg, ShutdownResult, StfuResponse,
6464
UpdateFulfillCommitFetch, WithChannelContext,
6565
};
6666
use crate::ln::channel_state::ChannelDetails;
@@ -938,6 +938,7 @@ struct MsgHandleErrInternal {
938938
closes_channel: bool,
939939
shutdown_finish: Option<(ShutdownResult, Option<(msgs::ChannelUpdate, NodeId, NodeId)>)>,
940940
tx_abort: Option<msgs::TxAbort>,
941+
exited_quiescence: bool,
941942
}
942943

943944
impl MsgHandleErrInternal {
@@ -952,6 +953,7 @@ impl MsgHandleErrInternal {
952953
closes_channel: false,
953954
shutdown_finish: None,
954955
tx_abort: None,
956+
exited_quiescence: false,
955957
}
956958
}
957959

@@ -970,7 +972,13 @@ impl MsgHandleErrInternal {
970972
}
971973

972974
fn from_no_close(err: msgs::LightningError) -> Self {
973-
Self { err, closes_channel: false, shutdown_finish: None, tx_abort: None }
975+
Self {
976+
err,
977+
closes_channel: false,
978+
shutdown_finish: None,
979+
tx_abort: None,
980+
exited_quiescence: false,
981+
}
974982
}
975983

976984
fn from_finish_shutdown(
@@ -991,6 +999,7 @@ impl MsgHandleErrInternal {
991999
closes_channel: true,
9921000
shutdown_finish: Some((shutdown_res, channel_update)),
9931001
tx_abort: None,
1002+
exited_quiescence: false,
9941003
}
9951004
}
9961005

@@ -1026,7 +1035,13 @@ impl MsgHandleErrInternal {
10261035
},
10271036
},
10281037
};
1029-
Self { err, closes_channel: false, shutdown_finish: None, tx_abort }
1038+
Self {
1039+
err,
1040+
closes_channel: false,
1041+
shutdown_finish: None,
1042+
tx_abort,
1043+
exited_quiescence: false,
1044+
}
10301045
}
10311046

10321047
fn dont_send_error_message(&mut self) {
@@ -1042,6 +1057,11 @@ impl MsgHandleErrInternal {
10421057
fn closes_channel(&self) -> bool {
10431058
self.closes_channel
10441059
}
1060+
1061+
fn with_exited_quiescence(mut self, exited_quiescence: bool) -> Self {
1062+
self.exited_quiescence = exited_quiescence;
1063+
self
1064+
}
10451065
}
10461066

10471067
/// For events which result in both a RevokeAndACK and a CommitmentUpdate, by default they should
@@ -4348,15 +4368,26 @@ impl<
43484368
});
43494369
}
43504370

4351-
if let Some(msg_event) = msg_event {
4371+
let mut holding_cell_res = None;
4372+
if msg_event.is_some() || err_internal.exited_quiescence {
43524373
let per_peer_state = self.per_peer_state.read().unwrap();
43534374
if let Some(peer_state_mutex) = per_peer_state.get(&counterparty_node_id) {
43544375
let mut peer_state = peer_state_mutex.lock().unwrap();
4355-
if peer_state.is_connected {
4356-
peer_state.pending_msg_events.push(msg_event);
4376+
if let Some(msg_event) = msg_event {
4377+
if peer_state.is_connected {
4378+
peer_state.pending_msg_events.push(msg_event);
4379+
}
43574380
}
4381+
// We need to enqueue the `tx_abort` in `pending_msg_events` above before we
4382+
// enqueue any commitment updates generated by freeing holding cell HTLCs.
4383+
holding_cell_res = err_internal
4384+
.exited_quiescence
4385+
.then(|| self.check_free_peer_holding_cells(&mut peer_state));
43584386
}
43594387
}
4388+
if let Some(res) = holding_cell_res {
4389+
self.handle_holding_cell_free_result(res);
4390+
}
43604391

43614392
// Return error in case higher-API need one
43624393
err_internal.err
@@ -11192,9 +11223,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1119211223
}
1119311224

1119411225
fn internal_tx_msg<
11195-
HandleTxMsgFn: Fn(
11196-
&mut Channel<SP>,
11197-
) -> Result<InteractiveTxMessageSend, (ChannelError, Option<SpliceFundingFailed>)>,
11226+
HandleTxMsgFn: Fn(&mut Channel<SP>) -> Result<InteractiveTxMessageSend, InteractiveTxMsgError>,
1119811227
>(
1119911228
&self, counterparty_node_id: &PublicKey, channel_id: ChannelId,
1120011229
tx_msg_handler: HandleTxMsgFn,
@@ -11215,7 +11244,11 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1121511244
peer_state.pending_msg_events.push(msg_send_event);
1121611245
Ok(NotifyOption::SkipPersistHandleEvents)
1121711246
},
11218-
Err((error, splice_funding_failed)) => {
11247+
Err(InteractiveTxMsgError {
11248+
err,
11249+
splice_funding_failed,
11250+
exited_quiescence,
11251+
}) => {
1121911252
if let Some(splice_funding_failed) = splice_funding_failed {
1122011253
let pending_events = &mut self.pending_events.lock().unwrap();
1122111254
pending_events.push_back((
@@ -11231,7 +11264,10 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1123111264
None,
1123211265
));
1123311266
}
11234-
Err(MsgHandleErrInternal::from_chan_no_close(error, channel_id))
11267+
debug_assert!(!exited_quiescence || matches!(err, ChannelError::Abort(_)));
11268+
11269+
Err(MsgHandleErrInternal::from_chan_no_close(err, channel_id)
11270+
.with_exited_quiescence(exited_quiescence))
1123511271
},
1123611272
}
1123711273
},
@@ -11361,7 +11397,11 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1136111397

1136211398
Ok(persist)
1136311399
},
11364-
Err((error, splice_funding_failed)) => {
11400+
Err(InteractiveTxMsgError {
11401+
err,
11402+
splice_funding_failed,
11403+
exited_quiescence,
11404+
}) => {
1136511405
if let Some(splice_funding_failed) = splice_funding_failed {
1136611406
let pending_events = &mut self.pending_events.lock().unwrap();
1136711407
pending_events.push_back((
@@ -11377,7 +11417,10 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1137711417
None,
1137811418
));
1137911419
}
11380-
Err(MsgHandleErrInternal::from_chan_no_close(error, msg.channel_id))
11420+
debug_assert!(!exited_quiescence || matches!(err, ChannelError::Abort(_)));
11421+
11422+
Err(MsgHandleErrInternal::from_chan_no_close(err, msg.channel_id)
11423+
.with_exited_quiescence(exited_quiescence))
1138111424
},
1138211425
}
1138311426
},

0 commit comments

Comments
 (0)