@@ -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;
22
23
23
24
/// Used to give chain error details upstream
24
25
pub enum ChainError {
@@ -253,11 +254,22 @@ impl<'a, CL: Deref<Target = ChainListener + 'a> + 'a> BlockNotifier<'a, CL> {
253
254
}
254
255
255
256
/// Register the given listener to receive events.
256
- // TODO: unregister
257
257
pub fn register_listener ( & self , listener : CL ) {
258
258
let mut vec = self . listeners . lock ( ) . unwrap ( ) ;
259
259
vec. push ( listener) ;
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. 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
+ }
261
273
262
274
/// Notify listeners that a block was connected given a full, unfiltered block.
263
275
///
@@ -388,3 +400,76 @@ impl ChainWatchInterfaceUtil {
388
400
watched. does_match_tx ( tx)
389
401
}
390
402
}
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