@@ -19,6 +19,7 @@ use std::sync::atomic::{AtomicUsize, Ordering};
19
19
use std:: collections:: HashSet ;
20
20
use std:: ops:: Deref ;
21
21
use std:: marker:: PhantomData ;
22
+ use std:: ptr:: eq as ptr_eq;
22
23
23
24
/// Used to give chain error details upstream
24
25
pub enum ChainError {
@@ -252,12 +253,21 @@ impl<'a, CL: Deref<Target = ChainListener + 'a> + 'a> BlockNotifier<'a, CL> {
252
253
}
253
254
254
255
/// Register the given listener to receive events.
255
- // TODO: unregister
256
256
pub fn register_listener ( & self , listener : CL ) {
257
257
let mut vec = self . listeners . lock ( ) . unwrap ( ) ;
258
258
vec. push ( listener) ;
259
259
}
260
260
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
+
261
271
/// Notify listeners that a block was connected given a full, unfiltered block.
262
272
///
263
273
/// Handles re-scanning the block and calling block_connected again if listeners register new
@@ -376,3 +386,59 @@ impl ChainWatchInterfaceUtil {
376
386
watched. does_match_tx ( tx)
377
387
}
378
388
}
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