Merge pull request #875 from TheBlueMatt/2021-04-fix-bench
[rust-lightning] / lightning / src / ln / channelmanager.rs
index efb2fe9c37bd9a8ec2c9a36d9a521072a6f8c6f3..d2ea7dfea798baea181dec19838cf2b55ccaad22 100644 (file)
@@ -19,6 +19,7 @@
 //!
 
 use bitcoin::blockdata::block::{Block, BlockHeader};
+use bitcoin::blockdata::transaction::Transaction;
 use bitcoin::blockdata::constants::genesis_block;
 use bitcoin::network::constants::Network;
 
@@ -337,7 +338,7 @@ pub(super) struct ChannelHolder<Signer: Sign> {
 }
 
 /// Events which we process internally but cannot be procsesed immediately at the generation site
-/// for some reason. They are handled in timer_chan_freshness_every_min, so may be processed with
+/// for some reason. They are handled in timer_tick_occurred, so may be processed with
 /// quite some time lag.
 enum BackgroundEvent {
        /// Handle a ChannelMonitorUpdate that closes a channel, broadcasting its current latest holder
@@ -402,7 +403,7 @@ pub type SimpleRefChannelManager<'a, 'b, 'c, 'd, 'e, M, T, F, L> = ChannelManage
 /// ChannelUpdate messages informing peers that the channel is temporarily disabled. To avoid
 /// spam due to quick disconnection/reconnection, updates are not sent until the channel has been
 /// offline for a full minute. In order to track this, you must call
-/// timer_chan_freshness_every_min roughly once per minute, though it doesn't have to be perfect.
+/// timer_tick_occurred roughly once per minute, though it doesn't have to be perfect.
 ///
 /// Rather than using a plain ChannelManager, it is preferable to use either a SimpleArcChannelManager
 /// a SimpleRefChannelManager, for conciseness. See their documentation for more details, but
@@ -852,10 +853,11 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
 
        /// Creates a new outbound channel to the given remote node and with the given value.
        ///
-       /// user_id will be provided back as user_channel_id in FundingGenerationReady and
-       /// FundingBroadcastSafe events to allow tracking of which events correspond with which
-       /// create_channel call. Note that user_channel_id defaults to 0 for inbound channels, so you
-       /// may wish to avoid using 0 for user_id here.
+       /// user_id will be provided back as user_channel_id in FundingGenerationReady events to allow
+       /// tracking of which events correspond with which create_channel call. Note that the
+       /// user_channel_id defaults to 0 for inbound channels, so you may wish to avoid using 0 for
+       /// user_id here. user_id has no meaning inside of LDK, it is simply copied to events and
+       /// otherwise ignored.
        ///
        /// If successful, will generate a SendOpenChannel message event, so you should probably poll
        /// PeerManager::process_events afterwards.
@@ -1538,32 +1540,75 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
 
        /// Call this upon creation of a funding transaction for the given channel.
        ///
-       /// Note that ALL inputs in the transaction pointed to by funding_txo MUST spend SegWit outputs
-       /// or your counterparty can steal your funds!
+       /// Returns an [`APIError::APIMisuseError`] if the funding_transaction spent non-SegWit outputs
+       /// or if no output was found which matches the parameters in [`Event::FundingGenerationReady`].
        ///
        /// Panics if a funding transaction has already been provided for this channel.
        ///
-       /// May panic if the funding_txo is duplicative with some other channel (note that this should
-       /// be trivially prevented by using unique funding transaction keys per-channel).
-       pub fn funding_transaction_generated(&self, temporary_channel_id: &[u8; 32], funding_txo: OutPoint) {
+       /// 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).
+       ///
+       /// Do NOT broadcast the funding transaction yourself. When we have safely received our
+       /// counterparty's signature the funding transaction will automatically be broadcast via the
+       /// [`BroadcasterInterface`] provided when this `ChannelManager` was constructed.
+       ///
+       /// Note that this includes RBF or similar transaction replacement strategies - lightning does
+       /// not currently support replacing a funding transaction on an existing channel. Instead,
+       /// create a new channel with a conflicting funding transaction.
+       pub fn funding_transaction_generated(&self, temporary_channel_id: &[u8; 32], funding_transaction: Transaction) -> Result<(), APIError> {
                let _persistence_guard = PersistenceNotifierGuard::new(&self.total_consistency_lock, &self.persistence_notifier);
 
+               for inp in funding_transaction.input.iter() {
+                       if inp.witness.is_empty() {
+                               return Err(APIError::APIMisuseError {
+                                       err: "Funding transaction must be fully signed and spend Segwit outputs".to_owned()
+                               });
+                       }
+               }
+
                let (chan, msg) = {
                        let (res, chan) = match self.channel_state.lock().unwrap().by_id.remove(temporary_channel_id) {
                                Some(mut chan) => {
-                                       (chan.get_outbound_funding_created(funding_txo, &self.logger)
+                                       let mut output_index = None;
+                                       let expected_spk = chan.get_funding_redeemscript().to_v0_p2wsh();
+                                       for (idx, outp) in funding_transaction.output.iter().enumerate() {
+                                               if outp.script_pubkey == expected_spk && outp.value == chan.get_value_satoshis() {
+                                                       if output_index.is_some() {
+                                                               return Err(APIError::APIMisuseError {
+                                                                       err: "Multiple outputs matched the expected script and value".to_owned()
+                                                               });
+                                                       }
+                                                       if idx > u16::max_value() as usize {
+                                                               return Err(APIError::APIMisuseError {
+                                                                       err: "Transaction had more than 2^16 outputs, which is not supported".to_owned()
+                                                               });
+                                                       }
+                                                       output_index = Some(idx as u16);
+                                               }
+                                       }
+                                       if output_index.is_none() {
+                                               return Err(APIError::APIMisuseError {
+                                                       err: "No output matched the script_pubkey and value in the FundingGenerationReady event".to_owned()
+                                               });
+                                       }
+                                       let funding_txo = OutPoint { txid: funding_transaction.txid(), index: output_index.unwrap() };
+
+                                       (chan.get_outbound_funding_created(funding_transaction, funding_txo, &self.logger)
                                                .map_err(|e| if let ChannelError::Close(msg) = e {
                                                        MsgHandleErrInternal::from_finish_shutdown(msg, chan.channel_id(), chan.force_shutdown(true), None)
                                                } else { unreachable!(); })
                                        , chan)
                                },
-                               None => return
+                               None => { return Err(APIError::ChannelUnavailable { err: "No such channel".to_owned() }) },
                        };
                        match handle_error!(self, res, chan.get_counterparty_node_id()) {
                                Ok(funding_msg) => {
                                        (chan, funding_msg)
                                },
-                               Err(_) => { return; }
+                               Err(_) => { return Err(APIError::ChannelUnavailable {
+                                       err: "Error deriving keys or signing initial commitment transactions - either our RNG or our counterparty's RNG is broken or the Signer refused to sign".to_owned()
+                               }) },
                        }
                };
 
@@ -1580,6 +1625,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
                                e.insert(chan);
                        }
                }
+               Ok(())
        }
 
        fn get_announcement_sigs(&self, chan: &Channel<Signer>) -> Option<msgs::AnnouncementSignatures> {
@@ -1913,10 +1959,10 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
                events.append(&mut new_events);
        }
 
-       /// Free the background events, generally called from timer_chan_freshness_every_min.
+       /// Free the background events, generally called from timer_tick_occurred.
        ///
        /// Exposed for testing to allow us to process events quickly without generating accidental
-       /// BroadcastChannelUpdate events in timer_chan_freshness_every_min.
+       /// BroadcastChannelUpdate events in timer_tick_occurred.
        ///
        /// Expects the caller to have a total_consistency_lock read lock.
        fn process_background_events(&self) {
@@ -1945,7 +1991,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
        /// This method handles all the details, and must be called roughly once per minute.
        ///
        /// Note that in some rare cases this may generate a `chain::Watch::update_channel` call.
-       pub fn timer_chan_freshness_every_min(&self) {
+       pub fn timer_tick_occurred(&self) {
                let _persistence_guard = PersistenceNotifierGuard::new(&self.total_consistency_lock, &self.persistence_notifier);
                self.process_background_events();
 
@@ -2372,7 +2418,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
                                return;
                        }
 
-                       let (raa, commitment_update, order, pending_forwards, mut pending_failures, needs_broadcast_safe, funding_locked) = channel.monitor_updating_restored(&self.logger);
+                       let (raa, commitment_update, order, pending_forwards, mut pending_failures, funding_broadcastable, funding_locked) = channel.monitor_updating_restored(&self.logger);
                        if !pending_forwards.is_empty() {
                                htlc_forwards.push((channel.get_short_channel_id().expect("We can't have pending forwards before funding confirmation"), funding_txo.clone(), pending_forwards));
                        }
@@ -2404,11 +2450,8 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
                                        handle_cs!();
                                },
                        }
-                       if needs_broadcast_safe {
-                               pending_events.push(events::Event::FundingBroadcastSafe {
-                                       funding_txo: channel.get_funding_txo().unwrap(),
-                                       user_channel_id: channel.get_user_id(),
-                               });
+                       if let Some(tx) = funding_broadcastable {
+                               self.tx_broadcaster.broadcast_transaction(&tx);
                        }
                        if let Some(msg) = funding_locked {
                                pending_msg_events.push(events::MessageSendEvent::SendFundingLocked {
@@ -2542,7 +2585,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
        }
 
        fn internal_funding_signed(&self, counterparty_node_id: &PublicKey, msg: &msgs::FundingSigned) -> Result<(), MsgHandleErrInternal> {
-               let (funding_txo, user_id) = {
+               let funding_tx = {
                        let last_block_hash = *self.last_block_hash.read().unwrap();
                        let mut channel_lock = self.channel_state.lock().unwrap();
                        let channel_state = &mut *channel_lock;
@@ -2551,23 +2594,19 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
                                        if chan.get().get_counterparty_node_id() != *counterparty_node_id {
                                                return Err(MsgHandleErrInternal::send_err_msg_no_close("Got a message for a channel from the wrong node!".to_owned(), msg.channel_id));
                                        }
-                                       let monitor = match chan.get_mut().funding_signed(&msg, last_block_hash, &self.logger) {
+                                       let (monitor, funding_tx) = match chan.get_mut().funding_signed(&msg, last_block_hash, &self.logger) {
                                                Ok(update) => update,
                                                Err(e) => try_chan_entry!(self, Err(e), channel_state, chan),
                                        };
                                        if let Err(e) = self.chain_monitor.watch_channel(chan.get().get_funding_txo().unwrap(), monitor) {
                                                return_monitor_err!(self, e, channel_state, chan, RAACommitmentOrder::RevokeAndACKFirst, false, false);
                                        }
-                                       (chan.get().get_funding_txo().unwrap(), chan.get().get_user_id())
+                                       funding_tx
                                },
                                hash_map::Entry::Vacant(_) => return Err(MsgHandleErrInternal::send_err_msg_no_close("Failed to find corresponding channel".to_owned(), msg.channel_id))
                        }
                };
-               let mut pending_events = self.pending_events.lock().unwrap();
-               pending_events.push(events::Event::FundingBroadcastSafe {
-                       funding_txo,
-                       user_channel_id: user_id,
-               });
+               self.tx_broadcaster.broadcast_transaction(&funding_tx);
                Ok(())
        }
 
@@ -3235,7 +3274,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
                        // We cannot broadcast our latest local state via monitor update (as
                        // Channel::force_shutdown tries to make us do) as we may still be in initialization,
                        // so we track the update internally and handle it when the user next calls
-                       // timer_chan_freshness_every_min, guaranteeing we're running normally.
+                       // timer_tick_occurred, guaranteeing we're running normally.
                        if let Some((funding_txo, update)) = failure.0.take() {
                                assert_eq!(update.updates.len(), 1);
                                if let ChannelMonitorUpdateStep::ChannelForceClosed { should_broadcast } = update.updates[0] {
@@ -4441,7 +4480,6 @@ pub mod bench {
        use chain::chainmonitor::ChainMonitor;
        use chain::channelmonitor::Persist;
        use chain::keysinterface::{KeysManager, InMemorySigner};
-       use chain::transaction::OutPoint;
        use ln::channelmanager::{ChainParameters, ChannelManager, PaymentHash, PaymentPreimage};
        use ln::features::InitFeatures;
        use ln::functional_test_utils::*;
@@ -4519,14 +4557,13 @@ pub mod bench {
                        tx = Transaction { version: 2, lock_time: 0, input: Vec::new(), output: vec![TxOut {
                                value: 8_000_000, script_pubkey: output_script,
                        }]};
-                       let funding_outpoint = OutPoint { txid: tx.txid(), index: 0 };
-                       node_a.funding_transaction_generated(&temporary_channel_id, funding_outpoint);
+                       node_a.funding_transaction_generated(&temporary_channel_id, tx.clone()).unwrap();
                } 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()));
                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()));
 
-               get_event!(node_a_holder, Event::FundingBroadcastSafe);
+               assert_eq!(&tx_broadcaster.txn_broadcasted.lock().unwrap()[..], &[tx.clone()]);
 
                let block = Block {
                        header: BlockHeader { version: 0x20000000, prev_blockhash: genesis_hash, merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 },