Skip to content

Commit 2f34641

Browse files
authored
Merge pull request #502 from rloomba/rloomba/add_unregister_listener
[chaininterface] Add ability for BlockNotifier to unregister listeners
2 parents 69c3eb2 + 7d62346 commit 2f34641

File tree

2 files changed

+88
-2
lines changed

2 files changed

+88
-2
lines changed

lightning/src/chain/chaininterface.rs

Lines changed: 86 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use std::sync::atomic::{AtomicUsize, Ordering};
1919
use std::collections::HashSet;
2020
use std::ops::Deref;
2121
use std::marker::PhantomData;
22+
use std::ptr;
2223

2324
/// Used to give chain error details upstream
2425
pub 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+
}

lightning/src/ln/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ mod onion_utils;
2727
mod wire;
2828

2929
#[cfg(test)]
30-
#[macro_use] mod functional_test_utils;
30+
#[macro_use]
31+
pub(crate) mod functional_test_utils;
3132
#[cfg(test)]
3233
mod functional_tests;
3334
#[cfg(test)]

0 commit comments

Comments
 (0)