@@ -19,6 +19,7 @@ use std::sync::atomic::{AtomicUsize, Ordering};
1919use std:: collections:: HashSet ;
2020use std:: ops:: Deref ;
2121use std:: marker:: PhantomData ;
22+ use std:: ptr:: eq as ptr_eq;
2223
2324/// Used to give chain error details upstream
2425pub enum ChainError {
@@ -252,12 +253,21 @@ impl<'a, CL: Deref<Target = ChainListener + 'a> + 'a> BlockNotifier<'a, CL> {
252253 }
253254
254255 /// Register the given listener to receive events.
255- // TODO: unregister
256256 pub fn register_listener ( & self , listener : CL ) {
257257 let mut vec = self . listeners . lock ( ) . unwrap ( ) ;
258258 vec. push ( listener) ;
259259 }
260260
261+ /// Unregister the given listener to no longer
262+ /// receive events.
263+ ///
264+ /// If the same listener is registered multiple times, unregistering
265+ /// will remove ALL occurrences of that listener.
266+ pub fn unregister_listener ( & self , listener : CL ) {
267+ let mut vec = self . listeners . lock ( ) . unwrap ( ) ;
268+ vec. retain ( |item| !ptr_eq ( & ( * * item) as * const _ , & ( * listener) as * const _ ) ) ;
269+ }
270+
261271 /// Notify listeners that a block was connected given a full, unfiltered block.
262272 ///
263273 /// Handles re-scanning the block and calling block_connected again if listeners register new
@@ -376,3 +386,59 @@ impl ChainWatchInterfaceUtil {
376386 watched. does_match_tx ( tx)
377387 }
378388}
389+
390+ #[ cfg( test) ]
391+ mod tests {
392+ use ln:: functional_test_utils:: { create_node_cfgs} ;
393+ use super :: { BlockNotifier , ChainListener } ;
394+ use std:: ptr:: eq as ptr_eq;
395+
396+ #[ test]
397+ fn register_listener_test ( ) {
398+ let node_cfgs = create_node_cfgs ( 1 ) ;
399+ let block_notifier = BlockNotifier :: new ( node_cfgs[ 0 ] . chain_monitor . clone ( ) ) ;
400+ let listener = & node_cfgs[ 0 ] . chan_monitor . simple_monitor as & ChainListener ;
401+ block_notifier. register_listener ( listener) ;
402+ let vec = block_notifier. listeners . lock ( ) . unwrap ( ) ;
403+ assert_eq ! ( vec. len( ) , 1 ) ;
404+ let item = vec. first ( ) . clone ( ) . unwrap ( ) ;
405+ assert ! ( ptr_eq( & ( * * item) as * const _, & ( * listener) as * const _) ) ;
406+ }
407+
408+ #[ test]
409+ fn unregister_single_listener_test ( ) {
410+ let node_cfgs = create_node_cfgs ( 2 ) ;
411+ let block_notifier = BlockNotifier :: new ( node_cfgs[ 0 ] . chain_monitor . clone ( ) ) ;
412+ let listener1 = & node_cfgs[ 0 ] . chan_monitor . simple_monitor as & ChainListener ;
413+ let listener2 = & node_cfgs[ 1 ] . chan_monitor . simple_monitor as & ChainListener ;
414+ block_notifier. register_listener ( listener1) ;
415+ block_notifier. register_listener ( listener2) ;
416+ let vec = block_notifier. listeners . lock ( ) . unwrap ( ) ;
417+ assert_eq ! ( vec. len( ) , 2 ) ;
418+ drop ( vec) ;
419+ block_notifier. unregister_listener ( listener1) ;
420+ let vec = block_notifier. listeners . lock ( ) . unwrap ( ) ;
421+ assert_eq ! ( vec. len( ) , 1 ) ;
422+ let item = vec. first ( ) . clone ( ) . unwrap ( ) ;
423+ assert ! ( ptr_eq( & ( * * item) as * const _, & ( * listener2) as * const _) ) ;
424+ }
425+
426+ #[ test]
427+ fn unregister_multiple_of_the_same_listeners_test ( ) {
428+ let node_cfgs = create_node_cfgs ( 2 ) ;
429+ let block_notifier = BlockNotifier :: new ( node_cfgs[ 0 ] . chain_monitor . clone ( ) ) ;
430+ let listener1 = & node_cfgs[ 0 ] . chan_monitor . simple_monitor as & ChainListener ;
431+ let listener2 = & node_cfgs[ 1 ] . chan_monitor . simple_monitor as & ChainListener ;
432+ block_notifier. register_listener ( listener1) ;
433+ block_notifier. register_listener ( listener1) ;
434+ block_notifier. register_listener ( listener2) ;
435+ let vec = block_notifier. listeners . lock ( ) . unwrap ( ) ;
436+ assert_eq ! ( vec. len( ) , 3 ) ;
437+ drop ( vec) ;
438+ block_notifier. unregister_listener ( listener1) ;
439+ let vec = block_notifier. listeners . lock ( ) . unwrap ( ) ;
440+ assert_eq ! ( vec. len( ) , 1 ) ;
441+ let item = vec. first ( ) . clone ( ) . unwrap ( ) ;
442+ assert ! ( ptr_eq( & ( * * item) as * const _, & ( * listener2) as * const _) ) ;
443+ }
444+ }
0 commit comments