From 6b12dd207f31fcf80faca1a649118ad28dee00bf Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Tue, 20 Apr 2021 10:24:08 -0700 Subject: [PATCH 1/4] Define chain::Confirm trait Define a separate trait akin to chain::Listen for notifying when transactions have been confirmed on chain or unconfirmed during a chain reorganization. Whereas chain::Listen is used for block-oriented chain sources, chain::Confirm is used for chain sources supplying data for activity related to transactions and outputs registered via chain::Filter. --- lightning/src/chain/mod.rs | 91 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 87 insertions(+), 4 deletions(-) diff --git a/lightning/src/chain/mod.rs b/lightning/src/chain/mod.rs index 18c7fd55d7b..7d25a066076 100644 --- a/lightning/src/chain/mod.rs +++ b/lightning/src/chain/mod.rs @@ -16,7 +16,7 @@ use bitcoin::hash_types::{BlockHash, Txid}; use chain::channelmonitor::{ChannelMonitor, ChannelMonitorUpdate, ChannelMonitorUpdateErr, MonitorEvent}; use chain::keysinterface::Sign; -use chain::transaction::OutPoint; +use chain::transaction::{OutPoint, TransactionData}; pub mod chaininterface; pub mod chainmonitor; @@ -45,10 +45,13 @@ pub trait Access: Send + Sync { fn get_utxo(&self, genesis_hash: &BlockHash, short_channel_id: u64) -> Result; } -/// The `Listen` trait is used to be notified of when blocks have been connected or disconnected -/// from the chain. +/// The `Listen` trait is used to notify when blocks have been connected or disconnected from the +/// chain. /// -/// Useful when needing to replay chain data upon startup or as new chain events occur. +/// Useful when needing to replay chain data upon startup or as new chain events occur. Clients +/// sourcing chain data using a block-oriented API should prefer this interface over [`Confirm`]. +/// Such clients fetch the entire header chain whereas clients using [`Confirm`] only fetch headers +/// when needed. pub trait Listen { /// Notifies the listener that a block was added at the given height. fn block_connected(&self, block: &Block, height: u32); @@ -57,6 +60,86 @@ pub trait Listen { fn block_disconnected(&self, header: &BlockHeader, height: u32); } +/// The `Confirm` trait is used to notify when transactions have been confirmed on chain or +/// unconfirmed during a chain reorganization. +/// +/// Clients sourcing chain data using a transaction-oriented API should prefer this interface over +/// [`Listen`]. For instance, an Electrum client may implement [`Filter`] by subscribing to activity +/// related to registered transactions and outputs. Upon notification, it would pass along the +/// matching transactions using this interface. +/// +/// # Use +/// +/// The intended use is as follows: +/// - Call [`transactions_confirmed`] to process any on-chain activity of interest. +/// - Call [`transaction_unconfirmed`] to process any transaction returned by [`get_relevant_txids`] +/// that has been reorganized out of the chain. +/// - Call [`best_block_updated`] whenever a new chain tip becomes available. +/// +/// # Order +/// +/// Clients must call these methods in chain order. Specifically: +/// - Transactions confirmed in a block must be given before transactions confirmed in a later +/// block. +/// - Dependent transactions within the same block must be given in topological order, possibly in +/// separate calls. +/// - Unconfirmed transactions must be given after the original confirmations and before any +/// reconfirmation. +/// +/// See individual method documentation for further details. +/// +/// [`transactions_confirmed`]: Self::transactions_confirmed +/// [`transaction_unconfirmed`]: Self::transaction_unconfirmed +/// [`best_block_updated`]: Self::best_block_updated +/// [`get_relevant_txids`]: Self::get_relevant_txids +pub trait Confirm { + /// Processes transactions confirmed in a block with a given header and height. + /// + /// Should be called for any transactions registered by [`Filter::register_tx`] or any + /// transactions spending an output registered by [`Filter::register_output`]. Such transactions + /// appearing in the same block do not need to be included in the same call; instead, multiple + /// calls with additional transactions may be made so long as they are made in [chain order]. + /// + /// May be called before or after [`best_block_updated`] for the corresponding block. However, + /// in the event of a chain reorganization, it must not be called with a `header` that is no + /// longer in the chain as of the last call to [`best_block_updated`]. + /// + /// [chain order]: Self#order + /// [`best_block_updated`]: Self::best_block_updated + fn transactions_confirmed(&self, header: &BlockHeader, txdata: &TransactionData, height: u32); + + /// Processes a transaction that is no longer confirmed as result of a chain reorganization. + /// + /// Should be called for any transaction returned by [`get_relevant_txids`] if it has been + /// reorganized out of the best chain. Once called, the given transaction should not be returned + /// by [`get_relevant_txids`] unless it has been reconfirmed via [`transactions_confirmed`]. + /// + /// [`get_relevant_txids`]: Self::get_relevant_txids + /// [`transactions_confirmed`]: Self::transactions_confirmed + fn transaction_unconfirmed(&self, txid: &Txid); + + /// Processes an update to the best header connected at the given height. + /// + /// Should be called when a new header is available but may be skipped for intermediary blocks + /// if they become available at the same time. + fn best_block_updated(&self, header: &BlockHeader, height: u32); + + /// Returns transactions that should be monitored for reorganization out of the chain. + /// + /// Should include any transactions passed to [`transactions_confirmed`] that have insufficient + /// confirmations to be safe from a chain reorganization. Should not include any transactions + /// passed to [`transaction_unconfirmed`] unless later reconfirmed. + /// + /// May be called to determine the subset of transactions that must still be monitored for + /// reorganization. Will be idempotent between calls but may change as a result of calls to the + /// other interface methods. Thus, this is useful to determine which transactions may need to be + /// given to [`transaction_unconfirmed`]. + /// + /// [`transactions_confirmed`]: Self::transactions_confirmed + /// [`transaction_unconfirmed`]: Self::transaction_unconfirmed + fn get_relevant_txids(&self) -> Vec; +} + /// The `Watch` trait defines behavior for watching on-chain activity pertaining to channels as /// blocks are connected and disconnected. /// From 23c4c8b7c78ab2db5ccb8358186e5923fbce5ca3 Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Tue, 20 Apr 2021 13:39:00 -0700 Subject: [PATCH 2/4] Implement chain::Confirm for relevant structs --- fuzz/src/chanmon_consistency.rs | 5 +- fuzz/src/full_stack.rs | 6 +- lightning/src/chain/chainmonitor.rs | 18 +- lightning/src/chain/channelmonitor.rs | 47 +++-- lightning/src/ln/channel.rs | 8 +- lightning/src/ln/channelmanager.rs | 214 ++++++++-------------- lightning/src/ln/functional_test_utils.rs | 28 +-- lightning/src/ln/reorg_tests.rs | 2 +- 8 files changed, 144 insertions(+), 184 deletions(-) diff --git a/fuzz/src/chanmon_consistency.rs b/fuzz/src/chanmon_consistency.rs index 9d0a90ee1cd..96da87b624e 100644 --- a/fuzz/src/chanmon_consistency.rs +++ b/fuzz/src/chanmon_consistency.rs @@ -30,6 +30,7 @@ use bitcoin::hashes::sha256::Hash as Sha256; use bitcoin::hash_types::{BlockHash, WPubkeyHash}; use lightning::chain; +use lightning::chain::Confirm; use lightning::chain::chainmonitor; use lightning::chain::channelmonitor; use lightning::chain::channelmonitor::{ChannelMonitor, ChannelMonitorUpdateErr, MonitorEvent}; @@ -428,11 +429,11 @@ pub fn do_test(data: &[u8], out: Out) { let chain_hash = genesis_block(Network::Bitcoin).block_hash(); let mut header = BlockHeader { version: 0x20000000, prev_blockhash: chain_hash, merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 }; let txdata: Vec<_> = channel_txn.iter().enumerate().map(|(i, tx)| (i + 1, tx)).collect(); - $node.transactions_confirmed(&header, 1, &txdata); + $node.transactions_confirmed(&header, &txdata, 1); for _ in 2..100 { header = BlockHeader { version: 0x20000000, prev_blockhash: header.block_hash(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 }; } - $node.update_best_block(&header, 99); + $node.best_block_updated(&header, 99); } } } diff --git a/fuzz/src/full_stack.rs b/fuzz/src/full_stack.rs index 91ebb99018c..dac57613ce0 100644 --- a/fuzz/src/full_stack.rs +++ b/fuzz/src/full_stack.rs @@ -27,7 +27,7 @@ use bitcoin::hashes::sha256::Hash as Sha256; use bitcoin::hash_types::{Txid, BlockHash, WPubkeyHash}; use lightning::chain; -use lightning::chain::Listen; +use lightning::chain::{Confirm, Listen}; use lightning::chain::chaininterface::{BroadcasterInterface, ConfirmationTarget, FeeEstimator}; use lightning::chain::chainmonitor; use lightning::chain::transaction::OutPoint; @@ -207,8 +207,8 @@ impl<'a> MoneyLossDetector<'a> { self.blocks_connected += 1; let header = BlockHeader { version: 0x20000000, prev_blockhash: self.header_hashes[self.height].0, merkle_root: Default::default(), time: self.blocks_connected, bits: 42, nonce: 42 }; self.height += 1; - self.manager.transactions_confirmed(&header, self.height as u32, &txdata); - self.manager.update_best_block(&header, self.height as u32); + self.manager.transactions_confirmed(&header, &txdata, self.height as u32); + self.manager.best_block_updated(&header, self.height as u32); (*self.monitor).block_connected(&header, &txdata, self.height as u32); if self.header_hashes.len() > self.height { self.header_hashes[self.height] = (header.block_hash(), self.blocks_connected); diff --git a/lightning/src/chain/chainmonitor.rs b/lightning/src/chain/chainmonitor.rs index ee6df63a1e0..aeab80a7ae5 100644 --- a/lightning/src/chain/chainmonitor.rs +++ b/lightning/src/chain/chainmonitor.rs @@ -94,11 +94,11 @@ where C::Target: chain::Filter, /// [`ChannelMonitor::transactions_confirmed`]. /// /// 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. + /// blocks. May be called before or after [`best_block_updated`] for transactions in the + /// corresponding block. See [`best_block_updated`] for further calling expectations. /// /// [`block_connected`]: Self::block_connected - /// [`update_best_block`]: Self::update_best_block + /// [`best_block_updated`]: Self::best_block_updated pub fn transactions_confirmed(&self, header: &BlockHeader, txdata: &TransactionData, height: u32) { self.process_chain_data(header, txdata, |monitor, txdata| { monitor.transactions_confirmed( @@ -108,7 +108,7 @@ where C::Target: chain::Filter, /// Dispatches to per-channel monitors, which are responsible for updating their on-chain view /// of a channel and reacting accordingly based on the new chain tip. For details, see - /// [`ChannelMonitor::update_best_block`]. + /// [`ChannelMonitor::best_block_updated`]. /// /// 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 @@ -122,12 +122,12 @@ where C::Target: chain::Filter, /// [`block_connected`]: Self::block_connected /// [`transactions_confirmed`]: Self::transactions_confirmed /// [`transaction_unconfirmed`]: Self::transaction_unconfirmed - pub fn update_best_block(&self, header: &BlockHeader, height: u32) { + pub fn best_block_updated(&self, header: &BlockHeader, height: u32) { self.process_chain_data(header, &[], |monitor, txdata| { // While in practice there shouldn't be any recursive calls when given empty txdata, // it's still possible if a chain::Filter implementation returns a transaction. debug_assert!(txdata.is_empty()); - monitor.update_best_block( + monitor.best_block_updated( header, height, &*self.broadcaster, &*self.fee_estimator, &*self.logger) }); } @@ -187,11 +187,11 @@ where C::Target: chain::Filter, /// [`ChannelMonitor::transaction_unconfirmed`] for details. /// /// 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. + /// than blocks. May be called before or after [`best_block_updated`] for transactions in the + /// corresponding block. See [`best_block_updated`] for further calling expectations. /// /// [`block_disconnected`]: Self::block_disconnected - /// [`update_best_block`]: Self::update_best_block + /// [`best_block_updated`]: Self::best_block_updated pub fn transaction_unconfirmed(&self, txid: &Txid) { let monitors = self.monitors.read().unwrap(); for monitor in monitors.values() { diff --git a/lightning/src/chain/channelmonitor.rs b/lightning/src/chain/channelmonitor.rs index 777bc06bfb8..d6fd023b4de 100644 --- a/lightning/src/chain/channelmonitor.rs +++ b/lightning/src/chain/channelmonitor.rs @@ -1311,11 +1311,9 @@ impl ChannelMonitor { /// 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 [`update_best_block`] for transactions in the - /// corresponding block. See [`update_best_block`] for further calling expectations. + /// blocks. See [`chain::Confirm`] for calling expectations. /// /// [`block_connected`]: Self::block_connected - /// [`update_best_block`]: Self::update_best_block pub fn transactions_confirmed( &self, header: &BlockHeader, @@ -1337,11 +1335,9 @@ impl ChannelMonitor { /// 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. + /// than blocks. See [`chain::Confirm`] for calling expectations. /// /// [`block_disconnected`]: Self::block_disconnected - /// [`update_best_block`]: Self::update_best_block pub fn transaction_unconfirmed( &self, txid: &Txid, @@ -1361,18 +1357,10 @@ impl ChannelMonitor { /// [`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. 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. + /// blocks. See [`chain::Confirm`] for calling expectations. /// /// [`block_connected`]: Self::block_connected - /// [`transactions_confirmed`]: Self::transactions_confirmed - /// [`transaction_unconfirmed`]: Self::transaction_unconfirmed - pub fn update_best_block( + pub fn best_block_updated( &self, header: &BlockHeader, height: u32, @@ -1385,7 +1373,7 @@ impl ChannelMonitor { F::Target: FeeEstimator, L::Target: Logger, { - self.inner.lock().unwrap().update_best_block( + self.inner.lock().unwrap().best_block_updated( header, height, broadcaster, fee_estimator, logger) } @@ -2109,7 +2097,7 @@ impl ChannelMonitorImpl { self.transactions_confirmed(header, txdata, height, broadcaster, fee_estimator, logger) } - fn update_best_block( + fn best_block_updated( &mut self, header: &BlockHeader, height: u32, @@ -2727,6 +2715,29 @@ where } } +impl chain::Confirm for (ChannelMonitor, T, F, L) +where + T::Target: BroadcasterInterface, + F::Target: FeeEstimator, + L::Target: Logger, +{ + fn transactions_confirmed(&self, header: &BlockHeader, txdata: &TransactionData, height: u32) { + self.0.transactions_confirmed(header, txdata, height, &*self.1, &*self.2, &*self.3); + } + + fn transaction_unconfirmed(&self, txid: &Txid) { + self.0.transaction_unconfirmed(txid, &*self.1, &*self.2, &*self.3); + } + + fn best_block_updated(&self, header: &BlockHeader, height: u32) { + self.0.best_block_updated(header, height, &*self.1, &*self.2, &*self.3); + } + + fn get_relevant_txids(&self) -> Vec { + self.0.get_relevant_txids() + } +} + const MAX_ALLOC_SIZE: usize = 64*1024; impl<'a, Signer: Sign, K: KeysInterface> ReadableArgs<&'a K> diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index 5f987427979..512b6d96ab3 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -3600,7 +3600,7 @@ impl Channel { } } // If we allow 1-conf funding, we may need to check for funding_locked here and - // send it immediately instead of waiting for an update_best_block call (which + // send it immediately instead of waiting for a best_block_updated call (which // may have already happened for this block). if let Some(funding_locked) = self.check_get_funding_locked(height) { return Ok(Some(funding_locked)); @@ -3631,7 +3631,7 @@ impl Channel { /// /// May return some HTLCs (and their payment_hash) which have timed out and should be failed /// back. - pub fn update_best_block(&mut self, height: u32, highest_header_time: u32) -> Result<(Option, Vec<(HTLCSource, PaymentHash)>), msgs::ErrorMessage> { + pub fn best_block_updated(&mut self, height: u32, highest_header_time: u32) -> Result<(Option, Vec<(HTLCSource, PaymentHash)>), msgs::ErrorMessage> { let mut timed_out_htlcs = Vec::new(); let unforwarded_htlc_cltv_limit = height + HTLC_FAIL_BACK_BUFFER; self.holding_cell_htlc_updates.retain(|htlc_update| { @@ -3683,14 +3683,14 @@ impl Channel { /// before the channel has reached funding_locked and we can just wait for more blocks. pub fn funding_transaction_unconfirmed(&mut self) -> Result<(), msgs::ErrorMessage> { if self.funding_tx_confirmation_height != 0 { - // We handle the funding disconnection by calling update_best_block with a height one + // We handle the funding disconnection by calling best_block_updated with a height one // below where our funding was connected, implying a reorg back to conf_height - 1. let reorg_height = self.funding_tx_confirmation_height - 1; // We use the time field to bump the current time we set on channel updates if its // larger. If we don't know that time has moved forward, we can just set it to the last // time we saw and it will be ignored. let best_time = self.update_time_counter; - match self.update_best_block(reorg_height, best_time) { + match self.best_block_updated(reorg_height, best_time) { Ok((funding_locked, timed_out_htlcs)) => { assert!(funding_locked.is_none(), "We can't generate a funding with 0 confirmations?"); assert!(timed_out_htlcs.is_empty(), "We can't have accepted HTLCs with a timeout before our funding confirmation?"); diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index 39426b3fa7b..978171b1ba4 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -36,6 +36,7 @@ use bitcoin::secp256k1::ecdh::SharedSecret; use bitcoin::secp256k1; use chain; +use chain::Confirm; use chain::Watch; use chain::chaininterface::{BroadcasterInterface, FeeEstimator}; use chain::channelmonitor::{ChannelMonitor, ChannelMonitorUpdate, ChannelMonitorUpdateStep, ChannelMonitorUpdateErr, HTLC_FAIL_BACK_BUFFER, CLTV_CLAIM_BUFFER, LATENCY_GRACE_PERIOD_BLOCKS, ANTI_REORG_DELAY, MonitorEvent, CLOSED_CHANNEL_UPDATE_ID}; @@ -3363,8 +3364,8 @@ where } let txdata: Vec<_> = block.txdata.iter().enumerate().collect(); - self.transactions_confirmed(&block.header, height, &txdata); - self.update_best_block(&block.header, height); + self.transactions_confirmed(&block.header, &txdata, height); + self.best_block_updated(&block.header, height); } fn block_disconnected(&self, header: &BlockHeader, height: u32) { @@ -3379,16 +3380,88 @@ where *best_block = BestBlock::new(header.prev_blockhash, new_height) } - self.do_chain_event(Some(new_height), |channel| channel.update_best_block(new_height, header.time)); + self.do_chain_event(Some(new_height), |channel| channel.best_block_updated(new_height, header.time)); + } +} + +impl chain::Confirm for ChannelManager +where + M::Target: chain::Watch, + T::Target: BroadcasterInterface, + K::Target: KeysInterface, + F::Target: FeeEstimator, + L::Target: Logger, +{ + fn transactions_confirmed(&self, header: &BlockHeader, txdata: &TransactionData, height: u32) { + // Note that we MUST NOT end up calling methods on self.chain_monitor here - we're called + // during initialization prior to the chain_monitor being fully configured in some cases. + // See the docs for `ChannelManagerReadArgs` for more. + + let block_hash = header.block_hash(); + log_trace!(self.logger, "{} transactions included in block {} at height {} provided", txdata.len(), block_hash, height); + + let _persistence_guard = PersistenceNotifierGuard::new(&self.total_consistency_lock, &self.persistence_notifier); + self.do_chain_event(Some(height), |channel| channel.transactions_confirmed(&block_hash, height, txdata, &self.logger).map(|a| (a, Vec::new()))); + } + + fn best_block_updated(&self, header: &BlockHeader, height: u32) { + // Note that we MUST NOT end up calling methods on self.chain_monitor here - we're called + // during initialization prior to the chain_monitor being fully configured in some cases. + // See the docs for `ChannelManagerReadArgs` for more. + + let block_hash = header.block_hash(); + log_trace!(self.logger, "New best block: {} at height {}", block_hash, height); + + let _persistence_guard = PersistenceNotifierGuard::new(&self.total_consistency_lock, &self.persistence_notifier); + + *self.best_block.write().unwrap() = BestBlock::new(block_hash, height); + + self.do_chain_event(Some(height), |channel| channel.best_block_updated(height, header.time)); + + loop { + // Update last_node_announcement_serial to be the max of its current value and the + // block timestamp. This should keep us close to the current time without relying on + // having an explicit local time source. + // Just in case we end up in a race, we loop until we either successfully update + // last_node_announcement_serial or decide we don't need to. + let old_serial = self.last_node_announcement_serial.load(Ordering::Acquire); + if old_serial >= header.time as usize { break; } + if self.last_node_announcement_serial.compare_exchange(old_serial, header.time as usize, Ordering::AcqRel, Ordering::Relaxed).is_ok() { + break; + } + } + } + + fn get_relevant_txids(&self) -> Vec { + let channel_state = self.channel_state.lock().unwrap(); + let mut res = Vec::with_capacity(channel_state.short_to_id.len()); + for chan in channel_state.by_id.values() { + if let Some(funding_txo) = chan.get_funding_txo() { + res.push(funding_txo.txid); + } + } + res + } + + fn transaction_unconfirmed(&self, txid: &Txid) { + let _persistence_guard = PersistenceNotifierGuard::new(&self.total_consistency_lock, &self.persistence_notifier); + self.do_chain_event(None, |channel| { + if let Some(funding_txo) = channel.get_funding_txo() { + if funding_txo.txid == *txid { + channel.funding_transaction_unconfirmed().map(|_| (None, Vec::new())) + } else { Ok((None, Vec::new())) } + } else { Ok((None, Vec::new())) } + }); } } impl ChannelManager - where M::Target: chain::Watch, - T::Target: BroadcasterInterface, - K::Target: KeysInterface, - F::Target: FeeEstimator, - L::Target: Logger, +where + M::Target: chain::Watch, + T::Target: BroadcasterInterface, + K::Target: KeysInterface, + F::Target: FeeEstimator, + L::Target: Logger, { /// Calls a function which handles an on-chain event (blocks dis/connected, transactions /// un/confirmed, etc) on each channel, handling any resulting errors or messages generated by @@ -3482,131 +3555,6 @@ impl ChannelMana } } - /// Updates channel state to take note of transactions which were confirmed in the given block - /// at the given height. - /// - /// Note that you must still call (or have called) [`update_best_block`] with the block - /// information which is included here. - /// - /// This method may be called before or after [`update_best_block`] for a given block's - /// transaction data and may be called multiple times with additional transaction data for a - /// given block. - /// - /// This method may be called for a previous block after an [`update_best_block`] call has - /// been made for a later block, however it must *not* be called with transaction data from a - /// block which is no longer in the best chain (ie where [`update_best_block`] has already - /// been informed about a blockchain reorganization which no longer includes the block which - /// corresponds to `header`). - /// - /// [`update_best_block`]: `Self::update_best_block` - pub fn transactions_confirmed(&self, header: &BlockHeader, height: u32, txdata: &TransactionData) { - // Note that we MUST NOT end up calling methods on self.chain_monitor here - we're called - // during initialization prior to the chain_monitor being fully configured in some cases. - // See the docs for `ChannelManagerReadArgs` for more. - - let block_hash = header.block_hash(); - log_trace!(self.logger, "{} transactions included in block {} at height {} provided", txdata.len(), block_hash, height); - - let _persistence_guard = PersistenceNotifierGuard::new(&self.total_consistency_lock, &self.persistence_notifier); - self.do_chain_event(Some(height), |channel| channel.transactions_confirmed(&block_hash, height, txdata, &self.logger).map(|a| (a, Vec::new()))); - } - - /// Updates channel state with the current best blockchain tip. You should attempt to call this - /// quickly after a new block becomes available, however if multiple new blocks become - /// available at the same time, only a single `update_best_block()` call needs to be made. - /// - /// This method should also be called immediately after any block disconnections, once at the - /// reorganization fork point, and once with the new chain tip. Calling this method at the - /// blockchain reorganization fork point ensures we learn when a funding transaction which was - /// previously confirmed is reorganized out of the blockchain, ensuring we do not continue to - /// accept payments which cannot be enforced on-chain. - /// - /// In both the block-connection and block-disconnection case, this method may be called either - /// once per block connected or disconnected, or simply at the fork point and new tip(s), - /// skipping any intermediary blocks. - pub fn update_best_block(&self, header: &BlockHeader, height: u32) { - // Note that we MUST NOT end up calling methods on self.chain_monitor here - we're called - // during initialization prior to the chain_monitor being fully configured in some cases. - // See the docs for `ChannelManagerReadArgs` for more. - - let block_hash = header.block_hash(); - log_trace!(self.logger, "New best block: {} at height {}", block_hash, height); - - let _persistence_guard = PersistenceNotifierGuard::new(&self.total_consistency_lock, &self.persistence_notifier); - - *self.best_block.write().unwrap() = BestBlock::new(block_hash, height); - - self.do_chain_event(Some(height), |channel| channel.update_best_block(height, header.time)); - - loop { - // Update last_node_announcement_serial to be the max of its current value and the - // block timestamp. This should keep us close to the current time without relying on - // having an explicit local time source. - // Just in case we end up in a race, we loop until we either successfully update - // last_node_announcement_serial or decide we don't need to. - let old_serial = self.last_node_announcement_serial.load(Ordering::Acquire); - if old_serial >= header.time as usize { break; } - if self.last_node_announcement_serial.compare_exchange(old_serial, header.time as usize, Ordering::AcqRel, Ordering::Relaxed).is_ok() { - break; - } - } - } - - /// Gets the set of txids which should be monitored for their confirmation state. - /// - /// If you're providing information about reorganizations via [`transaction_unconfirmed`], this - /// is the set of transactions which you may need to call [`transaction_unconfirmed`] for. - /// - /// This may be useful to poll to determine the set of transactions which must be registered - /// with an Electrum server or for which an Electrum server needs to be polled to determine - /// transaction confirmation state. - /// - /// This may update after any [`transactions_confirmed`] or [`block_connected`] call. - /// - /// Note that this is NOT the set of transactions which must be included in calls to - /// [`transactions_confirmed`] if they are confirmed, but a small subset of it. - /// - /// [`transactions_confirmed`]: Self::transactions_confirmed - /// [`transaction_unconfirmed`]: Self::transaction_unconfirmed - /// [`block_connected`]: chain::Listen::block_connected - pub fn get_relevant_txids(&self) -> Vec { - let channel_state = self.channel_state.lock().unwrap(); - let mut res = Vec::with_capacity(channel_state.short_to_id.len()); - for chan in channel_state.by_id.values() { - if let Some(funding_txo) = chan.get_funding_txo() { - res.push(funding_txo.txid); - } - } - res - } - - /// Marks a transaction as having been reorganized out of the blockchain. - /// - /// If a transaction is included in [`get_relevant_txids`], and is no longer in the main branch - /// of the blockchain, this function should be called to indicate that the transaction should - /// be considered reorganized out. - /// - /// Once this is called, the given transaction will no longer appear on [`get_relevant_txids`], - /// though this may be called repeatedly for a given transaction without issue. - /// - /// Note that if the transaction is confirmed on the main chain in a different block (indicated - /// via a call to [`transactions_confirmed`]), it may re-appear in [`get_relevant_txids`], thus - /// be very wary of race-conditions wherein the final state of a transaction indicated via - /// these APIs is not the same as its state on the blockchain. - /// - /// [`transactions_confirmed`]: Self::transactions_confirmed - /// [`get_relevant_txids`]: Self::get_relevant_txids - pub fn transaction_unconfirmed(&self, txid: &Txid) { - let _persistence_guard = PersistenceNotifierGuard::new(&self.total_consistency_lock, &self.persistence_notifier); - self.do_chain_event(None, |channel| { - if let Some(funding_txo) = channel.get_funding_txo() { - if funding_txo.txid == *txid { - channel.funding_transaction_unconfirmed().map(|_| (None, Vec::new())) - } else { Ok((None, Vec::new())) } - } else { Ok((None, Vec::new())) } - }); - } - /// Blocks until ChannelManager needs to be persisted or a timeout is reached. It returns a bool /// indicating whether persistence is necessary. Only one listener on /// `await_persistable_update` or `await_persistable_update_timeout` is guaranteed to be woken diff --git a/lightning/src/ln/functional_test_utils.rs b/lightning/src/ln/functional_test_utils.rs index dee3c6ea395..53d0ad8561f 100644 --- a/lightning/src/ln/functional_test_utils.rs +++ b/lightning/src/ln/functional_test_utils.rs @@ -10,7 +10,7 @@ //! A bunch of useful utilities for building networks of nodes and exchanging messages between //! nodes for functional tests. -use chain::{Listen, Watch}; +use chain::{Confirm, Listen, Watch}; use chain::channelmonitor::ChannelMonitor; use chain::transaction::OutPoint; use ln::channelmanager::{BestBlock, ChainParameters, ChannelManager, ChannelManagerReadArgs, RAACommitmentOrder, PaymentPreimage, PaymentHash, PaymentSecret, PaymentSendFailure}; @@ -79,17 +79,17 @@ pub fn confirm_transaction_at<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, tx: &T /// The possible ways we may notify a ChannelManager of a new block #[derive(Clone, Copy, PartialEq)] pub enum ConnectStyle { - /// Calls update_best_block first, detecting transactions in the block only after receiving the + /// Calls best_block_updated first, detecting transactions in the block only after receiving the /// header and height information. BestBlockFirst, /// The same as BestBlockFirst, however when we have multiple blocks to connect, we only - /// make a single update_best_block call. + /// make a single best_block_updated call. BestBlockFirstSkippingBlocks, /// Calls transactions_confirmed first, detecting transactions in the block before updating the /// header and height information. TransactionsFirst, /// The same as TransactionsFirst, however when we have multiple blocks to connect, we only - /// make a single update_best_block call. + /// make a single best_block_updated call. TransactionsFirstSkippingBlocks, /// Provides the full block via the chain::Listen interface. In the current code this is /// equivalent to TransactionsFirst with some additional assertions. @@ -128,16 +128,16 @@ fn do_connect_block<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, block: &Block, s let txdata: Vec<_> = block.txdata.iter().enumerate().collect(); match *node.connect_style.borrow() { ConnectStyle::BestBlockFirst|ConnectStyle::BestBlockFirstSkippingBlocks => { - node.chain_monitor.chain_monitor.update_best_block(&block.header, height); + node.chain_monitor.chain_monitor.best_block_updated(&block.header, height); node.chain_monitor.chain_monitor.transactions_confirmed(&block.header, &txdata, height); - node.node.update_best_block(&block.header, height); - node.node.transactions_confirmed(&block.header, height, &txdata); + node.node.best_block_updated(&block.header, height); + node.node.transactions_confirmed(&block.header, &txdata, height); }, ConnectStyle::TransactionsFirst|ConnectStyle::TransactionsFirstSkippingBlocks => { node.chain_monitor.chain_monitor.transactions_confirmed(&block.header, &txdata, height); - node.chain_monitor.chain_monitor.update_best_block(&block.header, height); - node.node.transactions_confirmed(&block.header, height, &txdata); - node.node.update_best_block(&block.header, height); + node.chain_monitor.chain_monitor.best_block_updated(&block.header, height); + node.node.transactions_confirmed(&block.header, &txdata, height); + node.node.best_block_updated(&block.header, height); }, ConnectStyle::FullBlockViaListen => { node.chain_monitor.chain_monitor.block_connected(&block.header, &txdata, height); @@ -162,13 +162,13 @@ pub fn disconnect_blocks<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, count: u32) }, ConnectStyle::BestBlockFirstSkippingBlocks|ConnectStyle::TransactionsFirstSkippingBlocks => { if i == count - 1 { - node.chain_monitor.chain_monitor.update_best_block(&prev_header.0, prev_header.1); - node.node.update_best_block(&prev_header.0, prev_header.1); + node.chain_monitor.chain_monitor.best_block_updated(&prev_header.0, prev_header.1); + node.node.best_block_updated(&prev_header.0, prev_header.1); } }, _ => { - node.chain_monitor.chain_monitor.update_best_block(&prev_header.0, prev_header.1); - node.node.update_best_block(&prev_header.0, prev_header.1); + node.chain_monitor.chain_monitor.best_block_updated(&prev_header.0, prev_header.1); + node.node.best_block_updated(&prev_header.0, prev_header.1); }, } } diff --git a/lightning/src/ln/reorg_tests.rs b/lightning/src/ln/reorg_tests.rs index d5a3d042f29..05001d69e0c 100644 --- a/lightning/src/ln/reorg_tests.rs +++ b/lightning/src/ln/reorg_tests.rs @@ -10,7 +10,7 @@ //! Further functional tests which test blockchain reorganizations. use chain::channelmonitor::{ANTI_REORG_DELAY, ChannelMonitor}; -use chain::Watch; +use chain::{Confirm, Watch}; use ln::channelmanager::{ChannelManager, ChannelManagerReadArgs}; use ln::features::InitFeatures; use ln::msgs::{ChannelMessageHandler, ErrorAction, HTLCFailChannelUpdate}; From 93d20ff63e7b2b41804f46a4e1e342f82ede1d27 Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Thu, 22 Apr 2021 00:11:00 -0700 Subject: [PATCH 3/4] Implement chain::Confirm for ChainMonitor --- lightning/src/chain/chainmonitor.rs | 120 +++++++++++----------------- 1 file changed, 47 insertions(+), 73 deletions(-) diff --git a/lightning/src/chain/chainmonitor.rs b/lightning/src/chain/chainmonitor.rs index aeab80a7ae5..8c2e761fa46 100644 --- a/lightning/src/chain/chainmonitor.rs +++ b/lightning/src/chain/chainmonitor.rs @@ -89,49 +89,6 @@ where C::Target: chain::Filter, }); } - /// Dispatches to per-channel monitors, which are responsible for updating their on-chain view - /// of a channel and reacting accordingly to newly confirmed transactions. For details, see - /// [`ChannelMonitor::transactions_confirmed`]. - /// - /// Used instead of [`block_connected`] by clients that are notified of transactions rather than - /// blocks. May be called before or after [`best_block_updated`] for transactions in the - /// corresponding block. See [`best_block_updated`] for further calling expectations. - /// - /// [`block_connected`]: Self::block_connected - /// [`best_block_updated`]: Self::best_block_updated - pub fn transactions_confirmed(&self, header: &BlockHeader, txdata: &TransactionData, height: u32) { - self.process_chain_data(header, txdata, |monitor, txdata| { - monitor.transactions_confirmed( - header, txdata, height, &*self.broadcaster, &*self.fee_estimator, &*self.logger) - }); - } - - /// Dispatches to per-channel monitors, which are responsible for updating their on-chain view - /// of a channel and reacting accordingly based on the new chain tip. For details, see - /// [`ChannelMonitor::best_block_updated`]. - /// - /// 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. 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 best_block_updated(&self, header: &BlockHeader, height: u32) { - self.process_chain_data(header, &[], |monitor, txdata| { - // While in practice there shouldn't be any recursive calls when given empty txdata, - // it's still possible if a chain::Filter implementation returns a transaction. - debug_assert!(txdata.is_empty()); - monitor.best_block_updated( - header, height, &*self.broadcaster, &*self.fee_estimator, &*self.logger) - }); - } - fn process_chain_data(&self, header: &BlockHeader, txdata: &TransactionData, process: FN) where FN: Fn(&ChannelMonitor, &TransactionData) -> Vec @@ -182,36 +139,6 @@ where C::Target: chain::Filter, } } - /// Dispatches to per-channel monitors, which are responsible for updating their on-chain view - /// of a channel based on transactions unconfirmed as a result of a chain reorganization. See - /// [`ChannelMonitor::transaction_unconfirmed`] for details. - /// - /// Used instead of [`block_disconnected`] by clients that are notified of transactions rather - /// than blocks. May be called before or after [`best_block_updated`] for transactions in the - /// corresponding block. See [`best_block_updated`] for further calling expectations. - /// - /// [`block_disconnected`]: Self::block_disconnected - /// [`best_block_updated`]: Self::best_block_updated - pub fn transaction_unconfirmed(&self, txid: &Txid) { - let monitors = self.monitors.read().unwrap(); - for monitor in monitors.values() { - monitor.transaction_unconfirmed(txid, &*self.broadcaster, &*self.fee_estimator, &*self.logger); - } - } - - /// Returns the set of txids that should be monitored for re-organization out of the chain. - pub fn get_relevant_txids(&self) -> Vec { - let mut txids = Vec::new(); - let monitors = self.monitors.read().unwrap(); - for monitor in monitors.values() { - txids.append(&mut monitor.get_relevant_txids()); - } - - txids.sort_unstable(); - txids.dedup(); - txids - } - /// Creates a new `ChainMonitor` used to watch on-chain activity pertaining to channels. /// /// When an optional chain source implementing [`chain::Filter`] is provided, the chain monitor @@ -251,6 +178,53 @@ where } } +impl +chain::Confirm for ChainMonitor +where + ChannelSigner: Sign, + C::Target: chain::Filter, + T::Target: BroadcasterInterface, + F::Target: FeeEstimator, + L::Target: Logger, + P::Target: channelmonitor::Persist, +{ + fn transactions_confirmed(&self, header: &BlockHeader, txdata: &TransactionData, height: u32) { + self.process_chain_data(header, txdata, |monitor, txdata| { + monitor.transactions_confirmed( + header, txdata, height, &*self.broadcaster, &*self.fee_estimator, &*self.logger) + }); + } + + fn transaction_unconfirmed(&self, txid: &Txid) { + let monitors = self.monitors.read().unwrap(); + for monitor in monitors.values() { + monitor.transaction_unconfirmed(txid, &*self.broadcaster, &*self.fee_estimator, &*self.logger); + } + } + + fn best_block_updated(&self, header: &BlockHeader, height: u32) { + self.process_chain_data(header, &[], |monitor, txdata| { + // While in practice there shouldn't be any recursive calls when given empty txdata, + // it's still possible if a chain::Filter implementation returns a transaction. + debug_assert!(txdata.is_empty()); + monitor.best_block_updated( + header, height, &*self.broadcaster, &*self.fee_estimator, &*self.logger) + }); + } + + fn get_relevant_txids(&self) -> Vec { + let mut txids = Vec::new(); + let monitors = self.monitors.read().unwrap(); + for monitor in monitors.values() { + txids.append(&mut monitor.get_relevant_txids()); + } + + txids.sort_unstable(); + txids.dedup(); + txids + } +} + impl chain::Watch for ChainMonitor where C::Target: chain::Filter, From 99e2283aee3fb7ab512ad5688d2eb5e926d6d9f9 Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Thu, 22 Apr 2021 09:52:10 -0700 Subject: [PATCH 4/4] Drop pub functions for ChainMonitor's Listen impl --- fuzz/src/full_stack.rs | 3 +- lightning/src/chain/chainmonitor.rs | 33 +++++++------------ lightning/src/ln/chanmon_update_fail_tests.rs | 5 +-- lightning/src/ln/functional_test_utils.rs | 4 +-- lightning/src/ln/functional_tests.rs | 13 +++++--- 5 files changed, 27 insertions(+), 31 deletions(-) diff --git a/fuzz/src/full_stack.rs b/fuzz/src/full_stack.rs index dac57613ce0..73a9a67a74e 100644 --- a/fuzz/src/full_stack.rs +++ b/fuzz/src/full_stack.rs @@ -209,7 +209,8 @@ impl<'a> MoneyLossDetector<'a> { self.height += 1; self.manager.transactions_confirmed(&header, &txdata, self.height as u32); self.manager.best_block_updated(&header, self.height as u32); - (*self.monitor).block_connected(&header, &txdata, self.height as u32); + (*self.monitor).transactions_confirmed(&header, &txdata, self.height as u32); + (*self.monitor).best_block_updated(&header, self.height as u32); if self.header_hashes.len() > self.height { self.header_hashes[self.height] = (header.block_hash(), self.blocks_connected); } else { diff --git a/lightning/src/chain/chainmonitor.rs b/lightning/src/chain/chainmonitor.rs index 8c2e761fa46..95a786f696d 100644 --- a/lightning/src/chain/chainmonitor.rs +++ b/lightning/src/chain/chainmonitor.rs @@ -74,7 +74,7 @@ where C::Target: chain::Filter, P::Target: channelmonitor::Persist, { /// Dispatches to per-channel monitors, which are responsible for updating their on-chain view - /// of a channel and reacting accordingly based on transactions in the connected block. See + /// of a channel and reacting accordingly based on transactions in the given chain data. See /// [`ChannelMonitor::block_connected`] for details. Any HTLCs that were resolved on chain will /// be returned by [`chain::Watch::release_pending_monitor_events`]. /// @@ -82,13 +82,6 @@ where C::Target: chain::Filter, /// calls must not exclude any transactions matching the new outputs nor any in-block /// descendants of such transactions. It is not necessary to re-fetch the block to obtain /// updated `txdata`. - pub fn block_connected(&self, header: &BlockHeader, txdata: &TransactionData, height: u32) { - self.process_chain_data(header, txdata, |monitor, txdata| { - monitor.block_connected( - header, txdata, height, &*self.broadcaster, &*self.fee_estimator, &*self.logger) - }); - } - fn process_chain_data(&self, header: &BlockHeader, txdata: &TransactionData, process: FN) where FN: Fn(&ChannelMonitor, &TransactionData) -> Vec @@ -129,16 +122,6 @@ where C::Target: chain::Filter, } } - /// Dispatches to per-channel monitors, which are responsible for updating their on-chain view - /// of a channel based on the disconnected block. See [`ChannelMonitor::block_disconnected`] for - /// details. - pub fn block_disconnected(&self, header: &BlockHeader, disconnected_height: u32) { - let monitors = self.monitors.read().unwrap(); - for monitor in monitors.values() { - monitor.block_disconnected(header, disconnected_height, &*self.broadcaster, &*self.fee_estimator, &*self.logger); - } - } - /// Creates a new `ChainMonitor` used to watch on-chain activity pertaining to channels. /// /// When an optional chain source implementing [`chain::Filter`] is provided, the chain monitor @@ -158,7 +141,7 @@ where C::Target: chain::Filter, } } -impl +impl chain::Listen for ChainMonitor where ChannelSigner: Sign, @@ -169,12 +152,20 @@ where P::Target: channelmonitor::Persist, { fn block_connected(&self, block: &Block, height: u32) { + let header = &block.header; let txdata: Vec<_> = block.txdata.iter().enumerate().collect(); - ChainMonitor::block_connected(self, &block.header, &txdata, height); + self.process_chain_data(header, &txdata, |monitor, txdata| { + monitor.block_connected( + header, txdata, height, &*self.broadcaster, &*self.fee_estimator, &*self.logger) + }); } fn block_disconnected(&self, header: &BlockHeader, height: u32) { - ChainMonitor::block_disconnected(self, header, height); + let monitors = self.monitors.read().unwrap(); + for monitor in monitors.values() { + monitor.block_disconnected( + header, height, &*self.broadcaster, &*self.fee_estimator, &*self.logger); + } } } diff --git a/lightning/src/ln/chanmon_update_fail_tests.rs b/lightning/src/ln/chanmon_update_fail_tests.rs index a7cc5377a25..ee9936b3329 100644 --- a/lightning/src/ln/chanmon_update_fail_tests.rs +++ b/lightning/src/ln/chanmon_update_fail_tests.rs @@ -12,11 +12,12 @@ //! There are a bunch of these as their handling is relatively error-prone so they are split out //! here. See also the chanmon_fail_consistency fuzz test. -use bitcoin::blockdata::block::BlockHeader; +use bitcoin::blockdata::block::{Block, BlockHeader}; use bitcoin::hash_types::BlockHash; use bitcoin::network::constants::Network; use chain::channelmonitor::{ChannelMonitor, ChannelMonitorUpdateErr}; use chain::transaction::OutPoint; +use chain::Listen; use chain::Watch; use ln::channelmanager::{RAACommitmentOrder, PaymentPreimage, PaymentHash, PaymentSecret, PaymentSendFailure}; use ln::features::InitFeatures; @@ -114,7 +115,7 @@ fn test_monitor_and_persister_update_fail() { chain_mon }; let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 }; - chain_mon.chain_monitor.block_connected(&header, &[], 200); + chain_mon.chain_monitor.block_connected(&Block { header, txdata: vec![] }, 200); // Set the persister's return value to be a TemporaryFailure. persister.set_update_ret(Err(ChannelMonitorUpdateErr::TemporaryFailure)); diff --git a/lightning/src/ln/functional_test_utils.rs b/lightning/src/ln/functional_test_utils.rs index 53d0ad8561f..dce4e6289b9 100644 --- a/lightning/src/ln/functional_test_utils.rs +++ b/lightning/src/ln/functional_test_utils.rs @@ -140,8 +140,8 @@ fn do_connect_block<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, block: &Block, s node.node.best_block_updated(&block.header, height); }, ConnectStyle::FullBlockViaListen => { - node.chain_monitor.chain_monitor.block_connected(&block.header, &txdata, height); - Listen::block_connected(node.node, &block, height); + node.chain_monitor.chain_monitor.block_connected(&block, height); + node.node.block_connected(&block, height); } } } diff --git a/lightning/src/ln/functional_tests.rs b/lightning/src/ln/functional_tests.rs index 9a0c06e776c..731bf7c1b0e 100644 --- a/lightning/src/ln/functional_tests.rs +++ b/lightning/src/ln/functional_tests.rs @@ -12,6 +12,7 @@ //! claim outputs on-chain. use chain; +use chain::Listen; use chain::Watch; use chain::channelmonitor; use chain::channelmonitor::{ChannelMonitor, CLTV_CLAIM_BUFFER, LATENCY_GRACE_PERIOD_BLOCKS, ANTI_REORG_DELAY}; @@ -8225,7 +8226,7 @@ fn test_update_err_monitor_lockdown() { watchtower }; let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 }; - watchtower.chain_monitor.block_connected(&header, &[], 200); + watchtower.chain_monitor.block_connected(&Block { header, txdata: vec![] }, 200); // Try to update ChannelMonitor assert!(nodes[1].node.claim_funds(preimage, &None, 9_000_000)); @@ -8284,7 +8285,7 @@ fn test_concurrent_monitor_claim() { watchtower }; let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 }; - watchtower_alice.chain_monitor.block_connected(&header, &vec![], CHAN_CONFIRM_DEPTH + 1 + TEST_FINAL_CLTV + LATENCY_GRACE_PERIOD_BLOCKS); + watchtower_alice.chain_monitor.block_connected(&Block { header, txdata: vec![] }, CHAN_CONFIRM_DEPTH + 1 + TEST_FINAL_CLTV + LATENCY_GRACE_PERIOD_BLOCKS); // Watchtower Alice should have broadcast a commitment/HTLC-timeout { @@ -8310,7 +8311,7 @@ fn test_concurrent_monitor_claim() { watchtower }; let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 }; - watchtower_bob.chain_monitor.block_connected(&header, &vec![], CHAN_CONFIRM_DEPTH + TEST_FINAL_CLTV + LATENCY_GRACE_PERIOD_BLOCKS); + watchtower_bob.chain_monitor.block_connected(&Block { header, txdata: vec![] }, CHAN_CONFIRM_DEPTH + TEST_FINAL_CLTV + LATENCY_GRACE_PERIOD_BLOCKS); // Route another payment to generate another update with still previous HTLC pending let (_, payment_hash) = get_payment_preimage_hash!(nodes[0]); @@ -8336,7 +8337,8 @@ fn test_concurrent_monitor_claim() { check_added_monitors!(nodes[0], 1); //// Provide one more block to watchtower Bob, expect broadcast of commitment and HTLC-Timeout - watchtower_bob.chain_monitor.block_connected(&header, &vec![], CHAN_CONFIRM_DEPTH + 1 + TEST_FINAL_CLTV + LATENCY_GRACE_PERIOD_BLOCKS); + let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 }; + watchtower_bob.chain_monitor.block_connected(&Block { header, txdata: vec![] }, CHAN_CONFIRM_DEPTH + 1 + TEST_FINAL_CLTV + LATENCY_GRACE_PERIOD_BLOCKS); // Watchtower Bob should have broadcast a commitment/HTLC-timeout let bob_state_y; @@ -8348,7 +8350,8 @@ fn test_concurrent_monitor_claim() { }; // We confirm Bob's state Y on Alice, she should broadcast a HTLC-timeout - watchtower_alice.chain_monitor.block_connected(&header, &vec![(0, &bob_state_y)], CHAN_CONFIRM_DEPTH + 2 + TEST_FINAL_CLTV + LATENCY_GRACE_PERIOD_BLOCKS); + let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 }; + watchtower_alice.chain_monitor.block_connected(&Block { header, txdata: vec![bob_state_y.clone()] }, CHAN_CONFIRM_DEPTH + 2 + TEST_FINAL_CLTV + LATENCY_GRACE_PERIOD_BLOCKS); { let htlc_txn = chanmon_cfgs[0].tx_broadcaster.txn_broadcasted.lock().unwrap(); // We broadcast twice the transaction, once due to the HTLC-timeout, once due