X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fchain%2Fchaininterface.rs;h=3a2e69cd1cbe2bad22b8a06e58802fbe8a9f2dc9;hb=e1f7d4e22703331b40df46551cecb3884f7e5179;hp=32fef48eb44a54acaa7a576502ad1e0f1e56311d;hpb=969f8630133d8f53050d7ad48ca7a1450ebae08b;p=rust-lightning diff --git a/lightning/src/chain/chaininterface.rs b/lightning/src/chain/chaininterface.rs index 32fef48eb..3a2e69cd1 100644 --- a/lightning/src/chain/chaininterface.rs +++ b/lightning/src/chain/chaininterface.rs @@ -14,9 +14,11 @@ use bitcoin::network::constants::Network; use util::logger::Logger; -use std::sync::{Mutex,Weak,MutexGuard,Arc}; +use std::sync::{Mutex, MutexGuard, Arc}; use std::sync::atomic::{AtomicUsize, Ordering}; use std::collections::HashSet; +use std::ops::Deref; +use std::marker::PhantomData; /// Used to give chain error details upstream pub enum ChainError { @@ -50,6 +52,15 @@ pub trait ChainWatchInterface: Sync + Send { /// bytes are the block height, the next 3 the transaction index within the block, and the /// final two the output within the transaction. fn get_chain_utxo(&self, genesis_hash: Sha256dHash, unspent_tx_output_identifier: u64) -> Result<(Script, u64), ChainError>; + + /// Gets the list of transactions and transaction indices that the ChainWatchInterface is + /// watching for. + fn filter_block<'a>(&self, block: &'a Block) -> (Vec<&'a Transaction>, Vec); + + /// Returns a usize that changes when the ChainWatchInterface's watched data is modified. + /// Users of `filter_block` should pre-save a copy of `reentered`'s return value and use it to + /// determine whether they need to re-filter a given block. + fn reentered(&self) -> usize; } /// An interface to send a transaction to the Bitcoin network. @@ -106,6 +117,9 @@ pub trait FeeEstimator: Sync + Send { fn get_est_sat_per_1000_weight(&self, confirmation_target: ConfirmationTarget) -> u64; } +/// Minimum relay fee as required by bitcoin network mempool policy. +pub const MIN_RELAY_FEE_SAT_PER_1000_WEIGHT: u64 = 4000; + /// Utility for tracking registered txn/outpoints and checking for matches pub struct ChainWatchedUtil { watch_all: bool, @@ -193,26 +207,48 @@ impl ChainWatchedUtil { } } +/// 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 = Arc>>; + +/// 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> = BlockNotifier<'a, &'a ChainListener>; + /// Utility for notifying listeners about new blocks, and handling block rescans if new watch /// data is registered. -pub struct BlockNotifier<'a> { - listeners: Mutex>>, //TODO(vmw): try removing Weak +/// +/// 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 + 'a> { + listeners: Mutex>, chain_monitor: Arc, + phantom: PhantomData<&'a ()>, } -impl<'a> BlockNotifier<'a> { +impl<'a, CL: Deref + 'a> BlockNotifier<'a, CL> { /// Constructs a new BlockNotifier without any listeners. - pub fn new(chain_monitor: Arc) -> BlockNotifier<'a> { + pub fn new(chain_monitor: Arc) -> BlockNotifier<'a, CL> { BlockNotifier { listeners: Mutex::new(Vec::new()), chain_monitor, + phantom: PhantomData, } } - /// Register the given listener to receive events. Only a weak pointer is provided and - /// the registration should be freed once that pointer expires. + /// Register the given listener to receive events. // TODO: unregister - pub fn register_listener(&self, listener: Weak) { + pub fn register_listener(&self, listener: CL) { let mut vec = self.listeners.lock().unwrap(); vec.push(listener); } @@ -238,12 +274,9 @@ impl<'a> BlockNotifier<'a> { pub fn block_connected_checked(&self, header: &BlockHeader, height: u32, txn_matched: &[&Transaction], indexes_of_txn_matched: &[u32]) -> bool { let last_seen = self.chain_monitor.reentered(); - let listeners = self.listeners.lock().unwrap().clone(); + let listeners = self.listeners.lock().unwrap(); for listener in listeners.iter() { - match listener.upgrade() { - Some(arc) => arc.block_connected(header, height, txn_matched, indexes_of_txn_matched), - None => () - } + listener.block_connected(header, height, txn_matched, indexes_of_txn_matched); } return last_seen != self.chain_monitor.reentered(); } @@ -251,12 +284,9 @@ impl<'a> BlockNotifier<'a> { /// Notify listeners that a block was disconnected. pub fn block_disconnected(&self, header: &BlockHeader, disconnected_height: u32) { - let listeners = self.listeners.lock().unwrap().clone(); + let listeners = self.listeners.lock().unwrap(); for listener in listeners.iter() { - match listener.upgrade() { - Some(arc) => arc.block_disconnected(&header, disconnected_height), - None => () - } + listener.block_disconnected(&header, disconnected_height); } } @@ -301,6 +331,25 @@ impl ChainWatchInterface for ChainWatchInterfaceUtil { } Err(ChainError::NotSupported) } + + fn filter_block<'a>(&self, block: &'a Block) -> (Vec<&'a Transaction>, Vec) { + let mut matched = Vec::new(); + let mut matched_index = Vec::new(); + { + let watched = self.watched.lock().unwrap(); + for (index, transaction) in block.txdata.iter().enumerate() { + if self.does_match_tx_unguarded(transaction, &watched) { + matched.push(transaction); + matched_index.push(index as u32); + } + } + } + (matched, matched_index) + } + + fn reentered(&self) -> usize { + self.reentered.load(Ordering::Relaxed) + } } impl ChainWatchInterfaceUtil {