From 7d6234662cb49d38dcd792ef8034e5111401e75e Mon Sep 17 00:00:00 2001 From: Ryan Loomba Date: Sat, 15 Feb 2020 00:04:09 -0800 Subject: [PATCH] add functionality for BlockNotifier to unregister a previously registered listener, in order to no longer receive events --- lightning/src/chain/chaininterface.rs | 87 ++++++++++++++++++++++++++- lightning/src/ln/mod.rs | 3 +- 2 files changed, 88 insertions(+), 2 deletions(-) diff --git a/lightning/src/chain/chaininterface.rs b/lightning/src/chain/chaininterface.rs index 0845eb5fc..ad08c817d 100644 --- a/lightning/src/chain/chaininterface.rs +++ b/lightning/src/chain/chaininterface.rs @@ -19,6 +19,7 @@ use std::sync::atomic::{AtomicUsize, Ordering}; use std::collections::HashSet; use std::ops::Deref; use std::marker::PhantomData; +use std::ptr; /// Used to give chain error details upstream pub enum ChainError { @@ -252,11 +253,22 @@ impl<'a, CL: Deref + 'a> BlockNotifier<'a, CL> { } /// Register the given listener to receive events. - // TODO: unregister 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 given a full, unfiltered block. /// @@ -376,3 +388,76 @@ impl ChainWatchInterfaceUtil { watched.does_match_tx(tx) } } + +#[cfg(test)] +mod tests { + use ln::functional_test_utils::{create_node_cfgs}; + use super::{BlockNotifier, ChainListener}; + use std::ptr; + + #[test] + fn register_listener_test() { + let node_cfgs = create_node_cfgs(1); + let block_notifier = BlockNotifier::new(node_cfgs[0].chain_monitor.clone()); + assert_eq!(block_notifier.listeners.lock().unwrap().len(), 0); + let listener = &node_cfgs[0].chan_monitor.simple_monitor as &ChainListener; + block_notifier.register_listener(listener); + let vec = block_notifier.listeners.lock().unwrap(); + assert_eq!(vec.len(), 1); + let item = vec.first().clone().unwrap(); + assert!(ptr::eq(&(**item), &(*listener))); + } + + #[test] + fn unregister_single_listener_test() { + let node_cfgs = create_node_cfgs(2); + let block_notifier = BlockNotifier::new(node_cfgs[0].chain_monitor.clone()); + let listener1 = &node_cfgs[0].chan_monitor.simple_monitor as &ChainListener; + let listener2 = &node_cfgs[1].chan_monitor.simple_monitor as &ChainListener; + block_notifier.register_listener(listener1); + block_notifier.register_listener(listener2); + 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().clone().unwrap(); + assert!(ptr::eq(&(**item), &(*listener2))); + } + + #[test] + fn unregister_single_listener_ref_test() { + let node_cfgs = create_node_cfgs(2); + let block_notifier = BlockNotifier::new(node_cfgs[0].chain_monitor.clone()); + block_notifier.register_listener(&node_cfgs[0].chan_monitor.simple_monitor as &ChainListener); + block_notifier.register_listener(&node_cfgs[1].chan_monitor.simple_monitor as &ChainListener); + let vec = block_notifier.listeners.lock().unwrap(); + assert_eq!(vec.len(), 2); + drop(vec); + block_notifier.unregister_listener(&node_cfgs[0].chan_monitor.simple_monitor); + let vec = block_notifier.listeners.lock().unwrap(); + assert_eq!(vec.len(), 1); + let item = vec.first().clone().unwrap(); + assert!(ptr::eq(&(**item), &(*&node_cfgs[1].chan_monitor.simple_monitor))); + } + + #[test] + fn unregister_multiple_of_the_same_listeners_test() { + let node_cfgs = create_node_cfgs(2); + let block_notifier = BlockNotifier::new(node_cfgs[0].chain_monitor.clone()); + let listener1 = &node_cfgs[0].chan_monitor.simple_monitor as &ChainListener; + let listener2 = &node_cfgs[1].chan_monitor.simple_monitor as &ChainListener; + block_notifier.register_listener(listener1); + block_notifier.register_listener(listener1); + block_notifier.register_listener(listener2); + 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().clone().unwrap(); + assert!(ptr::eq(&(**item), &(*listener2))); + } +} diff --git a/lightning/src/ln/mod.rs b/lightning/src/ln/mod.rs index 9a2a90fd4..14864ddb5 100644 --- a/lightning/src/ln/mod.rs +++ b/lightning/src/ln/mod.rs @@ -27,7 +27,8 @@ mod onion_utils; mod wire; #[cfg(test)] -#[macro_use] mod functional_test_utils; +#[macro_use] +pub(crate) mod functional_test_utils; #[cfg(test)] mod functional_tests; #[cfg(test)] -- 2.39.5