X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fchain%2Fchannelmonitor.rs;h=7088d32d1607e1f4fa0137d6ceda9182d32ca3b2;hb=a8fa5a1685d84d3b07732e4ecc04e2dc7ba06a00;hp=3f9c83bb54393290c40b9a6784bcce7dd48c53da;hpb=4f4e84ef4d39a0fc81b3fd3c6c54611616860844;p=rust-lightning diff --git a/lightning/src/chain/channelmonitor.rs b/lightning/src/chain/channelmonitor.rs index 3f9c83bb..7088d32d 100644 --- a/lightning/src/chain/channelmonitor.rs +++ b/lightning/src/chain/channelmonitor.rs @@ -1669,6 +1669,33 @@ impl ChannelMonitor { current_height, &broadcaster, &fee_estimator, &logger, ); } + + /// 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`] + /// 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 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_outputs(&self, tx: &Transaction, confirmation_height: u32) -> Vec { + 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_outputs(tx) + } else { + Vec::new() + } + } } impl ChannelMonitorImpl { @@ -3441,7 +3468,7 @@ impl ChannelMonitorImpl { } 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_outputs(&tx, height, &block_hash, &logger); } } @@ -3987,34 +4014,18 @@ impl ChannelMonitorImpl { } } - /// Check if any transaction broadcasted is paying fund back to some address we can assume to own - fn is_paying_spendable_output(&mut self, tx: &Transaction, height: u32, block_hash: &BlockHash, logger: &L) where L::Target: Logger { - let mut spendable_output = None; - 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 { + let mut spendable_outputs = Vec::new(); + for (i, outp) in tx.output.iter().enumerate() { if outp.script_pubkey == self.destination_script { - spendable_output = Some(SpendableOutputDescriptor::StaticOutput { + spendable_outputs.push(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 { + 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, @@ -4023,27 +4034,32 @@ impl ChannelMonitorImpl { 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 { + 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, channel_value_satoshis: self.channel_value_satoshis, })); - break; } if self.shutdown_script.as_ref() == Some(&outp.script_pubkey) { - spendable_output = Some(SpendableOutputDescriptor::StaticOutput { + spendable_outputs.push(SpendableOutputDescriptor::StaticOutput { outpoint: OutPoint { txid: tx.txid(), index: i as u16 }, output: outp.clone(), }); - break; } } - if let Some(spendable_output) = spendable_output { + 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_outputs( + &mut self, tx: &Transaction, height: u32, block_hash: &BlockHash, logger: &L, + ) where L::Target: Logger { + for spendable_output in self.get_spendable_outputs(tx) { let entry = OnchainEventEntry { txid: tx.txid(), transaction: Some(tx.clone()),