Decode `HTLCFailReason`s in a util method on the enum
[rust-lightning] / lightning / src / chain / channelmonitor.rs
index 1cbc85350302ab27d86758609b4632fa8b67722c..92f1a8df45d8e88bb75e9db80c7974fa89a430ec 100644 (file)
@@ -2869,7 +2869,37 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
 
                let mut watch_outputs = Vec::new();
                let mut claimable_outpoints = Vec::new();
-               for tx in &txn_matched {
+               'tx_iter: for tx in &txn_matched {
+                       let txid = tx.txid();
+                       // If a transaction has already been confirmed, ensure we don't bother processing it duplicatively.
+                       if Some(txid) == self.funding_spend_confirmed {
+                               log_debug!(logger, "Skipping redundant processing of funding-spend tx {} as it was previously confirmed", txid);
+                               continue 'tx_iter;
+                       }
+                       for ev in self.onchain_events_awaiting_threshold_conf.iter() {
+                               if ev.txid == txid {
+                                       if let Some(conf_hash) = ev.block_hash {
+                                               assert_eq!(header.block_hash(), conf_hash,
+                                                       "Transaction {} was already confirmed and is being re-confirmed in a different block.\n\
+                                                       This indicates a severe bug in the transaction connection logic - a reorg should have been processed first!", ev.txid);
+                                       }
+                                       log_debug!(logger, "Skipping redundant processing of confirming tx {} as it was previously confirmed", txid);
+                                       continue 'tx_iter;
+                               }
+                       }
+                       for htlc in self.htlcs_resolved_on_chain.iter() {
+                               if Some(txid) == htlc.resolving_txid {
+                                       log_debug!(logger, "Skipping redundant processing of HTLC resolution tx {} as it was previously confirmed", txid);
+                                       continue 'tx_iter;
+                               }
+                       }
+                       for spendable_txid in self.spendable_txids_confirmed.iter() {
+                               if txid == *spendable_txid {
+                                       log_debug!(logger, "Skipping redundant processing of spendable tx {} as it was previously confirmed", txid);
+                                       continue 'tx_iter;
+                               }
+                       }
+
                        if tx.input.len() == 1 {
                                // Assuming our keys were not leaked (in which case we're screwed no matter what),
                                // commitment transactions and HTLC transactions will all only ever have one input,
@@ -2879,7 +2909,7 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
                                if prevout.txid == self.funding_info.0.txid && prevout.vout == self.funding_info.0.index as u32 {
                                        let mut balance_spendable_csv = None;
                                        log_info!(logger, "Channel {} closed by funding output spend in txid {}.",
-                                               log_bytes!(self.funding_info.0.to_channel_id()), tx.txid());
+                                               log_bytes!(self.funding_info.0.to_channel_id()), txid);
                                        self.funding_spend_seen = true;
                                        let mut commitment_tx_to_counterparty_output = None;
                                        if (tx.input[0].sequence.0 >> 8*3) as u8 == 0x80 && (tx.lock_time.0 >> 8*3) as u8 == 0x20 {
@@ -2902,7 +2932,6 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
                                                        }
                                                }
                                        }
-                                       let txid = tx.txid();
                                        self.onchain_events_awaiting_threshold_conf.push(OnchainEventEntry {
                                                txid,
                                                transaction: Some((*tx).clone()),
@@ -3121,10 +3150,24 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
                F::Target: FeeEstimator,
                L::Target: Logger,
        {
-               self.onchain_events_awaiting_threshold_conf.retain(|ref entry| if entry.txid == *txid {
-                       log_info!(logger, "Removing onchain event with txid {}", txid);
-                       false
-               } else { true });
+               let mut removed_height = None;
+               for entry in self.onchain_events_awaiting_threshold_conf.iter() {
+                       if entry.txid == *txid {
+                               removed_height = Some(entry.height);
+                               break;
+                       }
+               }
+
+               if let Some(removed_height) = removed_height {
+                       log_info!(logger, "transaction_unconfirmed of txid {} implies height {} was reorg'd out", txid, removed_height);
+                       self.onchain_events_awaiting_threshold_conf.retain(|ref entry| if entry.height >= removed_height {
+                               log_info!(logger, "Transaction {} reorg'd out", entry.txid);
+                               false
+                       } else { true });
+               }
+
+               debug_assert!(!self.onchain_events_awaiting_threshold_conf.iter().any(|ref entry| entry.txid == *txid));
+
                self.onchain_tx_handler.transaction_unconfirmed(txid, broadcaster, fee_estimator, logger);
        }
 
@@ -4043,7 +4086,7 @@ mod tests {
                        SecretKey::from_slice(&[41; 32]).unwrap(),
                        [41; 32],
                        0,
-                       [0; 32]
+                       [0; 32],
                );
 
                let counterparty_pubkeys = ChannelPublicKeys {
@@ -4064,6 +4107,7 @@ mod tests {
                        }),
                        funding_outpoint: Some(funding_outpoint),
                        opt_anchors: None,
+                       opt_non_zero_fee_anchors: None,
                };
                // Prune with one old state and a holder commitment tx holding a few overlaps with the
                // old state.