Allow retrieval of SpendableOutputDescriptors from relevant transactions
[rust-lightning] / lightning / src / chain / channelmonitor.rs
index 3f9c83bb54393290c40b9a6784bcce7dd48c53da..f652bbf362fe67767a922d563d4f4d43555a2964 100644 (file)
@@ -1669,6 +1669,33 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitor<Signer> {
                        current_height, &broadcaster, &fee_estimator, &logger,
                );
        }
+
+       /// 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`]
+       /// confirmations.
+       ///
+       /// Descriptors returned by this method are primarily exposed via [`Event::SpendableOutputs`]
+       /// once they are no longer under reorg risk. This method serves as a way to retrieve these
+       /// descriptors at a later time, either for historical purposes, or to replay any
+       /// missed/unhandled descriptors. For the purpose of gathering historical records, if the
+       /// channel close has fully resolved (i.e., [`ChannelMonitor::get_claimable_balances`] returns
+       /// an empty set), you can retrieve all spendable outputs by providing all descendant spending
+       /// 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.
+       ///
+       /// `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> {
+               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)
+               } else {
+                       None
+               }
+       }
 }
 
 impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
@@ -3441,7 +3468,7 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
                                }
                                self.is_resolving_htlc_output(&tx, height, &block_hash, &logger);
 
-                               self.is_paying_spendable_output(&tx, height, &block_hash, &logger);
+                               self.check_tx_and_push_spendable_output(&tx, height, &block_hash, &logger);
                        }
                }
 
@@ -3987,9 +4014,7 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
                }
        }
 
-       /// Check if any transaction broadcasted is paying fund back to some address we can assume to own
-       fn is_paying_spendable_output<L: Deref>(&mut self, tx: &Transaction, height: u32, block_hash: &BlockHash, logger: &L) where L::Target: Logger {
-               let mut spendable_output = None;
+       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
@@ -4006,15 +4031,14 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
                                continue;
                        }
                        if outp.script_pubkey == self.destination_script {
-                               spendable_output =  Some(SpendableOutputDescriptor::StaticOutput {
+                               return Some(SpendableOutputDescriptor::StaticOutput {
                                        outpoint: OutPoint { txid: tx.txid(), index: i as u16 },
                                        output: outp.clone(),
                                });
-                               break;
                        }
                        if let Some(ref broadcasted_holder_revokable_script) = self.broadcasted_holder_revokable_script {
                                if broadcasted_holder_revokable_script.0 == outp.script_pubkey {
-                                       spendable_output =  Some(SpendableOutputDescriptor::DelayedPaymentOutput(DelayedPaymentOutputDescriptor {
+                                       return Some(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,
@@ -4023,27 +4047,32 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
                                                channel_keys_id: self.channel_keys_id,
                                                channel_value_satoshis: self.channel_value_satoshis,
                                        }));
-                                       break;
                                }
                        }
                        if self.counterparty_payment_script == outp.script_pubkey {
-                               spendable_output = Some(SpendableOutputDescriptor::StaticPaymentOutput(StaticPaymentOutputDescriptor {
+                               return Some(SpendableOutputDescriptor::StaticPaymentOutput(StaticPaymentOutputDescriptor {
                                        outpoint: OutPoint { txid: tx.txid(), index: i as u16 },
                                        output: outp.clone(),
                                        channel_keys_id: self.channel_keys_id,
                                        channel_value_satoshis: self.channel_value_satoshis,
                                }));
-                               break;
                        }
                        if self.shutdown_script.as_ref() == Some(&outp.script_pubkey) {
-                               spendable_output = Some(SpendableOutputDescriptor::StaticOutput {
+                               return Some(SpendableOutputDescriptor::StaticOutput {
                                        outpoint: OutPoint { txid: tx.txid(), index: i as u16 },
                                        output: outp.clone(),
                                });
-                               break;
                        }
                }
-               if let Some(spendable_output) = spendable_output {
+               None
+       }
+
+       /// 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>(
+               &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) {
                        let entry = OnchainEventEntry {
                                txid: tx.txid(),
                                transaction: Some(tx.clone()),