Simplify BlockNotifier tests
[rust-lightning] / lightning / src / chain / chaininterface.rs
1 //! Traits and utility impls which allow other parts of rust-lightning to interact with the
2 //! blockchain.
3 //!
4 //! Includes traits for monitoring and receiving notifications of new blocks and block
5 //! disconnections, transaction broadcasting, and feerate information requests.
6
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};
14
15 use std::sync::{Mutex, MutexGuard, Arc};
16 use std::sync::atomic::{AtomicUsize, Ordering};
17 use std::collections::HashSet;
18 use std::ops::Deref;
19 use std::marker::PhantomData;
20 use std::ptr;
21
22 /// Used to give chain error details upstream
23 #[derive(Clone)]
24 pub enum ChainError {
25         /// Client doesn't support UTXO lookup (but the chain hash matches our genesis block hash)
26         NotSupported,
27         /// Chain isn't the one watched
28         NotWatched,
29         /// Tx doesn't exist or is unconfirmed
30         UnknownTx,
31 }
32
33 /// An interface to request notification of certain scripts as they appear the
34 /// chain.
35 ///
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
38 /// events).
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);
42
43         /// Provides an outpoint which must be watched for, providing any transactions which spend the
44         /// given outpoint.
45         fn install_watch_outpoint(&self, outpoint: (Txid, u32), out_script: &Script);
46
47         /// Indicates that a listener needs to see all transactions.
48         fn watch_all_txn(&self);
49
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>;
55
56         /// Gets the list of transaction indices within a given block that the ChainWatchInterface is
57         /// watching for.
58         fn filter_block(&self, header: &BlockHeader, txdata: &[(usize, &Transaction)]) -> Vec<usize>;
59
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;
64 }
65
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);
70 }
71
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);
77
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);
82 }
83
84 /// An enum that represents the speed at which we want a transaction to confirm used for feerate
85 /// estimation.
86 pub enum ConfirmationTarget {
87         /// We are happy with this transaction confirming slowly when feerate drops some.
88         Background,
89         /// We'd like this transaction to confirm without major delay, but 12-18 blocks is fine.
90         Normal,
91         /// We'd like this transaction to confirm in the next few blocks.
92         HighPriority,
93 }
94
95 /// A trait which should be implemented to provide feerate information on a number of time
96 /// horizons.
97 ///
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
100 /// events).
101 pub trait FeeEstimator: Sync + Send {
102         /// Gets estimated satoshis of fee required per 1000 Weight-Units.
103         ///
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).
106         ///
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;
111 }
112
113 /// Minimum relay fee as required by bitcoin network mempool policy.
114 pub const MIN_RELAY_FEE_SAT_PER_1000_WEIGHT: u64 = 4000;
115
116 /// Utility for tracking registered txn/outpoints and checking for matches
117 #[cfg_attr(test, derive(PartialEq))]
118 pub struct ChainWatchedUtil {
119         watch_all: bool,
120
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...
123         #[cfg(test)]
124         watched_txn: HashSet<(Txid, Script)>,
125         #[cfg(not(test))]
126         watched_txn: HashSet<Script>,
127
128         watched_outpoints: HashSet<(Txid, u32)>,
129 }
130
131 impl ChainWatchedUtil {
132         /// Constructs an empty (watches nothing) ChainWatchedUtil
133         pub fn new() -> Self {
134                 Self {
135                         watch_all: false,
136                         watched_txn: HashSet::new(),
137                         watched_outpoints: HashSet::new(),
138                 }
139         }
140
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; }
145                 #[cfg(test)]
146                 {
147                         self.watched_txn.insert((txid.clone(), script_pub_key.clone()))
148                 }
149                 #[cfg(not(test))]
150                 {
151                         let _tx_unused = txid; // It's used in cfg(test), though
152                         self.watched_txn.insert(script_pub_key.clone())
153                 }
154         }
155
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)
161         }
162
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;
168                 true
169         }
170
171         /// Checks if a given transaction matches the current filter.
172         pub fn does_match_tx(&self, tx: &Transaction) -> bool {
173                 if self.watch_all {
174                         return true;
175                 }
176                 for out in tx.output.iter() {
177                         #[cfg(test)]
178                         for &(ref txid, ref script) in self.watched_txn.iter() {
179                                 if *script == out.script_pubkey {
180                                         if tx.txid() == *txid {
181                                                 return true;
182                                         }
183                                 }
184                         }
185                         #[cfg(not(test))]
186                         for script in self.watched_txn.iter() {
187                                 if *script == out.script_pubkey {
188                                         return true;
189                                 }
190                         }
191                 }
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 {
196                                         return true;
197                                 }
198                         }
199                 }
200                 false
201         }
202 }
203
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>>>;
210
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>;
219
220 /// Utility for notifying listeners when blocks are connected or disconnected.
221 ///
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 ()>,
229 }
230
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> {
234                 BlockNotifier {
235                         listeners: Mutex::new(Vec::new()),
236                         phantom: PhantomData,
237                 }
238         }
239
240         /// Register the given listener to receive events.
241         pub fn register_listener(&self, listener: CL) {
242                 let mut vec = self.listeners.lock().unwrap();
243                 vec.push(listener);
244         }
245         /// Unregister the given listener to no longer
246         /// receive events.
247         ///
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)));
256         }
257
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);
264                 }
265         }
266
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);
272                 }
273         }
274 }
275
276 /// Utility to capture some common parts of ChainWatchInterface implementors.
277 ///
278 /// Keeping a local copy of this in a ChainWatchInterface implementor is likely useful.
279 pub struct ChainWatchInterfaceUtil {
280         network: Network,
281         watched: Mutex<ChainWatchedUtil>,
282         reentered: AtomicUsize,
283 }
284
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).
288 #[cfg(test)]
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()
293         }
294 }
295
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);
302                 }
303         }
304
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);
309                 }
310         }
311
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);
316                 }
317         }
318
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);
322                 }
323                 Err(ChainError::NotSupported)
324         }
325
326         fn filter_block(&self, _header: &BlockHeader, txdata: &[(usize, &Transaction)]) -> Vec<usize> {
327                 let mut matched_index = Vec::new();
328                 {
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);
333                                 }
334                         }
335                 }
336                 matched_index
337         }
338
339         fn reentered(&self) -> usize {
340                 self.reentered.load(Ordering::Relaxed)
341         }
342 }
343
344 impl ChainWatchInterfaceUtil {
345         /// Creates a new ChainWatchInterfaceUtil for the given network
346         pub fn new(network: Network) -> ChainWatchInterfaceUtil {
347                 ChainWatchInterfaceUtil {
348                         network,
349                         watched: Mutex::new(ChainWatchedUtil::new()),
350                         reentered: AtomicUsize::new(1),
351                 }
352         }
353
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)
358         }
359
360         fn does_match_tx_unguarded(&self, tx: &Transaction, watched: &MutexGuard<ChainWatchedUtil>) -> bool {
361                 watched.does_match_tx(tx)
362         }
363 }
364
365 #[cfg(test)]
366 mod tests {
367         use bitcoin::blockdata::block::BlockHeader;
368         use bitcoin::blockdata::transaction::Transaction;
369         use super::{BlockNotifier, ChainListener};
370         use std::ptr;
371
372         struct TestChainListener(u8);
373
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) {}
377         }
378
379         #[test]
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));
389         }
390
391         #[test]
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);
400                 drop(vec);
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));
406         }
407
408         #[test]
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);
418                 drop(vec);
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));
424         }
425 }