@@ -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;
2223
2324/// Used to give chain error details upstream
2425pub enum ChainError {
@@ -253,11 +254,22 @@ impl<'a, CL: Deref<Target = ChainListener + 'a> + 'a> BlockNotifier<'a, CL> {
253254 }
254255
255256 /// Register the given listener to receive events.
256- // TODO: unregister
257257 pub fn register_listener ( & self , listener : CL ) {
258258 let mut vec = self . listeners . lock ( ) . unwrap ( ) ;
259259 vec. push ( listener) ;
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. Comparison is done using
266+ /// the pointer returned by the Deref trait implementation.
267+ pub fn unregister_listener ( & self , listener : CL ) {
268+ let mut vec = self . listeners . lock ( ) . unwrap ( ) ;
269+ // item is a ref to an abstract thing that dereferences to a ChainListener,
270+ // so dereference it twice to get the ChainListener itself
271+ vec. retain ( |item | !ptr:: eq ( & ( * * item) , & ( * listener) ) ) ;
272+ }
261273
262274 /// Notify listeners that a block was connected given a full, unfiltered block.
263275 ///
@@ -388,3 +400,76 @@ impl ChainWatchInterfaceUtil {
388400 watched. does_match_tx ( tx)
389401 }
390402}
403+
404+ #[ cfg( test) ]
405+ mod tests {
406+ use ln:: functional_test_utils:: { create_node_cfgs} ;
407+ use super :: { BlockNotifier , ChainListener } ;
408+ use std:: ptr;
409+
410+ #[ test]
411+ fn register_listener_test ( ) {
412+ let node_cfgs = create_node_cfgs ( 1 ) ;
413+ let block_notifier = BlockNotifier :: new ( node_cfgs[ 0 ] . chain_monitor . clone ( ) ) ;
414+ assert_eq ! ( block_notifier. listeners. lock( ) . unwrap( ) . len( ) , 0 ) ;
415+ let listener = & node_cfgs[ 0 ] . chan_monitor . simple_monitor as & ChainListener ;
416+ block_notifier. register_listener ( listener) ;
417+ let vec = block_notifier. listeners . lock ( ) . unwrap ( ) ;
418+ assert_eq ! ( vec. len( ) , 1 ) ;
419+ let item = vec. first ( ) . clone ( ) . unwrap ( ) ;
420+ assert ! ( ptr:: eq( & ( * * item) , & ( * listener) ) ) ;
421+ }
422+
423+ #[ test]
424+ fn unregister_single_listener_test ( ) {
425+ let node_cfgs = create_node_cfgs ( 2 ) ;
426+ let block_notifier = BlockNotifier :: new ( node_cfgs[ 0 ] . chain_monitor . clone ( ) ) ;
427+ let listener1 = & node_cfgs[ 0 ] . chan_monitor . simple_monitor as & ChainListener ;
428+ let listener2 = & node_cfgs[ 1 ] . chan_monitor . simple_monitor as & ChainListener ;
429+ block_notifier. register_listener ( listener1) ;
430+ block_notifier. register_listener ( listener2) ;
431+ let vec = block_notifier. listeners . lock ( ) . unwrap ( ) ;
432+ assert_eq ! ( vec. len( ) , 2 ) ;
433+ drop ( vec) ;
434+ block_notifier. unregister_listener ( listener1) ;
435+ let vec = block_notifier. listeners . lock ( ) . unwrap ( ) ;
436+ assert_eq ! ( vec. len( ) , 1 ) ;
437+ let item = vec. first ( ) . clone ( ) . unwrap ( ) ;
438+ assert ! ( ptr:: eq( & ( * * item) , & ( * listener2) ) ) ;
439+ }
440+
441+ #[ test]
442+ fn unregister_single_listener_ref_test ( ) {
443+ let node_cfgs = create_node_cfgs ( 2 ) ;
444+ let block_notifier = BlockNotifier :: new ( node_cfgs[ 0 ] . chain_monitor . clone ( ) ) ;
445+ block_notifier. register_listener ( & node_cfgs[ 0 ] . chan_monitor . simple_monitor as & ChainListener ) ;
446+ block_notifier. register_listener ( & node_cfgs[ 1 ] . chan_monitor . simple_monitor as & ChainListener ) ;
447+ let vec = block_notifier. listeners . lock ( ) . unwrap ( ) ;
448+ assert_eq ! ( vec. len( ) , 2 ) ;
449+ drop ( vec) ;
450+ block_notifier. unregister_listener ( & node_cfgs[ 0 ] . chan_monitor . simple_monitor ) ;
451+ let vec = block_notifier. listeners . lock ( ) . unwrap ( ) ;
452+ assert_eq ! ( vec. len( ) , 1 ) ;
453+ let item = vec. first ( ) . clone ( ) . unwrap ( ) ;
454+ assert ! ( ptr:: eq( & ( * * item) , & ( * & node_cfgs[ 1 ] . chan_monitor. simple_monitor) ) ) ;
455+ }
456+
457+ #[ test]
458+ fn unregister_multiple_of_the_same_listeners_test ( ) {
459+ let node_cfgs = create_node_cfgs ( 2 ) ;
460+ let block_notifier = BlockNotifier :: new ( node_cfgs[ 0 ] . chain_monitor . clone ( ) ) ;
461+ let listener1 = & node_cfgs[ 0 ] . chan_monitor . simple_monitor as & ChainListener ;
462+ let listener2 = & node_cfgs[ 1 ] . chan_monitor . simple_monitor as & ChainListener ;
463+ block_notifier. register_listener ( listener1) ;
464+ block_notifier. register_listener ( listener1) ;
465+ block_notifier. register_listener ( listener2) ;
466+ let vec = block_notifier. listeners . lock ( ) . unwrap ( ) ;
467+ assert_eq ! ( vec. len( ) , 3 ) ;
468+ drop ( vec) ;
469+ block_notifier. unregister_listener ( listener1) ;
470+ let vec = block_notifier. listeners . lock ( ) . unwrap ( ) ;
471+ assert_eq ! ( vec. len( ) , 1 ) ;
472+ let item = vec. first ( ) . clone ( ) . unwrap ( ) ;
473+ assert ! ( ptr:: eq( & ( * * item) , & ( * listener2) ) ) ;
474+ }
475+ }
0 commit comments