@@ -45,16 +45,20 @@ pub trait ChainWatchInterface: Sync + Send {
45
45
/// Indicates that a listener needs to see all transactions.
46
46
fn watch_all_txn ( & self ) ;
47
47
48
- /// Register the given listener to receive events. Only a weak pointer is provided and the
49
- /// registration should be freed once that pointer expires.
50
- fn register_listener ( & self , listener : Weak < ChainListener > ) ;
51
- //TODO: unregister
52
-
53
48
/// Gets the script and value in satoshis for a given unspent transaction output given a
54
49
/// short_channel_id (aka unspent_tx_output_identier). For BTC/tBTC channels the top three
55
50
/// bytes are the block height, the next 3 the transaction index within the block, and the
56
51
/// final two the output within the transaction.
57
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 ;
58
62
}
59
63
60
64
/// An interface to send a transaction to the Bitcoin network.
@@ -198,13 +202,81 @@ impl ChainWatchedUtil {
198
202
}
199
203
}
200
204
205
+ /// Utility for notifying listeners about new blocks, and handling block rescans if new watch
206
+ /// data is registered.
207
+ pub struct BlockNotifier < ' a > {
208
+ listeners : Mutex < Vec < Weak < ChainListener + ' a > > > , //TODO(vmw): try removing Weak
209
+ chain_monitor : Arc < ChainWatchInterface > ,
210
+ }
211
+
212
+ impl < ' a > BlockNotifier < ' a > {
213
+ /// Constructs a new BlockNotifier without any listeners.
214
+ pub fn new ( chain_monitor : Arc < ChainWatchInterface > ) -> BlockNotifier < ' a > {
215
+ BlockNotifier {
216
+ listeners : Mutex :: new ( Vec :: new ( ) ) ,
217
+ chain_monitor,
218
+ }
219
+ }
220
+
221
+ /// Register the given listener to receive events. Only a weak pointer is provided and
222
+ /// the registration should be freed once that pointer expires.
223
+ // TODO: unregister
224
+ pub fn register_listener ( & self , listener : Weak < ChainListener + ' a > ) {
225
+ let mut vec = self . listeners . lock ( ) . unwrap ( ) ;
226
+ vec. push ( listener) ;
227
+ }
228
+
229
+ /// Notify listeners that a block was connected given a full, unfiltered block.
230
+ ///
231
+ /// Handles re-scanning the block and calling block_connected again if listeners register new
232
+ /// watch data during the callbacks for you (see ChainListener::block_connected for more info).
233
+ pub fn block_connected < ' b > ( & self , block : & ' b Block , height : u32 ) {
234
+ let mut reentered = true ;
235
+ while reentered {
236
+ let ( matched, matched_index) = self . chain_monitor . filter_block ( block) ;
237
+ reentered = self . block_connected_checked ( & block. header , height, matched. as_slice ( ) , matched_index. as_slice ( ) ) ;
238
+ }
239
+ }
240
+
241
+ /// Notify listeners that a block was connected, given pre-filtered list of transactions in the
242
+ /// block which matched the filter (probably using does_match_tx).
243
+ ///
244
+ /// Returns true if notified listeners registered additional watch data (implying that the
245
+ /// block must be re-scanned and this function called again prior to further block_connected
246
+ /// calls, see ChainListener::block_connected for more info).
247
+ pub fn block_connected_checked ( & self , header : & BlockHeader , height : u32 , txn_matched : & [ & Transaction ] , indexes_of_txn_matched : & [ u32 ] ) -> bool {
248
+ let last_seen = self . chain_monitor . reentered ( ) ;
249
+
250
+ let listeners = self . listeners . lock ( ) . unwrap ( ) . clone ( ) ;
251
+ for listener in listeners. iter ( ) {
252
+ match listener. upgrade ( ) {
253
+ Some ( arc) => arc. block_connected ( header, height, txn_matched, indexes_of_txn_matched) ,
254
+ None => ( )
255
+ }
256
+ }
257
+ return last_seen != self . chain_monitor . reentered ( ) ;
258
+ }
259
+
260
+
261
+ /// Notify listeners that a block was disconnected.
262
+ pub fn block_disconnected ( & self , header : & BlockHeader , disconnected_height : u32 ) {
263
+ let listeners = self . listeners . lock ( ) . unwrap ( ) . clone ( ) ;
264
+ for listener in listeners. iter ( ) {
265
+ match listener. upgrade ( ) {
266
+ Some ( arc) => arc. block_disconnected ( & header, disconnected_height) ,
267
+ None => ( )
268
+ }
269
+ }
270
+ }
271
+
272
+ }
273
+
201
274
/// Utility to capture some common parts of ChainWatchInterface implementors.
202
275
///
203
276
/// Keeping a local copy of this in a ChainWatchInterface implementor is likely useful.
204
277
pub struct ChainWatchInterfaceUtil {
205
278
network : Network ,
206
279
watched : Mutex < ChainWatchedUtil > ,
207
- listeners : Mutex < Vec < Weak < ChainListener > > > ,
208
280
reentered : AtomicUsize ,
209
281
logger : Arc < Logger > ,
210
282
}
@@ -232,17 +304,31 @@ impl ChainWatchInterface for ChainWatchInterfaceUtil {
232
304
}
233
305
}
234
306
235
- fn register_listener ( & self , listener : Weak < ChainListener > ) {
236
- let mut vec = self . listeners . lock ( ) . unwrap ( ) ;
237
- vec. push ( listener) ;
238
- }
239
-
240
307
fn get_chain_utxo ( & self , genesis_hash : Sha256dHash , _unspent_tx_output_identifier : u64 ) -> Result < ( Script , u64 ) , ChainError > {
241
308
if genesis_hash != genesis_block ( self . network ) . header . bitcoin_hash ( ) {
242
309
return Err ( ChainError :: NotWatched ) ;
243
310
}
244
311
Err ( ChainError :: NotSupported )
245
312
}
313
+
314
+ fn filter_block < ' a > ( & self , block : & ' a Block ) -> ( Vec < & ' a Transaction > , Vec < u32 > ) {
315
+ let mut matched = Vec :: new ( ) ;
316
+ let mut matched_index = Vec :: new ( ) ;
317
+ {
318
+ let watched = self . watched . lock ( ) . unwrap ( ) ;
319
+ for ( index, transaction) in block. txdata . iter ( ) . enumerate ( ) {
320
+ if self . does_match_tx_unguarded ( transaction, & watched) {
321
+ matched. push ( transaction) ;
322
+ matched_index. push ( index as u32 ) ;
323
+ }
324
+ }
325
+ }
326
+ ( matched, matched_index)
327
+ }
328
+
329
+ fn reentered ( & self ) -> usize {
330
+ self . reentered . load ( Ordering :: Relaxed )
331
+ }
246
332
}
247
333
248
334
impl ChainWatchInterfaceUtil {
@@ -251,63 +337,11 @@ impl ChainWatchInterfaceUtil {
251
337
ChainWatchInterfaceUtil {
252
338
network : network,
253
339
watched : Mutex :: new ( ChainWatchedUtil :: new ( ) ) ,
254
- listeners : Mutex :: new ( Vec :: new ( ) ) ,
255
340
reentered : AtomicUsize :: new ( 1 ) ,
256
341
logger : logger,
257
342
}
258
343
}
259
344
260
- /// Notify listeners that a block was connected given a full, unfiltered block.
261
- ///
262
- /// Handles re-scanning the block and calling block_connected again if listeners register new
263
- /// watch data during the callbacks for you (see ChainListener::block_connected for more info).
264
- pub fn block_connected_with_filtering ( & self , block : & Block , height : u32 ) {
265
- let mut reentered = true ;
266
- while reentered {
267
- let mut matched = Vec :: new ( ) ;
268
- let mut matched_index = Vec :: new ( ) ;
269
- {
270
- let watched = self . watched . lock ( ) . unwrap ( ) ;
271
- for ( index, transaction) in block. txdata . iter ( ) . enumerate ( ) {
272
- if self . does_match_tx_unguarded ( transaction, & watched) {
273
- matched. push ( transaction) ;
274
- matched_index. push ( index as u32 ) ;
275
- }
276
- }
277
- }
278
- reentered = self . block_connected_checked ( & block. header , height, matched. as_slice ( ) , matched_index. as_slice ( ) ) ;
279
- }
280
- }
281
-
282
- /// Notify listeners that a block was disconnected.
283
- pub fn block_disconnected ( & self , header : & BlockHeader , disconnected_height : u32 ) {
284
- let listeners = self . listeners . lock ( ) . unwrap ( ) . clone ( ) ;
285
- for listener in listeners. iter ( ) {
286
- match listener. upgrade ( ) {
287
- Some ( arc) => arc. block_disconnected ( & header, disconnected_height) ,
288
- None => ( )
289
- }
290
- }
291
- }
292
-
293
- /// Notify listeners that a block was connected, given pre-filtered list of transactions in the
294
- /// block which matched the filter (probably using does_match_tx).
295
- ///
296
- /// Returns true if notified listeners registered additional watch data (implying that the
297
- /// block must be re-scanned and this function called again prior to further block_connected
298
- /// calls, see ChainListener::block_connected for more info).
299
- pub fn block_connected_checked ( & self , header : & BlockHeader , height : u32 , txn_matched : & [ & Transaction ] , indexes_of_txn_matched : & [ u32 ] ) -> bool {
300
- let last_seen = self . reentered . load ( Ordering :: Relaxed ) ;
301
-
302
- let listeners = self . listeners . lock ( ) . unwrap ( ) . clone ( ) ;
303
- for listener in listeners. iter ( ) {
304
- match listener. upgrade ( ) {
305
- Some ( arc) => arc. block_connected ( header, height, txn_matched, indexes_of_txn_matched) ,
306
- None => ( )
307
- }
308
- }
309
- return last_seen != self . reentered . load ( Ordering :: Relaxed ) ;
310
- }
311
345
312
346
/// Checks if a given transaction matches the current filter.
313
347
pub fn does_match_tx ( & self , tx : & Transaction ) -> bool {
0 commit comments