]> git.bitcoin.ninja Git - rust-lightning/commitdiff
Add `FundingTxBroadcastSafe` event
authorjbesraa <jbesraa@gmail.com>
Thu, 9 May 2024 13:37:33 +0000 (16:37 +0300)
committerjbesraa <jbesraa@gmail.com>
Thu, 13 Jun 2024 06:02:06 +0000 (09:02 +0300)
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.

lightning/src/events/mod.rs
lightning/src/ln/channel.rs
lightning/src/ln/channelmanager.rs
lightning/src/ln/functional_test_utils.rs
lightning/src/ln/functional_tests.rs

index 45ed895ade7a0f9010c07a3bc7de73e1e1dd6913..285de35ed75ed08ee90e46ca506af875e95816bd 100644 (file)
@@ -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.
index d6ab1876ae0a31af8dfacc5bac01e35ed438e008..ac316d450d69b54e9cffb534e87ae62cb4d4b837 100644 (file)
@@ -1413,6 +1413,9 @@ pub(super) struct ChannelContext<SP: Deref> 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<SP: Deref> 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<PendingChannelMonitorUpdate>,
+
+       /// 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<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider  {
@@ -1752,6 +1763,7 @@ impl<SP: Deref> ChannelContext<SP> 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<SP: Deref> ChannelContext<SP> 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<SP: Deref> ChannelContext<SP> 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<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider  {
 
                        blocked_monitor_updates: Vec::new(),
                        local_initiated_shutdown: None,
+                       is_manual_broadcast: false,
                })
        }
 
@@ -2227,6 +2243,10 @@ impl<SP: Deref> ChannelContext<SP> 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<SP: Deref> ChannelContext<SP> 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<SP: Deref> ChannelContext<SP> 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<SP: Deref> ChannelContext<SP> 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<SP: Deref> Writeable for Channel<SP> 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<SP: Deref> Writeable for Channel<SP> 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<SP: Deref> Writeable for Channel<SP> 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<u64> = 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<PublicKey> = None;
                let mut next_holder_commitment_point_opt: Option<PublicKey> = 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,
index 992fd3c6f02d258c82a570e40567ddc2049b06c3..36b17cead0d31818145a5c68c8af318aa99c7164 100644 (file)
@@ -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<FundingOutput: FnMut(&OutboundV1Channel<SP>, &Transaction) -> Result<OutPoint, &'static str>>(
                &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 <https://bitcoinops.org/en/topics/fee-sniping/> 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]);
+                       }
                }
 
                {
index 7e57f20595a5b05630ace9de66b6a854043c7f56..fa2496077c4e5f5ac9033c24e9239a584a93212a 100644 (file)
@@ -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) {
index 7cd0f376d2e431d1fe8fe56c5353d281dbf28e55..9b1bf83bf511e773f61b6fe22f7dbf4d9e7cde1f 100644 (file)
@@ -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();
+}
+