Skip to content

Commit 7d62346

Browse files
committed
add functionality for BlockNotifier to unregister a previously registered listener, in order to no longer receive events
1 parent fc03ab1 commit 7d62346

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 {
@@ -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+
}

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)