Handle retrying sign_counterparty_commitment outb funding failures
[rust-lightning] / lightning / src / ln / channel.rs
index c6375e1a7c733327885780bac4c36b63e6d759ac..134be90ea1986fec44c291d1523caeb39894f652 100644 (file)
@@ -533,6 +533,15 @@ pub(super) struct MonitorRestoreUpdates {
        pub announcement_sigs: Option<msgs::AnnouncementSignatures>,
 }
 
+/// The return value of `signer_maybe_unblocked`
+#[allow(unused)]
+pub(super) struct SignerResumeUpdates {
+       pub commitment_update: Option<msgs::CommitmentUpdate>,
+       pub funding_signed: Option<msgs::FundingSigned>,
+       pub funding_created: Option<msgs::FundingCreated>,
+       pub channel_ready: Option<msgs::ChannelReady>,
+}
+
 /// The return value of `channel_reestablish`
 pub(super) struct ReestablishResponses {
        pub channel_ready: Option<msgs::ChannelReady>,
@@ -2091,6 +2100,35 @@ 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,
+               })
+       }
 }
 
 // Internal utility functions for channels
@@ -3912,6 +3950,33 @@ impl<SP: Deref> Channel<SP> where
                Ok(())
        }
 
+       /// Indicates that the signer may have some signatures for us, so we should retry if we're
+       /// blocked.
+       #[allow(unused)]
+       pub fn signer_maybe_unblocked<L: Deref>(&mut self, logger: &L) -> SignerResumeUpdates where L::Target: Logger {
+               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 = 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" },
+                       if funding_signed.is_some() { "a" } else { "no" },
+                       if funding_created.is_some() { "a" } else { "no" },
+                       if channel_ready.is_some() { "a" } else { "no" });
+
+               SignerResumeUpdates {
+                       commitment_update,
+                       funding_signed,
+                       funding_created,
+                       channel_ready,
+               }
+       }
+
        fn get_last_revoke_and_ack(&self) -> msgs::RevokeAndACK {
                let next_per_commitment_point = self.context.holder_signer.as_ref().get_per_commitment_point(self.context.cur_holder_commitment_transaction_number, &self.context.secp_ctx);
                let per_commitment_secret = self.context.holder_signer.as_ref().release_commitment_secret(self.context.cur_holder_commitment_transaction_number + 2);
@@ -5966,18 +6031,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,
@@ -6002,8 +6055,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;
@@ -6020,21 +6071,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,
@@ -6687,7 +6730,7 @@ 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, Signature), ChannelError> where L::Target: Logger {
+       fn funding_created_signature<L: Deref>(&mut self, sig: &Signature, logger: &L) -> Result<(CommitmentTransaction, CommitmentTransaction, Option<Signature>), 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);
@@ -6716,7 +6759,7 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {
                        // 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_err(|_| ChannelError::Close("Failed to get signatures for new commitment_signed".to_owned()))?.0;
+                                       .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))
@@ -6726,7 +6769,7 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {
 
        pub fn funding_created<L: Deref>(
                mut self, msg: &msgs::FundingCreated, best_block: BestBlock, signer_provider: &SP, logger: &L
-       ) -> Result<(Channel<SP>, msgs::FundingSigned, ChannelMonitor<<SP::Target as SignerProvider>::Signer>), (Self, ChannelError)>
+       ) -> Result<(Channel<SP>, Option<msgs::FundingSigned>, ChannelMonitor<<SP::Target as SignerProvider>::Signer>), (Self, ChannelError)>
        where
                L::Target: Logger
        {
@@ -6751,7 +6794,7 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {
                // 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, signature) = match self.funding_created_signature(&msg.signature, logger) {
+               let (counterparty_initial_commitment_tx, initial_commitment_tx, sig_opt) = match self.funding_created_signature(&msg.signature, logger) {
                        Ok(res) => res,
                        Err(ChannelError::Close(e)) => {
                                self.context.channel_transaction_parameters.funding_outpoint = None;
@@ -6815,12 +6858,19 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {
                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());
 
-               Ok((channel, msgs::FundingSigned {
-                       channel_id,
-                       signature,
-                       #[cfg(taproot)]
-                       partial_signature_with_nonce: None,
-               }, channel_monitor))
+               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))
        }
 }
 
@@ -7908,7 +7958,7 @@ mod tests {
                let (_, funding_signed_msg, _) = node_b_chan.funding_created(&funding_created_msg.unwrap(), best_block, &&keys_provider, &&logger).map_err(|_| ()).unwrap();
 
                // Node B --> Node A: funding signed
-               let _ = node_a_chan.funding_signed(&funding_signed_msg, best_block, &&keys_provider, &&logger).unwrap();
+               let _ = node_a_chan.funding_signed(&funding_signed_msg.unwrap(), best_block, &&keys_provider, &&logger).unwrap();
 
                // Put some inbound and outbound HTLCs in A's channel.
                let htlc_amount_msat = 11_092_000; // put an amount below A's effective dust limit but above B's.
@@ -8035,7 +8085,7 @@ mod tests {
                let (mut node_b_chan, funding_signed_msg, _) = node_b_chan.funding_created(&funding_created_msg.unwrap(), best_block, &&keys_provider, &&logger).map_err(|_| ()).unwrap();
 
                // Node B --> Node A: funding signed
-               let _ = node_a_chan.funding_signed(&funding_signed_msg, best_block, &&keys_provider, &&logger).unwrap();
+               let _ = node_a_chan.funding_signed(&funding_signed_msg.unwrap(), best_block, &&keys_provider, &&logger).unwrap();
 
                // Now disconnect the two nodes and check that the commitment point in
                // Node B's channel_reestablish message is sane.
@@ -8223,7 +8273,7 @@ mod tests {
                let (_, funding_signed_msg, _) = node_b_chan.funding_created(&funding_created_msg.unwrap(), best_block, &&keys_provider, &&logger).map_err(|_| ()).unwrap();
 
                // Node B --> Node A: funding signed
-               let _ = node_a_chan.funding_signed(&funding_signed_msg, best_block, &&keys_provider, &&logger).unwrap();
+               let _ = node_a_chan.funding_signed(&funding_signed_msg.unwrap(), best_block, &&keys_provider, &&logger).unwrap();
 
                // Make sure that receiving a channel update will update the Channel as expected.
                let update = ChannelUpdate {
@@ -9308,7 +9358,7 @@ mod tests {
                // Receive funding_signed, but the channel will be configured to hold sending channel_ready and
                // broadcasting the funding transaction until the batch is ready.
                let _ = node_a_chan.funding_signed(
-                       &funding_signed_msg,
+                       &funding_signed_msg.unwrap(),
                        best_block,
                        &&keys_provider,
                        &&logger,