Implement reorg-safety for SpendableOutputDescriptor detection
[rust-lightning] / lightning / src / ln / channelmonitor.rs
index 28ca6714acafaf51c16af07722af0b977fb8300e..9b25da5b4c9fd23ce938f551f798021a17efd592 100644 (file)
@@ -594,6 +594,9 @@ enum OnchainEvent {
        HTLCUpdate {
                htlc_update: (HTLCSource, PaymentHash),
        },
+       MaturingOutput {
+               descriptor: SpendableOutputDescriptor,
+       },
 }
 
 const SERIALIZATION_VERSION: u8 = 1;
@@ -1065,6 +1068,10 @@ impl<ChanSigner: ChannelKeys + Writeable> ChannelMonitor<ChanSigner> {
                                                htlc_update.0.write(writer)?;
                                                htlc_update.1.write(writer)?;
                                        },
+                                       OnchainEvent::MaturingOutput { ref descriptor } => {
+                                               1u8.write(writer)?;
+                                               descriptor.write(writer)?;
+                                       },
                                }
                        }
                }
@@ -1561,6 +1568,7 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
                                                                                                        OnchainEvent::HTLCUpdate { ref htlc_update } => {
                                                                                                                return htlc_update.0 != **source
                                                                                                        },
+                                                                                                       _ => true
                                                                                                }
                                                                                        });
                                                                                        e.push(OnchainEvent::HTLCUpdate { htlc_update: ((**source).clone(), htlc.payment_hash.clone())});
@@ -1625,6 +1633,7 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
                                                                                                OnchainEvent::HTLCUpdate { ref htlc_update } => {
                                                                                                        return htlc_update.0 != **source
                                                                                                },
+                                                                                               _ => true
                                                                                        }
                                                                                });
                                                                                e.push(OnchainEvent::HTLCUpdate { htlc_update: ((**source).clone(), htlc.payment_hash.clone())});
@@ -1808,6 +1817,7 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
                                                                OnchainEvent::HTLCUpdate { ref htlc_update } => {
                                                                        return htlc_update.0 != $source
                                                                },
+                                                               _ => true
                                                        }
                                                });
                                                e.push(OnchainEvent::HTLCUpdate { htlc_update: ($source, $payment_hash)});
@@ -1961,7 +1971,6 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
 
                log_trace!(self, "Block {} at height {} connected with {} txn matched", block_hash, height, txn_matched.len());
                let mut watch_outputs = Vec::new();
-               let mut spendable_outputs = Vec::new();
                let mut claimable_outpoints = Vec::new();
                for tx in txn_matched {
                        if tx.input.len() == 1 {
@@ -2011,9 +2020,7 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
                        // we call is_resolving_htlc_output here outside of the tx.input.len() == 1 check.
                        self.is_resolving_htlc_output(&tx, height);
 
-                       if let Some(spendable_output) = self.is_paying_spendable_output(&tx) {
-                               spendable_outputs.push(spendable_output);
-                       }
+                       self.is_paying_spendable_output(&tx, height);
                }
                let should_broadcast = if let Some(_) = self.current_local_signed_commitment_tx {
                        self.would_broadcast_at_height(height)
@@ -2058,6 +2065,12 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
                                                        source: htlc_update.0,
                                                });
                                        },
+                                       OnchainEvent::MaturingOutput { descriptor } => {
+                                               log_trace!(self, "Descriptor {} has got enough confirmations to be passed upstream", log_spendable!(descriptor));
+                                               self.pending_events.push(events::Event::SpendableOutputs {
+                                                       outputs: vec![descriptor]
+                                               });
+                                       }
                                }
                        }
                }
@@ -2068,16 +2081,6 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
                        self.outputs_to_watch.insert(txid.clone(), output_scripts.iter().map(|o| o.script_pubkey.clone()).collect());
                }
 
-               for spend in spendable_outputs.iter() {
-                       log_trace!(self, "Announcing spendable output to user: {}", log_spendable!(spend));
-               }
-
-               if spendable_outputs.len() > 0 {
-                       self.pending_events.push(events::Event::SpendableOutputs {
-                               outputs: spendable_outputs,
-                       });
-               }
-
                watch_outputs
        }
 
@@ -2089,6 +2092,7 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
                if let Some(_) = self.onchain_events_waiting_threshold_conf.remove(&(height + ANTI_REORG_DELAY - 1)) {
                        //We may discard:
                        //- htlc update there as failure-trigger tx (revoked commitment tx, non-revoked commitment tx, HTLC-timeout tx) has been disconnected
+                       //- maturing spendable output has transaction paying us has been disconnected
                }
 
                self.onchain_tx_handler.block_disconnected(height, broadcaster, fee_estimator);
@@ -2291,6 +2295,7 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
                                                                        OnchainEvent::HTLCUpdate { ref htlc_update } => {
                                                                                return htlc_update.0 != source
                                                                        },
+                                                                       _ => true
                                                                }
                                                        });
                                                        e.push(OnchainEvent::HTLCUpdate { htlc_update: (source, payment_hash)});
@@ -2305,39 +2310,54 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
        }
 
        /// Check if any transaction broadcasted is paying fund back to some address we can assume to own
-       fn is_paying_spendable_output(&self, tx: &Transaction) -> Option<SpendableOutputDescriptor> {
+       fn is_paying_spendable_output(&mut self, tx: &Transaction, height: u32) {
+               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 outp.script_pubkey == self.destination_script {
-                               return Some(SpendableOutputDescriptor::StaticOutput {
+                               spendable_output =  Some(SpendableOutputDescriptor::StaticOutput {
                                        outpoint: BitcoinOutPoint { txid: tx.txid(), vout: i as u32 },
                                        output: outp.clone(),
                                });
+                               break;
                        } else if let Some(ref broadcasted_local_revokable_script) = self.broadcasted_local_revokable_script {
                                if broadcasted_local_revokable_script.0 == outp.script_pubkey {
-                                       return Some(SpendableOutputDescriptor::DynamicOutputP2WSH {
+                                       spendable_output =  Some(SpendableOutputDescriptor::DynamicOutputP2WSH {
                                                outpoint: BitcoinOutPoint { txid: tx.txid(), vout: i as u32 },
                                                key: broadcasted_local_revokable_script.1,
                                                witness_script: broadcasted_local_revokable_script.2.clone(),
                                                to_self_delay: self.their_to_self_delay.unwrap(),
                                                output: outp.clone(),
                                        });
+                                       break;
                                }
                        } else if let Some(ref broadcasted_remote_payment_script) = self.broadcasted_remote_payment_script {
                                if broadcasted_remote_payment_script.0 == outp.script_pubkey {
-                                       return Some(SpendableOutputDescriptor::DynamicOutputP2WPKH {
+                                       spendable_output = Some(SpendableOutputDescriptor::DynamicOutputP2WPKH {
                                                outpoint: BitcoinOutPoint { txid: tx.txid(), vout: i as u32 },
                                                key: broadcasted_remote_payment_script.1,
                                                output: outp.clone(),
                                        });
+                                       break;
                                }
                        } else if outp.script_pubkey == self.shutdown_script {
-                               return Some(SpendableOutputDescriptor::StaticOutput {
-                                               outpoint: BitcoinOutPoint { txid: tx.txid(), vout: i as u32 },
-                                               output: outp.clone(),
+                               spendable_output = Some(SpendableOutputDescriptor::StaticOutput {
+                                       outpoint: BitcoinOutPoint { txid: tx.txid(), vout: i as u32 },
+                                       output: outp.clone(),
                                });
                        }
                }
-               None
+               if let Some(spendable_output) = spendable_output {
+                       log_trace!(self, "Maturing {} until {}", log_spendable!(spendable_output), height + ANTI_REORG_DELAY - 1);
+                       match self.onchain_events_waiting_threshold_conf.entry(height + ANTI_REORG_DELAY - 1) {
+                               hash_map::Entry::Occupied(mut entry) => {
+                                       let e = entry.get_mut();
+                                       e.push(OnchainEvent::MaturingOutput { descriptor: spendable_output });
+                               }
+                               hash_map::Entry::Vacant(entry) => {
+                                       entry.insert(vec![OnchainEvent::MaturingOutput { descriptor: spendable_output }]);
+                               }
+                       }
+               }
        }
 }
 
@@ -2588,6 +2608,12 @@ impl<ChanSigner: ChannelKeys + Readable> ReadableArgs<Arc<Logger>> for (Sha256dH
                                                        htlc_update: (htlc_source, hash)
                                                }
                                        },
+                                       1 => {
+                                               let descriptor = Readable::read(reader)?;
+                                               OnchainEvent::MaturingOutput {
+                                                       descriptor
+                                               }
+                                       },
                                        _ => return Err(DecodeError::InvalidValue),
                                };
                                events.push(ev);