/// };
///
/// let mut cache = UnboundedCache::new();
-/// let mut monitor_listener = (RefCell::new(monitor), &*tx_broadcaster, &*fee_estimator, &*logger);
+/// let mut monitor_listener = channelmonitor::MonitorTraits {
+/// monitor: &mut monitor, broadcaster: &*tx_broadcaster, fee_estimator: &*fee_estimator, logger: &*logger
+/// };
+/// let mut manager_ref = &manager;
/// let listeners = vec![
/// (monitor_block_hash, &mut monitor_listener as &mut dyn chain::Listen),
-/// (manager_block_hash, &mut manager as &mut dyn chain::Listen),
+/// (manager_block_hash, &mut manager_ref as &mut dyn chain::Listen),
/// ];
/// let chain_tip =
/// init::sync_listeners(block_source, Network::Bitcoin, &mut cache, listeners).await.unwrap();
///
-/// let monitor = monitor_listener.0.into_inner();
/// chain_monitor.watch_channel(monitor.get_funding_txo().0, monitor);
///
/// let chain_poller = poll::ChainPoller::new(block_source, Network::Bitcoin);
// Disconnect any stale blocks, but keep them in the cache for the next iteration.
let header_cache = &mut ReadOnlyCache(header_cache);
let (common_ancestor, connected_blocks) = {
- let chain_listener = &DynamicChainListener(chain_listener);
+ let chain_listener = DynamicChainListener(chain_listener);
let mut chain_notifier = ChainNotifier { header_cache, chain_listener };
let difference =
chain_notifier.find_difference(new_header, &old_header, &mut chain_poller).await?;
// Connect new blocks for all listeners at once to avoid re-fetching blocks.
if let Some(common_ancestor) = most_common_ancestor {
- let chain_listener = &ChainListenerSet(chain_listeners_at_height);
+ let chain_listener = ChainListenerSet(chain_listeners_at_height);
let mut chain_notifier = ChainNotifier { header_cache, chain_listener };
chain_notifier.connect_blocks(common_ancestor, most_connected_blocks, &mut chain_poller)
.await.or_else(|(e, _)| Err(e))?;
struct DynamicChainListener<'a>(&'a mut dyn chain::Listen);
impl<'a> chain::Listen for DynamicChainListener<'a> {
- fn block_connected(&self, _block: &Block, _height: u32) {
+ fn block_connected(&mut self, _block: &Block, _height: u32) {
unreachable!()
}
- fn block_disconnected(&self, header: &BlockHeader, height: u32) {
+ fn block_disconnected(&mut self, header: &BlockHeader, height: u32) {
self.0.block_disconnected(header, height)
}
}
struct ChainListenerSet<'a>(Vec<(u32, &'a mut dyn chain::Listen)>);
impl<'a> chain::Listen for ChainListenerSet<'a> {
- fn block_connected(&self, block: &Block, height: u32) {
- for (starting_height, chain_listener) in self.0.iter() {
+ fn block_connected(&mut self, block: &Block, height: u32) {
+ for (starting_height, chain_listener) in self.0.iter_mut() {
if height > *starting_height {
chain_listener.block_connected(block, height);
}
}
}
- fn block_disconnected(&self, _header: &BlockHeader, _height: u32) {
+ fn block_disconnected(&mut self, _header: &BlockHeader, _height: u32) {
unreachable!()
}
}
/// custom cache eviction policy. This offers flexibility to those sensitive to resource usage.
/// Hence, there is a trade-off between a lower memory footprint and potentially increased network
/// I/O as headers are re-fetched during fork detection.
-pub struct SpvClient<'a, P: Poll, C: Cache, L: Deref>
-where L::Target: chain::Listen {
+pub struct SpvClient<'a, P: Poll, C: Cache, L: chain::Listen> {
chain_tip: ValidatedBlockHeader,
chain_poller: P,
chain_notifier: ChainNotifier<'a, C, L>,
}
}
-impl<'a, P: Poll, C: Cache, L: Deref> SpvClient<'a, P, C, L> where L::Target: chain::Listen {
+impl<'a, P: Poll, C: Cache, L: chain::Listen> SpvClient<'a, P, C, L> {
/// Creates a new SPV client using `chain_tip` as the best known chain tip.
///
/// Subsequent calls to [`poll_best_tip`] will poll for the best chain tip using the given chain
/// Notifies [listeners] of blocks that have been connected or disconnected from the chain.
///
/// [listeners]: ../../lightning/chain/trait.Listen.html
-pub struct ChainNotifier<'a, C: Cache, L: Deref> where L::Target: chain::Listen {
+pub struct ChainNotifier<'a, C: Cache, L: chain::Listen> {
/// Cache for looking up headers before fetching from a block source.
header_cache: &'a mut C,
connected_blocks: Vec<ValidatedBlockHeader>,
}
-impl<'a, C: Cache, L: Deref> ChainNotifier<'a, C, L> where L::Target: chain::Listen {
+impl<'a, C: Cache, L: chain::Listen> ChainNotifier<'a, C, L> {
/// Finds the first common ancestor between `new_header` and `old_header`, disconnecting blocks
/// from `old_header` to get to that point and then connecting blocks until `new_header`.
///
let poller = poll::ChainPoller::new(&mut chain, Network::Testnet);
let mut cache = UnboundedCache::new();
- let mut listener = NullChainListener {};
- let mut client = SpvClient::new(best_tip, poller, &mut cache, &mut listener);
+ let listener = NullChainListener {};
+ let mut client = SpvClient::new(best_tip, poller, &mut cache, listener);
match client.poll_best_tip().await {
Err(e) => {
assert_eq!(e.kind(), BlockSourceErrorKind::Persistent);
let poller = poll::ChainPoller::new(&mut chain, Network::Testnet);
let mut cache = UnboundedCache::new();
- let mut listener = NullChainListener {};
- let mut client = SpvClient::new(common_tip, poller, &mut cache, &mut listener);
+ let listener = NullChainListener {};
+ let mut client = SpvClient::new(common_tip, poller, &mut cache, listener);
match client.poll_best_tip().await {
Err(e) => panic!("Unexpected error: {:?}", e),
Ok((chain_tip, blocks_connected)) => {
let poller = poll::ChainPoller::new(&mut chain, Network::Testnet);
let mut cache = UnboundedCache::new();
- let mut listener = NullChainListener {};
- let mut client = SpvClient::new(old_tip, poller, &mut cache, &mut listener);
+ let listener = NullChainListener {};
+ let mut client = SpvClient::new(old_tip, poller, &mut cache, listener);
match client.poll_best_tip().await {
Err(e) => panic!("Unexpected error: {:?}", e),
Ok((chain_tip, blocks_connected)) => {
let poller = poll::ChainPoller::new(&mut chain, Network::Testnet);
let mut cache = UnboundedCache::new();
- let mut listener = NullChainListener {};
- let mut client = SpvClient::new(old_tip, poller, &mut cache, &mut listener);
+ let listener = NullChainListener {};
+ let mut client = SpvClient::new(old_tip, poller, &mut cache, listener);
match client.poll_best_tip().await {
Err(e) => panic!("Unexpected error: {:?}", e),
Ok((chain_tip, blocks_connected)) => {
let poller = poll::ChainPoller::new(&mut chain, Network::Testnet);
let mut cache = UnboundedCache::new();
- let mut listener = NullChainListener {};
- let mut client = SpvClient::new(old_tip, poller, &mut cache, &mut listener);
+ let listener = NullChainListener {};
+ let mut client = SpvClient::new(old_tip, poller, &mut cache, listener);
match client.poll_best_tip().await {
Err(e) => panic!("Unexpected error: {:?}", e),
Ok((chain_tip, blocks_connected)) => {
let poller = poll::ChainPoller::new(&mut chain, Network::Testnet);
let mut cache = UnboundedCache::new();
- let mut listener = NullChainListener {};
- let mut client = SpvClient::new(best_tip, poller, &mut cache, &mut listener);
+ let listener = NullChainListener {};
+ let mut client = SpvClient::new(best_tip, poller, &mut cache, listener);
match client.poll_best_tip().await {
Err(e) => panic!("Unexpected error: {:?}", e),
Ok((chain_tip, blocks_connected)) => {
let new_tip = chain.tip();
let old_tip = chain.at_height(1);
- let chain_listener = &MockChainListener::new()
+ let chain_listener = MockChainListener::new()
.expect_block_connected(*chain.at_height(2))
.expect_block_connected(*new_tip);
let mut notifier = ChainNotifier {
let new_tip = test_chain.tip();
let old_tip = main_chain.tip();
- let chain_listener = &MockChainListener::new();
+ let chain_listener = MockChainListener::new();
let mut notifier = ChainNotifier {
header_cache: &mut main_chain.header_cache(0..=1),
chain_listener,
let new_tip = fork_chain.tip();
let old_tip = main_chain.tip();
- let chain_listener = &MockChainListener::new()
+ let chain_listener = MockChainListener::new()
.expect_block_disconnected(*old_tip)
.expect_block_connected(*new_tip);
let mut notifier = ChainNotifier {
let new_tip = fork_chain.tip();
let old_tip = main_chain.tip();
- let chain_listener = &MockChainListener::new()
+ let chain_listener = MockChainListener::new()
.expect_block_disconnected(*old_tip)
.expect_block_disconnected(*main_chain.at_height(2))
.expect_block_connected(*new_tip);
let new_tip = fork_chain.tip();
let old_tip = main_chain.tip();
- let chain_listener = &MockChainListener::new()
+ let chain_listener = MockChainListener::new()
.expect_block_disconnected(*old_tip)
.expect_block_connected(*fork_chain.at_height(2))
.expect_block_connected(*new_tip);
let new_tip = chain.tip();
let old_tip = chain.at_height(1);
- let chain_listener = &MockChainListener::new();
+ let chain_listener = MockChainListener::new();
let mut notifier = ChainNotifier {
header_cache: &mut chain.header_cache(0..=1),
chain_listener,
let new_tip = chain.tip();
let old_tip = chain.at_height(1);
- let chain_listener = &MockChainListener::new();
+ let chain_listener = MockChainListener::new();
let mut notifier = ChainNotifier {
header_cache: &mut chain.header_cache(0..=3),
chain_listener,
let new_tip = chain.tip();
let old_tip = chain.at_height(1);
- let chain_listener = &MockChainListener::new()
+ let chain_listener = MockChainListener::new()
.expect_block_connected(*chain.at_height(2));
let mut notifier = ChainNotifier {
header_cache: &mut chain.header_cache(0..=3),
pub struct NullChainListener;
impl chain::Listen for NullChainListener {
- fn block_connected(&self, _block: &Block, _height: u32) {}
- fn block_disconnected(&self, _header: &BlockHeader, _height: u32) {}
+ fn block_connected(&mut self, _block: &Block, _height: u32) {}
+ fn block_disconnected(&mut self, _header: &BlockHeader, _height: u32) {}
}
pub struct MockChainListener {
}
impl chain::Listen for MockChainListener {
- fn block_connected(&self, block: &Block, height: u32) {
+ fn block_connected(&mut self, block: &Block, height: u32) {
match self.expected_blocks_connected.borrow_mut().pop_front() {
None => {
panic!("Unexpected block connected: {:?}", block.block_hash());
}
}
- fn block_disconnected(&self, header: &BlockHeader, height: u32) {
+ fn block_disconnected(&mut self, header: &BlockHeader, height: u32) {
match self.expected_blocks_disconnected.borrow_mut().pop_front() {
None => {
panic!("Unexpected block disconnected: {:?}", header.block_hash());
}
impl<ChannelSigner: Sign, C: Deref + Send + Sync, T: Deref + Send + Sync, F: Deref + Send + Sync, L: Deref + Send + Sync, P: Deref + Send + Sync>
-chain::Listen for ChainMonitor<ChannelSigner, C, T, F, L, P>
+chain::sealed::DerefListen for ChainMonitor<ChannelSigner, C, T, F, L, P>
where
ChannelSigner: Sign,
C::Target: chain::Filter,
use std::cell::RefCell;
use std::collections::{HashMap, HashSet, hash_map};
use std::{cmp, mem};
-use std::ops::Deref;
+use std::ops::{Deref, DerefMut};
use std::io::Error;
/// An update generated by the underlying Channel itself which contains some new information the
fn update_persisted_channel(&self, id: OutPoint, update: &ChannelMonitorUpdate, data: &ChannelMonitor<ChannelSigner>) -> Result<(), ChannelMonitorUpdateErr>;
}
-impl<Signer: Sign, T: Deref, F: Deref, L: Deref> chain::Listen for (RefCell<ChannelMonitor<Signer>>, T, F, L)
+
+/// does things
+pub struct MonitorTraits<CM: DerefMut<Target=ChannelMonitor<Signer>>, Signer: Sign, T: Deref, F: Deref, L: Deref> {
+ /// a
+ pub monitor: CM,
+ /// b
+ pub broadcaster: T,
+ /// c
+ pub fee_estimator: F,
+ /// d
+ pub logger: L,
+}
+
+impl<CM: DerefMut<Target=ChannelMonitor<Signer>>, Signer: Sign, T: Deref, F: Deref, L: Deref>
+chain::Listen for MonitorTraits<CM, Signer, T, F, L>
where
T::Target: BroadcasterInterface,
F::Target: FeeEstimator,
L::Target: Logger,
{
- fn block_connected(&self, block: &Block, height: u32) {
+ fn block_connected(&mut self, block: &Block, height: u32) {
let txdata: Vec<_> = block.txdata.iter().enumerate().collect();
- self.0.borrow_mut().block_connected(&block.header, &txdata, height, &*self.1, &*self.2, &*self.3);
+ self.monitor.block_connected(&block.header, &txdata, height, &*self.broadcaster, &*self.fee_estimator, &*self.logger);
}
- fn block_disconnected(&self, header: &BlockHeader, height: u32) {
- self.0.borrow_mut().block_disconnected(header, height, &*self.1, &*self.2, &*self.3);
+ fn block_disconnected(&mut self, header: &BlockHeader, height: u32) {
+ self.monitor.block_disconnected(header, height, &*self.broadcaster, &*self.fee_estimator, &*self.logger);
}
}
use chain::keysinterface::Sign;
use chain::transaction::OutPoint;
+use std::ops::Deref;
+
pub mod chaininterface;
pub mod chainmonitor;
pub mod channelmonitor;
/// Useful when needing to replay chain data upon startup or as new chain events occur.
pub trait Listen {
/// Notifies the listener that a block was added at the given height.
- fn block_connected(&self, block: &Block, height: u32);
+ fn block_connected(&mut self, block: &Block, height: u32);
/// Notifies the listener that a block was removed at the given height.
- fn block_disconnected(&self, header: &BlockHeader, height: u32);
+ fn block_disconnected(&mut self, header: &BlockHeader, height: u32);
+}
+
+pub(crate) mod sealed {
+ use super::*;
+ /// Rustc currently isn't smart enough to figure out that two impls are not conflicting when they
+ /// both impl for `Deref` but with a different `Target`
+ /// (https://github.com/rust-lang/rust/issues/20400). Instead, we use the workaround suggested at
+ /// https://stackoverflow.com/questions/40392524/conflicting-trait-implementations-even-though-associated-types-differ/40408431#40408431
+ pub trait DerefListen {
+ fn block_connected(&self, block: &Block, height: u32);
+ fn block_disconnected(&self, header: &BlockHeader, height: u32);
+ }
+ impl<T: Deref, U: Deref> DerefListen for (T, U) where T::Target: DerefListen, U::Target: DerefListen {
+ fn block_connected(&self, block: &Block, height: u32) {
+ Deref::deref(&self.0).block_connected(block, height);
+ Deref::deref(&self.1).block_connected(block, height);
+ }
+
+ fn block_disconnected(&self, header: &BlockHeader, height: u32) {
+ Deref::deref(&self.0).block_disconnected(header, height);
+ Deref::deref(&self.1).block_disconnected(header, height);
+ }
+ }
+}
+impl<T: Deref> Listen for T where T::Target: sealed::DerefListen {
+ fn block_connected(&mut self, block: &Block, height: u32) {
+ sealed::DerefListen::block_connected(Deref::deref(self), block, height);
+ }
+ fn block_disconnected(&mut self, header: &BlockHeader, height: u32) {
+ sealed::DerefListen::block_disconnected(Deref::deref(self), header, height);
+ }
}
+
/// The `Watch` trait defines behavior for watching on-chain activity pertaining to channels as
/// blocks are connected and disconnected.
///
/// `script_pubkey` as the spending condition.
fn register_output(&self, outpoint: &OutPoint, script_pubkey: &Script);
}
-
-impl<T: Listen> Listen for std::ops::Deref<Target = T> {
- fn block_connected(&self, block: &Block, height: u32) {
- (**self).block_connected(block, height);
- }
-
- fn block_disconnected(&self, header: &BlockHeader, height: u32) {
- (**self).block_disconnected(header, height);
- }
-}
-
-impl<T: std::ops::Deref, U: std::ops::Deref> Listen for (T, U)
-where
- T::Target: Listen,
- U::Target: Listen,
-{
- fn block_connected(&self, block: &Block, height: u32) {
- self.0.block_connected(block, height);
- self.1.block_connected(block, height);
- }
-
- fn block_disconnected(&self, header: &BlockHeader, height: u32) {
- self.0.block_disconnected(header, height);
- self.1.block_disconnected(header, height);
- }
-}
}
}
-impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> chain::Listen for ChannelManager<Signer, M, T, K, F, L>
+impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> chain::sealed::DerefListen for ChannelManager<Signer, M, T, K, F, L>
where
M::Target: chain::Watch<Signer>,
T::Target: BroadcasterInterface,