From: Elias Rohrer Date: Fri, 10 Mar 2023 15:30:37 +0000 (+0100) Subject: Add `ChannelPending` event emitted upon `funding_signed` X-Git-Tag: v0.0.115~42^2 X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=commitdiff_plain;h=9873c7dad851a0ffa16f38a4788115cb5e0f5907;p=rust-lightning Add `ChannelPending` event emitted upon `funding_signed` Currently, users don't have good way of being notified when channel open negotiations have succeeded and new channels are pending confirmation on chain. To this end, we add a new `ChannelPending` event that is emitted when send or receive a `funding_signed` message, i.e., at the last moment before waiting for the confirmation period. We track whether the event had previously been emitted in `Channel` and remove it from `internal_funding_created` entirely. Hence, we now only emit the event after ChannelMonitorUpdate completion, or upon channel reestablish. This mitigates a race condition where where we wouldn't persist the event *and* wouldn't regenerate it on restart, therefore potentially losing it, if async CMU wouldn't complete before ChannelManager persistence. --- diff --git a/fuzz/src/chanmon_consistency.rs b/fuzz/src/chanmon_consistency.rs index f6be6cdaf..56bd685d1 100644 --- a/fuzz/src/chanmon_consistency.rs +++ b/fuzz/src/chanmon_consistency.rs @@ -526,7 +526,18 @@ pub fn do_test(data: &[u8], underlying_out: Out) { msg.clone() } else { panic!("Wrong event type"); } }; + let events = $dest.get_and_clear_pending_events(); + assert_eq!(events.len(), 1); + if let events::Event::ChannelPending{ ref counterparty_node_id, .. } = events[0] { + assert_eq!(counterparty_node_id, &$source.get_our_node_id()); + } else { panic!("Wrong event type"); } + $source.handle_funding_signed(&$dest.get_our_node_id(), &funding_signed); + let events = $source.get_and_clear_pending_events(); + assert_eq!(events.len(), 1); + if let events::Event::ChannelPending{ ref counterparty_node_id, .. } = events[0] { + assert_eq!(counterparty_node_id, &$dest.get_our_node_id()); + } else { panic!("Wrong event type"); } funding_output } } diff --git a/lightning-background-processor/src/lib.rs b/lightning-background-processor/src/lib.rs index 884a7c226..541813c7e 100644 --- a/lightning-background-processor/src/lib.rs +++ b/lightning-background-processor/src/lib.rs @@ -710,7 +710,7 @@ mod tests { use lightning::chain::keysinterface::{InMemorySigner, KeysManager}; use lightning::chain::transaction::OutPoint; use lightning::events::{Event, PathFailure, MessageSendEventsProvider, MessageSendEvent}; - use lightning::get_event_msg; + use lightning::{get_event_msg, get_event}; use lightning::ln::PaymentHash; use lightning::ln::channelmanager; use lightning::ln::channelmanager::{BREAKDOWN_TIMEOUT, ChainParameters, MIN_CLTV_EXPIRY_DELTA, PaymentId}; @@ -1058,7 +1058,10 @@ mod tests { ($node_a: expr, $node_b: expr, $temporary_channel_id: expr, $tx: expr) => {{ $node_a.node.funding_transaction_generated(&$temporary_channel_id, &$node_b.node.get_our_node_id(), $tx.clone()).unwrap(); $node_b.node.handle_funding_created(&$node_a.node.get_our_node_id(), &get_event_msg!($node_a, MessageSendEvent::SendFundingCreated, $node_b.node.get_our_node_id())); + get_event!($node_b, Event::ChannelPending); + $node_a.node.handle_funding_signed(&$node_b.node.get_our_node_id(), &get_event_msg!($node_b, MessageSendEvent::SendFundingSigned, $node_a.node.get_our_node_id())); + get_event!($node_a, Event::ChannelPending); }} } diff --git a/lightning/src/events/mod.rs b/lightning/src/events/mod.rs index a96d36b64..2d576d33a 100644 --- a/lightning/src/events/mod.rs +++ b/lightning/src/events/mod.rs @@ -32,7 +32,9 @@ use crate::util::ser::{BigSize, FixedLengthReader, Writeable, Writer, MaybeReada use crate::util::string::UntrustedString; use crate::routing::router::{RouteHop, RouteParameters}; -use bitcoin::{PackedLockTime, Transaction}; +use bitcoin::{PackedLockTime, Transaction, OutPoint}; +#[cfg(anchors)] +use bitcoin::{Txid, TxIn, TxOut, Witness}; use bitcoin::blockdata::script::Script; use bitcoin::hashes::Hash; use bitcoin::hashes::sha256::Hash as Sha256; @@ -608,12 +610,39 @@ pub enum Event { /// The caveat described above the `fee_earned_msat` field applies here as well. outbound_amount_forwarded_msat: Option, }, + /// Used to indicate that a channel with the given `channel_id` is being opened and pending + /// confirmation on-chain. + /// + /// This event is emitted when the funding transaction has been signed and is broadcast to the + /// network. For 0conf channels it will be immediately followed by the corresponding + /// [`Event::ChannelReady`] event. + ChannelPending { + /// The `channel_id` of the channel that is pending confirmation. + channel_id: [u8; 32], + /// The `user_channel_id` value passed in to [`ChannelManager::create_channel`] for outbound + /// channels, or to [`ChannelManager::accept_inbound_channel`] for inbound channels if + /// [`UserConfig::manually_accept_inbound_channels`] config flag is set to true. Otherwise + /// `user_channel_id` will be randomized for an inbound channel. + /// + /// [`ChannelManager::create_channel`]: crate::ln::channelmanager::ChannelManager::create_channel + /// [`ChannelManager::accept_inbound_channel`]: crate::ln::channelmanager::ChannelManager::accept_inbound_channel + /// [`UserConfig::manually_accept_inbound_channels`]: crate::util::config::UserConfig::manually_accept_inbound_channels + user_channel_id: u128, + /// The `temporary_channel_id` this channel used to be known by during channel establishment. + /// + /// Will be `None` for channels created prior to LDK version 0.0.115. + former_temporary_channel_id: Option<[u8; 32]>, + /// The `node_id` of the channel counterparty. + counterparty_node_id: PublicKey, + /// The outpoint of the channel's funding transaction. + funding_txo: OutPoint, + }, /// Used to indicate that a channel with the given `channel_id` is ready to /// be used. This event is emitted either when the funding transaction has been confirmed /// on-chain, or, in case of a 0conf channel, when both parties have confirmed the channel /// establishment. ChannelReady { - /// The channel_id of the channel that is ready. + /// The `channel_id` of the channel that is ready. channel_id: [u8; 32], /// The `user_channel_id` value passed in to [`ChannelManager::create_channel`] for outbound /// channels, or to [`ChannelManager::accept_inbound_channel`] for inbound channels if @@ -624,7 +653,7 @@ pub enum Event { /// [`ChannelManager::accept_inbound_channel`]: crate::ln::channelmanager::ChannelManager::accept_inbound_channel /// [`UserConfig::manually_accept_inbound_channels`]: crate::util::config::UserConfig::manually_accept_inbound_channels user_channel_id: u128, - /// The node_id of the channel counterparty. + /// The `node_id` of the channel counterparty. counterparty_node_id: PublicKey, /// The features that this channel will operate with. channel_type: ChannelTypeFeatures, @@ -632,7 +661,7 @@ pub enum Event { /// Used to indicate that a previously opened channel with the given `channel_id` is in the /// process of closure. ChannelClosed { - /// The channel_id of the channel which has been closed. Note that on-chain transactions + /// The `channel_id` of the channel which has been closed. Note that on-chain transactions /// resolving the channel are likely still awaiting confirmation. channel_id: [u8; 32], /// The `user_channel_id` value passed in to [`ChannelManager::create_channel`] for outbound @@ -931,6 +960,16 @@ impl Writeable for Event { (6, channel_type, required), }); }, + &Event::ChannelPending { ref channel_id, ref user_channel_id, ref former_temporary_channel_id, ref counterparty_node_id, ref funding_txo } => { + 31u8.write(writer)?; + write_tlv_fields!(writer, { + (0, channel_id, required), + (2, user_channel_id, required), + (4, former_temporary_channel_id, required), + (6, counterparty_node_id, required), + (8, funding_txo, required), + }); + }, // Note that, going forward, all new events must only write data inside of // `write_tlv_fields`. Versions 0.0.101+ will ignore odd-numbered events that write // data via `write_tlv_fields`. @@ -1271,6 +1310,31 @@ impl MaybeReadable for Event { }; f() }, + 31u8 => { + let f = || { + let mut channel_id = [0; 32]; + let mut user_channel_id: u128 = 0; + let mut former_temporary_channel_id = None; + let mut counterparty_node_id = RequiredWrapper(None); + let mut funding_txo = RequiredWrapper(None); + read_tlv_fields!(reader, { + (0, channel_id, required), + (2, user_channel_id, required), + (4, former_temporary_channel_id, required), + (6, counterparty_node_id, required), + (8, funding_txo, required), + }); + + Ok(Some(Event::ChannelPending { + channel_id, + user_channel_id, + former_temporary_channel_id, + counterparty_node_id: counterparty_node_id.0.unwrap(), + funding_txo: funding_txo.0.unwrap() + })) + }; + f() + }, // Versions prior to 0.0.100 did not ignore odd types, instead returning InvalidValue. // Version 0.0.100 failed to properly ignore odd types, possibly resulting in corrupt // reads. diff --git a/lightning/src/ln/chanmon_update_fail_tests.rs b/lightning/src/ln/chanmon_update_fail_tests.rs index b57f70d79..94df7371a 100644 --- a/lightning/src/ln/chanmon_update_fail_tests.rs +++ b/lightning/src/ln/chanmon_update_fail_tests.rs @@ -1864,6 +1864,7 @@ fn do_during_funding_monitor_fail(confirm_a_first: bool, restore_b_before_conf: let (outpoint, latest_update, _) = nodes[0].chain_monitor.latest_monitor_update_id.lock().unwrap().get(&channel_id).unwrap().clone(); nodes[0].chain_monitor.chain_monitor.force_channel_monitor_updated(outpoint, latest_update); check_added_monitors!(nodes[0], 0); + expect_channel_pending_event(&nodes[0], &nodes[1].node.get_our_node_id()); let events = nodes[0].node.get_and_clear_pending_events(); assert_eq!(events.len(), 0); @@ -1885,6 +1886,9 @@ fn do_during_funding_monitor_fail(confirm_a_first: bool, restore_b_before_conf: nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id()); nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id()); reconnect_nodes(&nodes[0], &nodes[1], (false, confirm_a_first), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (false, false)); + + // But we want to re-emit ChannelPending + expect_channel_pending_event(&nodes[1], &nodes[0].node.get_our_node_id()); assert!(nodes[0].node.get_and_clear_pending_msg_events().is_empty()); assert!(nodes[1].node.get_and_clear_pending_msg_events().is_empty()); @@ -2808,6 +2812,7 @@ fn do_test_outbound_reload_without_init_mon(use_0conf: bool) { let funding_created_msg = get_event_msg!(nodes[0], MessageSendEvent::SendFundingCreated, nodes[1].node.get_our_node_id()); nodes[1].node.handle_funding_created(&nodes[0].node.get_our_node_id(), &funding_created_msg); check_added_monitors!(nodes[1], 1); + expect_channel_pending_event(&nodes[1], &nodes[0].node.get_our_node_id()); let bs_signed_locked = nodes[1].node.get_and_clear_pending_msg_events(); assert_eq!(bs_signed_locked.len(), if use_0conf { 2 } else { 1 }); @@ -2906,6 +2911,7 @@ fn do_test_inbound_reload_without_init_mon(use_0conf: bool, lock_commitment: boo nodes[0].node.handle_funding_signed(&nodes[1].node.get_our_node_id(), &funding_signed_msg); check_added_monitors!(nodes[0], 1); + expect_channel_pending_event(&nodes[0], &nodes[1].node.get_our_node_id()); let as_funding_tx = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().split_off(0); if lock_commitment { diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index f1c5cae25..666c48442 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -499,6 +499,7 @@ pub(super) struct Channel { user_id: u128, channel_id: [u8; 32], + temporary_channel_id: Option<[u8; 32]>, // Will be `None` for channels created prior to 0.0.115. channel_state: u32, // When we reach max(6 blocks, minimum_depth), we need to send an AnnouncementSigs message to @@ -729,6 +730,9 @@ pub(super) struct Channel { // blinded paths instead of simple scid+node_id aliases. outbound_scid_alias: u64, + // We track whether we already emitted a `ChannelPending` event. + channel_pending_event_emitted: bool, + // We track whether we already emitted a `ChannelReady` event. channel_ready_event_emitted: bool, @@ -991,6 +995,8 @@ impl Channel { } } + let temporary_channel_id = entropy_source.get_secure_random_bytes(); + Ok(Channel { user_id, @@ -1004,7 +1010,8 @@ impl Channel { inbound_handshake_limits_override: Some(config.channel_handshake_limits.clone()), - channel_id: entropy_source.get_secure_random_bytes(), + channel_id: temporary_channel_id, + temporary_channel_id: Some(temporary_channel_id), channel_state: ChannelState::OurInitSent as u32, announcement_sigs_state: AnnouncementSigsState::NotSent, secp_ctx, @@ -1103,6 +1110,7 @@ impl Channel { latest_inbound_scid_alias: None, outbound_scid_alias, + channel_pending_event_emitted: false, channel_ready_event_emitted: false, #[cfg(any(test, fuzzing))] @@ -1350,6 +1358,7 @@ impl Channel { inbound_handshake_limits_override: None, channel_id: msg.temporary_channel_id, + temporary_channel_id: Some(msg.temporary_channel_id), channel_state: (ChannelState::OurInitSent as u32) | (ChannelState::TheirInitSent as u32), announcement_sigs_state: AnnouncementSigsState::NotSent, secp_ctx, @@ -1451,6 +1460,7 @@ impl Channel { latest_inbound_scid_alias: None, outbound_scid_alias, + channel_pending_event_emitted: false, channel_ready_event_emitted: false, #[cfg(any(test, fuzzing))] @@ -4550,6 +4560,13 @@ impl Channel { self.channel_id } + // Return the `temporary_channel_id` used during channel establishment. + // + // Will return `None` for channels created prior to LDK version 0.0.115. + pub fn temporary_channel_id(&self) -> Option<[u8; 32]> { + self.temporary_channel_id + } + pub fn minimum_depth(&self) -> Option { self.minimum_depth } @@ -4694,6 +4711,21 @@ impl Channel { self.prev_config.map(|prev_config| prev_config.0) } + // Checks whether we should emit a `ChannelPending` event. + pub(crate) fn should_emit_channel_pending_event(&mut self) -> bool { + self.is_funding_initiated() && !self.channel_pending_event_emitted + } + + // Returns whether we already emitted a `ChannelPending` event. + pub(crate) fn channel_pending_event_emitted(&self) -> bool { + self.channel_pending_event_emitted + } + + // Remembers that we already emitted a `ChannelPending` event. + pub(crate) fn set_channel_pending_event_emitted(&mut self) { + self.channel_pending_event_emitted = true; + } + // Checks whether we should emit a `ChannelReady` event. pub(crate) fn should_emit_channel_ready_event(&mut self) -> bool { self.is_usable() && !self.channel_ready_event_emitted @@ -6420,6 +6452,7 @@ impl Writeable for Channel { if self.holder_max_htlc_value_in_flight_msat != Self::get_holder_max_htlc_value_in_flight_msat(self.channel_value_satoshis, &old_max_in_flight_percent_config) { Some(self.holder_max_htlc_value_in_flight_msat) } else { None }; + let channel_pending_event_emitted = Some(self.channel_pending_event_emitted); let channel_ready_event_emitted = Some(self.channel_ready_event_emitted); // `user_id` used to be a single u64 value. In order to remain backwards compatible with @@ -6452,6 +6485,8 @@ impl Writeable for Channel { (23, channel_ready_event_emitted, option), (25, user_id_high_opt, option), (27, self.channel_keys_id, required), + (29, self.temporary_channel_id, option), + (31, channel_pending_event_emitted, option), }); Ok(()) @@ -6719,10 +6754,12 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch let mut announcement_sigs_state = Some(AnnouncementSigsState::NotSent); let mut latest_inbound_scid_alias = None; let mut outbound_scid_alias = None; + let mut channel_pending_event_emitted = None; let mut channel_ready_event_emitted = None; let mut user_id_high_opt: Option = None; let mut channel_keys_id: Option<[u8; 32]> = None; + let mut temporary_channel_id: Option<[u8; 32]> = None; read_tlv_fields!(reader, { (0, announcement_sigs, option), @@ -6743,6 +6780,8 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch (23, channel_ready_event_emitted, option), (25, user_id_high_opt, option), (27, channel_keys_id, option), + (29, temporary_channel_id, option), + (31, channel_pending_event_emitted, option), }); let (channel_keys_id, holder_signer) = if let Some(channel_keys_id) = channel_keys_id { @@ -6807,6 +6846,7 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch inbound_handshake_limits_override: None, channel_id, + temporary_channel_id, channel_state, announcement_sigs_state: announcement_sigs_state.unwrap(), secp_ctx, @@ -6899,6 +6939,7 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch // Later in the ChannelManager deserialization phase we scan for channels and assign scid aliases if its missing outbound_scid_alias: outbound_scid_alias.unwrap_or(0), + channel_pending_event_emitted: channel_pending_event_emitted.unwrap_or(true), channel_ready_event_emitted: channel_ready_event_emitted.unwrap_or(true), #[cfg(any(test, fuzzing))] diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index d591788f6..e18c13363 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -1496,18 +1496,31 @@ macro_rules! send_channel_ready { }} } +macro_rules! emit_channel_pending_event { + ($locked_events: expr, $channel: expr) => { + if $channel.should_emit_channel_pending_event() { + $locked_events.push(events::Event::ChannelPending { + channel_id: $channel.channel_id(), + former_temporary_channel_id: $channel.temporary_channel_id(), + counterparty_node_id: $channel.get_counterparty_node_id(), + user_channel_id: $channel.get_user_id(), + funding_txo: $channel.get_funding_txo().unwrap().into_bitcoin_outpoint(), + }); + $channel.set_channel_pending_event_emitted(); + } + } +} + macro_rules! emit_channel_ready_event { - ($self: expr, $channel: expr) => { + ($locked_events: expr, $channel: expr) => { if $channel.should_emit_channel_ready_event() { - { - let mut pending_events = $self.pending_events.lock().unwrap(); - pending_events.push(events::Event::ChannelReady { - channel_id: $channel.channel_id(), - user_channel_id: $channel.get_user_id(), - counterparty_node_id: $channel.get_counterparty_node_id(), - channel_type: $channel.get_channel_type().clone(), - }); - } + debug_assert!($channel.channel_pending_event_emitted()); + $locked_events.push(events::Event::ChannelReady { + channel_id: $channel.channel_id(), + user_channel_id: $channel.get_user_id(), + counterparty_node_id: $channel.get_counterparty_node_id(), + channel_type: $channel.get_channel_type().clone(), + }); $channel.set_channel_ready_event_emitted(); } } @@ -4253,8 +4266,6 @@ where }); } - emit_channel_ready_event!(self, channel); - macro_rules! handle_cs { () => { if let Some(update) = commitment_update { pending_msg_events.push(events::MessageSendEvent::UpdateHTLCs { @@ -4287,6 +4298,12 @@ where self.tx_broadcaster.broadcast_transaction(&tx); } + { + let mut pending_events = self.pending_events.lock().unwrap(); + emit_channel_pending_event!(pending_events, channel); + emit_channel_ready_event!(pending_events, channel); + } + htlc_forwards } @@ -4711,7 +4728,10 @@ where } } - emit_channel_ready_event!(self, chan.get_mut()); + { + let mut pending_events = self.pending_events.lock().unwrap(); + emit_channel_ready_event!(pending_events, chan.get_mut()); + } Ok(()) }, @@ -6036,7 +6056,10 @@ where } } - emit_channel_ready_event!(self, channel); + { + let mut pending_events = self.pending_events.lock().unwrap(); + emit_channel_ready_event!(pending_events, channel); + } if let Some(announcement_sigs) = announcement_sigs { log_trace!(self.logger, "Sending announcement_signatures for channel {}", log_bytes!(channel.channel_id())); @@ -8463,6 +8486,7 @@ mod tests { assert_eq!(nodes_0_lock.len(), 1); assert!(nodes_0_lock.contains_key(channel_id)); } + expect_channel_pending_event(&nodes[1], &nodes[0].node.get_our_node_id()); { // Assert that `nodes[1]`'s `id_to_peer` map is populated with the channel as soon as @@ -8475,6 +8499,7 @@ mod tests { let funding_signed = get_event_msg!(nodes[1], MessageSendEvent::SendFundingSigned, nodes[0].node.get_our_node_id()); nodes[0].node.handle_funding_signed(&nodes[1].node.get_our_node_id(), &funding_signed); check_added_monitors!(nodes[0], 1); + expect_channel_pending_event(&nodes[0], &nodes[1].node.get_our_node_id()); let (channel_ready, _) = create_chan_between_nodes_with_value_confirm(&nodes[0], &nodes[1], &tx); let (announcement, nodes_0_update, nodes_1_update) = create_chan_between_nodes_with_value_b(&nodes[0], &nodes[1], &channel_ready); update_nodes_with_chan_announce(&nodes, 0, 1, &announcement, &nodes_0_update, &nodes_1_update); @@ -8617,10 +8642,13 @@ mod tests { nodes[1].node.handle_funding_created(&nodes[0].node.get_our_node_id(), &funding_created_msg); check_added_monitors!(nodes[1], 1); + expect_channel_pending_event(&nodes[1], &nodes[0].node.get_our_node_id()); + let funding_signed = get_event_msg!(nodes[1], MessageSendEvent::SendFundingSigned, nodes[0].node.get_our_node_id()); nodes[0].node.handle_funding_signed(&nodes[1].node.get_our_node_id(), &funding_signed); check_added_monitors!(nodes[0], 1); + expect_channel_pending_event(&nodes[0], &nodes[1].node.get_our_node_id()); } open_channel_msg.temporary_channel_id = nodes[0].keys_manager.get_secure_random_bytes(); } @@ -8840,7 +8868,7 @@ pub mod bench { use crate::chain::chainmonitor::{ChainMonitor, Persist}; use crate::chain::keysinterface::{EntropySource, KeysManager, InMemorySigner}; use crate::events::{Event, MessageSendEvent, MessageSendEventsProvider}; - use crate::ln::channelmanager::{self, BestBlock, ChainParameters, ChannelManager, PaymentHash, PaymentPreimage, PaymentId}; + use crate::ln::channelmanager::{BestBlock, ChainParameters, ChannelManager, PaymentHash, PaymentPreimage, PaymentId}; use crate::ln::functional_test_utils::*; use crate::ln::msgs::{ChannelMessageHandler, Init}; use crate::routing::gossip::NetworkGraph; @@ -8921,7 +8949,24 @@ pub mod bench { } else { panic!(); } node_b.handle_funding_created(&node_a.get_our_node_id(), &get_event_msg!(node_a_holder, MessageSendEvent::SendFundingCreated, node_b.get_our_node_id())); + let events_b = node_b.get_and_clear_pending_events(); + assert_eq!(events_b.len(), 1); + match events_b[0] { + Event::ChannelPending{ ref counterparty_node_id, .. } => { + assert_eq!(*counterparty_node_id, node_a.get_our_node_id()); + }, + _ => panic!("Unexpected event"), + } + node_a.handle_funding_signed(&node_b.get_our_node_id(), &get_event_msg!(node_b_holder, MessageSendEvent::SendFundingSigned, node_a.get_our_node_id())); + let events_a = node_a.get_and_clear_pending_events(); + assert_eq!(events_a.len(), 1); + match events_a[0] { + Event::ChannelPending{ ref counterparty_node_id, .. } => { + assert_eq!(*counterparty_node_id, node_b.get_our_node_id()); + }, + _ => panic!("Unexpected event"), + } assert_eq!(&tx_broadcaster.txn_broadcasted.lock().unwrap()[..], &[tx.clone()]); diff --git a/lightning/src/ln/functional_test_utils.rs b/lightning/src/ln/functional_test_utils.rs index 61b927c53..d7fd9c8e9 100644 --- a/lightning/src/ln/functional_test_utils.rs +++ b/lightning/src/ln/functional_test_utils.rs @@ -883,6 +883,7 @@ pub fn sign_funding_transaction<'a, 'b, 'c>(node_a: &Node<'a, 'b, 'c>, node_b: & assert_eq!(added_monitors[0].0, funding_output); added_monitors.clear(); } + expect_channel_pending_event(&node_b, &node_a.node.get_our_node_id()); node_a.node.handle_funding_signed(&node_b.node.get_our_node_id(), &get_event_msg!(node_b, MessageSendEvent::SendFundingSigned, node_a.node.get_our_node_id())); { @@ -891,6 +892,7 @@ pub fn sign_funding_transaction<'a, 'b, 'c>(node_a: &Node<'a, 'b, 'c>, node_b: & assert_eq!(added_monitors[0].0, funding_output); added_monitors.clear(); } + expect_channel_pending_event(&node_a, &node_b.node.get_our_node_id()); let events_4 = node_a.node.get_and_clear_pending_events(); assert_eq!(events_4.len(), 0); @@ -942,6 +944,8 @@ pub fn open_zero_conf_channel<'a, 'b, 'c, 'd>(initiator: &'a Node<'b, 'c, 'd>, r MessageSendEvent::SendFundingSigned { node_id, msg } => { assert_eq!(*node_id, initiator.node.get_our_node_id()); initiator.node.handle_funding_signed(&receiver.node.get_our_node_id(), &msg); + expect_channel_pending_event(&initiator, &receiver.node.get_our_node_id()); + expect_channel_pending_event(&receiver, &initiator.node.get_our_node_id()); check_added_monitors!(initiator, 1); assert_eq!(initiator.tx_broadcaster.txn_broadcasted.lock().unwrap().len(), 1); @@ -955,11 +959,13 @@ pub fn open_zero_conf_channel<'a, 'b, 'c, 'd>(initiator: &'a Node<'b, 'c, 'd>, r MessageSendEvent::SendChannelReady { node_id, msg } => { assert_eq!(*node_id, initiator.node.get_our_node_id()); initiator.node.handle_channel_ready(&receiver.node.get_our_node_id(), &msg); + expect_channel_ready_event(&initiator, &receiver.node.get_our_node_id()); } _ => panic!("Unexpected event"), } receiver.node.handle_channel_ready(&initiator.node.get_our_node_id(), &as_channel_ready); + expect_channel_ready_event(&receiver, &initiator.node.get_our_node_id()); let as_channel_update = get_event_msg!(initiator, MessageSendEvent::SendChannelUpdate, receiver.node.get_our_node_id()); let bs_channel_update = get_event_msg!(receiver, MessageSendEvent::SendChannelUpdate, initiator.node.get_our_node_id()); @@ -970,9 +976,6 @@ pub fn open_zero_conf_channel<'a, 'b, 'c, 'd>(initiator: &'a Node<'b, 'c, 'd>, r assert_eq!(initiator.node.list_usable_channels().len(), initiator_channels + 1); assert_eq!(receiver.node.list_usable_channels().len(), receiver_channels + 1); - expect_channel_ready_event(&initiator, &receiver.node.get_our_node_id()); - expect_channel_ready_event(&receiver, &initiator.node.get_our_node_id()); - (tx, as_channel_ready.channel_id) } @@ -1097,7 +1100,10 @@ pub fn create_unannounced_chan_between_nodes_with_value<'a, 'b, 'c, 'd>(nodes: & check_added_monitors!(nodes[b], 1); let cs_funding_signed = get_event_msg!(nodes[b], MessageSendEvent::SendFundingSigned, nodes[a].node.get_our_node_id()); + expect_channel_pending_event(&nodes[b], &nodes[a].node.get_our_node_id()); + nodes[a].node.handle_funding_signed(&nodes[b].node.get_our_node_id(), &cs_funding_signed); + expect_channel_pending_event(&nodes[a], &nodes[b].node.get_our_node_id()); check_added_monitors!(nodes[a], 1); assert_eq!(nodes[a].tx_broadcaster.txn_broadcasted.lock().unwrap().len(), 1); @@ -1801,6 +1807,18 @@ macro_rules! expect_payment_forwarded { } } +#[cfg(any(test, feature = "_bench_unstable", feature = "_test_utils"))] +pub fn expect_channel_pending_event<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, expected_counterparty_node_id: &PublicKey) { + let events = node.node.get_and_clear_pending_events(); + assert_eq!(events.len(), 1); + match events[0] { + crate::events::Event::ChannelPending { ref counterparty_node_id, .. } => { + assert_eq!(*expected_counterparty_node_id, *counterparty_node_id); + }, + _ => panic!("Unexpected event"), + } +} + #[cfg(any(test, feature = "_bench_unstable", feature = "_test_utils"))] pub fn expect_channel_ready_event<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, expected_counterparty_node_id: &PublicKey) { let events = node.node.get_and_clear_pending_events(); @@ -1813,7 +1831,6 @@ pub fn expect_channel_ready_event<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, ex } } - pub struct PaymentFailedConditions<'a> { pub(crate) expected_htlc_error_data: Option<(u16, &'a [u8])>, pub(crate) expected_blamed_scid: Option, diff --git a/lightning/src/ln/functional_tests.rs b/lightning/src/ln/functional_tests.rs index 56586b0a2..4f73627f4 100644 --- a/lightning/src/ln/functional_tests.rs +++ b/lightning/src/ln/functional_tests.rs @@ -541,6 +541,8 @@ fn do_test_sanity_on_in_flight_opens(steps: u8) { assert_eq!(added_monitors[0].0, funding_output); added_monitors.clear(); } + expect_channel_pending_event(&nodes[1], &nodes[0].node.get_our_node_id()); + let funding_signed = get_event_msg!(nodes[1], MessageSendEvent::SendFundingSigned, nodes[0].node.get_our_node_id()); if steps & 0x0f == 5 { return; } @@ -552,6 +554,7 @@ fn do_test_sanity_on_in_flight_opens(steps: u8) { added_monitors.clear(); } + expect_channel_pending_event(&nodes[0], &nodes[1].node.get_our_node_id()); let events_4 = nodes[0].node.get_and_clear_pending_events(); assert_eq!(events_4.len(), 0); @@ -8854,6 +8857,8 @@ fn test_duplicate_chan_id() { assert_eq!(added_monitors[0].0, funding_output); added_monitors.clear(); } + expect_channel_pending_event(&nodes[1], &nodes[0].node.get_our_node_id()); + let funding_signed_msg = get_event_msg!(nodes[1], MessageSendEvent::SendFundingSigned, nodes[0].node.get_our_node_id()); let funding_outpoint = crate::chain::transaction::OutPoint { txid: funding_created_msg.funding_txid, index: funding_created_msg.funding_output_index }; @@ -8929,6 +8934,7 @@ fn test_duplicate_chan_id() { assert_eq!(added_monitors[0].0, funding_output); added_monitors.clear(); } + expect_channel_pending_event(&nodes[0], &nodes[1].node.get_our_node_id()); let events_4 = nodes[0].node.get_and_clear_pending_events(); assert_eq!(events_4.len(), 0); @@ -9043,9 +9049,11 @@ fn test_invalid_funding_tx() { nodes[0].node.funding_transaction_generated_unchecked(&temporary_channel_id, &nodes[1].node.get_our_node_id(), tx.clone(), 0).unwrap(); nodes[1].node.handle_funding_created(&nodes[0].node.get_our_node_id(), &get_event_msg!(nodes[0], MessageSendEvent::SendFundingCreated, nodes[1].node.get_our_node_id())); check_added_monitors!(nodes[1], 1); + expect_channel_pending_event(&nodes[1], &nodes[0].node.get_our_node_id()); nodes[0].node.handle_funding_signed(&nodes[1].node.get_our_node_id(), &get_event_msg!(nodes[1], MessageSendEvent::SendFundingSigned, nodes[0].node.get_our_node_id())); check_added_monitors!(nodes[0], 1); + expect_channel_pending_event(&nodes[0], &nodes[1].node.get_our_node_id()); let events_1 = nodes[0].node.get_and_clear_pending_events(); assert_eq!(events_1.len(), 0); @@ -9575,9 +9583,11 @@ fn do_test_max_dust_htlc_exposure(dust_outbound_balance: bool, exposure_breach_e nodes[0].node.funding_transaction_generated(&temporary_channel_id, &nodes[1].node.get_our_node_id(), tx.clone()).unwrap(); nodes[1].node.handle_funding_created(&nodes[0].node.get_our_node_id(), &get_event_msg!(nodes[0], MessageSendEvent::SendFundingCreated, nodes[1].node.get_our_node_id())); check_added_monitors!(nodes[1], 1); + expect_channel_pending_event(&nodes[1], &nodes[0].node.get_our_node_id()); nodes[0].node.handle_funding_signed(&nodes[1].node.get_our_node_id(), &get_event_msg!(nodes[1], MessageSendEvent::SendFundingSigned, nodes[0].node.get_our_node_id())); check_added_monitors!(nodes[0], 1); + expect_channel_pending_event(&nodes[0], &nodes[1].node.get_our_node_id()); let (channel_ready, channel_id) = create_chan_between_nodes_with_value_confirm(&nodes[0], &nodes[1], &tx); let (announcement, as_update, bs_update) = create_chan_between_nodes_with_value_b(&nodes[0], &nodes[1], &channel_ready); diff --git a/lightning/src/ln/priv_short_conf_tests.rs b/lightning/src/ln/priv_short_conf_tests.rs index 6d1df42d1..313d84c53 100644 --- a/lightning/src/ln/priv_short_conf_tests.rs +++ b/lightning/src/ln/priv_short_conf_tests.rs @@ -362,7 +362,10 @@ fn test_inbound_scid_privacy() { check_added_monitors!(nodes[2], 1); let cs_funding_signed = get_event_msg!(nodes[2], MessageSendEvent::SendFundingSigned, nodes[1].node.get_our_node_id()); + expect_channel_pending_event(&nodes[2], &nodes[1].node.get_our_node_id()); + nodes[1].node.handle_funding_signed(&nodes[2].node.get_our_node_id(), &cs_funding_signed); + expect_channel_pending_event(&nodes[1], &nodes[2].node.get_our_node_id()); check_added_monitors!(nodes[1], 1); let conf_height = core::cmp::max(nodes[1].best_block_info().1 + 1, nodes[2].best_block_info().1 + 1); @@ -599,6 +602,7 @@ fn test_0conf_channel_with_async_monitor() { let channel_id = funding_output.to_channel_id(); nodes[1].chain_monitor.complete_sole_pending_chan_update(&channel_id); + expect_channel_pending_event(&nodes[1], &nodes[0].node.get_our_node_id()); let bs_signed_locked = nodes[1].node.get_and_clear_pending_msg_events(); assert_eq!(bs_signed_locked.len(), 2); @@ -624,6 +628,22 @@ fn test_0conf_channel_with_async_monitor() { assert!(nodes[0].node.get_and_clear_pending_msg_events().is_empty()); nodes[0].chain_monitor.complete_sole_pending_chan_update(&channel_id); + + let events = nodes[0].node.get_and_clear_pending_events(); + assert_eq!(events.len(), 2); + match events[0] { + crate::events::Event::ChannelPending { ref counterparty_node_id, .. } => { + assert_eq!(nodes[1].node.get_our_node_id(), *counterparty_node_id); + }, + _ => panic!("Unexpected event"), + } + match events[1] { + crate::events::Event::ChannelReady { ref counterparty_node_id, .. } => { + assert_eq!(nodes[1].node.get_our_node_id(), *counterparty_node_id); + }, + _ => panic!("Unexpected event"), + } + let as_locked_update = nodes[0].node.get_and_clear_pending_msg_events(); // Note that the funding transaction is actually released when @@ -638,7 +658,6 @@ fn test_0conf_channel_with_async_monitor() { } _ => panic!("Unexpected event"), } - expect_channel_ready_event(&nodes[0], &nodes[1].node.get_our_node_id()); expect_channel_ready_event(&nodes[1], &nodes[0].node.get_our_node_id()); let bs_channel_update = get_event_msg!(nodes[1], MessageSendEvent::SendChannelUpdate, nodes[0].node.get_our_node_id()); diff --git a/lightning/src/ln/reload_tests.rs b/lightning/src/ln/reload_tests.rs index ffb6ba0e8..202ecce65 100644 --- a/lightning/src/ln/reload_tests.rs +++ b/lightning/src/ln/reload_tests.rs @@ -261,6 +261,9 @@ fn test_manager_serialize_deserialize_events() { } // Normally, this is where node_a would broadcast the funding transaction, but the test de/serializes first instead + expect_channel_pending_event(&node_a, &node_b.node.get_our_node_id()); + expect_channel_pending_event(&node_b, &node_a.node.get_our_node_id()); + nodes.push(node_a); nodes.push(node_b);