From: jbesraa Date: Thu, 9 May 2024 13:37:33 +0000 (+0300) Subject: Add `FundingTxBroadcastSafe` event X-Git-Url: http://git.bitcoin.ninja/?a=commitdiff_plain;h=b06df26b9f73b2f59d4df01735b9a08d821ccf19;p=rust-lightning Add `FundingTxBroadcastSafe` event The `FundingTxBroadcastSafe` event indicates that we have received `funding_signed` message from our counterparty and that you should broadcast the funding transaction. This event is only emitted if upon generating the funding transaction you call `ChannelManager::unsafe_manual_funding_transaction_generated` that will emit this event instead of `ChannelPending` event. `ChannelManager::unsafe_manual_funding_transaction_generated` wont check if the funding transaction is signed, those its unsafe. It is manual because you are responsibile on broadcasting the transaction once the event is received. --- diff --git a/lightning/src/events/mod.rs b/lightning/src/events/mod.rs index 45ed895ad..285de35ed 100644 --- a/lightning/src/events/mod.rs +++ b/lightning/src/events/mod.rs @@ -532,6 +532,37 @@ pub enum Event { /// [`UserConfig::manually_accept_inbound_channels`]: crate::util::config::UserConfig::manually_accept_inbound_channels user_channel_id: u128, }, + /// Used to indicate that the counterparty node has provided the signature(s) required to + /// recover our funds in case they go offline. + /// + /// It is safe (and your responsibility) to broadcast the funding transaction upon receiving this + /// event. + /// + /// This event is only emitted if you called + /// [`ChannelManager::unsafe_manual_funding_transaction_generated`] instead of + /// [`ChannelManager::funding_transaction_generated`]. + /// + /// [`ChannelManager::unsafe_manual_funding_transaction_generated`]: crate::ln::channelmanager::ChannelManager::unsafe_manual_funding_transaction_generated + /// [`ChannelManager::funding_transaction_generated`]: crate::ln::channelmanager::ChannelManager::funding_transaction_generated + FundingTxBroadcastSafe { + /// The `channel_id` indicating which channel has reached this stage. + channel_id: ChannelId, + /// 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, + /// Channel funding transaction + funding_tx: Transaction, + /// The `node_id` of the channel counterparty. + counterparty_node_id: PublicKey, + /// The `temporary_channel_id` this channel used to be known by during channel establishment. + former_temporary_channel_id: ChannelId, + }, /// Indicates that we've been offered a payment and it needs to be claimed via calling /// [`ChannelManager::claim_funds`] with the preimage given in [`PaymentPurpose`]. /// @@ -1447,7 +1478,17 @@ impl Writeable for Event { write_tlv_fields!(writer, { (0, peer_node_id, required), }); - } + }, + &Event::FundingTxBroadcastSafe { ref channel_id, ref user_channel_id, ref funding_tx, ref counterparty_node_id, ref former_temporary_channel_id} => { + 41u8.write(writer)?; + write_tlv_fields!(writer, { + (0, channel_id, required), + (2, user_channel_id, required), + (4, funding_tx, required), + (6, counterparty_node_id, required), + (8, former_temporary_channel_id, 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`. @@ -1884,6 +1925,27 @@ impl MaybeReadable for Event { }; f() }, + 41u8 => { + let mut channel_id = RequiredWrapper(None); + let mut user_channel_id = RequiredWrapper(None); + let mut funding_tx = RequiredWrapper(None); + let mut counterparty_node_id = RequiredWrapper(None); + let mut former_temporary_channel_id = RequiredWrapper(None); + read_tlv_fields!(reader, { + (0, channel_id, required), + (2, user_channel_id, required), + (4, funding_tx, required), + (6, counterparty_node_id, required), + (8, former_temporary_channel_id, required) + }); + Ok(Some(Event::FundingTxBroadcastSafe { + channel_id: channel_id.0.unwrap(), + user_channel_id: user_channel_id.0.unwrap(), + funding_tx: funding_tx.0.unwrap(), + counterparty_node_id: counterparty_node_id.0.unwrap(), + former_temporary_channel_id: former_temporary_channel_id.0.unwrap(), + })) + }, // 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/channel.rs b/lightning/src/ln/channel.rs index d6ab1876a..ac316d450 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -1413,6 +1413,9 @@ pub(super) struct ChannelContext where SP::Target: SignerProvider { // We track whether we already emitted a `ChannelPending` event. channel_pending_event_emitted: bool, + // We track whether we already emitted a `FundingTxBroadcastSafe` event. + funding_tx_broadcast_safe_event_emitted: bool, + // We track whether we already emitted a `ChannelReady` event. channel_ready_event_emitted: bool, @@ -1429,6 +1432,14 @@ pub(super) struct ChannelContext where SP::Target: SignerProvider { /// If we can't release a [`ChannelMonitorUpdate`] until some external action completes, we /// store it here and only release it to the `ChannelManager` once it asks for it. blocked_monitor_updates: Vec, + + /// Using this flag will prevent the funding transaction from being broadcasted + /// and will allow the user to manually broadcast it. + /// + /// The funding transaction can be accessed through the [`Event::FundingTxBroadcastSafe`] event. + /// + /// [`Event::FundingTxBroadcastSafe`]: crate::events::Event::FundingTxBroadcastSafe + is_manual_broadcast: bool, } impl ChannelContext where SP::Target: SignerProvider { @@ -1752,6 +1763,7 @@ impl ChannelContext where SP::Target: SignerProvider { outbound_scid_alias: 0, channel_pending_event_emitted: false, + funding_tx_broadcast_safe_event_emitted: false, channel_ready_event_emitted: false, #[cfg(any(test, fuzzing))] @@ -1763,6 +1775,8 @@ impl ChannelContext where SP::Target: SignerProvider { local_initiated_shutdown: None, blocked_monitor_updates: Vec::new(), + + is_manual_broadcast: false, }; Ok(channel_context) @@ -1976,6 +1990,7 @@ impl ChannelContext where SP::Target: SignerProvider { outbound_scid_alias, channel_pending_event_emitted: false, + funding_tx_broadcast_safe_event_emitted: false, channel_ready_event_emitted: false, #[cfg(any(test, fuzzing))] @@ -1986,6 +2001,7 @@ impl ChannelContext where SP::Target: SignerProvider { blocked_monitor_updates: Vec::new(), local_initiated_shutdown: None, + is_manual_broadcast: false, }) } @@ -2227,6 +2243,10 @@ impl ChannelContext where SP::Target: SignerProvider { self.config.options.forwarding_fee_proportional_millionths } + pub fn is_manual_broadcast(&self) -> bool { + self.is_manual_broadcast + } + pub fn get_cltv_expiry_delta(&self) -> u16 { cmp::max(self.config.options.cltv_expiry_delta, MIN_CLTV_EXPIRY_DELTA) } @@ -2261,6 +2281,11 @@ impl ChannelContext where SP::Target: SignerProvider { self.channel_pending_event_emitted } + // Returns whether we already emitted a `FundingTxBroadcastSafe` event. + pub(crate) fn funding_tx_broadcast_safe_event_emitted(&self) -> bool { + self.funding_tx_broadcast_safe_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; @@ -2276,6 +2301,11 @@ impl ChannelContext where SP::Target: SignerProvider { self.channel_ready_event_emitted = true; } + // Remembers that we already emitted a `FundingTxBroadcastSafe` event. + pub(crate) fn set_funding_tx_broadcast_safe_event_emitted(&mut self) { + self.funding_tx_broadcast_safe_event_emitted = true; + } + /// Tracks the number of ticks elapsed since the previous [`ChannelConfig`] was updated. Once /// [`EXPIRE_PREV_CONFIG_TICKS`] is reached, the previous config is considered expired and will /// no longer be considered when forwarding HTLCs. @@ -2312,6 +2342,17 @@ impl ChannelContext where SP::Target: SignerProvider { did_channel_update } + /// Marking the channel as manual broadcast is used in order to prevent LDK from automatically + /// broadcasting the funding transaction. + /// + /// This is useful if you wish to get hold of the funding transaction before it is broadcasted + /// via [`Event::FundingTxBroadcastSafe`] event. + /// + /// [`Event::FundingTxBroadcastSafe`]: crate::events::Event::FundingTxBroadcastSafe + pub fn set_manual_broadcast(&mut self) { + self.is_manual_broadcast = true; + } + /// Returns true if funding_signed was sent/received and the /// funding transaction has been broadcast if necessary. pub fn is_funding_broadcast(&self) -> bool { @@ -8662,6 +8703,7 @@ impl Writeable for Channel where SP::Target: SignerProvider { let channel_pending_event_emitted = Some(self.context.channel_pending_event_emitted); let channel_ready_event_emitted = Some(self.context.channel_ready_event_emitted); + let funding_tx_broadcast_safe_event_emitted = Some(self.context.funding_tx_broadcast_safe_event_emitted); // `user_id` used to be a single u64 value. In order to remain backwards compatible with // versions prior to 0.0.113, the u128 is serialized as two separate u64 values. Therefore, @@ -8674,6 +8716,7 @@ impl Writeable for Channel where SP::Target: SignerProvider { if !self.context.monitor_pending_update_adds.is_empty() { monitor_pending_update_adds = Some(&self.context.monitor_pending_update_adds); } + let is_manual_broadcast = Some(self.context.is_manual_broadcast); // `current_point` will become optional when async signing is implemented. let cur_holder_commitment_point = Some(self.context.holder_commitment_point.current_point()); @@ -8718,6 +8761,8 @@ impl Writeable for Channel where SP::Target: SignerProvider { (45, cur_holder_commitment_point, option), (47, next_holder_commitment_point, option), (49, self.context.local_initiated_shutdown, option), // Added in 0.0.122 + (51, is_manual_broadcast, option), + (53, funding_tx_broadcast_safe_event_emitted, option) }); Ok(()) @@ -9006,6 +9051,7 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch let mut outbound_scid_alias = None; let mut channel_pending_event_emitted = None; let mut channel_ready_event_emitted = None; + let mut funding_tx_broadcast_safe_event_emitted = None; let mut user_id_high_opt: Option = None; let mut channel_keys_id: Option<[u8; 32]> = None; @@ -9029,6 +9075,7 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch let mut cur_holder_commitment_point_opt: Option = None; let mut next_holder_commitment_point_opt: Option = None; + let mut is_manual_broadcast = None; read_tlv_fields!(reader, { (0, announcement_sigs, option), @@ -9063,6 +9110,8 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch (45, cur_holder_commitment_point_opt, option), (47, next_holder_commitment_point_opt, option), (49, local_initiated_shutdown, option), + (51, is_manual_broadcast, option), + (53, funding_tx_broadcast_safe_event_emitted, option), }); let (channel_keys_id, holder_signer) = if let Some(channel_keys_id) = channel_keys_id { @@ -9303,6 +9352,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), + funding_tx_broadcast_safe_event_emitted: funding_tx_broadcast_safe_event_emitted.unwrap_or(false), channel_pending_event_emitted: channel_pending_event_emitted.unwrap_or(true), channel_ready_event_emitted: channel_ready_event_emitted.unwrap_or(true), @@ -9315,6 +9365,7 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch local_initiated_shutdown, blocked_monitor_updates: blocked_monitor_updates.unwrap(), + is_manual_broadcast: is_manual_broadcast.unwrap_or(false), }, #[cfg(any(dual_funding, splicing))] dual_funding_channel_context: None, diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index 992fd3c6f..36b17cead 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -2548,6 +2548,20 @@ macro_rules! send_channel_ready { } }} } +macro_rules! emit_funding_tx_broadcast_safe_event { + ($locked_events: expr, $channel: expr, $funding_tx: expr) => { + if !$channel.context.funding_tx_broadcast_safe_event_emitted() { + $locked_events.push_back((events::Event::FundingTxBroadcastSafe { + channel_id: $channel.context.channel_id(), + user_channel_id: $channel.context.get_user_id(), + funding_tx: $funding_tx, + counterparty_node_id: $channel.context.get_counterparty_node_id(), + former_temporary_channel_id: $channel.context.temporary_channel_id().expect("Unreachable: FundingTxBroadcastSafe event feature added to channel establishment process in LDK v0.124.0 where this should never be None."), + }, None)); + $channel.context.set_funding_tx_broadcast_safe_event_emitted(); + } + } +} macro_rules! emit_channel_pending_event { ($locked_events: expr, $channel: expr) => { @@ -4188,7 +4202,7 @@ where /// which checks the correctness of the funding transaction given the associated channel. fn funding_transaction_generated_intern, &Transaction) -> Result>( &self, temporary_channel_id: &ChannelId, counterparty_node_id: &PublicKey, funding_transaction: Transaction, is_batch_funding: bool, - mut find_funding_output: FundingOutput, + mut find_funding_output: FundingOutput, is_manual_broadcast: bool, ) -> Result<(), APIError> { let per_peer_state = self.per_peer_state.read().unwrap(); let peer_state_mutex = per_peer_state.get(counterparty_node_id) @@ -4253,6 +4267,9 @@ where msg, }); } + if is_manual_broadcast { + chan.context.set_manual_broadcast(); + } match peer_state.channel_by_id.entry(chan.context.channel_id()) { hash_map::Entry::Occupied(_) => { panic!("Generated duplicate funding txid?"); @@ -4284,7 +4301,7 @@ where pub(crate) fn funding_transaction_generated_unchecked(&self, temporary_channel_id: &ChannelId, counterparty_node_id: &PublicKey, funding_transaction: Transaction, output_index: u16) -> Result<(), APIError> { self.funding_transaction_generated_intern(temporary_channel_id, counterparty_node_id, funding_transaction, false, |_, tx| { Ok(OutPoint { txid: tx.txid(), index: output_index }) - }) + }, false) } /// Call this upon creation of a funding transaction for the given channel. @@ -4321,6 +4338,46 @@ where self.batch_funding_transaction_generated(&[(temporary_channel_id, counterparty_node_id)], funding_transaction) } + + /// Unsafe: This method does not check if the funding transaction is signed, i.e., if the + /// witness data is empty or not. It is the caller's responsibility to ensure that the funding + /// transaction is final. + /// + /// If you wish to use a safer method, use [`ChannelManager::funding_transaction_generated`]. + /// + /// Call this in response to a [`Event::FundingGenerationReady`] event. + /// + /// Note that if this method is called successfully, the funding transaction won't be + /// broadcasted and you are expected to broadcast it manually when receiving the + /// [`Event::FundingTxBroadcastSafe`] event. + /// + /// Returns an [`APIError::APIMisuseError`] if no output was found which matches the parameters + /// in [`Event::FundingGenerationReady`]. + /// + /// Returns [`APIError::ChannelUnavailable`] if a funding transaction has already been provided + /// for the channel or if the channel has been closed as indicated by [`Event::ChannelClosed`]. + /// + /// May panic if the output found in the funding transaction is duplicative with some other + /// channel (note that this should be trivially prevented by using unique funding transaction + /// keys per-channel). + /// + /// Note to keep the miner incentives aligned in moving the blockchain forward, we recommend + /// the wallet software generating the funding transaction to apply anti-fee sniping as + /// implemented by Bitcoin Core wallet. See for + /// more details. + /// + /// [`Event::FundingGenerationReady`]: crate::events::Event::FundingGenerationReady + /// [`Event::FundingTxBroadcastSafe`]: crate::events::Event::FundingTxBroadcastSafe + /// [`Event::ChannelClosed`]: crate::events::Event::ChannelClosed + /// [`ChannelManager::funding_transaction_generated`]: crate::ln::channelmanager::ChannelManager::funding_transaction_generated + pub fn unsafe_manual_funding_transaction_generated(&self, temporary_channel_id: &ChannelId, counterparty_node_id: &PublicKey, funding_transaction: Transaction) -> Result<(), APIError> { + let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self); + + let temporary_channels = &[(temporary_channel_id, counterparty_node_id)]; + return self.batch_funding_transaction_generated_intern(temporary_channels, funding_transaction, true); + + } + /// Call this upon creation of a batch funding transaction for the given channels. /// /// Return values are identical to [`Self::funding_transaction_generated`], respective to @@ -4344,6 +4401,11 @@ where } } } + result.and(self.batch_funding_transaction_generated_intern(temporary_channels, funding_transaction, false)) + } + + fn batch_funding_transaction_generated_intern(&self, temporary_channels: &[(&ChannelId, &PublicKey)], funding_transaction: Transaction, is_manual_broadcast: bool) -> Result<(), APIError> { + let mut result = Ok(()); if funding_transaction.output.len() > u16::max_value() as usize { result = result.and(Err(APIError::APIMisuseError { err: "Transaction had more than 2^16 outputs, which is not supported".to_owned() @@ -4411,7 +4473,8 @@ where funding_batch_state.push((ChannelId::v1_from_funding_outpoint(outpoint), *counterparty_node_id, false)); } Ok(outpoint) - }) + }, + is_manual_broadcast) ); } if let Err(ref e) = result { @@ -6559,8 +6622,14 @@ where } if let Some(tx) = funding_broadcastable { - log_info!(logger, "Broadcasting funding transaction with txid {}", tx.txid()); - self.tx_broadcaster.broadcast_transactions(&[&tx]); + if channel.context.is_manual_broadcast() { + log_info!(logger, "Not broadcasting funding transaction with txid {} as it is manually managed", tx.txid()); + let mut pending_events = self.pending_events.lock().unwrap(); + emit_funding_tx_broadcast_safe_event!(pending_events, channel, tx); + } else { + log_info!(logger, "Broadcasting funding transaction with txid {}", tx.txid()); + self.tx_broadcaster.broadcast_transactions(&[&tx]); + } } { diff --git a/lightning/src/ln/functional_test_utils.rs b/lightning/src/ln/functional_test_utils.rs index 7e57f2059..fa2496077 100644 --- a/lightning/src/ln/functional_test_utils.rs +++ b/lightning/src/ln/functional_test_utils.rs @@ -1135,6 +1135,39 @@ pub fn create_coinbase_funding_transaction<'a, 'b, 'c>(node: &Node<'a, 'b, 'c>, internal_create_funding_transaction(node, expected_counterparty_node_id, expected_chan_value, expected_user_chan_id, true) } +pub fn create_funding_tx_without_witness_data<'a, 'b, 'c>(node: &Node<'a, 'b, 'c>, + expected_counterparty_node_id: &PublicKey, expected_chan_value: u64, expected_user_chan_id: u128) -> (ChannelId, Transaction, OutPoint) { + let chan_id = *node.network_chan_count.borrow(); + + let events = node.node.get_and_clear_pending_events(); + assert_eq!(events.len(), 1); + match events[0] { + Event::FundingGenerationReady { ref temporary_channel_id, ref counterparty_node_id, ref channel_value_satoshis, ref output_script, user_channel_id } => { + assert_eq!(counterparty_node_id, expected_counterparty_node_id); + assert_eq!(*channel_value_satoshis, expected_chan_value); + assert_eq!(user_channel_id, expected_user_chan_id); + + let dummy_outpoint = bitcoin::OutPoint { txid: bitcoin::Txid::from_slice(&[1; 32]).unwrap(), vout: 0 }; + let dummy_script_sig = bitcoin::ScriptBuf::new(); + let dummy_sequence = bitcoin::Sequence::ZERO; + let dummy_witness = bitcoin::Witness::new(); + let input = vec![TxIn { + previous_output: dummy_outpoint, + script_sig: dummy_script_sig, + sequence: dummy_sequence, + witness: dummy_witness, + }]; + + let tx = Transaction { version: transaction::Version(chan_id as i32), lock_time: LockTime::ZERO, input, output: vec![TxOut { + value: Amount::from_sat(*channel_value_satoshis), script_pubkey: output_script.clone(), + }]}; + let funding_outpoint = OutPoint { txid: tx.txid(), index: 0 }; + (*temporary_channel_id, tx, funding_outpoint) + }, + _ => panic!("Unexpected event"), + } +} + fn internal_create_funding_transaction<'a, 'b, 'c>(node: &Node<'a, 'b, 'c>, expected_counterparty_node_id: &PublicKey, expected_chan_value: u64, expected_user_chan_id: u128, coinbase: bool) -> (ChannelId, Transaction, OutPoint) { diff --git a/lightning/src/ln/functional_tests.rs b/lightning/src/ln/functional_tests.rs index 7cd0f376d..9b1bf83bf 100644 --- a/lightning/src/ln/functional_tests.rs +++ b/lightning/src/ln/functional_tests.rs @@ -3783,6 +3783,32 @@ fn test_peer_disconnected_before_funding_broadcasted() { , [nodes[0].node.get_our_node_id()], 1000000); } +#[test] +fn test_unsafe_manual_funding_transaction_generated() { + let chanmon_cfgs = create_chanmon_cfgs(2); + let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); + let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]); + let nodes = create_network(2, &node_cfgs, &node_chanmgrs); + + let expected_temporary_channel_id = nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 1_000_000, 500_000_000, 42, None, None).unwrap(); + let open_channel = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id()); + nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), &open_channel); + let accept_channel = get_event_msg!(nodes[1], MessageSendEvent::SendAcceptChannel, nodes[0].node.get_our_node_id()); + nodes[0].node.handle_accept_channel(&nodes[1].node.get_our_node_id(), &accept_channel); + + let (temporary_channel_id, tx, _funding_output) = create_funding_tx_without_witness_data(&nodes[0], &nodes[1].node.get_our_node_id(), 1_000_000, 42); + assert_eq!(temporary_channel_id, expected_temporary_channel_id); + + assert!(nodes[0].node.unsafe_manual_funding_transaction_generated(&temporary_channel_id, &nodes[1].node.get_our_node_id(), tx.clone()).is_ok()); + let node_0_msg_events = nodes[0].node.get_and_clear_pending_msg_events(); + match node_0_msg_events[0] { + MessageSendEvent::SendFundingCreated { ref node_id, .. } => { + assert_eq!(node_id, &nodes[1].node.get_our_node_id()); + }, + _ => panic!("Unexpected event"), + } +} + #[test] fn test_simple_peer_disconnect() { // Test that we can reconnect when there are no lost messages @@ -11199,3 +11225,61 @@ fn test_accept_inbound_channel_errors_queued() { assert_eq!(get_err_msg(&nodes[1], &nodes[0].node.get_our_node_id()).channel_id, open_channel_msg.common_fields.temporary_channel_id); } + +#[test] +fn test_funding_signed_event() { + let mut cfg = UserConfig::default(); + cfg.channel_handshake_config.minimum_depth = 1; + let chanmon_cfgs = create_chanmon_cfgs(2); + let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); + let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[Some(cfg), Some(cfg)]); + let nodes = create_network(2, &node_cfgs, &node_chanmgrs); + + assert!(nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100_000, 0, 42, None, None).is_ok()); + let open_channel = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id()); + + nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), &open_channel); + let accept_channel = get_event_msg!(nodes[1], MessageSendEvent::SendAcceptChannel, nodes[0].node.get_our_node_id()); + + nodes[0].node.handle_accept_channel(&nodes[1].node.get_our_node_id(), &accept_channel); + let (temporary_channel_id, tx, _) = create_funding_transaction(&nodes[0], &nodes[1].node.get_our_node_id(), 100_000, 42); + nodes[0].node.unsafe_manual_funding_transaction_generated(&temporary_channel_id, &nodes[1].node.get_our_node_id(), tx.clone()).unwrap(); + check_added_monitors!(nodes[0], 0); + + let funding_created = 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); + 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); + let events = &nodes[0].node.get_and_clear_pending_events(); + assert_eq!(events.len(), 2); + match &events[0] { + crate::events::Event::FundingTxBroadcastSafe { funding_tx, .. } => { + assert_eq!(funding_tx.txid(), funding_created.funding_txid); + }, + _ => panic!("Unexpected event"), + }; + match &events[1] { + crate::events::Event::ChannelPending { counterparty_node_id, .. } => { + assert_eq!(*&nodes[1].node.get_our_node_id(), *counterparty_node_id); + }, + _ => panic!("Unexpected event"), + }; + + mine_transaction(&nodes[0], &tx); + mine_transaction(&nodes[1], &tx); + + let as_channel_ready = get_event_msg!(nodes[1], MessageSendEvent::SendChannelReady, nodes[0].node.get_our_node_id()); + nodes[1].node.handle_channel_ready(&nodes[0].node.get_our_node_id(), &as_channel_ready); + let as_channel_ready = get_event_msg!(nodes[0], MessageSendEvent::SendChannelReady, nodes[1].node.get_our_node_id()); + nodes[0].node.handle_channel_ready(&nodes[1].node.get_our_node_id(), &as_channel_ready); + + 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()); + nodes[0].node.get_and_clear_pending_msg_events(); + nodes[1].node.get_and_clear_pending_msg_events(); +} +