+
+ fn if_unbroadcasted_funding<F, O>(&self, f: F) -> Option<O>
+ where F: Fn() -> Option<O> {
+ if self.channel_state & ChannelState::FundingCreated as u32 != 0 ||
+ self.channel_state & ChannelState::WaitingForBatch as u32 != 0 {
+ f()
+ } else {
+ None
+ }
+ }
+
+ /// Returns the transaction if there is a pending funding transaction that is yet to be
+ /// broadcast.
+ pub fn unbroadcasted_funding(&self) -> Option<Transaction> {
+ self.if_unbroadcasted_funding(|| self.funding_transaction.clone())
+ }
+
+ /// Returns the transaction ID if there is a pending funding transaction that is yet to be
+ /// broadcast.
+ pub fn unbroadcasted_funding_txid(&self) -> Option<Txid> {
+ self.if_unbroadcasted_funding(||
+ self.channel_transaction_parameters.funding_outpoint.map(|txo| txo.txid)
+ )
+ }
+
+ /// Returns whether the channel is funded in a batch.
+ pub fn is_batch_funding(&self) -> bool {
+ self.is_batch_funding.is_some()
+ }
+
+ /// Returns the transaction ID if there is a pending batch funding transaction that is yet to be
+ /// broadcast.
+ pub fn unbroadcasted_batch_funding_txid(&self) -> Option<Txid> {
+ self.unbroadcasted_funding_txid().filter(|_| self.is_batch_funding())
+ }
+
+ /// Gets the latest commitment transaction and any dependent transactions for relay (forcing
+ /// shutdown of this channel - no more calls into this Channel may be made afterwards except
+ /// those explicitly stated to be allowed after shutdown completes, eg some simple getters).
+ /// Also returns the list of payment_hashes for channels which we can safely fail backwards
+ /// immediately (others we will have to allow to time out).
+ pub fn force_shutdown(&mut self, should_broadcast: bool) -> ShutdownResult {
+ // Note that we MUST only generate a monitor update that indicates force-closure - we're
+ // called during initialization prior to the chain_monitor in the encompassing ChannelManager
+ // being fully configured in some cases. Thus, its likely any monitor events we generate will
+ // be delayed in being processed! See the docs for `ChannelManagerReadArgs` for more.
+ assert!(self.channel_state != ChannelState::ShutdownComplete as u32);
+
+ // We go ahead and "free" any holding cell HTLCs or HTLCs we haven't yet committed to and
+ // return them to fail the payment.
+ let mut dropped_outbound_htlcs = Vec::with_capacity(self.holding_cell_htlc_updates.len());
+ let counterparty_node_id = self.get_counterparty_node_id();
+ for htlc_update in self.holding_cell_htlc_updates.drain(..) {
+ match htlc_update {
+ HTLCUpdateAwaitingACK::AddHTLC { source, payment_hash, .. } => {
+ dropped_outbound_htlcs.push((source, payment_hash, counterparty_node_id, self.channel_id));
+ },
+ _ => {}
+ }
+ }
+ let monitor_update = if let Some(funding_txo) = self.get_funding_txo() {
+ // If we haven't yet exchanged funding signatures (ie channel_state < FundingSent),
+ // returning a channel monitor update here would imply a channel monitor update before
+ // we even registered the channel monitor to begin with, which is invalid.
+ // Thus, if we aren't actually at a point where we could conceivably broadcast the
+ // funding transaction, don't return a funding txo (which prevents providing the
+ // monitor update to the user, even if we return one).
+ // See test_duplicate_chan_id and test_pre_lockin_no_chan_closed_update for more.
+ if self.channel_state & (ChannelState::FundingSent as u32 | ChannelState::ChannelReady as u32 | ChannelState::ShutdownComplete as u32) != 0 {
+ self.latest_monitor_update_id = CLOSED_CHANNEL_UPDATE_ID;
+ Some((self.get_counterparty_node_id(), funding_txo, ChannelMonitorUpdate {
+ update_id: self.latest_monitor_update_id,
+ updates: vec![ChannelMonitorUpdateStep::ChannelForceClosed { should_broadcast }],
+ }))
+ } else { None }
+ } else { None };
+ let unbroadcasted_batch_funding_txid = self.unbroadcasted_batch_funding_txid();
+
+ self.channel_state = ChannelState::ShutdownComplete as u32;
+ self.update_time_counter += 1;
+ ShutdownResult {
+ monitor_update,
+ dropped_outbound_htlcs,
+ 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)
+ }
+ }
+ }