+/// BlockNotifierArc is useful when you need a BlockNotifier that points to ChainListeners with
+/// static lifetimes, e.g. when you're using lightning-net-tokio (since tokio::spawn requires
+/// parameters with static lifetimes). Other times you can afford a reference, which is more
+/// efficient, in which case BlockNotifierRef is a more appropriate type. Defining these type
+/// aliases prevents issues such as overly long function definitions.
+pub type BlockNotifierArc<C> = Arc<BlockNotifier<'static, Arc<ChainListener>, C>>;
+
+/// BlockNotifierRef is useful when you want a BlockNotifier that points to ChainListeners
+/// with nonstatic lifetimes. This is useful for when static lifetimes are not needed. Nonstatic
+/// lifetimes are more efficient but less flexible, and should be used by default unless static
+/// lifetimes are required, e.g. when you're using lightning-net-tokio (since tokio::spawn
+/// requires parameters with static lifetimes), in which case BlockNotifierArc is a more
+/// appropriate type. Defining these type aliases for common usages prevents issues such as
+/// overly long function definitions.
+pub type BlockNotifierRef<'a, C> = BlockNotifier<'a, &'a ChainListener, C>;
+
+/// Utility for notifying listeners about new blocks, and handling block rescans if new watch
+/// data is registered.
+///
+/// Rather than using a plain BlockNotifier, it is preferable to use either a BlockNotifierArc
+/// or a BlockNotifierRef for conciseness. See their documentation for more details, but essentially
+/// you should default to using a BlockNotifierRef, and use a BlockNotifierArc instead when you
+/// require ChainListeners with static lifetimes, such as when you're using lightning-net-tokio.
+pub struct BlockNotifier<'a, CL: Deref<Target = ChainListener + 'a> + 'a, C: Deref> where C::Target: ChainWatchInterface {
+ listeners: Mutex<Vec<CL>>,
+ chain_monitor: C,
+ phantom: PhantomData<&'a ()>,
+}
+
+impl<'a, CL: Deref<Target = ChainListener + 'a> + 'a, C: Deref> BlockNotifier<'a, CL, C> where C::Target: ChainWatchInterface {
+ /// Constructs a new BlockNotifier without any listeners.
+ pub fn new(chain_monitor: C) -> BlockNotifier<'a, CL, C> {
+ BlockNotifier {
+ listeners: Mutex::new(Vec::new()),
+ chain_monitor,
+ phantom: PhantomData,
+ }
+ }
+
+ /// Register the given listener to receive events.
+ pub fn register_listener(&self, listener: CL) {
+ let mut vec = self.listeners.lock().unwrap();
+ vec.push(listener);
+ }
+ /// Unregister the given listener to no longer
+ /// receive events.
+ ///
+ /// If the same listener is registered multiple times, unregistering
+ /// will remove ALL occurrences of that listener. Comparison is done using
+ /// the pointer returned by the Deref trait implementation.
+ pub fn unregister_listener(&self, listener: CL) {
+ let mut vec = self.listeners.lock().unwrap();
+ // item is a ref to an abstract thing that dereferences to a ChainListener,
+ // so dereference it twice to get the ChainListener itself
+ vec.retain(|item | !ptr::eq(&(**item), &(*listener)));
+ }
+
+ /// Notify listeners that a block was connected given a full, unfiltered block.
+ ///
+ /// Handles re-scanning the block and calling block_connected again if listeners register new
+ /// watch data during the callbacks for you (see ChainListener::block_connected for more info).
+ pub fn block_connected(&self, block: &Block, height: u32) {
+ let mut reentered = true;
+ while reentered {
+ let matched_indexes = self.chain_monitor.filter_block(block);
+ let mut matched_txn = Vec::new();
+ for index in matched_indexes.iter() {
+ matched_txn.push(&block.txdata[*index]);
+ }
+ reentered = self.block_connected_checked(&block.header, height, matched_txn.as_slice(), matched_indexes.as_slice());
+ }
+ }
+
+ /// Notify listeners that a block was connected, given pre-filtered list of transactions in the
+ /// block which matched the filter (probably using does_match_tx).
+ ///
+ /// Returns true if notified listeners registered additional watch data (implying that the
+ /// block must be re-scanned and this function called again prior to further block_connected
+ /// calls, see ChainListener::block_connected for more info).
+ pub fn block_connected_checked(&self, header: &BlockHeader, height: u32, txn_matched: &[&Transaction], indexes_of_txn_matched: &[usize]) -> bool {
+ let last_seen = self.chain_monitor.reentered();
+
+ let listeners = self.listeners.lock().unwrap();
+ for listener in listeners.iter() {
+ listener.block_connected(header, height, txn_matched, indexes_of_txn_matched);
+ }
+ return last_seen != self.chain_monitor.reentered();
+ }
+
+ /// Notify listeners that a block was disconnected.
+ pub fn block_disconnected(&self, header: &BlockHeader, disconnected_height: u32) {
+ let listeners = self.listeners.lock().unwrap();
+ for listener in listeners.iter() {
+ listener.block_disconnected(&header, disconnected_height);
+ }
+ }
+}
+