Add MIN_RELAY_FEE_SAT_PER_1000_WEIGHT
[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_hashes::sha256d::Hash as Sha256dHash;
13 use bitcoin::network::constants::Network;
14
15 use util::logger::Logger;
16
17 use std::sync::{Mutex,Weak,MutexGuard,Arc};
18 use std::sync::atomic::{AtomicUsize, Ordering};
19 use std::collections::HashSet;
20
21 /// Used to give chain error details upstream
22 pub enum ChainError {
23         /// Client doesn't support UTXO lookup (but the chain hash matches our genesis block hash)
24         NotSupported,
25         /// Chain isn't the one watched
26         NotWatched,
27         /// Tx doesn't exist or is unconfirmed
28         UnknownTx,
29 }
30
31 /// An interface to request notification of certain scripts as they appear the
32 /// chain.
33 ///
34 /// Note that all of the functions implemented here *must* be reentrant-safe (obviously - they're
35 /// called from inside the library in response to ChainListener events, P2P events, or timer
36 /// events).
37 pub trait ChainWatchInterface: Sync + Send {
38         /// Provides a txid/random-scriptPubKey-in-the-tx which much be watched for.
39         fn install_watch_tx(&self, txid: &Sha256dHash, script_pub_key: &Script);
40
41         /// Provides an outpoint which must be watched for, providing any transactions which spend the
42         /// given outpoint.
43         fn install_watch_outpoint(&self, outpoint: (Sha256dHash, u32), out_script: &Script);
44
45         /// Indicates that a listener needs to see all transactions.
46         fn watch_all_txn(&self);
47
48         /// Gets the script and value in satoshis for a given unspent transaction output given a
49         /// short_channel_id (aka unspent_tx_output_identier). For BTC/tBTC channels the top three
50         /// bytes are the block height, the next 3 the transaction index within the block, and the
51         /// final two the output within the transaction.
52         fn get_chain_utxo(&self, genesis_hash: Sha256dHash, unspent_tx_output_identifier: u64) -> Result<(Script, u64), ChainError>;
53
54         /// Gets the list of transactions and transaction indices that the ChainWatchInterface is
55         /// watching for.
56         fn filter_block<'a>(&self, block: &'a Block) -> (Vec<&'a Transaction>, Vec<u32>);
57
58         /// Returns a usize that changes when the ChainWatchInterface's watched data is modified.
59         /// Users of `filter_block` should pre-save a copy of `reentered`'s return value and use it to
60         /// determine whether they need to re-filter a given block.
61         fn reentered(&self) -> usize;
62 }
63
64 /// An interface to send a transaction to the Bitcoin network.
65 pub trait BroadcasterInterface: Sync + Send {
66         /// Sends a transaction out to (hopefully) be mined.
67         fn broadcast_transaction(&self, tx: &Transaction);
68 }
69
70 /// A trait indicating a desire to listen for events from the chain
71 pub trait ChainListener: Sync + Send {
72         /// Notifies a listener that a block was connected.
73         /// Note that if a new transaction/outpoint is watched during a block_connected call, the block
74         /// *must* be re-scanned with the new transaction/outpoints and block_connected should be
75         /// called again with the same header and (at least) the new transactions.
76         ///
77         /// Note that if non-new transaction/outpoints may be registered during a call, a second call
78         /// *must not* happen.
79         ///
80         /// This also means those counting confirmations using block_connected callbacks should watch
81         /// for duplicate headers and not count them towards confirmations!
82         fn block_connected(&self, header: &BlockHeader, height: u32, txn_matched: &[&Transaction], indexes_of_txn_matched: &[u32]);
83         /// Notifies a listener that a block was disconnected.
84         /// Unlike block_connected, this *must* never be called twice for the same disconnect event.
85         /// Height must be the one of the block which was disconnected (not new height of the best chain)
86         fn block_disconnected(&self, header: &BlockHeader, disconnected_height: u32);
87 }
88
89 /// An enum that represents the speed at which we want a transaction to confirm used for feerate
90 /// estimation.
91 pub enum ConfirmationTarget {
92         /// We are happy with this transaction confirming slowly when feerate drops some.
93         Background,
94         /// We'd like this transaction to confirm without major delay, but 12-18 blocks is fine.
95         Normal,
96         /// We'd like this transaction to confirm in the next few blocks.
97         HighPriority,
98 }
99
100 /// A trait which should be implemented to provide feerate information on a number of time
101 /// horizons.
102 ///
103 /// Note that all of the functions implemented here *must* be reentrant-safe (obviously - they're
104 /// called from inside the library in response to ChainListener events, P2P events, or timer
105 /// events).
106 pub trait FeeEstimator: Sync + Send {
107         /// Gets estimated satoshis of fee required per 1000 Weight-Units.
108         ///
109         /// Must be no smaller than 253 (ie 1 satoshi-per-byte rounded up to ensure later round-downs
110         /// don't put us below 1 satoshi-per-byte).
111         ///
112         /// This translates to:
113         ///  * satoshis-per-byte * 250
114         ///  * ceil(satoshis-per-kbyte / 4)
115         fn get_est_sat_per_1000_weight(&self, confirmation_target: ConfirmationTarget) -> u64;
116 }
117
118 /// Minimum relay fee as required by bitcoin network mempool policy.
119 pub const MIN_RELAY_FEE_SAT_PER_1000_WEIGHT: u64 = 4000;
120
121 /// Utility for tracking registered txn/outpoints and checking for matches
122 pub struct ChainWatchedUtil {
123         watch_all: bool,
124
125         // We are more conservative in matching during testing to ensure everything matches *exactly*,
126         // even though during normal runtime we take more optimized match approaches...
127         #[cfg(test)]
128         watched_txn: HashSet<(Sha256dHash, Script)>,
129         #[cfg(not(test))]
130         watched_txn: HashSet<Script>,
131
132         watched_outpoints: HashSet<(Sha256dHash, u32)>,
133 }
134
135 impl ChainWatchedUtil {
136         /// Constructs an empty (watches nothing) ChainWatchedUtil
137         pub fn new() -> Self {
138                 Self {
139                         watch_all: false,
140                         watched_txn: HashSet::new(),
141                         watched_outpoints: HashSet::new(),
142                 }
143         }
144
145         /// Registers a tx for monitoring, returning true if it was a new tx and false if we'd already
146         /// been watching for it.
147         pub fn register_tx(&mut self, txid: &Sha256dHash, script_pub_key: &Script) -> bool {
148                 if self.watch_all { return false; }
149                 #[cfg(test)]
150                 {
151                         self.watched_txn.insert((txid.clone(), script_pub_key.clone()))
152                 }
153                 #[cfg(not(test))]
154                 {
155                         let _tx_unused = txid; // It's used in cfg(test), though
156                         self.watched_txn.insert(script_pub_key.clone())
157                 }
158         }
159
160         /// Registers an outpoint for monitoring, returning true if it was a new outpoint and false if
161         /// we'd already been watching for it
162         pub fn register_outpoint(&mut self, outpoint: (Sha256dHash, u32), _script_pub_key: &Script) -> bool {
163                 if self.watch_all { return false; }
164                 self.watched_outpoints.insert(outpoint)
165         }
166
167         /// Sets us to match all transactions, returning true if this is a new setting and false if
168         /// we'd already been set to match everything.
169         pub fn watch_all(&mut self) -> bool {
170                 if self.watch_all { return false; }
171                 self.watch_all = true;
172                 true
173         }
174
175         /// Checks if a given transaction matches the current filter.
176         pub fn does_match_tx(&self, tx: &Transaction) -> bool {
177                 if self.watch_all {
178                         return true;
179                 }
180                 for out in tx.output.iter() {
181                         #[cfg(test)]
182                         for &(ref txid, ref script) in self.watched_txn.iter() {
183                                 if *script == out.script_pubkey {
184                                         if tx.txid() == *txid {
185                                                 return true;
186                                         }
187                                 }
188                         }
189                         #[cfg(not(test))]
190                         for script in self.watched_txn.iter() {
191                                 if *script == out.script_pubkey {
192                                         return true;
193                                 }
194                         }
195                 }
196                 for input in tx.input.iter() {
197                         for outpoint in self.watched_outpoints.iter() {
198                                 let &(outpoint_hash, outpoint_index) = outpoint;
199                                 if outpoint_hash == input.previous_output.txid && outpoint_index == input.previous_output.vout {
200                                         return true;
201                                 }
202                         }
203                 }
204                 false
205         }
206 }
207
208 /// Utility for notifying listeners about new blocks, and handling block rescans if new watch
209 /// data is registered.
210 pub struct BlockNotifier<'a> {
211         listeners: Mutex<Vec<Weak<ChainListener + 'a>>>, //TODO(vmw): try removing Weak
212         chain_monitor: Arc<ChainWatchInterface>,
213 }
214
215 impl<'a> BlockNotifier<'a> {
216         /// Constructs a new BlockNotifier without any listeners.
217         pub fn new(chain_monitor: Arc<ChainWatchInterface>) -> BlockNotifier<'a> {
218                 BlockNotifier {
219                         listeners: Mutex::new(Vec::new()),
220                         chain_monitor,
221                 }
222         }
223
224         /// Register the given listener to receive events. Only a weak pointer is provided and
225         /// the registration should be freed once that pointer expires.
226         // TODO: unregister
227         pub fn register_listener(&self, listener: Weak<ChainListener + 'a>) {
228                 let mut vec = self.listeners.lock().unwrap();
229                 vec.push(listener);
230         }
231
232         /// Notify listeners that a block was connected given a full, unfiltered block.
233         ///
234         /// Handles re-scanning the block and calling block_connected again if listeners register new
235         /// watch data during the callbacks for you (see ChainListener::block_connected for more info).
236         pub fn block_connected<'b>(&self, block: &'b Block, height: u32) {
237                 let mut reentered = true;
238                 while reentered {
239                         let (matched, matched_index) = self.chain_monitor.filter_block(block);
240                         reentered = self.block_connected_checked(&block.header, height, matched.as_slice(), matched_index.as_slice());
241                 }
242         }
243
244         /// Notify listeners that a block was connected, given pre-filtered list of transactions in the
245         /// block which matched the filter (probably using does_match_tx).
246         ///
247         /// Returns true if notified listeners registered additional watch data (implying that the
248         /// block must be re-scanned and this function called again prior to further block_connected
249         /// calls, see ChainListener::block_connected for more info).
250         pub fn block_connected_checked(&self, header: &BlockHeader, height: u32, txn_matched: &[&Transaction], indexes_of_txn_matched: &[u32]) -> bool {
251                 let last_seen = self.chain_monitor.reentered();
252
253                 let listeners = self.listeners.lock().unwrap().clone();
254                 for listener in listeners.iter() {
255                         match listener.upgrade() {
256                                 Some(arc) => arc.block_connected(header, height, txn_matched, indexes_of_txn_matched),
257                                 None => ()
258                         }
259                 }
260                 return last_seen != self.chain_monitor.reentered();
261         }
262
263
264         /// Notify listeners that a block was disconnected.
265         pub fn block_disconnected(&self, header: &BlockHeader, disconnected_height: u32) {
266                 let listeners = self.listeners.lock().unwrap().clone();
267                 for listener in listeners.iter() {
268                         match listener.upgrade() {
269                                 Some(arc) => arc.block_disconnected(&header, disconnected_height),
270                                 None => ()
271                         }
272                 }
273         }
274
275 }
276
277 /// Utility to capture some common parts of ChainWatchInterface implementors.
278 ///
279 /// Keeping a local copy of this in a ChainWatchInterface implementor is likely useful.
280 pub struct ChainWatchInterfaceUtil {
281         network: Network,
282         watched: Mutex<ChainWatchedUtil>,
283         reentered: AtomicUsize,
284         logger: Arc<Logger>,
285 }
286
287 /// Register listener
288 impl ChainWatchInterface for ChainWatchInterfaceUtil {
289         fn install_watch_tx(&self, txid: &Sha256dHash, script_pub_key: &Script) {
290                 let mut watched = self.watched.lock().unwrap();
291                 if watched.register_tx(txid, script_pub_key) {
292                         self.reentered.fetch_add(1, Ordering::Relaxed);
293                 }
294         }
295
296         fn install_watch_outpoint(&self, outpoint: (Sha256dHash, u32), out_script: &Script) {
297                 let mut watched = self.watched.lock().unwrap();
298                 if watched.register_outpoint(outpoint, out_script) {
299                         self.reentered.fetch_add(1, Ordering::Relaxed);
300                 }
301         }
302
303         fn watch_all_txn(&self) {
304                 let mut watched = self.watched.lock().unwrap();
305                 if watched.watch_all() {
306                         self.reentered.fetch_add(1, Ordering::Relaxed);
307                 }
308         }
309
310         fn get_chain_utxo(&self, genesis_hash: Sha256dHash, _unspent_tx_output_identifier: u64) -> Result<(Script, u64), ChainError> {
311                 if genesis_hash != genesis_block(self.network).header.bitcoin_hash() {
312                         return Err(ChainError::NotWatched);
313                 }
314                 Err(ChainError::NotSupported)
315         }
316
317         fn filter_block<'a>(&self, block: &'a Block) -> (Vec<&'a Transaction>, Vec<u32>) {
318                 let mut matched = Vec::new();
319                 let mut matched_index = Vec::new();
320                 {
321                         let watched = self.watched.lock().unwrap();
322                         for (index, transaction) in block.txdata.iter().enumerate() {
323                                 if self.does_match_tx_unguarded(transaction, &watched) {
324                                         matched.push(transaction);
325                                         matched_index.push(index as u32);
326                                 }
327                         }
328                 }
329                 (matched, matched_index)
330         }
331
332         fn reentered(&self) -> usize {
333                 self.reentered.load(Ordering::Relaxed)
334         }
335 }
336
337 impl ChainWatchInterfaceUtil {
338         /// Creates a new ChainWatchInterfaceUtil for the given network
339         pub fn new(network: Network, logger: Arc<Logger>) -> ChainWatchInterfaceUtil {
340                 ChainWatchInterfaceUtil {
341                         network: network,
342                         watched: Mutex::new(ChainWatchedUtil::new()),
343                         reentered: AtomicUsize::new(1),
344                         logger: logger,
345                 }
346         }
347
348
349         /// Checks if a given transaction matches the current filter.
350         pub fn does_match_tx(&self, tx: &Transaction) -> bool {
351                 let watched = self.watched.lock().unwrap();
352                 self.does_match_tx_unguarded (tx, &watched)
353         }
354
355         fn does_match_tx_unguarded(&self, tx: &Transaction, watched: &MutexGuard<ChainWatchedUtil>) -> bool {
356                 watched.does_match_tx(tx)
357         }
358 }