Merge pull request #2966 from G8XSU/2647-distribute
[rust-lightning] / lightning / src / chain / channelmonitor.rs
index 29f7130fbdeaca2e807e09cba9a8e86e9537f1db..0e87f3569e605d0c25736a9d203bc1fe6170655f 100644 (file)
@@ -1812,6 +1812,12 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
                );
        }
 
+       /// Returns true if the monitor has pending claim requests that are not fully confirmed yet.
+       pub fn has_pending_claims(&self) -> bool
+       {
+               self.inner.lock().unwrap().onchain_tx_handler.has_pending_claims()
+       }
+
        /// Triggers rebroadcasts of pending claims from a force-closed channel after a transaction
        /// signature generation failure.
        pub fn signer_unblocked<B: Deref, F: Deref, L: Deref>(
@@ -1924,9 +1930,9 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
        }
 
        #[cfg(test)]
-       pub fn do_signer_call<F: FnMut(&Signer) -> ()>(&self, mut f: F) {
-               let inner = self.inner.lock().unwrap();
-               f(&inner.onchain_tx_handler.signer);
+       pub fn do_mut_signer_call<F: FnMut(&mut Signer) -> ()>(&self, mut f: F) {
+               let mut inner = self.inner.lock().unwrap();
+               f(&mut inner.onchain_tx_handler.signer);
        }
 }
 
@@ -2431,8 +2437,8 @@ macro_rules! fail_unbroadcast_htlcs {
                debug_assert_eq!($commitment_tx_confirmed.txid(), $commitment_txid_confirmed);
 
                macro_rules! check_htlc_fails {
-                       ($txid: expr, $commitment_tx: expr) => {
-                               if let Some(ref latest_outpoints) = $self.counterparty_claimable_outpoints.get($txid) {
+                       ($txid: expr, $commitment_tx: expr, $per_commitment_outpoints: expr) => {
+                               if let Some(ref latest_outpoints) = $per_commitment_outpoints {
                                        for &(ref htlc, ref source_option) in latest_outpoints.iter() {
                                                if let &Some(ref source) = source_option {
                                                        // Check if the HTLC is present in the commitment transaction that was
@@ -2492,10 +2498,10 @@ macro_rules! fail_unbroadcast_htlcs {
                        }
                }
                if let Some(ref txid) = $self.current_counterparty_commitment_txid {
-                       check_htlc_fails!(txid, "current");
+                       check_htlc_fails!(txid, "current", $self.counterparty_claimable_outpoints.get(txid));
                }
                if let Some(ref txid) = $self.prev_counterparty_commitment_txid {
-                       check_htlc_fails!(txid, "previous");
+                       check_htlc_fails!(txid, "previous", $self.counterparty_claimable_outpoints.get(txid));
                }
        } }
 }
@@ -2764,15 +2770,15 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
                // If the channel is force closed, try to claim the output from this preimage.
                // First check if a counterparty commitment transaction has been broadcasted:
                macro_rules! claim_htlcs {
-                       ($commitment_number: expr, $txid: expr) => {
-                               let (htlc_claim_reqs, _) = self.get_counterparty_output_claim_info($commitment_number, $txid, None);
+                       ($commitment_number: expr, $txid: expr, $htlcs: expr) => {
+                               let (htlc_claim_reqs, _) = self.get_counterparty_output_claim_info($commitment_number, $txid, None, $htlcs);
                                self.onchain_tx_handler.update_claims_view_from_requests(htlc_claim_reqs, self.best_block.height, self.best_block.height, broadcaster, fee_estimator, logger);
                        }
                }
                if let Some(txid) = self.current_counterparty_commitment_txid {
                        if txid == confirmed_spend_txid {
                                if let Some(commitment_number) = self.counterparty_commitment_txn_on_chain.get(&txid) {
-                                       claim_htlcs!(*commitment_number, txid);
+                                       claim_htlcs!(*commitment_number, txid, self.counterparty_claimable_outpoints.get(&txid));
                                } else {
                                        debug_assert!(false);
                                        log_error!(logger, "Detected counterparty commitment tx on-chain without tracking commitment number");
@@ -2783,7 +2789,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
                if let Some(txid) = self.prev_counterparty_commitment_txid {
                        if txid == confirmed_spend_txid {
                                if let Some(commitment_number) = self.counterparty_commitment_txn_on_chain.get(&txid) {
-                                       claim_htlcs!(*commitment_number, txid);
+                                       claim_htlcs!(*commitment_number, txid, self.counterparty_claimable_outpoints.get(&txid));
                                } else {
                                        debug_assert!(false);
                                        log_error!(logger, "Detected counterparty commitment tx on-chain without tracking commitment number");
@@ -2873,7 +2879,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
                F::Target: FeeEstimator,
                L::Target: Logger,
        {
-               let (claimable_outpoints, _) = self.generate_claimable_outpoints_and_watch_outputs(ClosureReason::HolderForceClosed);
+               let (claimable_outpoints, _) = self.generate_claimable_outpoints_and_watch_outputs(ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(true) });
                self.onchain_tx_handler.update_claims_view_from_requests(
                        claimable_outpoints, self.best_block.height, self.best_block.height, broadcaster,
                        fee_estimator, logger
@@ -3105,9 +3111,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
                                                        },
                                                        commitment_txid: htlc.commitment_txid,
                                                        per_commitment_number: htlc.per_commitment_number,
-                                                       per_commitment_point: self.onchain_tx_handler.signer.get_per_commitment_point(
-                                                               htlc.per_commitment_number, &self.onchain_tx_handler.secp_ctx,
-                                                       ),
+                                                       per_commitment_point: htlc.per_commitment_point,
                                                        feerate_per_kw: 0,
                                                        htlc: htlc.htlc,
                                                        preimage: htlc.preimage,
@@ -3233,16 +3237,14 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
        /// height > height + CLTV_SHARED_CLAIM_BUFFER. In any case, will install monitoring for
        /// HTLC-Success/HTLC-Timeout transactions.
        ///
-       /// Returns packages to claim the revoked output(s), as well as additional outputs to watch and
-       /// general information about the output that is to the counterparty in the commitment
-       /// transaction.
+       /// Returns packages to claim the revoked output(s) and general information about the output that
+       /// is to the counterparty in the commitment transaction.
        fn check_spend_counterparty_transaction<L: Deref>(&mut self, tx: &Transaction, height: u32, block_hash: &BlockHash, logger: &L)
-               -> (Vec<PackageTemplate>, TransactionOutputs, CommitmentTxCounterpartyOutputInfo)
+               -> (Vec<PackageTemplate>, CommitmentTxCounterpartyOutputInfo)
        where L::Target: Logger {
                // Most secp and related errors trying to create keys means we have no hope of constructing
                // a spend transaction...so we return no transactions to broadcast
                let mut claimable_outpoints = Vec::new();
-               let mut watch_outputs = Vec::new();
                let mut to_counterparty_output_info = None;
 
                let commitment_txid = tx.txid(); //TODO: This is gonna be a performance bottleneck for watchtowers!
@@ -3252,7 +3254,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
                        ( $thing : expr ) => {
                                match $thing {
                                        Ok(a) => a,
-                                       Err(_) => return (claimable_outpoints, (commitment_txid, watch_outputs), to_counterparty_output_info)
+                                       Err(_) => return (claimable_outpoints, to_counterparty_output_info)
                                }
                        };
                }
@@ -3280,14 +3282,13 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
                        }
 
                        // Then, try to find revoked htlc outputs
-                       if let Some(ref per_commitment_data) = per_commitment_option {
-                               for (_, &(ref htlc, _)) in per_commitment_data.iter().enumerate() {
+                       if let Some(per_commitment_claimable_data) = per_commitment_option {
+                               for (htlc, _) in per_commitment_claimable_data {
                                        if let Some(transaction_output_index) = htlc.transaction_output_index {
                                                if transaction_output_index as usize >= tx.output.len() ||
                                                                tx.output[transaction_output_index as usize].value != htlc.to_bitcoin_amount() {
                                                        // per_commitment_data is corrupt or our commitment signing key leaked!
-                                                       return (claimable_outpoints, (commitment_txid, watch_outputs),
-                                                               to_counterparty_output_info);
+                                                       return (claimable_outpoints, to_counterparty_output_info);
                                                }
                                                let revk_htlc_outp = RevokedHTLCOutput::build(per_commitment_point, self.counterparty_commitment_params.counterparty_delayed_payment_base_key, self.counterparty_commitment_params.counterparty_htlc_base_key, per_commitment_key, htlc.amount_msat / 1000, htlc.clone(), &self.onchain_tx_handler.channel_transaction_parameters.channel_type_features);
                                                let justice_package = PackageTemplate::build_package(commitment_txid, transaction_output_index, PackageSolvingData::RevokedHTLCOutput(revk_htlc_outp), htlc.cltv_expiry, height);
@@ -3300,14 +3301,11 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
                        if !claimable_outpoints.is_empty() || per_commitment_option.is_some() { // ie we're confident this is actually ours
                                // We're definitely a counterparty commitment transaction!
                                log_error!(logger, "Got broadcast of revoked counterparty commitment transaction, going to generate general spend tx with {} inputs", claimable_outpoints.len());
-                               for (idx, outp) in tx.output.iter().enumerate() {
-                                       watch_outputs.push((idx as u32, outp.clone()));
-                               }
                                self.counterparty_commitment_txn_on_chain.insert(commitment_txid, commitment_number);
 
-                               if let Some(per_commitment_data) = per_commitment_option {
+                               if let Some(per_commitment_claimable_data) = per_commitment_option {
                                        fail_unbroadcast_htlcs!(self, "revoked_counterparty", commitment_txid, tx, height,
-                                               block_hash, per_commitment_data.iter().map(|(htlc, htlc_source)|
+                                               block_hash, per_commitment_claimable_data.iter().map(|(htlc, htlc_source)|
                                                        (htlc, htlc_source.as_ref().map(|htlc_source| htlc_source.as_ref()))
                                                ), logger);
                                } else {
@@ -3320,7 +3318,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
                                                block_hash, [].iter().map(|reference| *reference), logger);
                                }
                        }
-               } else if let Some(per_commitment_data) = per_commitment_option {
+               } else if let Some(per_commitment_claimable_data) = per_commitment_option {
                        // While this isn't useful yet, there is a potential race where if a counterparty
                        // revokes a state at the same time as the commitment transaction for that state is
                        // confirmed, and the watchtower receives the block before the user, the user could
@@ -3328,35 +3326,31 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
                        // already processed the block, resulting in the counterparty_commitment_txn_on_chain entry
                        // not being generated by the above conditional. Thus, to be safe, we go ahead and
                        // insert it here.
-                       for (idx, outp) in tx.output.iter().enumerate() {
-                               watch_outputs.push((idx as u32, outp.clone()));
-                       }
                        self.counterparty_commitment_txn_on_chain.insert(commitment_txid, commitment_number);
 
                        log_info!(logger, "Got broadcast of non-revoked counterparty commitment transaction {}", commitment_txid);
                        fail_unbroadcast_htlcs!(self, "counterparty", commitment_txid, tx, height, block_hash,
-                               per_commitment_data.iter().map(|(htlc, htlc_source)|
+                               per_commitment_claimable_data.iter().map(|(htlc, htlc_source)|
                                        (htlc, htlc_source.as_ref().map(|htlc_source| htlc_source.as_ref()))
                                ), logger);
-
                        let (htlc_claim_reqs, counterparty_output_info) =
-                               self.get_counterparty_output_claim_info(commitment_number, commitment_txid, Some(tx));
+                               self.get_counterparty_output_claim_info(commitment_number, commitment_txid, Some(tx), per_commitment_option);
                        to_counterparty_output_info = counterparty_output_info;
                        for req in htlc_claim_reqs {
                                claimable_outpoints.push(req);
                        }
 
                }
-               (claimable_outpoints, (commitment_txid, watch_outputs), to_counterparty_output_info)
+               (claimable_outpoints, to_counterparty_output_info)
        }
 
        /// Returns the HTLC claim package templates and the counterparty output info
-       fn get_counterparty_output_claim_info(&self, commitment_number: u64, commitment_txid: Txid, tx: Option<&Transaction>)
+       fn get_counterparty_output_claim_info(&self, commitment_number: u64, commitment_txid: Txid, tx: Option<&Transaction>, per_commitment_option: Option<&Vec<(HTLCOutputInCommitment, Option<Box<HTLCSource>>)>>)
        -> (Vec<PackageTemplate>, CommitmentTxCounterpartyOutputInfo) {
                let mut claimable_outpoints = Vec::new();
                let mut to_counterparty_output_info: CommitmentTxCounterpartyOutputInfo = None;
 
-               let htlc_outputs = match self.counterparty_claimable_outpoints.get(&commitment_txid) {
+               let per_commitment_claimable_data = match per_commitment_option {
                        Some(outputs) => outputs,
                        None => return (claimable_outpoints, to_counterparty_output_info),
                };
@@ -3395,7 +3389,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
                        }
                }
 
-               for (_, &(ref htlc, _)) in htlc_outputs.iter().enumerate() {
+               for  &(ref htlc, _) in per_commitment_claimable_data.iter() {
                        if let Some(transaction_output_index) = htlc.transaction_output_index {
                                if let Some(transaction) = tx {
                                        if transaction_output_index as usize >= transaction.output.len() ||
@@ -3585,6 +3579,8 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
                        if counterparty_commitment_txid == confirmed_commitment_txid {
                                continue;
                        }
+                       // If we have generated claims for counterparty_commitment_txid earlier, we can rely on always
+                       // having claim related htlcs for counterparty_commitment_txid in counterparty_claimable_outpoints.
                        for (htlc, _) in self.counterparty_claimable_outpoints.get(counterparty_commitment_txid).unwrap_or(&vec![]) {
                                log_trace!(logger, "Canceling claims for previously confirmed counterparty commitment {}",
                                        counterparty_commitment_txid);
@@ -3777,24 +3773,25 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
                                        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.to_consensus_u32() >> 8*3) as u8 == 0x20 {
-                                               let (mut new_outpoints, new_outputs, counterparty_output_idx_sats) =
-                                                       self.check_spend_counterparty_transaction(&tx, height, &block_hash, &logger);
-                                               commitment_tx_to_counterparty_output = counterparty_output_idx_sats;
-                                               if !new_outputs.1.is_empty() {
-                                                       watch_outputs.push(new_outputs);
-                                               }
-                                               claimable_outpoints.append(&mut new_outpoints);
-                                               if new_outpoints.is_empty() {
-                                                       if let Some((mut new_outpoints, new_outputs)) = self.check_spend_holder_transaction(&tx, height, &block_hash, &logger) {
-                                                               #[cfg(not(fuzzing))]
-                                                               debug_assert!(commitment_tx_to_counterparty_output.is_none(),
-                                                                       "A commitment transaction matched as both a counterparty and local commitment tx?");
-                                                               if !new_outputs.1.is_empty() {
-                                                                       watch_outputs.push(new_outputs);
-                                                               }
-                                                               claimable_outpoints.append(&mut new_outpoints);
-                                                               balance_spendable_csv = Some(self.on_holder_tx_csv);
+                                               if let Some((mut new_outpoints, new_outputs)) = self.check_spend_holder_transaction(&tx, height, &block_hash, &logger) {
+                                                       if !new_outputs.1.is_empty() {
+                                                               watch_outputs.push(new_outputs);
+                                                       }
+
+                                                       claimable_outpoints.append(&mut new_outpoints);
+                                                       balance_spendable_csv = Some(self.on_holder_tx_csv);
+                                               } else {
+                                                       let mut new_watch_outputs = Vec::new();
+                                                       for (idx, outp) in tx.output.iter().enumerate() {
+                                                               new_watch_outputs.push((idx as u32, outp.clone()));
                                                        }
+                                                       watch_outputs.push((txid, new_watch_outputs));
+
+                                                       let (mut new_outpoints, counterparty_output_idx_sats) =
+                                                               self.check_spend_counterparty_transaction(&tx, height, &block_hash, &logger);
+                                                       commitment_tx_to_counterparty_output = counterparty_output_idx_sats;
+
+                                                       claimable_outpoints.append(&mut new_outpoints);
                                                }
                                        }
                                        self.onchain_events_awaiting_threshold_conf.push(OnchainEventEntry {
@@ -4220,9 +4217,8 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
                        }
 
                        macro_rules! check_htlc_valid_counterparty {
-                               ($counterparty_txid: expr, $htlc_output: expr) => {
-                                       if let Some(txid) = $counterparty_txid {
-                                               for &(ref pending_htlc, ref pending_source) in self.counterparty_claimable_outpoints.get(&txid).unwrap() {
+                               ($htlc_output: expr, $per_commitment_data: expr) => {
+                                               for &(ref pending_htlc, ref pending_source) in $per_commitment_data {
                                                        if pending_htlc.payment_hash == $htlc_output.payment_hash && pending_htlc.amount_msat == $htlc_output.amount_msat {
                                                                if let &Some(ref source) = pending_source {
                                                                        log_claim!("revoked counterparty commitment tx", false, pending_htlc, true);
@@ -4231,7 +4227,6 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
                                                                }
                                                        }
                                                }
-                                       }
                                }
                        }
 
@@ -4248,9 +4243,13 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
                                                                // resolve the source HTLC with the original sender.
                                                                payment_data = Some(((*source).clone(), htlc_output.payment_hash, htlc_output.amount_msat));
                                                        } else if !$holder_tx {
-                                                               check_htlc_valid_counterparty!(self.current_counterparty_commitment_txid, htlc_output);
+                                                               if let Some(current_counterparty_commitment_txid) = &self.current_counterparty_commitment_txid {
+                                                                       check_htlc_valid_counterparty!(htlc_output, self.counterparty_claimable_outpoints.get(current_counterparty_commitment_txid).unwrap());
+                                                               }
                                                                if payment_data.is_none() {
-                                                                       check_htlc_valid_counterparty!(self.prev_counterparty_commitment_txid, htlc_output);
+                                                                       if let Some(prev_counterparty_commitment_txid) = &self.prev_counterparty_commitment_txid {
+                                                                               check_htlc_valid_counterparty!(htlc_output, self.counterparty_claimable_outpoints.get(prev_counterparty_commitment_txid).unwrap());
+                                                                       }
                                                                }
                                                        }
                                                        if payment_data.is_none() {
@@ -4288,7 +4287,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
                                }
                        }
                        if let Some(ref htlc_outputs) = self.counterparty_claimable_outpoints.get(&input.previous_output.txid) {
-                               scan_commitment!(htlc_outputs.iter().map(|&(ref a, ref b)| (a, (b.as_ref().clone()).map(|boxed| &**boxed))),
+                               scan_commitment!(htlc_outputs.iter().map(|&(ref a, ref b)| (a, b.as_ref().map(|boxed| &**boxed))),
                                        "counterparty commitment tx", false);
                        }