4
4
//! [`Emitter`] is the main structure which sources blockchain data from [`bitcoincore_rpc::Client`].
5
5
//!
6
6
//! To only get block updates (exclude mempool transactions), the caller can use
7
- //! [`Emitter::next_block`] or/and [`Emitter::next_header`] until it returns `Ok(None)` (which means
8
- //! the chain tip is reached). A separate method, [`Emitter::mempool`] can be used to emit the whole
9
- //! mempool.
7
+ //! [`Emitter::next_block`] until it returns `Ok(None)` (which means the chain tip is reached). A
8
+ //! separate method, [`Emitter::mempool`] can be used to emit the whole mempool.
10
9
#![ warn( missing_docs) ]
11
10
12
11
use bdk_core:: { BlockId , CheckPoint } ;
13
12
use bitcoin:: { Block , BlockHash , Transaction , Txid } ;
14
- use bitcoincore_rpc:: bitcoincore_rpc_json;
15
- use std:: collections:: HashSet ;
13
+ use bitcoincore_rpc:: { bitcoincore_rpc_json, RpcApi } ;
14
+ use std:: { collections:: HashSet , ops :: Deref } ;
16
15
17
16
pub mod bip158;
18
17
@@ -23,8 +22,8 @@ pub use bitcoincore_rpc;
23
22
/// Refer to [module-level documentation] for more.
24
23
///
25
24
/// [module-level documentation]: crate
26
- pub struct Emitter < ' c , C > {
27
- client : & ' c C ,
25
+ pub struct Emitter < C > {
26
+ client : C ,
28
27
start_height : u32 ,
29
28
30
29
/// The checkpoint of the last-emitted block that is in the best chain. If it is later found
@@ -56,7 +55,17 @@ pub struct Emitter<'c, C> {
56
55
expected_mempool_txids : HashSet < Txid > ,
57
56
}
58
57
59
- impl < ' c , C : bitcoincore_rpc:: RpcApi > Emitter < ' c , C > {
58
+ /// Indicates that there are no initially expected mempool transactions.
59
+ ///
60
+ /// Pass this to the `expected_mempool_txids` field of [`Emitter::new`] when the wallet is known
61
+ /// to start empty (i.e. with no unconfirmed transactions).
62
+ pub const NO_EXPECTED_MEMPOOL_TXIDS : core:: iter:: Empty < Txid > = core:: iter:: empty ( ) ;
63
+
64
+ impl < C > Emitter < C >
65
+ where
66
+ C : Deref ,
67
+ C :: Target : RpcApi ,
68
+ {
60
69
/// Construct a new [`Emitter`].
61
70
///
62
71
/// `last_cp` informs the emitter of the chain we are starting off with. This way, the emitter
@@ -66,12 +75,13 @@ impl<'c, C: bitcoincore_rpc::RpcApi> Emitter<'c, C> {
66
75
/// original chain).
67
76
///
68
77
/// `expected_mempool_txids` is the initial set of unconfirmed txids provided by the wallet.
69
- /// This allows the [`Emitter`] to inform the wallet about relevant mempool evictions.
78
+ /// This allows the [`Emitter`] to inform the wallet about relevant mempool evictions. If it is
79
+ /// known that the wallet is empty, [`NO_EXPECTED_MEMPOOL_TXIDS`] can be used.
70
80
pub fn new (
71
- client : & ' c C ,
81
+ client : C ,
72
82
last_cp : CheckPoint ,
73
83
start_height : u32 ,
74
- expected_mempool_txids : HashSet < Txid > ,
84
+ expected_mempool_txids : impl IntoIterator < Item = impl Into < Txid > > ,
75
85
) -> Self {
76
86
Self {
77
87
client,
@@ -80,7 +90,7 @@ impl<'c, C: bitcoincore_rpc::RpcApi> Emitter<'c, C> {
80
90
last_block : None ,
81
91
last_mempool_time : 0 ,
82
92
last_mempool_tip : None ,
83
- expected_mempool_txids,
93
+ expected_mempool_txids : expected_mempool_txids . into_iter ( ) . map ( Into :: into ) . collect ( ) ,
84
94
}
85
95
}
86
96
@@ -102,7 +112,7 @@ impl<'c, C: bitcoincore_rpc::RpcApi> Emitter<'c, C> {
102
112
/// of height `h-1`, we want to re-emit this transaction until the receiver has seen the block
103
113
/// at height `h`.
104
114
pub fn mempool ( & mut self ) -> Result < MempoolEvent , bitcoincore_rpc:: Error > {
105
- let client = self . client ;
115
+ let client = & * self . client ;
106
116
107
117
// This is the emitted tip height during the last mempool emission.
108
118
let prev_mempool_tip = self
@@ -204,7 +214,7 @@ impl<'c, C: bitcoincore_rpc::RpcApi> Emitter<'c, C> {
204
214
205
215
/// Emit the next block height and block (if any).
206
216
pub fn next_block ( & mut self ) -> Result < Option < BlockEvent < Block > > , bitcoincore_rpc:: Error > {
207
- if let Some ( ( checkpoint, block) ) = poll ( self , |hash| self . client . get_block ( hash) ) ? {
217
+ if let Some ( ( checkpoint, block) ) = poll ( self , move |hash, client| client. get_block ( hash) ) ? {
208
218
// Stop tracking unconfirmed transactions that have been confirmed in this block.
209
219
for tx in & block. txdata {
210
220
self . expected_mempool_txids . remove ( & tx. compute_txid ( ) ) ;
@@ -247,7 +257,7 @@ impl MempoolEvent {
247
257
/// A newly emitted block from [`Emitter`].
248
258
#[ derive( Debug ) ]
249
259
pub struct BlockEvent < B > {
250
- /// Either a full [`Block`] or [`Header`] of the new block.
260
+ /// The block.
251
261
pub block : B ,
252
262
253
263
/// The checkpoint of the new block.
@@ -299,9 +309,10 @@ enum PollResponse {
299
309
300
310
fn poll_once < C > ( emitter : & Emitter < C > ) -> Result < PollResponse , bitcoincore_rpc:: Error >
301
311
where
302
- C : bitcoincore_rpc:: RpcApi ,
312
+ C : Deref ,
313
+ C :: Target : RpcApi ,
303
314
{
304
- let client = emitter. client ;
315
+ let client = & * emitter. client ;
305
316
306
317
if let Some ( last_res) = & emitter. last_block {
307
318
let next_hash = if last_res. height < emitter. start_height as _ {
@@ -355,15 +366,16 @@ fn poll<C, V, F>(
355
366
get_item : F ,
356
367
) -> Result < Option < ( CheckPoint , V ) > , bitcoincore_rpc:: Error >
357
368
where
358
- C : bitcoincore_rpc:: RpcApi ,
359
- F : Fn ( & BlockHash ) -> Result < V , bitcoincore_rpc:: Error > ,
369
+ C : Deref ,
370
+ C :: Target : RpcApi ,
371
+ F : Fn ( & BlockHash , & C :: Target ) -> Result < V , bitcoincore_rpc:: Error > ,
360
372
{
361
373
loop {
362
374
match poll_once ( emitter) ? {
363
375
PollResponse :: Block ( res) => {
364
376
let height = res. height as u32 ;
365
377
let hash = res. hash ;
366
- let item = get_item ( & hash) ?;
378
+ let item = get_item ( & hash, & emitter . client ) ?;
367
379
368
380
let new_cp = emitter
369
381
. last_cp
@@ -432,19 +444,23 @@ impl BitcoindRpcErrorExt for bitcoincore_rpc::Error {
432
444
433
445
#[ cfg( test) ]
434
446
mod test {
435
- use crate :: { bitcoincore_rpc:: RpcApi , Emitter } ;
436
- use bdk_bitcoind_rpc:: bitcoincore_rpc:: bitcoin:: Txid ;
447
+ use crate :: { bitcoincore_rpc:: RpcApi , Emitter , NO_EXPECTED_MEMPOOL_TXIDS } ;
437
448
use bdk_chain:: local_chain:: LocalChain ;
438
449
use bdk_testenv:: { anyhow, TestEnv } ;
439
- use bitcoin:: { hashes:: Hash , Address , Amount , ScriptBuf , WScriptHash } ;
450
+ use bitcoin:: { hashes:: Hash , Address , Amount , ScriptBuf , Txid , WScriptHash } ;
440
451
use std:: collections:: HashSet ;
441
452
442
453
#[ test]
443
454
fn test_expected_mempool_txids_accumulate_and_remove ( ) -> anyhow:: Result < ( ) > {
444
455
let env = TestEnv :: new ( ) ?;
445
456
let chain = LocalChain :: from_genesis_hash ( env. rpc_client ( ) . get_block_hash ( 0 ) ?) . 0 ;
446
457
let chain_tip = chain. tip ( ) ;
447
- let mut emitter = Emitter :: new ( env. rpc_client ( ) , chain_tip. clone ( ) , 1 , HashSet :: new ( ) ) ;
458
+ let mut emitter = Emitter :: new (
459
+ env. rpc_client ( ) ,
460
+ chain_tip. clone ( ) ,
461
+ 1 ,
462
+ NO_EXPECTED_MEMPOOL_TXIDS ,
463
+ ) ;
448
464
449
465
env. mine_blocks ( 100 , None ) ?;
450
466
while emitter. next_block ( ) ?. is_some ( ) { }
0 commit comments