- log_debug!(logger, "Received a valid revoke_and_ack for channel {}. Responding with a commitment update with {} HTLCs failed.",
- log_bytes!(self.context.channel_id()), update_fail_htlcs.len() + update_fail_malformed_htlcs.len());
- self.monitor_updating_paused(false, true, false, to_forward_infos, revoked_htlcs, finalized_claimed_htlcs);
- Ok((htlcs_to_fail, self.push_ret_blockable_mon_update(monitor_update)))
- } else {
- log_debug!(logger, "Received a valid revoke_and_ack for channel {} with no reply necessary.", log_bytes!(self.context.channel_id()));
- self.monitor_updating_paused(false, false, false, to_forward_infos, revoked_htlcs, finalized_claimed_htlcs);
- Ok((htlcs_to_fail, self.push_ret_blockable_mon_update(monitor_update)))
+ /// When a transaction is confirmed, we check whether it is or spends the funding transaction
+ /// In the first case, we store the confirmation height and calculating the short channel id.
+ /// In the second, we simply return an Err indicating we need to be force-closed now.
+ pub fn transactions_confirmed<NS: Deref, L: Deref>(
+ &mut self, block_hash: &BlockHash, height: u32, txdata: &TransactionData,
+ genesis_block_hash: BlockHash, node_signer: &NS, user_config: &UserConfig, logger: &L
+ ) -> Result<(Option<msgs::ChannelReady>, Option<msgs::AnnouncementSignatures>), ClosureReason>
+ where
+ NS::Target: NodeSigner,
+ L::Target: Logger
+ {
+ if let Some(funding_txo) = self.context.get_funding_txo() {
+ for &(index_in_block, tx) in txdata.iter() {
+ // Check if the transaction is the expected funding transaction, and if it is,
+ // check that it pays the right amount to the right script.
+ if self.context.funding_tx_confirmation_height == 0 {
+ if tx.txid() == funding_txo.txid {
+ let txo_idx = funding_txo.index as usize;
+ if txo_idx >= tx.output.len() || tx.output[txo_idx].script_pubkey != self.context.get_funding_redeemscript().to_v0_p2wsh() ||
+ tx.output[txo_idx].value != self.context.channel_value_satoshis {
+ if self.context.is_outbound() {
+ // If we generated the funding transaction and it doesn't match what it
+ // should, the client is really broken and we should just panic and
+ // tell them off. That said, because hash collisions happen with high
+ // probability in fuzzing mode, if we're fuzzing we just close the
+ // channel and move on.
+ #[cfg(not(fuzzing))]
+ panic!("Client called ChannelManager::funding_transaction_generated with bogus transaction!");
+ }
+ self.context.update_time_counter += 1;
+ let err_reason = "funding tx had wrong script/value or output index";
+ return Err(ClosureReason::ProcessingError { err: err_reason.to_owned() });
+ } else {
+ if self.context.is_outbound() {
+ for input in tx.input.iter() {
+ if input.witness.is_empty() {
+ // We generated a malleable funding transaction, implying we've
+ // just exposed ourselves to funds loss to our counterparty.
+ #[cfg(not(fuzzing))]
+ panic!("Client called ChannelManager::funding_transaction_generated with bogus transaction!");
+ }
+ }
+ }
+ self.context.funding_tx_confirmation_height = height;
+ self.context.funding_tx_confirmed_in = Some(*block_hash);
+ self.context.short_channel_id = match scid_from_parts(height as u64, index_in_block as u64, txo_idx as u64) {
+ Ok(scid) => Some(scid),
+ Err(_) => panic!("Block was bogus - either height was > 16 million, had > 16 million transactions, or had > 65k outputs"),
+ }
+ }
+ }
+ // If we allow 1-conf funding, we may need to check for channel_ready here and
+ // send it immediately instead of waiting for a best_block_updated call (which
+ // may have already happened for this block).
+ if let Some(channel_ready) = self.check_get_channel_ready(height) {
+ log_info!(logger, "Sending a channel_ready to our peer for channel {}", log_bytes!(self.context.channel_id));
+ let announcement_sigs = self.get_announcement_sigs(node_signer, genesis_block_hash, user_config, height, logger);
+ return Ok((Some(channel_ready), announcement_sigs));
+ }
+ }
+ for inp in tx.input.iter() {
+ if inp.previous_output == funding_txo.into_bitcoin_outpoint() {
+ log_info!(logger, "Detected channel-closing tx {} spending {}:{}, closing channel {}", tx.txid(), inp.previous_output.txid, inp.previous_output.vout, log_bytes!(self.context.channel_id()));
+ return Err(ClosureReason::CommitmentTxConfirmed);
+ }