Skip to content

Commit 2665465

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 ac0f53f commit 2665465

File tree

3 files changed

+87
-53
lines changed

3 files changed

+87
-53
lines changed

lightning/src/ln/channel.rs

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

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

2095-
Ok((tx_abort, splice_funding_failed))
2095+
Ok((tx_abort, splice_funding_failed, exited_quiescence))
20962096
}
20972097

20982098
#[rustfmt::skip]

lightning/src/ln/channelmanager.rs

Lines changed: 58 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -11632,55 +11632,68 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1163211632
fn internal_tx_abort(
1163311633
&self, counterparty_node_id: &PublicKey, msg: &msgs::TxAbort,
1163411634
) -> Result<NotifyOption, MsgHandleErrInternal> {
11635-
let per_peer_state = self.per_peer_state.read().unwrap();
11636-
let peer_state_mutex = per_peer_state.get(counterparty_node_id).ok_or_else(|| {
11637-
debug_assert!(false);
11638-
MsgHandleErrInternal::no_such_peer(counterparty_node_id, msg.channel_id)
11639-
})?;
11640-
let mut peer_state_lock = peer_state_mutex.lock().unwrap();
11641-
let peer_state = &mut *peer_state_lock;
11642-
match peer_state.channel_by_id.entry(msg.channel_id) {
11643-
hash_map::Entry::Occupied(mut chan_entry) => {
11644-
let res = chan_entry.get_mut().tx_abort(msg, &self.logger);
11645-
let (tx_abort, splice_failed) =
11646-
try_channel_entry!(self, peer_state, res, chan_entry);
11635+
let (result, holding_cell_res) = {
11636+
let per_peer_state = self.per_peer_state.read().unwrap();
11637+
let peer_state_mutex = per_peer_state.get(counterparty_node_id).ok_or_else(|| {
11638+
debug_assert!(false);
11639+
MsgHandleErrInternal::no_such_peer(counterparty_node_id, msg.channel_id)
11640+
})?;
11641+
let mut peer_state_lock = peer_state_mutex.lock().unwrap();
11642+
let peer_state = &mut *peer_state_lock;
11643+
match peer_state.channel_by_id.entry(msg.channel_id) {
11644+
hash_map::Entry::Occupied(mut chan_entry) => {
11645+
let res = chan_entry.get_mut().tx_abort(msg, &self.logger);
11646+
let (tx_abort, splice_failed, exited_quiescence) =
11647+
try_channel_entry!(self, peer_state, res, chan_entry);
1164711648

11648-
let persist = if tx_abort.is_some() || splice_failed.is_some() {
11649-
NotifyOption::DoPersist
11650-
} else {
11651-
NotifyOption::SkipPersistNoEvents
11652-
};
11649+
let persist = if tx_abort.is_some() || splice_failed.is_some() {
11650+
NotifyOption::DoPersist
11651+
} else {
11652+
NotifyOption::SkipPersistNoEvents
11653+
};
1165311654

11654-
if let Some(tx_abort_msg) = tx_abort {
11655-
peer_state.pending_msg_events.push(MessageSendEvent::SendTxAbort {
11656-
node_id: *counterparty_node_id,
11657-
msg: tx_abort_msg,
11658-
});
11659-
}
11655+
if let Some(tx_abort_msg) = tx_abort {
11656+
peer_state.pending_msg_events.push(MessageSendEvent::SendTxAbort {
11657+
node_id: *counterparty_node_id,
11658+
msg: tx_abort_msg,
11659+
});
11660+
}
1166011661

11661-
if let Some(splice_funding_failed) = splice_failed {
11662-
let pending_events = &mut self.pending_events.lock().unwrap();
11663-
pending_events.push_back((
11664-
events::Event::SpliceFailed {
11665-
channel_id: msg.channel_id,
11666-
counterparty_node_id: *counterparty_node_id,
11667-
user_channel_id: chan_entry.get().context().get_user_id(),
11668-
abandoned_funding_txo: splice_funding_failed.funding_txo,
11669-
channel_type: splice_funding_failed.channel_type,
11670-
contributed_inputs: splice_funding_failed.contributed_inputs,
11671-
contributed_outputs: splice_funding_failed.contributed_outputs,
11672-
},
11673-
None,
11674-
));
11675-
}
11662+
if let Some(splice_funding_failed) = splice_failed {
11663+
let pending_events = &mut self.pending_events.lock().unwrap();
11664+
pending_events.push_back((
11665+
events::Event::SpliceFailed {
11666+
channel_id: msg.channel_id,
11667+
counterparty_node_id: *counterparty_node_id,
11668+
user_channel_id: chan_entry.get().context().get_user_id(),
11669+
abandoned_funding_txo: splice_funding_failed.funding_txo,
11670+
channel_type: splice_funding_failed.channel_type,
11671+
contributed_inputs: splice_funding_failed.contributed_inputs,
11672+
contributed_outputs: splice_funding_failed.contributed_outputs,
11673+
},
11674+
None,
11675+
));
11676+
}
1167611677

11677-
Ok(persist)
11678-
},
11679-
hash_map::Entry::Vacant(_) => Err(MsgHandleErrInternal::no_such_channel_for_peer(
11680-
counterparty_node_id,
11681-
msg.channel_id,
11682-
)),
11683-
}
11678+
let holding_cell_res = if exited_quiescence {
11679+
self.check_free_peer_holding_cells(peer_state)
11680+
} else {
11681+
Vec::new()
11682+
};
11683+
(Ok(persist), holding_cell_res)
11684+
},
11685+
hash_map::Entry::Vacant(_) => (
11686+
Err(MsgHandleErrInternal::no_such_channel_for_peer(
11687+
counterparty_node_id,
11688+
msg.channel_id,
11689+
)),
11690+
Vec::new(),
11691+
),
11692+
}
11693+
};
11694+
11695+
self.handle_holding_cell_free_result(holding_cell_res);
11696+
result
1168411697
}
1168511698

1168611699
#[rustfmt::skip]

lightning/src/ln/splicing_tests.rs

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2037,6 +2037,13 @@ fn fail_splice_on_tx_abort() {
20372037
initiate_splice_in(initiator, acceptor, channel_id, Amount::from_sat(splice_in_amount));
20382038
let _ = complete_splice_handshake(initiator, acceptor);
20392039

2040+
// Queue an outgoing HTLC to the holding cell. It should be freed once we exit quiescence.
2041+
let (route, payment_hash, _payment_preimage, payment_secret) =
2042+
get_route_and_payment_hash!(initiator, acceptor, 1_000_000);
2043+
let onion = RecipientOnionFields::secret_only(payment_secret);
2044+
let payment_id = PaymentId(payment_hash.0);
2045+
initiator.node.send_payment_with_route(route, payment_hash, onion, payment_id).unwrap();
2046+
20402047
let tx_add_input =
20412048
get_event_msg!(initiator, MessageSendEvent::SendTxAddInput, node_id_acceptor);
20422049
acceptor.node.handle_tx_add_input(node_id_initiator, &tx_add_input);
@@ -2057,8 +2064,22 @@ fn fail_splice_on_tx_abort() {
20572064
_ => panic!("Expected Event::SpliceFailed"),
20582065
}
20592066

2060-
let tx_abort = get_event_msg!(initiator, MessageSendEvent::SendTxAbort, node_id_acceptor);
2061-
acceptor.node.handle_tx_abort(node_id_initiator, &tx_abort);
2067+
// We exit quiescence upon receiving `tx_abort`, so we should see our `tx_abort` echo and the
2068+
// holding cell be immediately freed.
2069+
let msg_events = initiator.node.get_and_clear_pending_msg_events();
2070+
assert_eq!(msg_events.len(), 2, "{msg_events:?}");
2071+
check_added_monitors(initiator, 1);
2072+
if let MessageSendEvent::SendTxAbort { msg, .. } = &msg_events[0] {
2073+
acceptor.node.handle_tx_abort(node_id_initiator, msg);
2074+
} else {
2075+
panic!("Unexpected event {:?}", msg_events[0]);
2076+
};
2077+
if let MessageSendEvent::UpdateHTLCs { updates, .. } = &msg_events[1] {
2078+
acceptor.node.handle_update_add_htlc(node_id_initiator, &updates.update_add_htlcs[0]);
2079+
do_commitment_signed_dance(acceptor, initiator, &updates.commitment_signed, false, false);
2080+
} else {
2081+
panic!("Unexpected event {:?}", msg_events[1]);
2082+
};
20622083
}
20632084

20642085
#[test]

0 commit comments

Comments
 (0)