Avoid unnecessarily alloc'ing a new buffer when decrypting messages
[rust-lightning] / lightning / src / ln / channel.rs
index 62a601f9347875781a84e09f6ae8eabcd389ea86..52db68c1323c771a45807fe5d21002b887d9e8d8 100644 (file)
@@ -1077,6 +1077,12 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider  {
                self.outbound_scid_alias
        }
 
+       /// Returns the holder signer for this channel.
+       #[cfg(test)]
+       pub fn get_signer(&self) -> &ChannelSignerType<<SP::Target as SignerProvider>::Signer> {
+               return &self.holder_signer
+       }
+
        /// Only allowed immediately after deserialization if get_outbound_scid_alias returns 0,
        /// indicating we were written by LDK prior to 0.0.106 which did not set outbound SCID aliases
        /// or prior to any channel actions during `Channel` initialization.
@@ -2100,6 +2106,71 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider  {
                        unbroadcasted_batch_funding_txid,
                }
        }
+
+       /// Only allowed after [`Self::channel_transaction_parameters`] is set.
+       fn get_funding_created_msg<L: Deref>(&mut self, logger: &L) -> Option<msgs::FundingCreated> where L::Target: Logger {
+               let counterparty_keys = self.build_remote_transaction_keys();
+               let counterparty_initial_commitment_tx = self.build_commitment_transaction(self.cur_counterparty_commitment_transaction_number, &counterparty_keys, false, false, logger).tx;
+               let signature = match &self.holder_signer {
+                       // TODO (taproot|arik): move match into calling method for Taproot
+                       ChannelSignerType::Ecdsa(ecdsa) => {
+                               ecdsa.sign_counterparty_commitment(&counterparty_initial_commitment_tx, Vec::new(), &self.secp_ctx)
+                                       .map(|(sig, _)| sig).ok()?
+                       }
+               };
+
+               if self.signer_pending_funding {
+                       log_trace!(logger, "Counterparty commitment signature ready for funding_created message: clearing signer_pending_funding");
+                       self.signer_pending_funding = false;
+               }
+
+               Some(msgs::FundingCreated {
+                       temporary_channel_id: self.temporary_channel_id.unwrap(),
+                       funding_txid: self.channel_transaction_parameters.funding_outpoint.as_ref().unwrap().txid,
+                       funding_output_index: self.channel_transaction_parameters.funding_outpoint.as_ref().unwrap().index,
+                       signature,
+                       #[cfg(taproot)]
+                       partial_signature_with_nonce: None,
+                       #[cfg(taproot)]
+                       next_local_nonce: None,
+               })
+       }
+
+       /// Only allowed after [`Self::channel_transaction_parameters`] is set.
+       fn get_funding_signed_msg<L: Deref>(&mut self, logger: &L) -> (CommitmentTransaction, Option<msgs::FundingSigned>) where L::Target: Logger {
+               let counterparty_keys = self.build_remote_transaction_keys();
+               let counterparty_initial_commitment_tx = self.build_commitment_transaction(self.cur_counterparty_commitment_transaction_number + 1, &counterparty_keys, false, false, logger).tx;
+
+               let counterparty_trusted_tx = counterparty_initial_commitment_tx.trust();
+               let counterparty_initial_bitcoin_tx = counterparty_trusted_tx.built_transaction();
+               log_trace!(logger, "Initial counterparty tx for channel {} is: txid {} tx {}",
+                       &self.channel_id(), counterparty_initial_bitcoin_tx.txid, encode::serialize_hex(&counterparty_initial_bitcoin_tx.transaction));
+
+               match &self.holder_signer {
+                       // TODO (arik): move match into calling method for Taproot
+                       ChannelSignerType::Ecdsa(ecdsa) => {
+                               let funding_signed = ecdsa.sign_counterparty_commitment(&counterparty_initial_commitment_tx, Vec::new(), &self.secp_ctx)
+                                       .map(|(signature, _)| msgs::FundingSigned {
+                                               channel_id: self.channel_id(),
+                                               signature,
+                                               #[cfg(taproot)]
+                                               partial_signature_with_nonce: None,
+                                       })
+                                       .ok();
+
+                               if funding_signed.is_none() {
+                                       log_trace!(logger, "Counterparty commitment signature not available for funding_signed message; setting signer_pending_funding");
+                                       self.signer_pending_funding = true;
+                               } else if self.signer_pending_funding {
+                                       log_trace!(logger, "Counterparty commitment signature available for funding_signed message; clearing signer_pending_funding");
+                                       self.signer_pending_funding = false;
+                               }
+
+                               // We sign "counterparty" commitment transaction, allowing them to broadcast the tx if they wish.
+                               (counterparty_initial_commitment_tx, funding_signed)
+                       }
+               }
+       }
 }
 
 // Internal utility functions for channels
@@ -3928,9 +3999,15 @@ impl<SP: Deref> Channel<SP> where
                let commitment_update = if self.context.signer_pending_commitment_update {
                        self.get_last_commitment_update_for_send(logger).ok()
                } else { None };
-               let funding_signed = None;
-               let channel_ready = None;
-               let funding_created = None;
+               let funding_signed = if self.context.signer_pending_funding && !self.context.is_outbound() {
+                       self.context.get_funding_signed_msg(logger).1
+               } else { None };
+               let channel_ready = if funding_signed.is_some() {
+                       self.check_get_channel_ready(0)
+               } else { None };
+               let funding_created = if self.context.signer_pending_funding && self.context.is_outbound() {
+                       self.context.get_funding_created_msg(logger)
+               } else { None };
 
                log_trace!(logger, "Signer unblocked with {} commitment_update, {} funding_signed, {} funding_created, and {} channel_ready",
                        if commitment_update.is_some() { "a" } else { "no" },
@@ -6000,18 +6077,6 @@ impl<SP: Deref> OutboundV1Channel<SP> where SP::Target: SignerProvider {
                })
        }
 
-       fn get_funding_created_signature<L: Deref>(&mut self, logger: &L) -> Result<Signature, ()> where L::Target: Logger {
-               let counterparty_keys = self.context.build_remote_transaction_keys();
-               let counterparty_initial_commitment_tx = self.context.build_commitment_transaction(self.context.cur_counterparty_commitment_transaction_number, &counterparty_keys, false, false, logger).tx;
-               match &self.context.holder_signer {
-                       // TODO (taproot|arik): move match into calling method for Taproot
-                       ChannelSignerType::Ecdsa(ecdsa) => {
-                               ecdsa.sign_counterparty_commitment(&counterparty_initial_commitment_tx, Vec::new(), &self.context.secp_ctx)
-                                       .map(|(sig, _)| sig)
-                       }
-               }
-       }
-
        /// Updates channel state with knowledge of the funding transaction's txid/index, and generates
        /// a funding_created message for the remote peer.
        /// Panics if called at some time other than immediately after initial handshake, if called twice,
@@ -6036,8 +6101,6 @@ impl<SP: Deref> OutboundV1Channel<SP> where SP::Target: SignerProvider {
                self.context.channel_transaction_parameters.funding_outpoint = Some(funding_txo);
                self.context.holder_signer.as_mut().provide_channel_parameters(&self.context.channel_transaction_parameters);
 
-               let temporary_channel_id = self.context.channel_id;
-
                // Now that we're past error-generating stuff, update our local state:
 
                self.context.channel_state = ChannelState::FundingCreated as u32;
@@ -6054,21 +6117,13 @@ impl<SP: Deref> OutboundV1Channel<SP> where SP::Target: SignerProvider {
                self.context.funding_transaction = Some(funding_transaction);
                self.context.is_batch_funding = Some(()).filter(|_| is_batch_funding);
 
-               let funding_created = if let Ok(signature) = self.get_funding_created_signature(logger) {
-                       Some(msgs::FundingCreated {
-                               temporary_channel_id,
-                               funding_txid: funding_txo.txid,
-                               funding_output_index: funding_txo.index,
-                               signature,
-                               #[cfg(taproot)]
-                               partial_signature_with_nonce: None,
-                               #[cfg(taproot)]
-                               next_local_nonce: None,
-                       })
-               } else {
-                       self.context.signer_pending_funding = true;
-                       None
-               };
+               let funding_created = self.context.get_funding_created_msg(logger);
+               if funding_created.is_none() {
+                       if !self.context.signer_pending_funding {
+                               log_trace!(logger, "funding_created awaiting signer; setting signer_pending_funding");
+                               self.context.signer_pending_funding = true;
+                       }
+               }
 
                let channel = Channel {
                        context: self.context,
@@ -6721,41 +6776,22 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {
                self.generate_accept_channel_message()
        }
 
-       fn funding_created_signature<L: Deref>(&mut self, sig: &Signature, logger: &L) -> Result<(CommitmentTransaction, CommitmentTransaction, Option<Signature>), ChannelError> where L::Target: Logger {
+       fn check_funding_created_signature<L: Deref>(&mut self, sig: &Signature, logger: &L) -> Result<CommitmentTransaction, ChannelError> where L::Target: Logger {
                let funding_script = self.context.get_funding_redeemscript();
 
                let keys = self.context.build_holder_transaction_keys(self.context.cur_holder_commitment_transaction_number);
                let initial_commitment_tx = self.context.build_commitment_transaction(self.context.cur_holder_commitment_transaction_number, &keys, true, false, logger).tx;
-               {
-                       let trusted_tx = initial_commitment_tx.trust();
-                       let initial_commitment_bitcoin_tx = trusted_tx.built_transaction();
-                       let sighash = initial_commitment_bitcoin_tx.get_sighash_all(&funding_script, self.context.channel_value_satoshis);
-                       // They sign the holder commitment transaction...
-                       log_trace!(logger, "Checking funding_created tx signature {} by key {} against tx {} (sighash {}) with redeemscript {} for channel {}.",
-                               log_bytes!(sig.serialize_compact()[..]), log_bytes!(self.context.counterparty_funding_pubkey().serialize()),
-                               encode::serialize_hex(&initial_commitment_bitcoin_tx.transaction), log_bytes!(sighash[..]),
-                               encode::serialize_hex(&funding_script), &self.context.channel_id());
-                       secp_check!(self.context.secp_ctx.verify_ecdsa(&sighash, &sig, self.context.counterparty_funding_pubkey()), "Invalid funding_created signature from peer".to_owned());
-               }
+               let trusted_tx = initial_commitment_tx.trust();
+               let initial_commitment_bitcoin_tx = trusted_tx.built_transaction();
+               let sighash = initial_commitment_bitcoin_tx.get_sighash_all(&funding_script, self.context.channel_value_satoshis);
+               // They sign the holder commitment transaction...
+               log_trace!(logger, "Checking funding_created tx signature {} by key {} against tx {} (sighash {}) with redeemscript {} for channel {}.",
+                       log_bytes!(sig.serialize_compact()[..]), log_bytes!(self.context.counterparty_funding_pubkey().serialize()),
+                       encode::serialize_hex(&initial_commitment_bitcoin_tx.transaction), log_bytes!(sighash[..]),
+                       encode::serialize_hex(&funding_script), &self.context.channel_id());
+               secp_check!(self.context.secp_ctx.verify_ecdsa(&sighash, &sig, self.context.counterparty_funding_pubkey()), "Invalid funding_created signature from peer".to_owned());
 
-               let counterparty_keys = self.context.build_remote_transaction_keys();
-               let counterparty_initial_commitment_tx = self.context.build_commitment_transaction(self.context.cur_counterparty_commitment_transaction_number, &counterparty_keys, false, false, logger).tx;
-
-               let counterparty_trusted_tx = counterparty_initial_commitment_tx.trust();
-               let counterparty_initial_bitcoin_tx = counterparty_trusted_tx.built_transaction();
-               log_trace!(logger, "Initial counterparty tx for channel {} is: txid {} tx {}",
-                       &self.context.channel_id(), counterparty_initial_bitcoin_tx.txid, encode::serialize_hex(&counterparty_initial_bitcoin_tx.transaction));
-
-               match &self.context.holder_signer {
-                       // TODO (arik): move match into calling method for Taproot
-                       ChannelSignerType::Ecdsa(ecdsa) => {
-                               let counterparty_signature = ecdsa.sign_counterparty_commitment(&counterparty_initial_commitment_tx, Vec::new(), &self.context.secp_ctx)
-                                       .map(|(sig, _)| sig).ok();
-
-                               // We sign "counterparty" commitment transaction, allowing them to broadcast the tx if they wish.
-                               Ok((counterparty_initial_commitment_tx, initial_commitment_tx, counterparty_signature))
-                       }
-               }
+               Ok(initial_commitment_tx)
        }
 
        pub fn funding_created<L: Deref>(
@@ -6782,10 +6818,10 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {
                let funding_txo = OutPoint { txid: msg.funding_txid, index: msg.funding_output_index };
                self.context.channel_transaction_parameters.funding_outpoint = Some(funding_txo);
                // This is an externally observable change before we finish all our checks.  In particular
-               // funding_created_signature may fail.
+               // check_funding_created_signature may fail.
                self.context.holder_signer.as_mut().provide_channel_parameters(&self.context.channel_transaction_parameters);
 
-               let (counterparty_initial_commitment_tx, initial_commitment_tx, sig_opt) = match self.funding_created_signature(&msg.signature, logger) {
+               let initial_commitment_tx = match self.check_funding_created_signature(&msg.signature, logger) {
                        Ok(res) => res,
                        Err(ChannelError::Close(e)) => {
                                self.context.channel_transaction_parameters.funding_outpoint = None;
@@ -6794,7 +6830,7 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {
                        Err(e) => {
                                // The only error we know how to handle is ChannelError::Close, so we fall over here
                                // to make sure we don't continue with an inconsistent state.
-                               panic!("unexpected error type from funding_created_signature {:?}", e);
+                               panic!("unexpected error type from check_funding_created_signature {:?}", e);
                        }
                };
 
@@ -6812,6 +6848,13 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {
 
                // Now that we're past error-generating stuff, update our local state:
 
+               self.context.channel_state = ChannelState::FundingSent as u32;
+               self.context.channel_id = funding_txo.to_channel_id();
+               self.context.cur_counterparty_commitment_transaction_number -= 1;
+               self.context.cur_holder_commitment_transaction_number -= 1;
+
+               let (counterparty_initial_commitment_tx, funding_signed) = self.context.get_funding_signed_msg(logger);
+
                let funding_redeemscript = self.context.get_funding_redeemscript();
                let funding_txo_script = funding_redeemscript.to_v0_p2wsh();
                let obscure_factor = get_commitment_transaction_number_obscure_factor(&self.context.get_holder_pubkeys().payment_point, &self.context.get_counterparty_pubkeys().payment_point, self.context.is_outbound());
@@ -6828,39 +6871,22 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {
 
                channel_monitor.provide_initial_counterparty_commitment_tx(
                        counterparty_initial_commitment_tx.trust().txid(), Vec::new(),
-                       self.context.cur_counterparty_commitment_transaction_number,
+                       self.context.cur_counterparty_commitment_transaction_number + 1,
                        self.context.counterparty_cur_commitment_point.unwrap(), self.context.feerate_per_kw,
                        counterparty_initial_commitment_tx.to_broadcaster_value_sat(),
                        counterparty_initial_commitment_tx.to_countersignatory_value_sat(), logger);
 
-               self.context.channel_state = ChannelState::FundingSent as u32;
-               self.context.channel_id = funding_txo.to_channel_id();
-               self.context.cur_counterparty_commitment_transaction_number -= 1;
-               self.context.cur_holder_commitment_transaction_number -= 1;
-
-               log_info!(logger, "Generated funding_signed for peer for channel {}", &self.context.channel_id());
+               log_info!(logger, "{} funding_signed for peer for channel {}",
+                       if funding_signed.is_some() { "Generated" } else { "Waiting for signature on" }, &self.context.channel_id());
 
                // Promote the channel to a full-fledged one now that we have updated the state and have a
                // `ChannelMonitor`.
                let mut channel = Channel {
                        context: self.context,
                };
-               let channel_id = channel.context.channel_id.clone();
                let need_channel_ready = channel.check_get_channel_ready(0).is_some();
                channel.monitor_updating_paused(false, false, need_channel_ready, Vec::new(), Vec::new(), Vec::new());
 
-               let funding_signed = if let Some(signature) = sig_opt {
-                       Some(msgs::FundingSigned {
-                               channel_id,
-                               signature,
-                               #[cfg(taproot)]
-                               partial_signature_with_nonce: None,
-                       })
-               } else {
-                       channel.context.signer_pending_funding = true;
-                       None
-               };
-
                Ok((channel, funding_signed, channel_monitor))
        }
 }