From 382c71cb2609941bee0c37ad7ac2a15205a503d6 Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Tue, 28 Jul 2020 18:08:46 -0700 Subject: [PATCH] Remove BlockNotifier BlockNotifier is a convenience for handing blocks to listeners. However, it requires that each listener conforms to the ChainListener interface. Additionally, there are only two listeners, ChannelManager and ChainMonitor, the latter of which may not be used when monitoring channels remotely. Remove BlockNotifier since it doesn't provide much value and constrains each listener to a specific interface. --- lightning/src/chain/chaininterface.rs | 140 +--------------------- lightning/src/ln/channelmanager.rs | 4 - lightning/src/ln/functional_test_utils.rs | 12 +- lightning/src/ln/functional_tests.rs | 8 +- 4 files changed, 6 insertions(+), 158 deletions(-) diff --git a/lightning/src/chain/chaininterface.rs b/lightning/src/chain/chaininterface.rs index 60c9c9ff0..2b56853df 100644 --- a/lightning/src/chain/chaininterface.rs +++ b/lightning/src/chain/chaininterface.rs @@ -4,16 +4,12 @@ //! Includes traits for monitoring and receiving notifications of new blocks and block //! disconnections, transaction broadcasting, and feerate information requests. -use bitcoin::blockdata::block::{Block, BlockHeader}; +use bitcoin::blockdata::block::BlockHeader; use bitcoin::blockdata::transaction::Transaction; use bitcoin::blockdata::script::Script; use bitcoin::hash_types::Txid; -use std::sync::{Mutex, Arc}; use std::collections::HashSet; -use std::ops::Deref; -use std::marker::PhantomData; -use std::ptr; /// An interface to send a transaction to the Bitcoin network. pub trait BroadcasterInterface: Sync + Send { @@ -152,137 +148,3 @@ impl ChainWatchedUtil { false } } - -/// BlockNotifierArc is useful when you need a BlockNotifier that points to ChainListeners with -/// static lifetimes, e.g. when you're using lightning-net-tokio (since tokio::spawn requires -/// parameters with static lifetimes). Other times you can afford a reference, which is more -/// efficient, in which case BlockNotifierRef is a more appropriate type. Defining these type -/// aliases prevents issues such as overly long function definitions. -pub type BlockNotifierArc = Arc>>; - -/// BlockNotifierRef is useful when you want a BlockNotifier that points to ChainListeners -/// with nonstatic lifetimes. This is useful for when static lifetimes are not needed. Nonstatic -/// lifetimes are more efficient but less flexible, and should be used by default unless static -/// lifetimes are required, e.g. when you're using lightning-net-tokio (since tokio::spawn -/// requires parameters with static lifetimes), in which case BlockNotifierArc is a more -/// appropriate type. Defining these type aliases for common usages prevents issues such as -/// overly long function definitions. -pub type BlockNotifierRef<'a> = BlockNotifier<'a, &'a ChainListener>; - -/// Utility for notifying listeners when blocks are connected or disconnected. -/// -/// Rather than using a plain BlockNotifier, it is preferable to use either a BlockNotifierArc -/// or a BlockNotifierRef for conciseness. See their documentation for more details, but essentially -/// you should default to using a BlockNotifierRef, and use a BlockNotifierArc instead when you -/// require ChainListeners with static lifetimes, such as when you're using lightning-net-tokio. -pub struct BlockNotifier<'a, CL: Deref + 'a> { - listeners: Mutex>, - phantom: PhantomData<&'a ()>, -} - -impl<'a, CL: Deref + 'a> BlockNotifier<'a, CL> { - /// Constructs a new BlockNotifier without any listeners. - pub fn new() -> BlockNotifier<'a, CL> { - BlockNotifier { - listeners: Mutex::new(Vec::new()), - phantom: PhantomData, - } - } - - /// Register the given listener to receive events. - pub fn register_listener(&self, listener: CL) { - let mut vec = self.listeners.lock().unwrap(); - vec.push(listener); - } - /// Unregister the given listener to no longer - /// receive events. - /// - /// If the same listener is registered multiple times, unregistering - /// will remove ALL occurrences of that listener. Comparison is done using - /// the pointer returned by the Deref trait implementation. - pub fn unregister_listener(&self, listener: CL) { - let mut vec = self.listeners.lock().unwrap(); - // item is a ref to an abstract thing that dereferences to a ChainListener, - // so dereference it twice to get the ChainListener itself - vec.retain(|item | !ptr::eq(&(**item), &(*listener))); - } - - /// Notify listeners that a block was connected. - pub fn block_connected(&self, block: &Block, height: u32) { - let txdata: Vec<_> = block.txdata.iter().enumerate().collect(); - let listeners = self.listeners.lock().unwrap(); - for listener in listeners.iter() { - listener.block_connected(&block.header, &txdata, height); - } - } - - /// Notify listeners that a block was disconnected. - pub fn block_disconnected(&self, header: &BlockHeader, disconnected_height: u32) { - let listeners = self.listeners.lock().unwrap(); - for listener in listeners.iter() { - listener.block_disconnected(&header, disconnected_height); - } - } -} - -#[cfg(test)] -mod tests { - use bitcoin::blockdata::block::BlockHeader; - use bitcoin::blockdata::transaction::Transaction; - use super::{BlockNotifier, ChainListener}; - use std::ptr; - - struct TestChainListener(u8); - - impl ChainListener for TestChainListener { - fn block_connected(&self, _header: &BlockHeader, _txdata: &[(usize, &Transaction)], _height: u32) {} - fn block_disconnected(&self, _header: &BlockHeader, _disconnected_height: u32) {} - } - - #[test] - fn register_listener_test() { - let block_notifier = BlockNotifier::new(); - assert_eq!(block_notifier.listeners.lock().unwrap().len(), 0); - let listener = &TestChainListener(0); - block_notifier.register_listener(listener as &ChainListener); - let vec = block_notifier.listeners.lock().unwrap(); - assert_eq!(vec.len(), 1); - let item = vec.first().unwrap(); - assert!(ptr::eq(&(**item), listener)); - } - - #[test] - fn unregister_single_listener_test() { - let block_notifier = BlockNotifier::new(); - let listener1 = &TestChainListener(1); - let listener2 = &TestChainListener(2); - block_notifier.register_listener(listener1 as &ChainListener); - block_notifier.register_listener(listener2 as &ChainListener); - let vec = block_notifier.listeners.lock().unwrap(); - assert_eq!(vec.len(), 2); - drop(vec); - block_notifier.unregister_listener(listener1); - let vec = block_notifier.listeners.lock().unwrap(); - assert_eq!(vec.len(), 1); - let item = vec.first().unwrap(); - assert!(ptr::eq(&(**item), listener2)); - } - - #[test] - fn unregister_multiple_of_the_same_listeners_test() { - let block_notifier = BlockNotifier::new(); - let listener1 = &TestChainListener(1); - let listener2 = &TestChainListener(2); - block_notifier.register_listener(listener1 as &ChainListener); - block_notifier.register_listener(listener1 as &ChainListener); - block_notifier.register_listener(listener2 as &ChainListener); - let vec = block_notifier.listeners.lock().unwrap(); - assert_eq!(vec.len(), 3); - drop(vec); - block_notifier.unregister_listener(listener1); - let vec = block_notifier.listeners.lock().unwrap(); - assert_eq!(vec.len(), 1); - let item = vec.first().unwrap(); - assert!(ptr::eq(&(**item), listener2)); - } -} diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index 006a71284..1dad51b1c 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -706,10 +706,6 @@ impl /// /// Users need to notify the new ChannelManager when a new block is connected or /// disconnected using its `block_connected` and `block_disconnected` methods. - /// However, rather than calling these methods directly, the user should register - /// the ChannelManager as a listener to the BlockNotifier and call the BlockNotifier's - /// `block_(dis)connected` methods, which will notify all registered listeners in one - /// go. pub fn new(network: Network, fee_est: F, chain_monitor: M, tx_broadcaster: T, logger: L, keys_manager: K, config: UserConfig, current_blockchain_height: usize) -> Self { let secp_ctx = Secp256k1::new(); diff --git a/lightning/src/ln/functional_test_utils.rs b/lightning/src/ln/functional_test_utils.rs index 871e0577d..3284ba757 100644 --- a/lightning/src/ln/functional_test_utils.rs +++ b/lightning/src/ln/functional_test_utils.rs @@ -3,7 +3,7 @@ use chain; use chain::Watch; -use chain::chaininterface; +use chain::chaininterface::ChainListener; use chain::transaction::OutPoint; use ln::channelmanager::{ChannelManager, ChannelManagerReadArgs, RAACommitmentOrder, PaymentPreimage, PaymentHash, PaymentSecret, PaymentSendFailure}; use ln::channelmonitor::ChannelMonitor; @@ -75,7 +75,6 @@ pub fn connect_blocks<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, depth: u32, he pub fn connect_block<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, block: &Block, height: u32) { use chain::WatchEventProvider; - use chain::chaininterface::ChainListener; let watch_events = node.chain_monitor.chain_monitor.release_pending_watch_events(); process_chain_watch_events(&watch_events); @@ -98,7 +97,8 @@ pub fn connect_block<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, block: &Block, fn process_chain_watch_events(_events: &Vec) {} pub fn disconnect_block<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, header: &BlockHeader, height: u32) { - node.block_notifier.block_disconnected(header, height) + node.chain_monitor.chain_monitor.block_disconnected(header, height); + node.node.block_disconnected(header, height); } pub struct TestChanMonCfg { @@ -119,7 +119,6 @@ pub struct NodeCfg<'a> { } pub struct Node<'a, 'b: 'a, 'c: 'b> { - pub block_notifier: chaininterface::BlockNotifierRef<'a>, pub chain_source: &'c test_utils::TestChainSource, pub tx_broadcaster: &'c test_utils::TestBroadcaster, pub chain_monitor: &'b test_utils::TestChainMonitor<'c>, @@ -1141,11 +1140,8 @@ pub fn create_network<'a, 'b: 'a, 'c: 'b>(node_count: usize, cfgs: &'b Vec