@@ -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 {
@@ -252,11 +253,22 @@ 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
+ /// 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
+ }
260
272
261
273
/// Notify listeners that a block was connected given a full, unfiltered block.
262
274
///
@@ -376,3 +388,76 @@ impl ChainWatchInterfaceUtil {
376
388
watched. does_match_tx ( tx)
377
389
}
378
390
}
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