From: Matt Corallo Date: Wed, 24 Feb 2021 20:38:32 +0000 (-0500) Subject: But what about mut? X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=commitdiff_plain;h=refs%2Fheads%2F2021-02-791-mut;p=rust-lightning But what about mut? --- diff --git a/lightning-block-sync/src/init.rs b/lightning-block-sync/src/init.rs index abefd1bcd..50f39e8a2 100644 --- a/lightning-block-sync/src/init.rs +++ b/lightning-block-sync/src/init.rs @@ -80,15 +80,17 @@ use lightning::chain; /// }; /// /// let mut cache = UnboundedCache::new(); -/// let mut monitor_listener = (RefCell::new(monitor), &*tx_broadcaster, &*fee_estimator, &*logger); +/// let mut monitor_listener = channelmonitor::MonitorTraits { +/// monitor: &mut monitor, broadcaster: &*tx_broadcaster, fee_estimator: &*fee_estimator, logger: &*logger +/// }; +/// let mut manager_ref = &manager; /// let listeners = vec![ /// (monitor_block_hash, &mut monitor_listener as &mut dyn chain::Listen), -/// (manager_block_hash, &mut manager as &mut dyn chain::Listen), +/// (manager_block_hash, &mut manager_ref as &mut dyn chain::Listen), /// ]; /// let chain_tip = /// init::sync_listeners(block_source, Network::Bitcoin, &mut cache, listeners).await.unwrap(); /// -/// let monitor = monitor_listener.0.into_inner(); /// chain_monitor.watch_channel(monitor.get_funding_txo().0, monitor); /// /// let chain_poller = poll::ChainPoller::new(block_source, Network::Bitcoin); @@ -132,7 +134,7 @@ pub async fn sync_listeners( // Disconnect any stale blocks, but keep them in the cache for the next iteration. let header_cache = &mut ReadOnlyCache(header_cache); let (common_ancestor, connected_blocks) = { - let chain_listener = &DynamicChainListener(chain_listener); + let chain_listener = DynamicChainListener(chain_listener); let mut chain_notifier = ChainNotifier { header_cache, chain_listener }; let difference = chain_notifier.find_difference(new_header, &old_header, &mut chain_poller).await?; @@ -150,7 +152,7 @@ pub async fn sync_listeners( // Connect new blocks for all listeners at once to avoid re-fetching blocks. if let Some(common_ancestor) = most_common_ancestor { - let chain_listener = &ChainListenerSet(chain_listeners_at_height); + let chain_listener = ChainListenerSet(chain_listeners_at_height); let mut chain_notifier = ChainNotifier { header_cache, chain_listener }; chain_notifier.connect_blocks(common_ancestor, most_connected_blocks, &mut chain_poller) .await.or_else(|(e, _)| Err(e))?; @@ -183,11 +185,11 @@ impl<'a, C: Cache> Cache for ReadOnlyCache<'a, C> { struct DynamicChainListener<'a>(&'a mut dyn chain::Listen); impl<'a> chain::Listen for DynamicChainListener<'a> { - fn block_connected(&self, _block: &Block, _height: u32) { + fn block_connected(&mut self, _block: &Block, _height: u32) { unreachable!() } - fn block_disconnected(&self, header: &BlockHeader, height: u32) { + fn block_disconnected(&mut self, header: &BlockHeader, height: u32) { self.0.block_disconnected(header, height) } } @@ -196,15 +198,15 @@ impl<'a> chain::Listen for DynamicChainListener<'a> { struct ChainListenerSet<'a>(Vec<(u32, &'a mut dyn chain::Listen)>); impl<'a> chain::Listen for ChainListenerSet<'a> { - fn block_connected(&self, block: &Block, height: u32) { - for (starting_height, chain_listener) in self.0.iter() { + fn block_connected(&mut self, block: &Block, height: u32) { + for (starting_height, chain_listener) in self.0.iter_mut() { if height > *starting_height { chain_listener.block_connected(block, height); } } } - fn block_disconnected(&self, _header: &BlockHeader, _height: u32) { + fn block_disconnected(&mut self, _header: &BlockHeader, _height: u32) { unreachable!() } } diff --git a/lightning-block-sync/src/lib.rs b/lightning-block-sync/src/lib.rs index f7e9db97f..614026856 100644 --- a/lightning-block-sync/src/lib.rs +++ b/lightning-block-sync/src/lib.rs @@ -159,8 +159,7 @@ pub struct BlockHeaderData { /// custom cache eviction policy. This offers flexibility to those sensitive to resource usage. /// Hence, there is a trade-off between a lower memory footprint and potentially increased network /// I/O as headers are re-fetched during fork detection. -pub struct SpvClient<'a, P: Poll, C: Cache, L: Deref> -where L::Target: chain::Listen { +pub struct SpvClient<'a, P: Poll, C: Cache, L: chain::Listen> { chain_tip: ValidatedBlockHeader, chain_poller: P, chain_notifier: ChainNotifier<'a, C, L>, @@ -208,7 +207,7 @@ impl Cache for UnboundedCache { } } -impl<'a, P: Poll, C: Cache, L: Deref> SpvClient<'a, P, C, L> where L::Target: chain::Listen { +impl<'a, P: Poll, C: Cache, L: chain::Listen> SpvClient<'a, P, C, L> { /// Creates a new SPV client using `chain_tip` as the best known chain tip. /// /// Subsequent calls to [`poll_best_tip`] will poll for the best chain tip using the given chain @@ -272,7 +271,7 @@ impl<'a, P: Poll, C: Cache, L: Deref> SpvClient<'a, P, C, L> where L::Target: ch /// Notifies [listeners] of blocks that have been connected or disconnected from the chain. /// /// [listeners]: ../../lightning/chain/trait.Listen.html -pub struct ChainNotifier<'a, C: Cache, L: Deref> where L::Target: chain::Listen { +pub struct ChainNotifier<'a, C: Cache, L: chain::Listen> { /// Cache for looking up headers before fetching from a block source. header_cache: &'a mut C, @@ -298,7 +297,7 @@ struct ChainDifference { connected_blocks: Vec, } -impl<'a, C: Cache, L: Deref> ChainNotifier<'a, C, L> where L::Target: chain::Listen { +impl<'a, C: Cache, L: chain::Listen> ChainNotifier<'a, C, L> { /// Finds the first common ancestor between `new_header` and `old_header`, disconnecting blocks /// from `old_header` to get to that point and then connecting blocks until `new_header`. /// @@ -419,8 +418,8 @@ mod spv_client_tests { let poller = poll::ChainPoller::new(&mut chain, Network::Testnet); let mut cache = UnboundedCache::new(); - let mut listener = NullChainListener {}; - let mut client = SpvClient::new(best_tip, poller, &mut cache, &mut listener); + let listener = NullChainListener {}; + let mut client = SpvClient::new(best_tip, poller, &mut cache, listener); match client.poll_best_tip().await { Err(e) => { assert_eq!(e.kind(), BlockSourceErrorKind::Persistent); @@ -438,8 +437,8 @@ mod spv_client_tests { let poller = poll::ChainPoller::new(&mut chain, Network::Testnet); let mut cache = UnboundedCache::new(); - let mut listener = NullChainListener {}; - let mut client = SpvClient::new(common_tip, poller, &mut cache, &mut listener); + let listener = NullChainListener {}; + let mut client = SpvClient::new(common_tip, poller, &mut cache, listener); match client.poll_best_tip().await { Err(e) => panic!("Unexpected error: {:?}", e), Ok((chain_tip, blocks_connected)) => { @@ -458,8 +457,8 @@ mod spv_client_tests { let poller = poll::ChainPoller::new(&mut chain, Network::Testnet); let mut cache = UnboundedCache::new(); - let mut listener = NullChainListener {}; - let mut client = SpvClient::new(old_tip, poller, &mut cache, &mut listener); + let listener = NullChainListener {}; + let mut client = SpvClient::new(old_tip, poller, &mut cache, listener); match client.poll_best_tip().await { Err(e) => panic!("Unexpected error: {:?}", e), Ok((chain_tip, blocks_connected)) => { @@ -478,8 +477,8 @@ mod spv_client_tests { let poller = poll::ChainPoller::new(&mut chain, Network::Testnet); let mut cache = UnboundedCache::new(); - let mut listener = NullChainListener {}; - let mut client = SpvClient::new(old_tip, poller, &mut cache, &mut listener); + let listener = NullChainListener {}; + let mut client = SpvClient::new(old_tip, poller, &mut cache, listener); match client.poll_best_tip().await { Err(e) => panic!("Unexpected error: {:?}", e), Ok((chain_tip, blocks_connected)) => { @@ -498,8 +497,8 @@ mod spv_client_tests { let poller = poll::ChainPoller::new(&mut chain, Network::Testnet); let mut cache = UnboundedCache::new(); - let mut listener = NullChainListener {}; - let mut client = SpvClient::new(old_tip, poller, &mut cache, &mut listener); + let listener = NullChainListener {}; + let mut client = SpvClient::new(old_tip, poller, &mut cache, listener); match client.poll_best_tip().await { Err(e) => panic!("Unexpected error: {:?}", e), Ok((chain_tip, blocks_connected)) => { @@ -519,8 +518,8 @@ mod spv_client_tests { let poller = poll::ChainPoller::new(&mut chain, Network::Testnet); let mut cache = UnboundedCache::new(); - let mut listener = NullChainListener {}; - let mut client = SpvClient::new(best_tip, poller, &mut cache, &mut listener); + let listener = NullChainListener {}; + let mut client = SpvClient::new(best_tip, poller, &mut cache, listener); match client.poll_best_tip().await { Err(e) => panic!("Unexpected error: {:?}", e), Ok((chain_tip, blocks_connected)) => { @@ -545,7 +544,7 @@ mod chain_notifier_tests { let new_tip = chain.tip(); let old_tip = chain.at_height(1); - let chain_listener = &MockChainListener::new() + let chain_listener = MockChainListener::new() .expect_block_connected(*chain.at_height(2)) .expect_block_connected(*new_tip); let mut notifier = ChainNotifier { @@ -566,7 +565,7 @@ mod chain_notifier_tests { let new_tip = test_chain.tip(); let old_tip = main_chain.tip(); - let chain_listener = &MockChainListener::new(); + let chain_listener = MockChainListener::new(); let mut notifier = ChainNotifier { header_cache: &mut main_chain.header_cache(0..=1), chain_listener, @@ -588,7 +587,7 @@ mod chain_notifier_tests { let new_tip = fork_chain.tip(); let old_tip = main_chain.tip(); - let chain_listener = &MockChainListener::new() + let chain_listener = MockChainListener::new() .expect_block_disconnected(*old_tip) .expect_block_connected(*new_tip); let mut notifier = ChainNotifier { @@ -610,7 +609,7 @@ mod chain_notifier_tests { let new_tip = fork_chain.tip(); let old_tip = main_chain.tip(); - let chain_listener = &MockChainListener::new() + let chain_listener = MockChainListener::new() .expect_block_disconnected(*old_tip) .expect_block_disconnected(*main_chain.at_height(2)) .expect_block_connected(*new_tip); @@ -633,7 +632,7 @@ mod chain_notifier_tests { let new_tip = fork_chain.tip(); let old_tip = main_chain.tip(); - let chain_listener = &MockChainListener::new() + let chain_listener = MockChainListener::new() .expect_block_disconnected(*old_tip) .expect_block_connected(*fork_chain.at_height(2)) .expect_block_connected(*new_tip); @@ -654,7 +653,7 @@ mod chain_notifier_tests { let new_tip = chain.tip(); let old_tip = chain.at_height(1); - let chain_listener = &MockChainListener::new(); + let chain_listener = MockChainListener::new(); let mut notifier = ChainNotifier { header_cache: &mut chain.header_cache(0..=1), chain_listener, @@ -672,7 +671,7 @@ mod chain_notifier_tests { let new_tip = chain.tip(); let old_tip = chain.at_height(1); - let chain_listener = &MockChainListener::new(); + let chain_listener = MockChainListener::new(); let mut notifier = ChainNotifier { header_cache: &mut chain.header_cache(0..=3), chain_listener, @@ -690,7 +689,7 @@ mod chain_notifier_tests { let new_tip = chain.tip(); let old_tip = chain.at_height(1); - let chain_listener = &MockChainListener::new() + let chain_listener = MockChainListener::new() .expect_block_connected(*chain.at_height(2)); let mut notifier = ChainNotifier { header_cache: &mut chain.header_cache(0..=3), diff --git a/lightning-block-sync/src/test_utils.rs b/lightning-block-sync/src/test_utils.rs index 8c37c94d8..093266e3e 100644 --- a/lightning-block-sync/src/test_utils.rs +++ b/lightning-block-sync/src/test_utils.rs @@ -166,8 +166,8 @@ impl BlockSource for Blockchain { pub struct NullChainListener; impl chain::Listen for NullChainListener { - fn block_connected(&self, _block: &Block, _height: u32) {} - fn block_disconnected(&self, _header: &BlockHeader, _height: u32) {} + fn block_connected(&mut self, _block: &Block, _height: u32) {} + fn block_disconnected(&mut self, _header: &BlockHeader, _height: u32) {} } pub struct MockChainListener { @@ -195,7 +195,7 @@ impl MockChainListener { } impl chain::Listen for MockChainListener { - fn block_connected(&self, block: &Block, height: u32) { + fn block_connected(&mut self, block: &Block, height: u32) { match self.expected_blocks_connected.borrow_mut().pop_front() { None => { panic!("Unexpected block connected: {:?}", block.block_hash()); @@ -207,7 +207,7 @@ impl chain::Listen for MockChainListener { } } - fn block_disconnected(&self, header: &BlockHeader, height: u32) { + fn block_disconnected(&mut self, header: &BlockHeader, height: u32) { match self.expected_blocks_disconnected.borrow_mut().pop_front() { None => { panic!("Unexpected block disconnected: {:?}", header.block_hash()); diff --git a/lightning/src/chain/chainmonitor.rs b/lightning/src/chain/chainmonitor.rs index 4cb9128d9..a3d0d22b1 100644 --- a/lightning/src/chain/chainmonitor.rs +++ b/lightning/src/chain/chainmonitor.rs @@ -141,7 +141,7 @@ where C::Target: chain::Filter, } impl -chain::Listen for ChainMonitor +chain::sealed::DerefListen for ChainMonitor where ChannelSigner: Sign, C::Target: chain::Filter, diff --git a/lightning/src/chain/channelmonitor.rs b/lightning/src/chain/channelmonitor.rs index 71490dd6e..4e2ca659f 100644 --- a/lightning/src/chain/channelmonitor.rs +++ b/lightning/src/chain/channelmonitor.rs @@ -53,7 +53,7 @@ use util::events::Event; use std::cell::RefCell; use std::collections::{HashMap, HashSet, hash_map}; use std::{cmp, mem}; -use std::ops::Deref; +use std::ops::{Deref, DerefMut}; use std::io::Error; /// An update generated by the underlying Channel itself which contains some new information the @@ -2299,19 +2299,33 @@ pub trait Persist: Send + Sync { fn update_persisted_channel(&self, id: OutPoint, update: &ChannelMonitorUpdate, data: &ChannelMonitor) -> Result<(), ChannelMonitorUpdateErr>; } -impl chain::Listen for (RefCell>, T, F, L) + +/// does things +pub struct MonitorTraits>, Signer: Sign, T: Deref, F: Deref, L: Deref> { + /// a + pub monitor: CM, + /// b + pub broadcaster: T, + /// c + pub fee_estimator: F, + /// d + pub logger: L, +} + +impl>, Signer: Sign, T: Deref, F: Deref, L: Deref> +chain::Listen for MonitorTraits where T::Target: BroadcasterInterface, F::Target: FeeEstimator, L::Target: Logger, { - fn block_connected(&self, block: &Block, height: u32) { + fn block_connected(&mut self, block: &Block, height: u32) { let txdata: Vec<_> = block.txdata.iter().enumerate().collect(); - self.0.borrow_mut().block_connected(&block.header, &txdata, height, &*self.1, &*self.2, &*self.3); + self.monitor.block_connected(&block.header, &txdata, height, &*self.broadcaster, &*self.fee_estimator, &*self.logger); } - fn block_disconnected(&self, header: &BlockHeader, height: u32) { - self.0.borrow_mut().block_disconnected(header, height, &*self.1, &*self.2, &*self.3); + fn block_disconnected(&mut self, header: &BlockHeader, height: u32) { + self.monitor.block_disconnected(header, height, &*self.broadcaster, &*self.fee_estimator, &*self.logger); } } diff --git a/lightning/src/chain/mod.rs b/lightning/src/chain/mod.rs index c1fceec8c..86f35ebca 100644 --- a/lightning/src/chain/mod.rs +++ b/lightning/src/chain/mod.rs @@ -18,6 +18,8 @@ use chain::channelmonitor::{ChannelMonitor, ChannelMonitorUpdate, ChannelMonitor use chain::keysinterface::Sign; use chain::transaction::OutPoint; +use std::ops::Deref; + pub mod chaininterface; pub mod chainmonitor; pub mod channelmonitor; @@ -53,12 +55,44 @@ pub trait Access: Send + Sync { /// Useful when needing to replay chain data upon startup or as new chain events occur. pub trait Listen { /// Notifies the listener that a block was added at the given height. - fn block_connected(&self, block: &Block, height: u32); + fn block_connected(&mut self, block: &Block, height: u32); /// Notifies the listener that a block was removed at the given height. - fn block_disconnected(&self, header: &BlockHeader, height: u32); + fn block_disconnected(&mut self, header: &BlockHeader, height: u32); +} + +pub(crate) mod sealed { + use super::*; + /// Rustc currently isn't smart enough to figure out that two impls are not conflicting when they + /// both impl for `Deref` but with a different `Target` + /// (https://github.com/rust-lang/rust/issues/20400). Instead, we use the workaround suggested at + /// https://stackoverflow.com/questions/40392524/conflicting-trait-implementations-even-though-associated-types-differ/40408431#40408431 + pub trait DerefListen { + fn block_connected(&self, block: &Block, height: u32); + fn block_disconnected(&self, header: &BlockHeader, height: u32); + } + impl DerefListen for (T, U) where T::Target: DerefListen, U::Target: DerefListen { + fn block_connected(&self, block: &Block, height: u32) { + Deref::deref(&self.0).block_connected(block, height); + Deref::deref(&self.1).block_connected(block, height); + } + + fn block_disconnected(&self, header: &BlockHeader, height: u32) { + Deref::deref(&self.0).block_disconnected(header, height); + Deref::deref(&self.1).block_disconnected(header, height); + } + } +} +impl Listen for T where T::Target: sealed::DerefListen { + fn block_connected(&mut self, block: &Block, height: u32) { + sealed::DerefListen::block_connected(Deref::deref(self), block, height); + } + fn block_disconnected(&mut self, header: &BlockHeader, height: u32) { + sealed::DerefListen::block_disconnected(Deref::deref(self), header, height); + } } + /// The `Watch` trait defines behavior for watching on-chain activity pertaining to channels as /// blocks are connected and disconnected. /// @@ -136,29 +170,3 @@ pub trait Filter: Send + Sync { /// `script_pubkey` as the spending condition. fn register_output(&self, outpoint: &OutPoint, script_pubkey: &Script); } - -impl Listen for std::ops::Deref { - fn block_connected(&self, block: &Block, height: u32) { - (**self).block_connected(block, height); - } - - fn block_disconnected(&self, header: &BlockHeader, height: u32) { - (**self).block_disconnected(header, height); - } -} - -impl Listen for (T, U) -where - T::Target: Listen, - U::Target: Listen, -{ - fn block_connected(&self, block: &Block, height: u32) { - self.0.block_connected(block, height); - self.1.block_connected(block, height); - } - - fn block_disconnected(&self, header: &BlockHeader, height: u32) { - self.0.block_disconnected(header, height); - self.1.block_disconnected(header, height); - } -} diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index 8f7fbde5f..ec2f1e4cc 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -3139,7 +3139,7 @@ impl EventsProvi } } -impl chain::Listen for ChannelManager +impl chain::sealed::DerefListen for ChannelManager where M::Target: chain::Watch, T::Target: BroadcasterInterface,