Retrieve all possible spendable outputs from transactions
[rust-lightning] / lightning / src / chain / channelmonitor.rs
index f652bbf362fe67767a922d563d4f4d43555a2964..7088d32d1607e1f4fa0137d6ceda9182d32ca3b2 100644 (file)
@@ -1670,8 +1670,8 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitor<Signer> {
                );
        }
 
-       /// Returns the descriptor for a relevant output (i.e., one that we can spend) within the
-       /// transaction if one exists and the transaction has at least [`ANTI_REORG_DELAY`]
+       /// Returns the descriptors for relevant outputs (i.e., those that we can spend) within the
+       /// transaction if they exist and the transaction has at least [`ANTI_REORG_DELAY`]
        /// confirmations.
        ///
        /// Descriptors returned by this method are primarily exposed via [`Event::SpendableOutputs`]
@@ -1683,17 +1683,17 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitor<Signer> {
        /// transactions starting from the channel's funding or closing transaction that have at least
        /// [`ANTI_REORG_DELAY`] confirmations.
        ///
-       /// `tx` is a transaction we'll scan the outputs of. Any transaction can be provided. If an
-       /// output which can be spent by us is found, a descriptor is returned.
+       /// `tx` is a transaction we'll scan the outputs of. Any transaction can be provided. If any
+       /// outputs which can be spent by us are found, at least one descriptor is returned.
        ///
        /// `confirmation_height` must be the height of the block in which `tx` was included in.
-       pub fn get_spendable_output(&self, tx: &Transaction, confirmation_height: u32) -> Option<SpendableOutputDescriptor> {
+       pub fn get_spendable_outputs(&self, tx: &Transaction, confirmation_height: u32) -> Vec<SpendableOutputDescriptor> {
                let inner = self.inner.lock().unwrap();
                let current_height = inner.best_block.height;
                if current_height.saturating_sub(ANTI_REORG_DELAY) + 1 >= confirmation_height {
-                       inner.get_spendable_output(tx)
+                       inner.get_spendable_outputs(tx)
                } else {
-                       None
+                       Vec::new()
                }
        }
 }
@@ -3468,7 +3468,7 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
                                }
                                self.is_resolving_htlc_output(&tx, height, &block_hash, &logger);
 
-                               self.check_tx_and_push_spendable_output(&tx, height, &block_hash, &logger);
+                               self.check_tx_and_push_spendable_outputs(&tx, height, &block_hash, &logger);
                        }
                }
 
@@ -4014,31 +4014,18 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
                }
        }
 
-       fn get_spendable_output(&self, tx: &Transaction) -> Option<SpendableOutputDescriptor> {
-               for (i, outp) in tx.output.iter().enumerate() { // There is max one spendable output for any channel tx, including ones generated by us
-                       if i > ::core::u16::MAX as usize {
-                               // While it is possible that an output exists on chain which is greater than the
-                               // 2^16th output in a given transaction, this is only possible if the output is not
-                               // in a lightning transaction and was instead placed there by some third party who
-                               // wishes to give us money for no reason.
-                               // Namely, any lightning transactions which we pre-sign will never have anywhere
-                               // near 2^16 outputs both because such transactions must have ~2^16 outputs who's
-                               // scripts are not longer than one byte in length and because they are inherently
-                               // non-standard due to their size.
-                               // Thus, it is completely safe to ignore such outputs, and while it may result in
-                               // us ignoring non-lightning fund to us, that is only possible if someone fills
-                               // nearly a full block with garbage just to hit this case.
-                               continue;
-                       }
+       fn get_spendable_outputs(&self, tx: &Transaction) -> Vec<SpendableOutputDescriptor> {
+               let mut spendable_outputs = Vec::new();
+               for (i, outp) in tx.output.iter().enumerate() {
                        if outp.script_pubkey == self.destination_script {
-                               return Some(SpendableOutputDescriptor::StaticOutput {
+                               spendable_outputs.push(SpendableOutputDescriptor::StaticOutput {
                                        outpoint: OutPoint { txid: tx.txid(), index: i as u16 },
                                        output: outp.clone(),
                                });
                        }
                        if let Some(ref broadcasted_holder_revokable_script) = self.broadcasted_holder_revokable_script {
                                if broadcasted_holder_revokable_script.0 == outp.script_pubkey {
-                                       return Some(SpendableOutputDescriptor::DelayedPaymentOutput(DelayedPaymentOutputDescriptor {
+                                       spendable_outputs.push(SpendableOutputDescriptor::DelayedPaymentOutput(DelayedPaymentOutputDescriptor {
                                                outpoint: OutPoint { txid: tx.txid(), index: i as u16 },
                                                per_commitment_point: broadcasted_holder_revokable_script.1,
                                                to_self_delay: self.on_holder_tx_csv,
@@ -4050,7 +4037,7 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
                                }
                        }
                        if self.counterparty_payment_script == outp.script_pubkey {
-                               return Some(SpendableOutputDescriptor::StaticPaymentOutput(StaticPaymentOutputDescriptor {
+                               spendable_outputs.push(SpendableOutputDescriptor::StaticPaymentOutput(StaticPaymentOutputDescriptor {
                                        outpoint: OutPoint { txid: tx.txid(), index: i as u16 },
                                        output: outp.clone(),
                                        channel_keys_id: self.channel_keys_id,
@@ -4058,21 +4045,21 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
                                }));
                        }
                        if self.shutdown_script.as_ref() == Some(&outp.script_pubkey) {
-                               return Some(SpendableOutputDescriptor::StaticOutput {
+                               spendable_outputs.push(SpendableOutputDescriptor::StaticOutput {
                                        outpoint: OutPoint { txid: tx.txid(), index: i as u16 },
                                        output: outp.clone(),
                                });
                        }
                }
-               None
+               spendable_outputs
        }
 
        /// Checks if the confirmed transaction is paying funds back to some address we can assume to
        /// own.
-       fn check_tx_and_push_spendable_output<L: Deref>(
+       fn check_tx_and_push_spendable_outputs<L: Deref>(
                &mut self, tx: &Transaction, height: u32, block_hash: &BlockHash, logger: &L,
        ) where L::Target: Logger {
-               if let Some(spendable_output) = self.get_spendable_output(tx) {
+               for spendable_output in self.get_spendable_outputs(tx) {
                        let entry = OnchainEventEntry {
                                txid: tx.txid(),
                                transaction: Some(tx.clone()),