@@ -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 {
@@ -252,11 +253,22 @@ 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 }
260+ /// Unregister the given listener to no longer
261+ /// receive events.
262+ ///
263+ /// If the same listener is registered multiple times, unregistering
264+ /// will remove ALL occurrences of that listener. Comparison is done using
265+ /// the pointer returned by the Deref trait implementation.
266+ pub fn unregister_listener ( & self , listener : CL ) {
267+ let mut vec = self . listeners . lock ( ) . unwrap ( ) ;
268+ // item is a ref to an abstract thing that dereferences to a ChainListener,
269+ // so dereference it twice to get the ChainListener itself
270+ vec. retain ( |item | !ptr:: eq ( & ( * * item) , & ( * listener) ) ) ;
271+ }
260272
261273 /// Notify listeners that a block was connected given a full, unfiltered block.
262274 ///
@@ -376,3 +388,76 @@ impl ChainWatchInterfaceUtil {
376388 watched. does_match_tx ( tx)
377389 }
378390}
391+
392+ #[ cfg( test) ]
393+ mod tests {
394+ use ln:: functional_test_utils:: { create_node_cfgs} ;
395+ use super :: { BlockNotifier , ChainListener } ;
396+ use std:: ptr;
397+
398+ #[ test]
399+ fn register_listener_test ( ) {
400+ let node_cfgs = create_node_cfgs ( 1 ) ;
401+ let block_notifier = BlockNotifier :: new ( node_cfgs[ 0 ] . chain_monitor . clone ( ) ) ;
402+ assert_eq ! ( block_notifier. listeners. lock( ) . unwrap( ) . len( ) , 0 ) ;
403+ let listener = & node_cfgs[ 0 ] . chan_monitor . simple_monitor as & ChainListener ;
404+ block_notifier. register_listener ( listener) ;
405+ let vec = block_notifier. listeners . lock ( ) . unwrap ( ) ;
406+ assert_eq ! ( vec. len( ) , 1 ) ;
407+ let item = vec. first ( ) . clone ( ) . unwrap ( ) ;
408+ assert ! ( ptr:: eq( & ( * * item) , & ( * listener) ) ) ;
409+ }
410+
411+ #[ test]
412+ fn unregister_single_listener_test ( ) {
413+ let node_cfgs = create_node_cfgs ( 2 ) ;
414+ let block_notifier = BlockNotifier :: new ( node_cfgs[ 0 ] . chain_monitor . clone ( ) ) ;
415+ let listener1 = & node_cfgs[ 0 ] . chan_monitor . simple_monitor as & ChainListener ;
416+ let listener2 = & node_cfgs[ 1 ] . chan_monitor . simple_monitor as & ChainListener ;
417+ block_notifier. register_listener ( listener1) ;
418+ block_notifier. register_listener ( listener2) ;
419+ let vec = block_notifier. listeners . lock ( ) . unwrap ( ) ;
420+ assert_eq ! ( vec. len( ) , 2 ) ;
421+ drop ( vec) ;
422+ block_notifier. unregister_listener ( listener1) ;
423+ let vec = block_notifier. listeners . lock ( ) . unwrap ( ) ;
424+ assert_eq ! ( vec. len( ) , 1 ) ;
425+ let item = vec. first ( ) . clone ( ) . unwrap ( ) ;
426+ assert ! ( ptr:: eq( & ( * * item) , & ( * listener2) ) ) ;
427+ }
428+
429+ #[ test]
430+ fn unregister_single_listener_ref_test ( ) {
431+ let node_cfgs = create_node_cfgs ( 2 ) ;
432+ let block_notifier = BlockNotifier :: new ( node_cfgs[ 0 ] . chain_monitor . clone ( ) ) ;
433+ block_notifier. register_listener ( & node_cfgs[ 0 ] . chan_monitor . simple_monitor as & ChainListener ) ;
434+ block_notifier. register_listener ( & node_cfgs[ 1 ] . chan_monitor . simple_monitor as & ChainListener ) ;
435+ let vec = block_notifier. listeners . lock ( ) . unwrap ( ) ;
436+ assert_eq ! ( vec. len( ) , 2 ) ;
437+ drop ( vec) ;
438+ block_notifier. unregister_listener ( & node_cfgs[ 0 ] . chan_monitor . simple_monitor ) ;
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) , & ( * & node_cfgs[ 1 ] . chan_monitor. simple_monitor) ) ) ;
443+ }
444+
445+ #[ test]
446+ fn unregister_multiple_of_the_same_listeners_test ( ) {
447+ let node_cfgs = create_node_cfgs ( 2 ) ;
448+ let block_notifier = BlockNotifier :: new ( node_cfgs[ 0 ] . chain_monitor . clone ( ) ) ;
449+ let listener1 = & node_cfgs[ 0 ] . chan_monitor . simple_monitor as & ChainListener ;
450+ let listener2 = & node_cfgs[ 1 ] . chan_monitor . simple_monitor as & ChainListener ;
451+ block_notifier. register_listener ( listener1) ;
452+ block_notifier. register_listener ( listener1) ;
453+ block_notifier. register_listener ( listener2) ;
454+ let vec = block_notifier. listeners . lock ( ) . unwrap ( ) ;
455+ assert_eq ! ( vec. len( ) , 3 ) ;
456+ drop ( vec) ;
457+ block_notifier. unregister_listener ( listener1) ;
458+ let vec = block_notifier. listeners . lock ( ) . unwrap ( ) ;
459+ assert_eq ! ( vec. len( ) , 1 ) ;
460+ let item = vec. first ( ) . clone ( ) . unwrap ( ) ;
461+ assert ! ( ptr:: eq( & ( * * item) , & ( * listener2) ) ) ;
462+ }
463+ }
0 commit comments