1 //! Traits and utility impls which allow other parts of rust-lightning to interact with the
4 //! Includes traits for monitoring and receiving notifications of new blocks and block
5 //! disconnections, transaction broadcasting, and feerate information requests.
7 use bitcoin::blockdata::block::{Block, BlockHeader};
8 use bitcoin::blockdata::transaction::Transaction;
9 use bitcoin::blockdata::script::Script;
10 use bitcoin::blockdata::constants::genesis_block;
11 use bitcoin::util::hash::BitcoinHash;
12 use bitcoin::network::constants::Network;
13 use bitcoin::hash_types::{Txid, BlockHash};
15 use std::sync::{Mutex, MutexGuard, Arc};
16 use std::sync::atomic::{AtomicUsize, Ordering};
17 use std::collections::HashSet;
19 use std::marker::PhantomData;
22 /// Used to give chain error details upstream
25 /// Client doesn't support UTXO lookup (but the chain hash matches our genesis block hash)
27 /// Chain isn't the one watched
29 /// Tx doesn't exist or is unconfirmed
33 /// An interface to request notification of certain scripts as they appear the
36 /// Note that all of the functions implemented here *must* be reentrant-safe (obviously - they're
37 /// called from inside the library in response to ChainListener events, P2P events, or timer
39 pub trait ChainWatchInterface: Sync + Send {
40 /// Provides a txid/random-scriptPubKey-in-the-tx which much be watched for.
41 fn install_watch_tx(&self, txid: &Txid, script_pub_key: &Script);
43 /// Provides an outpoint which must be watched for, providing any transactions which spend the
45 fn install_watch_outpoint(&self, outpoint: (Txid, u32), out_script: &Script);
47 /// Indicates that a listener needs to see all transactions.
48 fn watch_all_txn(&self);
50 /// Gets the script and value in satoshis for a given unspent transaction output given a
51 /// short_channel_id (aka unspent_tx_output_identier). For BTC/tBTC channels the top three
52 /// bytes are the block height, the next 3 the transaction index within the block, and the
53 /// final two the output within the transaction.
54 fn get_chain_utxo(&self, genesis_hash: BlockHash, unspent_tx_output_identifier: u64) -> Result<(Script, u64), ChainError>;
56 /// Gets the list of transaction indices within a given block that the ChainWatchInterface is
58 fn filter_block(&self, header: &BlockHeader, txdata: &[(usize, &Transaction)]) -> Vec<usize>;
60 /// Returns a usize that changes when the ChainWatchInterface's watched data is modified.
61 /// Users of `filter_block` should pre-save a copy of `reentered`'s return value and use it to
62 /// determine whether they need to re-filter a given block.
63 fn reentered(&self) -> usize;
66 /// An interface to send a transaction to the Bitcoin network.
67 pub trait BroadcasterInterface: Sync + Send {
68 /// Sends a transaction out to (hopefully) be mined.
69 fn broadcast_transaction(&self, tx: &Transaction);
72 /// A trait indicating a desire to listen for events from the chain
73 pub trait ChainListener: Sync + Send {
74 /// Notifies a listener that a block was connected. Transactions may be filtered and are given
75 /// paired with their position within the block.
76 fn block_connected(&self, header: &BlockHeader, txdata: &[(usize, &Transaction)], height: u32);
78 /// Notifies a listener that a block was disconnected.
79 /// Unlike block_connected, this *must* never be called twice for the same disconnect event.
80 /// Height must be the one of the block which was disconnected (not new height of the best chain)
81 fn block_disconnected(&self, header: &BlockHeader, disconnected_height: u32);
84 /// An enum that represents the speed at which we want a transaction to confirm used for feerate
86 pub enum ConfirmationTarget {
87 /// We are happy with this transaction confirming slowly when feerate drops some.
89 /// We'd like this transaction to confirm without major delay, but 12-18 blocks is fine.
91 /// We'd like this transaction to confirm in the next few blocks.
95 /// A trait which should be implemented to provide feerate information on a number of time
98 /// Note that all of the functions implemented here *must* be reentrant-safe (obviously - they're
99 /// called from inside the library in response to ChainListener events, P2P events, or timer
101 pub trait FeeEstimator: Sync + Send {
102 /// Gets estimated satoshis of fee required per 1000 Weight-Units.
104 /// Must be no smaller than 253 (ie 1 satoshi-per-byte rounded up to ensure later round-downs
105 /// don't put us below 1 satoshi-per-byte).
107 /// This translates to:
108 /// * satoshis-per-byte * 250
109 /// * ceil(satoshis-per-kbyte / 4)
110 fn get_est_sat_per_1000_weight(&self, confirmation_target: ConfirmationTarget) -> u32;
113 /// Minimum relay fee as required by bitcoin network mempool policy.
114 pub const MIN_RELAY_FEE_SAT_PER_1000_WEIGHT: u64 = 4000;
116 /// Utility for tracking registered txn/outpoints and checking for matches
117 #[cfg_attr(test, derive(PartialEq))]
118 pub struct ChainWatchedUtil {
121 // We are more conservative in matching during testing to ensure everything matches *exactly*,
122 // even though during normal runtime we take more optimized match approaches...
124 watched_txn: HashSet<(Txid, Script)>,
126 watched_txn: HashSet<Script>,
128 watched_outpoints: HashSet<(Txid, u32)>,
131 impl ChainWatchedUtil {
132 /// Constructs an empty (watches nothing) ChainWatchedUtil
133 pub fn new() -> Self {
136 watched_txn: HashSet::new(),
137 watched_outpoints: HashSet::new(),
141 /// Registers a tx for monitoring, returning true if it was a new tx and false if we'd already
142 /// been watching for it.
143 pub fn register_tx(&mut self, txid: &Txid, script_pub_key: &Script) -> bool {
144 if self.watch_all { return false; }
147 self.watched_txn.insert((txid.clone(), script_pub_key.clone()))
151 let _tx_unused = txid; // It's used in cfg(test), though
152 self.watched_txn.insert(script_pub_key.clone())
156 /// Registers an outpoint for monitoring, returning true if it was a new outpoint and false if
157 /// we'd already been watching for it
158 pub fn register_outpoint(&mut self, outpoint: (Txid, u32), _script_pub_key: &Script) -> bool {
159 if self.watch_all { return false; }
160 self.watched_outpoints.insert(outpoint)
163 /// Sets us to match all transactions, returning true if this is a new setting and false if
164 /// we'd already been set to match everything.
165 pub fn watch_all(&mut self) -> bool {
166 if self.watch_all { return false; }
167 self.watch_all = true;
171 /// Checks if a given transaction matches the current filter.
172 pub fn does_match_tx(&self, tx: &Transaction) -> bool {
176 for out in tx.output.iter() {
178 for &(ref txid, ref script) in self.watched_txn.iter() {
179 if *script == out.script_pubkey {
180 if tx.txid() == *txid {
186 for script in self.watched_txn.iter() {
187 if *script == out.script_pubkey {
192 for input in tx.input.iter() {
193 for outpoint in self.watched_outpoints.iter() {
194 let &(outpoint_hash, outpoint_index) = outpoint;
195 if outpoint_hash == input.previous_output.txid && outpoint_index == input.previous_output.vout {
204 /// BlockNotifierArc is useful when you need a BlockNotifier that points to ChainListeners with
205 /// static lifetimes, e.g. when you're using lightning-net-tokio (since tokio::spawn requires
206 /// parameters with static lifetimes). Other times you can afford a reference, which is more
207 /// efficient, in which case BlockNotifierRef is a more appropriate type. Defining these type
208 /// aliases prevents issues such as overly long function definitions.
209 pub type BlockNotifierArc = Arc<BlockNotifier<'static, Arc<ChainListener>>>;
211 /// BlockNotifierRef is useful when you want a BlockNotifier that points to ChainListeners
212 /// with nonstatic lifetimes. This is useful for when static lifetimes are not needed. Nonstatic
213 /// lifetimes are more efficient but less flexible, and should be used by default unless static
214 /// lifetimes are required, e.g. when you're using lightning-net-tokio (since tokio::spawn
215 /// requires parameters with static lifetimes), in which case BlockNotifierArc is a more
216 /// appropriate type. Defining these type aliases for common usages prevents issues such as
217 /// overly long function definitions.
218 pub type BlockNotifierRef<'a> = BlockNotifier<'a, &'a ChainListener>;
220 /// Utility for notifying listeners when blocks are connected or disconnected.
222 /// Rather than using a plain BlockNotifier, it is preferable to use either a BlockNotifierArc
223 /// or a BlockNotifierRef for conciseness. See their documentation for more details, but essentially
224 /// you should default to using a BlockNotifierRef, and use a BlockNotifierArc instead when you
225 /// require ChainListeners with static lifetimes, such as when you're using lightning-net-tokio.
226 pub struct BlockNotifier<'a, CL: Deref<Target = ChainListener + 'a> + 'a> {
227 listeners: Mutex<Vec<CL>>,
228 phantom: PhantomData<&'a ()>,
231 impl<'a, CL: Deref<Target = ChainListener + 'a> + 'a> BlockNotifier<'a, CL> {
232 /// Constructs a new BlockNotifier without any listeners.
233 pub fn new() -> BlockNotifier<'a, CL> {
235 listeners: Mutex::new(Vec::new()),
236 phantom: PhantomData,
240 /// Register the given listener to receive events.
241 pub fn register_listener(&self, listener: CL) {
242 let mut vec = self.listeners.lock().unwrap();
245 /// Unregister the given listener to no longer
248 /// If the same listener is registered multiple times, unregistering
249 /// will remove ALL occurrences of that listener. Comparison is done using
250 /// the pointer returned by the Deref trait implementation.
251 pub fn unregister_listener(&self, listener: CL) {
252 let mut vec = self.listeners.lock().unwrap();
253 // item is a ref to an abstract thing that dereferences to a ChainListener,
254 // so dereference it twice to get the ChainListener itself
255 vec.retain(|item | !ptr::eq(&(**item), &(*listener)));
258 /// Notify listeners that a block was connected.
259 pub fn block_connected(&self, block: &Block, height: u32) {
260 let txdata: Vec<_> = block.txdata.iter().enumerate().collect();
261 let listeners = self.listeners.lock().unwrap();
262 for listener in listeners.iter() {
263 listener.block_connected(&block.header, &txdata, height);
267 /// Notify listeners that a block was disconnected.
268 pub fn block_disconnected(&self, header: &BlockHeader, disconnected_height: u32) {
269 let listeners = self.listeners.lock().unwrap();
270 for listener in listeners.iter() {
271 listener.block_disconnected(&header, disconnected_height);
276 /// Utility to capture some common parts of ChainWatchInterface implementors.
278 /// Keeping a local copy of this in a ChainWatchInterface implementor is likely useful.
279 pub struct ChainWatchInterfaceUtil {
281 watched: Mutex<ChainWatchedUtil>,
282 reentered: AtomicUsize,
285 // We only expose PartialEq in test since its somewhat unclear exactly what it should do and we're
286 // only comparing a subset of fields (essentially just checking that the set of things we're
287 // watching is the same).
289 impl PartialEq for ChainWatchInterfaceUtil {
290 fn eq(&self, o: &Self) -> bool {
291 self.network == o.network &&
292 *self.watched.lock().unwrap() == *o.watched.lock().unwrap()
296 /// Register listener
297 impl ChainWatchInterface for ChainWatchInterfaceUtil {
298 fn install_watch_tx(&self, txid: &Txid, script_pub_key: &Script) {
299 let mut watched = self.watched.lock().unwrap();
300 if watched.register_tx(txid, script_pub_key) {
301 self.reentered.fetch_add(1, Ordering::Relaxed);
305 fn install_watch_outpoint(&self, outpoint: (Txid, u32), out_script: &Script) {
306 let mut watched = self.watched.lock().unwrap();
307 if watched.register_outpoint(outpoint, out_script) {
308 self.reentered.fetch_add(1, Ordering::Relaxed);
312 fn watch_all_txn(&self) {
313 let mut watched = self.watched.lock().unwrap();
314 if watched.watch_all() {
315 self.reentered.fetch_add(1, Ordering::Relaxed);
319 fn get_chain_utxo(&self, genesis_hash: BlockHash, _unspent_tx_output_identifier: u64) -> Result<(Script, u64), ChainError> {
320 if genesis_hash != genesis_block(self.network).header.bitcoin_hash() {
321 return Err(ChainError::NotWatched);
323 Err(ChainError::NotSupported)
326 fn filter_block(&self, _header: &BlockHeader, txdata: &[(usize, &Transaction)]) -> Vec<usize> {
327 let mut matched_index = Vec::new();
329 let watched = self.watched.lock().unwrap();
330 for (i, transaction) in txdata.iter().enumerate() {
331 if self.does_match_tx_unguarded(transaction.1, &watched) {
332 matched_index.push(i);
339 fn reentered(&self) -> usize {
340 self.reentered.load(Ordering::Relaxed)
344 impl ChainWatchInterfaceUtil {
345 /// Creates a new ChainWatchInterfaceUtil for the given network
346 pub fn new(network: Network) -> ChainWatchInterfaceUtil {
347 ChainWatchInterfaceUtil {
349 watched: Mutex::new(ChainWatchedUtil::new()),
350 reentered: AtomicUsize::new(1),
354 /// Checks if a given transaction matches the current filter.
355 pub fn does_match_tx(&self, tx: &Transaction) -> bool {
356 let watched = self.watched.lock().unwrap();
357 self.does_match_tx_unguarded (tx, &watched)
360 fn does_match_tx_unguarded(&self, tx: &Transaction, watched: &MutexGuard<ChainWatchedUtil>) -> bool {
361 watched.does_match_tx(tx)
367 use bitcoin::blockdata::block::BlockHeader;
368 use bitcoin::blockdata::transaction::Transaction;
369 use super::{BlockNotifier, ChainListener};
372 struct TestChainListener(u8);
374 impl ChainListener for TestChainListener {
375 fn block_connected(&self, _header: &BlockHeader, _txdata: &[(usize, &Transaction)], _height: u32) {}
376 fn block_disconnected(&self, _header: &BlockHeader, _disconnected_height: u32) {}
380 fn register_listener_test() {
381 let block_notifier = BlockNotifier::new();
382 assert_eq!(block_notifier.listeners.lock().unwrap().len(), 0);
383 let listener = &TestChainListener(0);
384 block_notifier.register_listener(listener as &ChainListener);
385 let vec = block_notifier.listeners.lock().unwrap();
386 assert_eq!(vec.len(), 1);
387 let item = vec.first().unwrap();
388 assert!(ptr::eq(&(**item), listener));
392 fn unregister_single_listener_test() {
393 let block_notifier = BlockNotifier::new();
394 let listener1 = &TestChainListener(1);
395 let listener2 = &TestChainListener(2);
396 block_notifier.register_listener(listener1 as &ChainListener);
397 block_notifier.register_listener(listener2 as &ChainListener);
398 let vec = block_notifier.listeners.lock().unwrap();
399 assert_eq!(vec.len(), 2);
401 block_notifier.unregister_listener(listener1);
402 let vec = block_notifier.listeners.lock().unwrap();
403 assert_eq!(vec.len(), 1);
404 let item = vec.first().unwrap();
405 assert!(ptr::eq(&(**item), listener2));
409 fn unregister_multiple_of_the_same_listeners_test() {
410 let block_notifier = BlockNotifier::new();
411 let listener1 = &TestChainListener(1);
412 let listener2 = &TestChainListener(2);
413 block_notifier.register_listener(listener1 as &ChainListener);
414 block_notifier.register_listener(listener1 as &ChainListener);
415 block_notifier.register_listener(listener2 as &ChainListener);
416 let vec = block_notifier.listeners.lock().unwrap();
417 assert_eq!(vec.len(), 3);
419 block_notifier.unregister_listener(listener1);
420 let vec = block_notifier.listeners.lock().unwrap();
421 assert_eq!(vec.len(), 1);
422 let item = vec.first().unwrap();
423 assert!(ptr::eq(&(**item), listener2));