Add ChannelMonitor::update_best_block
authorJeffrey Czyz <jkczyz@gmail.com>
Fri, 2 Apr 2021 02:44:46 +0000 (19:44 -0700)
committerJeffrey Czyz <jkczyz@gmail.com>
Wed, 14 Apr 2021 19:57:05 +0000 (12:57 -0700)
Expose a way for Electrum users to update the best block on a
ChannelMonitor independently of confirming transactions.

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

index 1a0b3dcdfcaeee1ea2b48b863496e08ff5182dab..6481e5a116bf1603d506cd2d1d150fbdbdb68f01 100644 (file)
@@ -1304,12 +1304,15 @@ impl<Signer: Sign> ChannelMonitor<Signer> {
                        header, height, broadcaster, fee_estimator, logger)
        }
 
-       /// Processes transactions from a block with the given header and height, returning new outputs
-       /// to watch. See [`block_connected`] for details.
+       /// Processes transactions confirmed in a block with the given header and height, returning new
+       /// outputs to watch. See [`block_connected`] for details.
        ///
-       /// TODO: Expand docs.
+       /// Used instead of [`block_connected`] 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_connected`]: Self::block_connected
+       /// [`update_best_block`]: Self::update_best_block
        pub fn transactions_confirmed<B: Deref, F: Deref, L: Deref>(
                &self,
                header: &BlockHeader,
@@ -1327,6 +1330,35 @@ impl<Signer: Sign> ChannelMonitor<Signer> {
                self.inner.lock().unwrap().transactions_confirmed(
                        header, txdata, height, broadcaster, fee_estimator, logger)
        }
+
+       /// Updates the monitor with the current best chain tip, returning new outputs to watch. See
+       /// [`block_connected`] for details.
+       ///
+       /// Used instead of [`block_connected`] by clients that are notified of transactions rather than
+       /// blocks. May be called before or after [`transactions_confirmed`] for the corresponding
+       /// block.
+       ///
+       /// Must be called after new blocks become available for the most recent block. Intermediary
+       /// blocks, however, may be safely skipped.
+       ///
+       /// [`block_connected`]: Self::block_connected
+       /// [`transactions_confirmed`]: Self::transactions_confirmed
+       pub fn update_best_block<B: Deref, F: Deref, L: Deref>(
+               &self,
+               header: &BlockHeader,
+               height: u32,
+               broadcaster: B,
+               fee_estimator: F,
+               logger: L,
+       ) -> Vec<(Txid, Vec<(u32, TxOut)>)>
+       where
+               B::Target: BroadcasterInterface,
+               F::Target: FeeEstimator,
+               L::Target: Logger,
+       {
+               self.inner.lock().unwrap().update_best_block(
+                       header, height, broadcaster, fee_estimator, logger)
+       }
 }
 
 impl<Signer: Sign> ChannelMonitorImpl<Signer> {
@@ -2028,10 +2060,40 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
                      F::Target: FeeEstimator,
                                        L::Target: Logger,
        {
-               self.best_block = BestBlock::new(header.block_hash(), height);
+               let block_hash = header.block_hash();
+               log_trace!(logger, "New best block {} at height {}", block_hash, height);
+               self.best_block = BestBlock::new(block_hash, height);
+
                self.transactions_confirmed(header, txdata, height, broadcaster, fee_estimator, logger)
        }
 
+       fn update_best_block<B: Deref, F: Deref, L: Deref>(
+               &mut self,
+               header: &BlockHeader,
+               height: u32,
+               broadcaster: B,
+               fee_estimator: F,
+               logger: L,
+       ) -> Vec<(Txid, Vec<(u32, TxOut)>)>
+       where
+               B::Target: BroadcasterInterface,
+               F::Target: FeeEstimator,
+               L::Target: Logger,
+       {
+               let block_hash = header.block_hash();
+               log_trace!(logger, "New best block {} at height {}", block_hash, height);
+
+               if height > self.best_block.height() {
+                       self.best_block = BestBlock::new(block_hash, height);
+                       self.block_confirmed(height, vec![], vec![], vec![], broadcaster, fee_estimator, logger)
+               } else {
+                       self.best_block = BestBlock::new(block_hash, height);
+                       self.onchain_events_waiting_threshold_conf.retain(|ref entry| entry.height <= height);
+                       self.onchain_tx_handler.block_disconnected(height + 1, broadcaster, fee_estimator, logger);
+                       Vec::new()
+               }
+       }
+
        fn transactions_confirmed<B: Deref, F: Deref, L: Deref>(
                &mut self,
                header: &BlockHeader,
@@ -2100,11 +2162,28 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
 
                        self.is_paying_spendable_output(&tx, height, &logger);
                }
+
+               self.block_confirmed(height, txn_matched, watch_outputs, claimable_outpoints, broadcaster, fee_estimator, logger)
+       }
+
+       fn block_confirmed<B: Deref, F: Deref, L: Deref>(
+               &mut self,
+               height: u32,
+               txn_matched: Vec<&Transaction>,
+               mut watch_outputs: Vec<(Txid, Vec<(u32, TxOut)>)>,
+               mut claimable_outpoints: Vec<ClaimRequest>,
+               broadcaster: B,
+               fee_estimator: F,
+               logger: L,
+       ) -> Vec<(Txid, Vec<(u32, TxOut)>)>
+       where
+               B::Target: BroadcasterInterface,
+               F::Target: FeeEstimator,
+               L::Target: Logger,
+       {
                let should_broadcast = self.would_broadcast_at_height(height, &logger);
                if should_broadcast {
                        claimable_outpoints.push(ClaimRequest { absolute_timelock: height, aggregable: false, outpoint: BitcoinOutPoint { txid: self.funding_info.0.txid.clone(), vout: self.funding_info.0.index as u32 }, witness_data: InputMaterial::Funding { funding_redeemscript: self.funding_redeemscript.clone() }});
-               }
-               if should_broadcast {
                        self.pending_monitor_events.push(MonitorEvent::CommitmentTxBroadcasted(self.funding_info.0));
                        let commitment_tx = self.onchain_tx_handler.get_fully_signed_holder_tx(&self.funding_redeemscript);
                        self.holder_tx_signed = true;
@@ -2211,7 +2290,7 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
                //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_events_waiting_threshold_conf.retain(|ref entry| entry.height != height);
+               self.onchain_events_waiting_threshold_conf.retain(|ref entry| entry.height < height);
 
                self.onchain_tx_handler.block_disconnected(height, broadcaster, fee_estimator, logger);
 
index 7613fa2b663b4f107f8100be032e97ef05cda1b7..67a82a480848aeec8d86325be36c6841c261cc8d 100644 (file)
@@ -848,8 +848,8 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
 
                // Check if any pending claim request must be rescheduled
                for (first_claim_txid, ref claim_data) in self.pending_claim_requests.iter() {
-                       if let Some(h) = claim_data.height_timer {
-                               if h == height {
+                       if let Some(height_timer) = claim_data.height_timer {
+                               if height >= height_timer {
                                        bump_candidates.insert(*first_claim_txid, (*claim_data).clone());
                                }
                        }
@@ -878,7 +878,7 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
                let onchain_events_waiting_threshold_conf =
                        self.onchain_events_waiting_threshold_conf.drain(..).collect::<Vec<_>>();
                for entry in onchain_events_waiting_threshold_conf {
-                       if entry.height == height {
+                       if entry.height >= height {
                                //- our claim tx on a commitment tx output
                                //- resurect outpoint back in its claimable set and regenerate tx
                                match entry.event {
@@ -912,7 +912,7 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
                // right now if one of the outpoint get disconnected, just erase whole pending claim request.
                let mut remove_request = Vec::new();
                self.claimable_outpoints.retain(|_, ref v|
-                       if v.1 == height {
+                       if v.1 >= height {
                        remove_request.push(v.0.clone());
                        false
                        } else { true });