Skip to content

Commit 112522f

Browse files
committed
Free holding cell upon handling a counterparty tx_abort
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 processing a counterparty's `tx_abort` message.
1 parent 3e9a10d commit 112522f

3 files changed

Lines changed: 87 additions & 53 deletions

File tree

lightning/src/ln/channel.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2001,13 +2001,13 @@ where
20012001

20022002
pub fn tx_abort<L: Logger>(
20032003
&mut self, msg: &msgs::TxAbort, logger: &L,
2004-
) -> Result<(Option<msgs::TxAbort>, Option<SpliceFundingFailed>), ChannelError> {
2004+
) -> Result<(Option<msgs::TxAbort>, Option<SpliceFundingFailed>, bool), ChannelError> {
20052005
// If we have not sent a `tx_abort` message for this negotiation previously, we need to echo
20062006
// back a tx_abort message according to the spec:
20072007
// https://github.com/lightning/bolts/blob/247e83d/02-peer-protocol.md?plain=1#L560-L561
20082008
// For rationale why we echo back `tx_abort`:
20092009
// https://github.com/lightning/bolts/blob/247e83d/02-peer-protocol.md?plain=1#L578-L580
2010-
let (should_ack, splice_funding_failed) = match &mut self.phase {
2010+
let (should_ack, splice_funding_failed, exited_quiescence) = match &mut self.phase {
20112011
ChannelPhase::Undefined => unreachable!(),
20122012
ChannelPhase::UnfundedOutboundV1(_) | ChannelPhase::UnfundedInboundV1(_) => {
20132013
let err = "Got an unexpected tx_abort message: This is an unfunded channel created with V1 channel establishment";
@@ -2016,7 +2016,7 @@ where
20162016
ChannelPhase::UnfundedV2(pending_v2_channel) => {
20172017
let had_constructor =
20182018
pending_v2_channel.interactive_tx_constructor.take().is_some();
2019-
(had_constructor, None)
2019+
(had_constructor, None, false)
20202020
},
20212021
ChannelPhase::Funded(funded_channel) => {
20222022
if funded_channel.has_pending_splice_awaiting_signatures()
@@ -2044,11 +2044,11 @@ where
20442044
.unwrap_or(false);
20452045
debug_assert!(has_funding_negotiation);
20462046
let splice_funding_failed = funded_channel.reset_pending_splice_state();
2047-
(true, splice_funding_failed)
2047+
(true, splice_funding_failed, true)
20482048
} else {
20492049
// We were not tracking the pending funding negotiation state anymore, likely
20502050
// due to a disconnection or already having sent our own `tx_abort`.
2051-
(false, None)
2051+
(false, None, false)
20522052
}
20532053
},
20542054
};
@@ -2064,7 +2064,7 @@ where
20642064
}
20652065
});
20662066

2067-
Ok((tx_abort, splice_funding_failed))
2067+
Ok((tx_abort, splice_funding_failed, exited_quiescence))
20682068
}
20692069

20702070
#[rustfmt::skip]

lightning/src/ln/channelmanager.rs

Lines changed: 58 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -11523,55 +11523,68 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1152311523
fn internal_tx_abort(
1152411524
&self, counterparty_node_id: &PublicKey, msg: &msgs::TxAbort,
1152511525
) -> Result<NotifyOption, MsgHandleErrInternal> {
11526-
let per_peer_state = self.per_peer_state.read().unwrap();
11527-
let peer_state_mutex = per_peer_state.get(counterparty_node_id).ok_or_else(|| {
11528-
debug_assert!(false);
11529-
MsgHandleErrInternal::no_such_peer(counterparty_node_id, msg.channel_id)
11530-
})?;
11531-
let mut peer_state_lock = peer_state_mutex.lock().unwrap();
11532-
let peer_state = &mut *peer_state_lock;
11533-
match peer_state.channel_by_id.entry(msg.channel_id) {
11534-
hash_map::Entry::Occupied(mut chan_entry) => {
11535-
let res = chan_entry.get_mut().tx_abort(msg, &self.logger);
11536-
let (tx_abort, splice_failed) =
11537-
try_channel_entry!(self, peer_state, res, chan_entry);
11526+
let (result, holding_cell_res) = {
11527+
let per_peer_state = self.per_peer_state.read().unwrap();
11528+
let peer_state_mutex = per_peer_state.get(counterparty_node_id).ok_or_else(|| {
11529+
debug_assert!(false);
11530+
MsgHandleErrInternal::no_such_peer(counterparty_node_id, msg.channel_id)
11531+
})?;
11532+
let mut peer_state_lock = peer_state_mutex.lock().unwrap();
11533+
let peer_state = &mut *peer_state_lock;
11534+
match peer_state.channel_by_id.entry(msg.channel_id) {
11535+
hash_map::Entry::Occupied(mut chan_entry) => {
11536+
let res = chan_entry.get_mut().tx_abort(msg, &self.logger);
11537+
let (tx_abort, splice_failed, exited_quiescence) =
11538+
try_channel_entry!(self, peer_state, res, chan_entry);
1153811539

11539-
let persist = if tx_abort.is_some() || splice_failed.is_some() {
11540-
NotifyOption::DoPersist
11541-
} else {
11542-
NotifyOption::SkipPersistNoEvents
11543-
};
11540+
let persist = if tx_abort.is_some() || splice_failed.is_some() {
11541+
NotifyOption::DoPersist
11542+
} else {
11543+
NotifyOption::SkipPersistNoEvents
11544+
};
1154411545

11545-
if let Some(tx_abort_msg) = tx_abort {
11546-
peer_state.pending_msg_events.push(MessageSendEvent::SendTxAbort {
11547-
node_id: *counterparty_node_id,
11548-
msg: tx_abort_msg,
11549-
});
11550-
}
11546+
if let Some(tx_abort_msg) = tx_abort {
11547+
peer_state.pending_msg_events.push(MessageSendEvent::SendTxAbort {
11548+
node_id: *counterparty_node_id,
11549+
msg: tx_abort_msg,
11550+
});
11551+
}
1155111552

11552-
if let Some(splice_funding_failed) = splice_failed {
11553-
let pending_events = &mut self.pending_events.lock().unwrap();
11554-
pending_events.push_back((
11555-
events::Event::SpliceFailed {
11556-
channel_id: msg.channel_id,
11557-
counterparty_node_id: *counterparty_node_id,
11558-
user_channel_id: chan_entry.get().context().get_user_id(),
11559-
abandoned_funding_txo: splice_funding_failed.funding_txo,
11560-
channel_type: splice_funding_failed.channel_type,
11561-
contributed_inputs: splice_funding_failed.contributed_inputs,
11562-
contributed_outputs: splice_funding_failed.contributed_outputs,
11563-
},
11564-
None,
11565-
));
11566-
}
11553+
if let Some(splice_funding_failed) = splice_failed {
11554+
let pending_events = &mut self.pending_events.lock().unwrap();
11555+
pending_events.push_back((
11556+
events::Event::SpliceFailed {
11557+
channel_id: msg.channel_id,
11558+
counterparty_node_id: *counterparty_node_id,
11559+
user_channel_id: chan_entry.get().context().get_user_id(),
11560+
abandoned_funding_txo: splice_funding_failed.funding_txo,
11561+
channel_type: splice_funding_failed.channel_type,
11562+
contributed_inputs: splice_funding_failed.contributed_inputs,
11563+
contributed_outputs: splice_funding_failed.contributed_outputs,
11564+
},
11565+
None,
11566+
));
11567+
}
1156711568

11568-
Ok(persist)
11569-
},
11570-
hash_map::Entry::Vacant(_) => Err(MsgHandleErrInternal::no_such_channel_for_peer(
11571-
counterparty_node_id,
11572-
msg.channel_id,
11573-
)),
11574-
}
11569+
let holding_cell_res = if exited_quiescence {
11570+
self.check_free_peer_holding_cells(peer_state)
11571+
} else {
11572+
Vec::new()
11573+
};
11574+
(Ok(persist), holding_cell_res)
11575+
},
11576+
hash_map::Entry::Vacant(_) => (
11577+
Err(MsgHandleErrInternal::no_such_channel_for_peer(
11578+
counterparty_node_id,
11579+
msg.channel_id,
11580+
)),
11581+
Vec::new(),
11582+
),
11583+
}
11584+
};
11585+
11586+
self.handle_holding_cell_free_result(holding_cell_res);
11587+
result
1157511588
}
1157611589

1157711590
#[rustfmt::skip]

lightning/src/ln/splicing_tests.rs

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1972,6 +1972,13 @@ fn fail_splice_on_tx_abort() {
19721972
// tx_complete.
19731973
let _ = complete_splice_handshake(initiator, acceptor, channel_id, contribution.clone());
19741974

1975+
// Queue an outgoing HTLC to the holding cell. It should be freed once we exit quiescence.
1976+
let (route, payment_hash, _payment_preimage, payment_secret) =
1977+
get_route_and_payment_hash!(initiator, acceptor, 1_000_000);
1978+
let onion = RecipientOnionFields::secret_only(payment_secret);
1979+
let payment_id = PaymentId(payment_hash.0);
1980+
initiator.node.send_payment_with_route(route, payment_hash, onion, payment_id).unwrap();
1981+
19751982
let tx_add_input =
19761983
get_event_msg!(initiator, MessageSendEvent::SendTxAddInput, node_id_acceptor);
19771984
acceptor.node.handle_tx_add_input(node_id_initiator, &tx_add_input);
@@ -1992,8 +1999,22 @@ fn fail_splice_on_tx_abort() {
19921999
_ => panic!("Expected Event::SpliceFailed"),
19932000
}
19942001

1995-
let tx_abort = get_event_msg!(initiator, MessageSendEvent::SendTxAbort, node_id_acceptor);
1996-
acceptor.node.handle_tx_abort(node_id_initiator, &tx_abort);
2002+
// We exit quiescence upon receiving `tx_abort`, so we should see our `tx_abort` echo and the
2003+
// holding cell be immediately freed.
2004+
let msg_events = initiator.node.get_and_clear_pending_msg_events();
2005+
assert_eq!(msg_events.len(), 2, "{msg_events:?}");
2006+
check_added_monitors(initiator, 1);
2007+
if let MessageSendEvent::SendTxAbort { msg, .. } = &msg_events[0] {
2008+
acceptor.node.handle_tx_abort(node_id_initiator, msg);
2009+
} else {
2010+
panic!("Unexpected event {:?}", msg_events[0]);
2011+
};
2012+
if let MessageSendEvent::UpdateHTLCs { updates, .. } = &msg_events[1] {
2013+
acceptor.node.handle_update_add_htlc(node_id_initiator, &updates.update_add_htlcs[0]);
2014+
do_commitment_signed_dance(acceptor, initiator, &updates.commitment_signed, false, false);
2015+
} else {
2016+
panic!("Unexpected event {:?}", msg_events[1]);
2017+
};
19972018
}
19982019

19992020
#[test]

0 commit comments

Comments
 (0)