Skip to content

Commit c3eaba9

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 bcf1e95 commit c3eaba9

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
@@ -2030,13 +2030,13 @@ where
20302030

20312031
pub fn tx_abort<L: Logger>(
20322032
&mut self, msg: &msgs::TxAbort, logger: &L,
2033-
) -> Result<(Option<msgs::TxAbort>, Option<SpliceFundingFailed>), ChannelError> {
2033+
) -> Result<(Option<msgs::TxAbort>, Option<SpliceFundingFailed>, bool), ChannelError> {
20342034
// If we have not sent a `tx_abort` message for this negotiation previously, we need to echo
20352035
// back a tx_abort message according to the spec:
20362036
// https://github.com/lightning/bolts/blob/247e83d/02-peer-protocol.md?plain=1#L560-L561
20372037
// For rationale why we echo back `tx_abort`:
20382038
// https://github.com/lightning/bolts/blob/247e83d/02-peer-protocol.md?plain=1#L578-L580
2039-
let (should_ack, splice_funding_failed) = match &mut self.phase {
2039+
let (should_ack, splice_funding_failed, exited_quiescence) = match &mut self.phase {
20402040
ChannelPhase::Undefined => unreachable!(),
20412041
ChannelPhase::UnfundedOutboundV1(_) | ChannelPhase::UnfundedInboundV1(_) => {
20422042
let err = "Got an unexpected tx_abort message: This is an unfunded channel created with V1 channel establishment";
@@ -2045,7 +2045,7 @@ where
20452045
ChannelPhase::UnfundedV2(pending_v2_channel) => {
20462046
let had_constructor =
20472047
pending_v2_channel.interactive_tx_constructor.take().is_some();
2048-
(had_constructor, None)
2048+
(had_constructor, None, false)
20492049
},
20502050
ChannelPhase::Funded(funded_channel) => {
20512051
if funded_channel.has_pending_splice_awaiting_signatures()
@@ -2073,11 +2073,11 @@ where
20732073
.unwrap_or(false);
20742074
debug_assert!(has_funding_negotiation);
20752075
let splice_funding_failed = funded_channel.reset_pending_splice_state();
2076-
(true, splice_funding_failed)
2076+
(true, splice_funding_failed, true)
20772077
} else {
20782078
// We were not tracking the pending funding negotiation state anymore, likely
20792079
// due to a disconnection or already having sent our own `tx_abort`.
2080-
(false, None)
2080+
(false, None, false)
20812081
}
20822082
},
20832083
};
@@ -2093,7 +2093,7 @@ where
20932093
}
20942094
});
20952095

2096-
Ok((tx_abort, splice_funding_failed))
2096+
Ok((tx_abort, splice_funding_failed, exited_quiescence))
20972097
}
20982098

20992099
#[rustfmt::skip]

lightning/src/ln/channelmanager.rs

Lines changed: 58 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -11548,55 +11548,68 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1154811548
fn internal_tx_abort(
1154911549
&self, counterparty_node_id: &PublicKey, msg: &msgs::TxAbort,
1155011550
) -> Result<NotifyOption, MsgHandleErrInternal> {
11551-
let per_peer_state = self.per_peer_state.read().unwrap();
11552-
let peer_state_mutex = per_peer_state.get(counterparty_node_id).ok_or_else(|| {
11553-
debug_assert!(false);
11554-
MsgHandleErrInternal::no_such_peer(counterparty_node_id, msg.channel_id)
11555-
})?;
11556-
let mut peer_state_lock = peer_state_mutex.lock().unwrap();
11557-
let peer_state = &mut *peer_state_lock;
11558-
match peer_state.channel_by_id.entry(msg.channel_id) {
11559-
hash_map::Entry::Occupied(mut chan_entry) => {
11560-
let res = chan_entry.get_mut().tx_abort(msg, &self.logger);
11561-
let (tx_abort, splice_failed) =
11562-
try_channel_entry!(self, peer_state, res, chan_entry);
11551+
let (result, holding_cell_res) = {
11552+
let per_peer_state = self.per_peer_state.read().unwrap();
11553+
let peer_state_mutex = per_peer_state.get(counterparty_node_id).ok_or_else(|| {
11554+
debug_assert!(false);
11555+
MsgHandleErrInternal::no_such_peer(counterparty_node_id, msg.channel_id)
11556+
})?;
11557+
let mut peer_state_lock = peer_state_mutex.lock().unwrap();
11558+
let peer_state = &mut *peer_state_lock;
11559+
match peer_state.channel_by_id.entry(msg.channel_id) {
11560+
hash_map::Entry::Occupied(mut chan_entry) => {
11561+
let res = chan_entry.get_mut().tx_abort(msg, &self.logger);
11562+
let (tx_abort, splice_failed, exited_quiescence) =
11563+
try_channel_entry!(self, peer_state, res, chan_entry);
1156311564

11564-
let persist = if tx_abort.is_some() || splice_failed.is_some() {
11565-
NotifyOption::DoPersist
11566-
} else {
11567-
NotifyOption::SkipPersistNoEvents
11568-
};
11565+
let persist = if tx_abort.is_some() || splice_failed.is_some() {
11566+
NotifyOption::DoPersist
11567+
} else {
11568+
NotifyOption::SkipPersistNoEvents
11569+
};
1156911570

11570-
if let Some(tx_abort_msg) = tx_abort {
11571-
peer_state.pending_msg_events.push(MessageSendEvent::SendTxAbort {
11572-
node_id: *counterparty_node_id,
11573-
msg: tx_abort_msg,
11574-
});
11575-
}
11571+
if let Some(tx_abort_msg) = tx_abort {
11572+
peer_state.pending_msg_events.push(MessageSendEvent::SendTxAbort {
11573+
node_id: *counterparty_node_id,
11574+
msg: tx_abort_msg,
11575+
});
11576+
}
1157611577

11577-
if let Some(splice_funding_failed) = splice_failed {
11578-
let pending_events = &mut self.pending_events.lock().unwrap();
11579-
pending_events.push_back((
11580-
events::Event::SpliceFailed {
11581-
channel_id: msg.channel_id,
11582-
counterparty_node_id: *counterparty_node_id,
11583-
user_channel_id: chan_entry.get().context().get_user_id(),
11584-
abandoned_funding_txo: splice_funding_failed.funding_txo,
11585-
channel_type: splice_funding_failed.channel_type,
11586-
contributed_inputs: splice_funding_failed.contributed_inputs,
11587-
contributed_outputs: splice_funding_failed.contributed_outputs,
11588-
},
11589-
None,
11590-
));
11591-
}
11578+
if let Some(splice_funding_failed) = splice_failed {
11579+
let pending_events = &mut self.pending_events.lock().unwrap();
11580+
pending_events.push_back((
11581+
events::Event::SpliceFailed {
11582+
channel_id: msg.channel_id,
11583+
counterparty_node_id: *counterparty_node_id,
11584+
user_channel_id: chan_entry.get().context().get_user_id(),
11585+
abandoned_funding_txo: splice_funding_failed.funding_txo,
11586+
channel_type: splice_funding_failed.channel_type,
11587+
contributed_inputs: splice_funding_failed.contributed_inputs,
11588+
contributed_outputs: splice_funding_failed.contributed_outputs,
11589+
},
11590+
None,
11591+
));
11592+
}
1159211593

11593-
Ok(persist)
11594-
},
11595-
hash_map::Entry::Vacant(_) => Err(MsgHandleErrInternal::no_such_channel_for_peer(
11596-
counterparty_node_id,
11597-
msg.channel_id,
11598-
)),
11599-
}
11594+
let holding_cell_res = if exited_quiescence {
11595+
self.check_free_peer_holding_cells(peer_state)
11596+
} else {
11597+
Vec::new()
11598+
};
11599+
(Ok(persist), holding_cell_res)
11600+
},
11601+
hash_map::Entry::Vacant(_) => (
11602+
Err(MsgHandleErrInternal::no_such_channel_for_peer(
11603+
counterparty_node_id,
11604+
msg.channel_id,
11605+
)),
11606+
Vec::new(),
11607+
),
11608+
}
11609+
};
11610+
11611+
self.handle_holding_cell_free_result(holding_cell_res);
11612+
result
1160011613
}
1160111614

1160211615
#[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)