Add ChannelMonitor::transaction_unconfirmed
authorJeffrey Czyz <jkczyz@gmail.com>
Sat, 27 Mar 2021 20:26:45 +0000 (16:26 -0400)
committerJeffrey Czyz <jkczyz@gmail.com>
Wed, 14 Apr 2021 19:57:05 +0000 (12:57 -0700)
Define an Electrum-friendly interface for ChannelMonitor where
transactions are unconfirmed independently from updating the latest
block.

lightning/src/chain/channelmonitor.rs
lightning/src/ln/onchaintx.rs

index 6481e5a116bf1603d506cd2d1d150fbdbdb68f01..650191dacdd8b58fee82715842b2825b23ca8aa1 100644 (file)
@@ -1331,6 +1331,29 @@ impl<Signer: Sign> ChannelMonitor<Signer> {
                        header, txdata, height, broadcaster, fee_estimator, logger)
        }
 
+       /// Processes a transaction that was reorganized out of the chain.
+       ///
+       /// Used instead of [`block_disconnected`] by clients that are notified of transactions rather
+       /// than blocks. May be called before or after [`update_best_block`] for transactions in the
+       /// corresponding block. See [`update_best_block`] for further calling expectations.
+       ///
+       /// [`block_disconnected`]: Self::block_disconnected
+       /// [`update_best_block`]: Self::update_best_block
+       pub fn transaction_unconfirmed<B: Deref, F: Deref, L: Deref>(
+               &self,
+               txid: &Txid,
+               broadcaster: B,
+               fee_estimator: F,
+               logger: L,
+       ) where
+               B::Target: BroadcasterInterface,
+               F::Target: FeeEstimator,
+               L::Target: Logger,
+       {
+               self.inner.lock().unwrap().transaction_unconfirmed(
+                       txid, broadcaster, fee_estimator, logger);
+       }
+
        /// Updates the monitor with the current best chain tip, returning new outputs to watch. See
        /// [`block_connected`] for details.
        ///
@@ -1339,10 +1362,13 @@ impl<Signer: Sign> ChannelMonitor<Signer> {
        /// block.
        ///
        /// Must be called after new blocks become available for the most recent block. Intermediary
-       /// blocks, however, may be safely skipped.
+       /// blocks, however, may be safely skipped. In the event of a chain re-organization, this only
+       /// needs to be called for the most recent block assuming `transaction_unconfirmed` is called
+       /// for any affected transactions.
        ///
        /// [`block_connected`]: Self::block_connected
        /// [`transactions_confirmed`]: Self::transactions_confirmed
+       /// [`transaction_unconfirmed`]: Self::transaction_unconfirmed
        pub fn update_best_block<B: Deref, F: Deref, L: Deref>(
                &self,
                header: &BlockHeader,
@@ -2229,13 +2255,13 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
                                                debug_assert!(
                                                        unmatured_htlcs.iter().find(|&htlc| htlc == &htlc_update.0).is_none(),
                                                        "An unmature HTLC transaction conflicts with a maturing one; failed to \
-                                                        call block_disconnected for a block containing the conflicting \
-                                                        transaction.");
+                                                        call either transaction_unconfirmed for the conflicting transaction \
+                                                        or block_disconnected for a block containing it.");
                                                debug_assert!(
                                                        matured_htlcs.iter().find(|&htlc| htlc == &htlc_update.0).is_none(),
                                                        "A matured HTLC transaction conflicts with a maturing one; failed to \
-                                                        call block_disconnected for a block containing the conflicting \
-                                                        transaction.");
+                                                        call either transaction_unconfirmed for the conflicting transaction \
+                                                        or block_disconnected for a block containing it.");
                                                matured_htlcs.push(htlc_update.0.clone());
                                        }
 
@@ -2297,6 +2323,21 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
                self.best_block = BestBlock::new(header.prev_blockhash, height - 1);
        }
 
+       fn transaction_unconfirmed<B: Deref, F: Deref, L: Deref>(
+               &mut self,
+               txid: &Txid,
+               broadcaster: B,
+               fee_estimator: F,
+               logger: L,
+       ) where
+               B::Target: BroadcasterInterface,
+               F::Target: FeeEstimator,
+               L::Target: Logger,
+       {
+               self.onchain_events_waiting_threshold_conf.retain(|ref entry| entry.txid != *txid);
+               self.onchain_tx_handler.transaction_unconfirmed(txid, broadcaster, fee_estimator, logger);
+       }
+
        /// Filters a block's `txdata` for transactions spending watched outputs or for any child
        /// transactions thereof.
        fn filter_block<'a>(&self, txdata: &TransactionData<'a>) -> Vec<&'a Transaction> {
index 67a82a480848aeec8d86325be36c6841c261cc8d..e0aa6eddd9e5ea7ccc60dc6b4f358838128ae58a 100644 (file)
@@ -869,6 +869,30 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
                }
        }
 
+       pub(crate) fn transaction_unconfirmed<B: Deref, F: Deref, L: Deref>(
+               &mut self,
+               txid: &Txid,
+               broadcaster: B,
+               fee_estimator: F,
+               logger: L,
+       ) where
+               B::Target: BroadcasterInterface,
+               F::Target: FeeEstimator,
+               L::Target: Logger,
+       {
+               let mut height = None;
+               for entry in self.onchain_events_waiting_threshold_conf.iter() {
+                       if entry.txid == *txid {
+                               height = Some(entry.height);
+                               break;
+                       }
+               }
+
+               if let Some(height) = height {
+                       self.block_disconnected(height, broadcaster, fee_estimator, logger);
+               }
+       }
+
        pub(crate) fn block_disconnected<B: Deref, F: Deref, L: Deref>(&mut self, height: u32, broadcaster: B, fee_estimator: F, logger: L)
                where B::Target: BroadcasterInterface,
                      F::Target: FeeEstimator,