From 01513745c3c3537d8474b3452ea7206743bc136c Mon Sep 17 00:00:00 2001 From: optout <13562139+optout21@users.noreply.github.com> Date: Fri, 3 May 2024 14:45:30 +0200 Subject: [PATCH] Fix missing ChannelPending and ChannelReady flags, by clearing corresponding state flags in splice_start() --- README.md | 15 ++++-- lightning/src/ln/channel.rs | 4 ++ lightning/src/ln/functional_tests_splice.rs | 59 +++++++++++++++------ 3 files changed, 58 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index ed732bc730e..fa480d8ff82 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ Client LDK Counterparty node (acceptor) internal_splice() - ChannelManager Do checks. Check if channel ID would change. Cycle back the channel to UnfundedInboundV2 splice_start() -- ChannelContext - Start the splice, update capacity, state, reset funding transaction + Start the splice, update capacity, state to NegotiatingFunding, reset funding transaction get_splice_ack() -- Channel begin_interactive_funding_tx_construction() - Channel begin_interactive_funding_tx_construction() - ChannelContext @@ -68,7 +68,7 @@ Client LDK Counterparty node (acceptor) Do checks, check against initial splice() Cycle back the channel to UnfundedOutboundV2 splice_start() -- ChannelContext - Start the splice, update capacity, state, reset funding transaction + Start the splice, update capacity, state to NegotiatingFunding, reset funding transaction event: SpliceAckedInputsContributionReady contains the pre & post capacities, channel ID --- @@ -93,6 +93,7 @@ provide extra input(s) for new funding message out: tx_add_output - for change message in: tx_complete message out: tx_add_output - for new funding + message in: tx_complete handle_tx_complete() - ChannelManager internal_tx_complete() -- ChannelManager @@ -102,7 +103,7 @@ provide extra input(s) for new funding get_initial_commitment_signed() - Channel Splicing-specific: Add signature on the previous funding tx input Mark finished interactive tx construction - Update channel state (FundingNegotiated) + Update channel state to FundingNegotiated event: FundingTransactionReadyForSigning contains the new funding transaction with the signature on the previous tx input message out: commitment_signed (UpdateHTLCs) @@ -127,7 +128,7 @@ action by client: Create and provide signature on the extra inputs get_initial_commitment_signed() - Channel Splicing-specific: Add signature on the previous funding tx input Mark finished interactive tx construction - Update channel state (FundingNegotiated) + Update channel state to FundingNegotiated message out: commitment_signed (UpdateHTLCs) channel state: Funded --- @@ -135,7 +136,7 @@ action by client: Create and provide signature on the extra inputs handle_commitment_signed() - ChannelManager internal_commitment_signed() -- ChannelManager commitment_signed_initial_v2() -- Channel - Update channel state to AwaitingChannelReadyFlags + Update channel state to AwaitingChannelReady watch_channel() - ChainMonitor received_commitment_signed() -- InteractiveTxSigningSession --- @@ -156,6 +157,7 @@ action by client: Create and provide signature on the extra inputs received_tx_signatures() -- InteractiveTxSigningSession Update signature on previous tx input (with shared signature) Update channel state to AwaitingChannelReady + event: ChannelPending Save funding transaction message out: tx_signatures funding transaction is ready, broadcast it @@ -168,6 +170,7 @@ action by client: Create and provide signature on the extra inputs received_tx_signatures() -- InteractiveTxSigningSession Update signature on previous tx input (with shared signature) Update channel state to AwaitingChannelReady + event: ChannelPending Save funding transaction funding transaction is ready, broadcast it --- @@ -185,9 +188,11 @@ Waiting for confirmation --- message in: channel_ready handle_channel_ready() - ChannelManager + event: ChannelReady message out: channel_update message in: channel_ready handle_channel_ready() - ChannelManager + event: ChannelReady message out: channel_update /end of sequence/ diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index 8d4b27ac792..eb9e61a5a31 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -3881,6 +3881,10 @@ impl ChannelContext where SP::Target: SignerProvider { self.funding_tx_confirmed_in = None; self.funding_tx_confirmation_height = 0; + // Clear these state flags, for sending `ChannelPending` and `ChannelReady` again + self.channel_pending_event_emitted = false; + self.channel_ready_event_emitted = false; + log_trace!(logger, "Splicing process started, new channel value {}, channel_id {}", self.channel_value_satoshis, self.channel_id); Ok(()) diff --git a/lightning/src/ln/functional_tests_splice.rs b/lightning/src/ln/functional_tests_splice.rs index 96e4c968e46..bfba0ab15bf 100644 --- a/lightning/src/ln/functional_tests_splice.rs +++ b/lightning/src/ln/functional_tests_splice.rs @@ -1096,8 +1096,18 @@ fn test_v2_splice_in() { }; let _res = initiator_node.node.handle_tx_signatures(&acceptor_node.node.get_our_node_id(), &tx_signatures_1); - let events_0 = initiator_node.node.get_and_clear_pending_events(); - assert_eq!(events_0.len(), 0); + + let events = initiator_node.node.get_and_clear_pending_events(); + assert_eq!(events.len(), 1); + match events[0] { + Event::ChannelPending { channel_id, former_temporary_channel_id, counterparty_node_id, funding_txo, .. } => { + assert_eq!(channel_id.to_string(), expected_funded_channel_id); + // TODO check if former_temporary_channel_id should be set to empty in this case (or previous non-temp channel id?) + assert_eq!(former_temporary_channel_id.unwrap().to_string(), expected_temporary_channel_id); + assert_eq!(counterparty_node_id, acceptor_node.node.get_our_node_id()); + } + _ => panic!("ChannelPending event missing, {:?}", events[0]), + }; let msg_events = initiator_node.node.get_and_clear_pending_msg_events(); assert_eq!(msg_events.len(), 1); let tx_signatures_0 = match msg_events[0] { @@ -1117,8 +1127,17 @@ fn test_v2_splice_in() { let _res = acceptor_node.node.handle_tx_signatures(&initiator_node.node.get_our_node_id(), &tx_signatures_0); - let events_1 = acceptor_node.node.get_and_clear_pending_events(); - assert_eq!(events_1.len(), 0); + let events = acceptor_node.node.get_and_clear_pending_events(); + assert_eq!(events.len(), 1); + match events[0] { + Event::ChannelPending { channel_id, former_temporary_channel_id, counterparty_node_id, funding_txo, .. } => { + assert_eq!(channel_id.to_string(), expected_funded_channel_id); + // TODO check if former_temporary_channel_id should be set to empty in this case (or previous non-temp channel id?) + assert_eq!(former_temporary_channel_id.unwrap().to_string(), expected_temporary_channel_id); + assert_eq!(counterparty_node_id, initiator_node.node.get_our_node_id()); + } + _ => panic!("ChannelPending event missing, {:?}", events[0]), + }; // Check that funding transaction has been broadcasted assert_eq!(chanmon_cfgs[initiator_node_index].tx_broadcaster.txn_broadcasted.lock().unwrap().len(), 2); @@ -1157,19 +1176,29 @@ fn test_v2_splice_in() { confirm_transaction(&acceptor_node, &broadcasted_splice_tx); let channel_ready_message2 = get_event_msg!(acceptor_node, MessageSendEvent::SendChannelReady, initiator_node.node.get_our_node_id()); - let _res = acceptor_node.node.handle_channel_ready(&initiator_node.node.get_our_node_id(), &channel_ready_message); - // let _ev = get_event!(acceptor_node, Event::ChannelReady); - let events_0 = acceptor_node.node.get_and_clear_pending_events(); - assert_eq!(events_0.len(), 0); - let _channel_update = get_event_msg!(acceptor_node, MessageSendEvent::SendChannelUpdate, initiator_node.node.get_our_node_id()); - // let _announcement_signatures2 = get_event_msg!(acceptor_node, MessageSendEvent::SendAnnouncementSignatures, initiator_node.node.get_our_node_id()); - let _res = initiator_node.node.handle_channel_ready(&acceptor_node.node.get_our_node_id(), &channel_ready_message2); - // let _ev = get_event!(initiator_node, Event::ChannelReady); - let events_0 = initiator_node.node.get_and_clear_pending_events(); - assert_eq!(events_0.len(), 0); + let events = initiator_node.node.get_and_clear_pending_events(); + assert_eq!(events.len(), 1); + match events[0] { + Event::ChannelReady { channel_id, counterparty_node_id, .. } => { + assert_eq!(channel_id.to_string(), expected_funded_channel_id); + assert_eq!(counterparty_node_id, acceptor_node.node.get_our_node_id()); + } + _ => panic!("ChannelReady event missing, {:?}", events[0]), + }; let _channel_update = get_event_msg!(initiator_node, MessageSendEvent::SendChannelUpdate, acceptor_node.node.get_our_node_id()); - // let _announcement_signatures1 = get_event_msg!(initiator_node, MessageSendEvent::SendAnnouncementSignatures, acceptor_node.node.get_our_node_id()); + + let _res = acceptor_node.node.handle_channel_ready(&initiator_node.node.get_our_node_id(), &channel_ready_message); + let events = acceptor_node.node.get_and_clear_pending_events(); + assert_eq!(events.len(), 1); + match events[0] { + Event::ChannelReady { channel_id, counterparty_node_id, .. } => { + assert_eq!(channel_id.to_string(), expected_funded_channel_id); + assert_eq!(counterparty_node_id, initiator_node.node.get_our_node_id()); + } + _ => panic!("ChannelReady event missing, {:?}", events[0]), + }; + let _channel_update = get_event_msg!(acceptor_node, MessageSendEvent::SendChannelUpdate, initiator_node.node.get_our_node_id()); // check new channel capacity and other parameters assert_eq!(initiator_node.node.list_channels().len(), 1);