Skip to content

Commit e42e74e

Browse files
authored
Merge pull request #4204 from wpaulino/splice-counterparty-tx-abort-before-commit-sig
Allow counterparty tx_abort before handling initial commitment signed
2 parents 95c4eaf + d282a47 commit e42e74e

File tree

5 files changed

+243
-44
lines changed

5 files changed

+243
-44
lines changed

lightning/src/ln/async_signer_tests.rs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -596,7 +596,7 @@ fn do_test_async_raa_peer_disconnect(
596596
}
597597

598598
// Expect the RAA
599-
let (_, revoke_and_ack, commitment_signed, resend_order, _, _, _) =
599+
let (_, revoke_and_ack, commitment_signed, resend_order, _, _, _, _) =
600600
handle_chan_reestablish_msgs!(dst, src);
601601
if test_case == UnblockSignerAcrossDisconnectCase::AtEnd {
602602
assert!(revoke_and_ack.is_none());
@@ -612,14 +612,14 @@ fn do_test_async_raa_peer_disconnect(
612612
dst.node.signer_unblocked(Some((src_node_id, chan_id)));
613613

614614
if test_case == UnblockSignerAcrossDisconnectCase::AtEnd {
615-
let (_, revoke_and_ack, commitment_signed, resend_order, _, _, _) =
615+
let (_, revoke_and_ack, commitment_signed, resend_order, _, _, _, _) =
616616
handle_chan_reestablish_msgs!(dst, src);
617617
assert!(revoke_and_ack.is_some());
618618
assert!(commitment_signed.is_some());
619619
assert!(resend_order == RAACommitmentOrder::RevokeAndACKFirst);
620620
} else {
621621
// Make sure we don't double send the RAA.
622-
let (_, revoke_and_ack, commitment_signed, _, _, _, _) =
622+
let (_, revoke_and_ack, commitment_signed, _, _, _, _, _) =
623623
handle_chan_reestablish_msgs!(dst, src);
624624
assert!(revoke_and_ack.is_none());
625625
assert!(commitment_signed.is_none());
@@ -746,7 +746,7 @@ fn do_test_async_commitment_signature_peer_disconnect(
746746
}
747747

748748
// Expect the RAA
749-
let (_, revoke_and_ack, commitment_signed, _, _, _, _) =
749+
let (_, revoke_and_ack, commitment_signed, _, _, _, _, _) =
750750
handle_chan_reestablish_msgs!(dst, src);
751751
assert!(revoke_and_ack.is_some());
752752
if test_case == UnblockSignerAcrossDisconnectCase::AtEnd {
@@ -760,11 +760,11 @@ fn do_test_async_commitment_signature_peer_disconnect(
760760
dst.node.signer_unblocked(Some((src_node_id, chan_id)));
761761

762762
if test_case == UnblockSignerAcrossDisconnectCase::AtEnd {
763-
let (_, _, commitment_signed, _, _, _, _) = handle_chan_reestablish_msgs!(dst, src);
763+
let (_, _, commitment_signed, _, _, _, _, _) = handle_chan_reestablish_msgs!(dst, src);
764764
assert!(commitment_signed.is_some());
765765
} else {
766766
// Make sure we don't double send the CS.
767-
let (_, _, commitment_signed, _, _, _, _) = handle_chan_reestablish_msgs!(dst, src);
767+
let (_, _, commitment_signed, _, _, _, _, _) = handle_chan_reestablish_msgs!(dst, src);
768768
assert!(commitment_signed.is_none());
769769
}
770770
}
@@ -882,6 +882,7 @@ fn do_test_async_commitment_signature_ordering(monitor_update_failure: bool) {
882882
assert!(as_resp.4.is_none());
883883
assert!(as_resp.5.is_none());
884884
assert!(as_resp.6.is_none());
885+
assert!(as_resp.7.is_none());
885886

886887
if monitor_update_failure {
887888
chanmon_cfgs[0].persister.set_update_ret(ChannelMonitorUpdateStatus::Completed);
@@ -904,6 +905,7 @@ fn do_test_async_commitment_signature_ordering(monitor_update_failure: bool) {
904905
assert!(as_resp.4.is_none());
905906
assert!(as_resp.5.is_none());
906907
assert!(as_resp.6.is_none());
908+
assert!(as_resp.7.is_none());
907909

908910
nodes[0].enable_channel_signer_op(&node_b_id, &chan_id, SignerOp::SignCounterpartyCommitment);
909911
nodes[0].node.signer_unblocked(Some((node_b_id, chan_id)));
@@ -929,6 +931,9 @@ fn do_test_async_commitment_signature_ordering(monitor_update_failure: bool) {
929931
assert!(as_resp.6.is_none());
930932
assert!(bs_resp.6.is_none());
931933

934+
assert!(as_resp.7.is_none());
935+
assert!(bs_resp.7.is_none());
936+
932937
// Now that everything is restored, get the CS + RAA and handle them.
933938
nodes[1]
934939
.node

lightning/src/ln/channel.rs

Lines changed: 72 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1654,7 +1654,7 @@ where
16541654
}
16551655
chan.context.channel_state.clear_local_stfu_sent();
16561656
chan.context.channel_state.clear_remote_stfu_sent();
1657-
if chan.should_reset_pending_splice_state() {
1657+
if chan.should_reset_pending_splice_state(false) {
16581658
// If there was a pending splice negotiation that failed due to disconnecting, we
16591659
// also take the opportunity to clean up our state.
16601660
let splice_funding_failed = chan.reset_pending_splice_state();
@@ -1775,7 +1775,7 @@ where
17751775
None
17761776
},
17771777
ChannelPhase::Funded(funded_channel) => {
1778-
if funded_channel.should_reset_pending_splice_state() {
1778+
if funded_channel.should_reset_pending_splice_state(false) {
17791779
funded_channel.reset_pending_splice_state()
17801780
} else {
17811781
debug_assert!(false, "We should never fail an interactive funding negotiation once we're exchanging tx_signatures");
@@ -1932,12 +1932,24 @@ where
19321932
(had_constructor, None)
19331933
},
19341934
ChannelPhase::Funded(funded_channel) => {
1935-
if funded_channel.has_pending_splice_awaiting_signatures() {
1935+
if funded_channel.has_pending_splice_awaiting_signatures()
1936+
&& funded_channel
1937+
.context()
1938+
.interactive_tx_signing_session
1939+
.as_ref()
1940+
.expect("We have a pending splice awaiting signatures")
1941+
.has_received_commitment_signed()
1942+
{
1943+
// We only force close once the counterparty tries to abort after committing to
1944+
// the splice via their initial `commitment_signed`. This is because our monitor
1945+
// state is updated with the post-splice commitment transaction upon receiving
1946+
// their `commitment_signed`, so we would need another monitor update to abandon
1947+
// it, which we don't currently support.
19361948
return Err(ChannelError::close(
19371949
"Received tx_abort while awaiting tx_signatures exchange".to_owned(),
19381950
));
19391951
}
1940-
if funded_channel.should_reset_pending_splice_state() {
1952+
if funded_channel.should_reset_pending_splice_state(true) {
19411953
let has_funding_negotiation = funded_channel
19421954
.pending_splice
19431955
.as_ref()
@@ -2681,19 +2693,6 @@ impl FundingNegotiation {
26812693
}
26822694

26832695
impl PendingFunding {
2684-
fn can_abandon_state(&self) -> bool {
2685-
self.funding_negotiation
2686-
.as_ref()
2687-
.map(|funding_negotiation| {
2688-
!matches!(funding_negotiation, FundingNegotiation::AwaitingSignatures { .. })
2689-
})
2690-
.unwrap_or_else(|| {
2691-
let has_negotiated_candidates = !self.negotiated_candidates.is_empty();
2692-
debug_assert!(has_negotiated_candidates);
2693-
!has_negotiated_candidates
2694-
})
2695-
}
2696-
26972696
fn check_get_splice_locked<SP: Deref>(
26982697
&mut self, context: &ChannelContext<SP>, confirmed_funding_index: usize, height: u32,
26992698
) -> Option<msgs::SpliceLocked>
@@ -6873,7 +6872,7 @@ pub struct SpliceFundingFailed {
68736872
}
68746873

68756874
macro_rules! maybe_create_splice_funding_failed {
6876-
($pending_splice: expr, $get: ident, $contributed_inputs_and_outputs: ident) => {{
6875+
($funded_channel: expr, $pending_splice: expr, $get: ident, $contributed_inputs_and_outputs: ident) => {{
68776876
$pending_splice
68786877
.and_then(|pending_splice| pending_splice.funding_negotiation.$get())
68796878
.filter(|funding_negotiation| funding_negotiation.is_initiator())
@@ -6895,10 +6894,12 @@ macro_rules! maybe_create_splice_funding_failed {
68956894
interactive_tx_constructor,
68966895
..
68976896
} => interactive_tx_constructor.$contributed_inputs_and_outputs(),
6898-
FundingNegotiation::AwaitingSignatures { .. } => {
6899-
debug_assert!(false);
6900-
(Vec::new(), Vec::new())
6901-
},
6897+
FundingNegotiation::AwaitingSignatures { .. } => $funded_channel
6898+
.context
6899+
.interactive_tx_signing_session
6900+
.$get()
6901+
.expect("We have a pending splice awaiting signatures")
6902+
.$contributed_inputs_and_outputs(),
69026903
};
69036904

69046905
SpliceFundingFailed {
@@ -6937,7 +6938,7 @@ where
69376938

69386939
fn maybe_fail_splice_negotiation(&mut self) -> Option<SpliceFundingFailed> {
69396940
if matches!(self.context.channel_state, ChannelState::ChannelReady(_)) {
6940-
if self.should_reset_pending_splice_state() {
6941+
if self.should_reset_pending_splice_state(false) {
69416942
self.reset_pending_splice_state()
69426943
} else {
69436944
match self.quiescent_action.take() {
@@ -7011,19 +7012,54 @@ where
70117012

70127013
/// Returns a boolean indicating whether we should reset the splice's
70137014
/// [`PendingFunding::funding_negotiation`].
7014-
fn should_reset_pending_splice_state(&self) -> bool {
7015+
fn should_reset_pending_splice_state(&self, counterparty_aborted: bool) -> bool {
70157016
self.pending_splice
70167017
.as_ref()
7017-
.map(|pending_splice| pending_splice.can_abandon_state())
7018+
.map(|pending_splice| {
7019+
pending_splice
7020+
.funding_negotiation
7021+
.as_ref()
7022+
.map(|funding_negotiation| {
7023+
let is_awaiting_signatures = matches!(
7024+
funding_negotiation,
7025+
FundingNegotiation::AwaitingSignatures { .. }
7026+
);
7027+
if counterparty_aborted {
7028+
!is_awaiting_signatures
7029+
|| !self
7030+
.context()
7031+
.interactive_tx_signing_session
7032+
.as_ref()
7033+
.expect("We have a pending splice awaiting signatures")
7034+
.has_received_commitment_signed()
7035+
} else {
7036+
!is_awaiting_signatures
7037+
}
7038+
})
7039+
.unwrap_or_else(|| {
7040+
let has_negotiated_candidates =
7041+
!pending_splice.negotiated_candidates.is_empty();
7042+
debug_assert!(has_negotiated_candidates);
7043+
!has_negotiated_candidates
7044+
})
7045+
})
70187046
.unwrap_or(false)
70197047
}
70207048

70217049
fn reset_pending_splice_state(&mut self) -> Option<SpliceFundingFailed> {
7022-
debug_assert!(self.should_reset_pending_splice_state());
7023-
debug_assert!(self.context.interactive_tx_signing_session.is_none());
7024-
self.context.channel_state.clear_quiescent();
7050+
debug_assert!(self.should_reset_pending_splice_state(true));
7051+
debug_assert!(
7052+
self.context.interactive_tx_signing_session.is_none()
7053+
|| !self
7054+
.context
7055+
.interactive_tx_signing_session
7056+
.as_ref()
7057+
.expect("We have a pending splice awaiting signatures")
7058+
.has_received_commitment_signed()
7059+
);
70257060

70267061
let splice_funding_failed = maybe_create_splice_funding_failed!(
7062+
self,
70277063
self.pending_splice.as_mut(),
70287064
take,
70297065
into_contributed_inputs_and_outputs
@@ -7033,15 +7069,19 @@ where
70337069
self.pending_splice.take();
70347070
}
70357071

7072+
self.context.channel_state.clear_quiescent();
7073+
self.context.interactive_tx_signing_session.take();
7074+
70367075
splice_funding_failed
70377076
}
70387077

70397078
pub(super) fn maybe_splice_funding_failed(&self) -> Option<SpliceFundingFailed> {
7040-
if !self.should_reset_pending_splice_state() {
7079+
if !self.should_reset_pending_splice_state(false) {
70417080
return None;
70427081
}
70437082

70447083
maybe_create_splice_funding_failed!(
7084+
self,
70457085
self.pending_splice.as_ref(),
70467086
as_ref,
70477087
to_contributed_inputs_and_outputs
@@ -11996,7 +12036,7 @@ where
1199612036
pub fn abandon_splice(
1199712037
&mut self,
1199812038
) -> Result<(msgs::TxAbort, Option<SpliceFundingFailed>), APIError> {
11999-
if self.should_reset_pending_splice_state() {
12039+
if self.should_reset_pending_splice_state(false) {
1200012040
let tx_abort =
1200112041
msgs::TxAbort { channel_id: self.context.channel_id(), data: Vec::new() };
1200212042
let splice_funding_failed = self.reset_pending_splice_state();
@@ -14361,7 +14401,7 @@ where
1436114401
}
1436214402
channel_state.clear_local_stfu_sent();
1436314403
channel_state.clear_remote_stfu_sent();
14364-
if self.should_reset_pending_splice_state()
14404+
if self.should_reset_pending_splice_state(false)
1436514405
|| !self.has_pending_splice_awaiting_signatures()
1436614406
{
1436714407
// We shouldn't be quiescent anymore upon reconnecting if:
@@ -14735,7 +14775,7 @@ where
1473514775
// We don't have to worry about resetting the pending `FundingNegotiation` because we
1473614776
// can only read `FundingNegotiation::AwaitingSignatures` variants anyway.
1473714777
let pending_splice =
14738-
self.pending_splice.as_ref().filter(|_| !self.should_reset_pending_splice_state());
14778+
self.pending_splice.as_ref().filter(|_| !self.should_reset_pending_splice_state(false));
1473914779

1474014780
write_tlv_fields!(writer, {
1474114781
(0, self.context.announcement_sigs, option),

lightning/src/ln/functional_test_utils.rs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4996,9 +4996,17 @@ macro_rules! handle_chan_reestablish_msgs {
49964996
($src_node: expr, $dst_node: expr) => {{
49974997
let msg_events = $src_node.node.get_and_clear_pending_msg_events();
49984998
let mut idx = 0;
4999+
5000+
let mut tx_abort = None;
5001+
if let Some(&MessageSendEvent::SendTxAbort { ref node_id, ref msg }) = msg_events.get(idx) {
5002+
idx += 1;
5003+
assert_eq!(*node_id, $dst_node.node.get_our_node_id());
5004+
tx_abort = Some(msg.clone());
5005+
}
5006+
49995007
let channel_ready =
50005008
if let Some(&MessageSendEvent::SendChannelReady { ref node_id, ref msg }) =
5001-
msg_events.get(0)
5009+
msg_events.get(idx)
50025010
{
50035011
idx += 1;
50045012
assert_eq!(*node_id, $dst_node.node.get_our_node_id());
@@ -5115,6 +5123,7 @@ macro_rules! handle_chan_reestablish_msgs {
51155123
announcement_sigs,
51165124
tx_signatures,
51175125
stfu,
5126+
tx_abort,
51185127
)
51195128
}};
51205129
}
@@ -5127,6 +5136,7 @@ pub struct ReconnectArgs<'a, 'b, 'c, 'd> {
51275136
pub send_stfu: (bool, bool),
51285137
pub send_interactive_tx_commit_sig: (bool, bool),
51295138
pub send_interactive_tx_sigs: (bool, bool),
5139+
pub send_tx_abort: (bool, bool),
51305140
pub expect_renegotiated_funding_locked_monitor_update: (bool, bool),
51315141
pub pending_responding_commitment_signed: (bool, bool),
51325142
/// Indicates that the pending responding commitment signed will be a dup for the recipient,
@@ -5150,6 +5160,7 @@ impl<'a, 'b, 'c, 'd> ReconnectArgs<'a, 'b, 'c, 'd> {
51505160
send_stfu: (false, false),
51515161
send_interactive_tx_commit_sig: (false, false),
51525162
send_interactive_tx_sigs: (false, false),
5163+
send_tx_abort: (false, false),
51535164
expect_renegotiated_funding_locked_monitor_update: (false, false),
51545165
pending_responding_commitment_signed: (false, false),
51555166
pending_responding_commitment_signed_dup_monitor: (false, false),
@@ -5174,6 +5185,7 @@ pub fn reconnect_nodes<'a, 'b, 'c, 'd>(args: ReconnectArgs<'a, 'b, 'c, 'd>) {
51745185
send_stfu,
51755186
send_interactive_tx_commit_sig,
51765187
send_interactive_tx_sigs,
5188+
send_tx_abort,
51775189
expect_renegotiated_funding_locked_monitor_update,
51785190
pending_htlc_adds,
51795191
pending_htlc_claims,
@@ -5305,6 +5317,12 @@ pub fn reconnect_nodes<'a, 'b, 'c, 'd>(args: ReconnectArgs<'a, 'b, 'c, 'd>) {
53055317
&commitment_update.commitment_signed,
53065318
)
53075319
}
5320+
if send_tx_abort.0 {
5321+
let tx_abort = chan_msgs.7.take().unwrap();
5322+
node_a.node.handle_tx_abort(node_b_id, &tx_abort);
5323+
} else {
5324+
assert!(chan_msgs.7.is_none());
5325+
}
53085326
if send_interactive_tx_sigs.0 {
53095327
let tx_signatures = chan_msgs.5.take().unwrap();
53105328
node_a.node.handle_tx_signatures(node_b_id, &tx_signatures);
@@ -5417,6 +5435,12 @@ pub fn reconnect_nodes<'a, 'b, 'c, 'd>(args: ReconnectArgs<'a, 'b, 'c, 'd>) {
54175435
&commitment_update.commitment_signed,
54185436
)
54195437
}
5438+
if send_tx_abort.1 {
5439+
let tx_abort = chan_msgs.7.take().unwrap();
5440+
node_a.node.handle_tx_abort(node_b_id, &tx_abort);
5441+
} else {
5442+
assert!(chan_msgs.7.is_none());
5443+
}
54205444
if send_interactive_tx_sigs.1 {
54215445
let tx_signatures = chan_msgs.5.take().unwrap();
54225446
node_b.node.handle_tx_signatures(node_a_id, &tx_signatures);

0 commit comments

Comments
 (0)