@@ -13,6 +13,7 @@ use bdk_core::bitcoin;
1313use bdk_core:: { BlockId , CheckPoint } ;
1414use bitcoin:: {
1515 bip158:: { self , BlockFilter } ,
16+ block:: Header ,
1617 Block , BlockHash , ScriptBuf ,
1718} ;
1819use bitcoincore_rpc;
@@ -21,6 +22,9 @@ use bitcoincore_rpc::RpcApi;
2122/// Block height
2223type Height = u32 ;
2324
25+ /// Block header with associated block hash.
26+ type HashedHeader = ( BlockHash , Header ) ;
27+
2428/// Type that generates block [`Event`]s by matching a list of script pubkeys against a
2529/// [`BlockFilter`].
2630#[ derive( Debug ) ]
@@ -31,8 +35,8 @@ pub struct FilterIter<'c, C> {
3135 spks : Vec < ScriptBuf > ,
3236 // local cp
3337 cp : Option < CheckPoint > ,
34- // blocks map
35- blocks : BTreeMap < Height , BlockHash > ,
38+ // block headers
39+ headers : BTreeMap < Height , HashedHeader > ,
3640 // heights of matching blocks
3741 matched : BTreeSet < Height > ,
3842 // best height counter
@@ -53,7 +57,7 @@ impl<'c, C: RpcApi> FilterIter<'c, C> {
5357 client,
5458 spks : vec ! [ ] ,
5559 cp : None ,
56- blocks : BTreeMap :: new ( ) ,
60+ headers : BTreeMap :: new ( ) ,
5761 matched : BTreeSet :: new ( ) ,
5862 height,
5963 start : height,
@@ -102,6 +106,11 @@ impl<'c, C: RpcApi> FilterIter<'c, C> {
102106 hash : tip_hash,
103107 } ) )
104108 }
109+
110+ /// Return all of the block headers that were collected during the scan.
111+ pub fn block_headers ( & self ) -> & BTreeMap < Height , ( BlockHash , Header ) > {
112+ & self . headers
113+ }
105114}
106115
107116/// Event inner type
@@ -151,27 +160,27 @@ impl<C: RpcApi> Iterator for FilterIter<'_, C> {
151160
152161 let mut reorg_depth = 0 ;
153162
154- loop {
163+ let header = loop {
155164 if reorg_depth >= Self :: MAX_REORG_DEPTH {
156165 return Err ( Error :: ReorgDepthExceeded ) ;
157166 }
158167
159168 let header = self . client . get_block_header ( & hash) ?;
160169
161170 let prev_height = height. saturating_sub ( 1 ) ;
162- match self . blocks . get ( & prev_height) . copied ( ) {
171+ match self . headers . get ( & prev_height) . copied ( ) {
163172 // Not enough data.
164- None => break ,
173+ None => break header ,
165174 // Ok, the chain is consistent.
166- Some ( prev_hash) if prev_hash == header. prev_blockhash => break ,
175+ Some ( ( prev_hash, _ ) ) if prev_hash == header. prev_blockhash => break header ,
167176 _ => {
168177 // Reorg detected, keep backtracking.
169178 height = height. saturating_sub ( 1 ) ;
170179 hash = self . client . get_block_hash ( height as u64 ) ?;
171180 reorg_depth += 1 ;
172181 }
173182 }
174- }
183+ } ;
175184
176185 let filter_bytes = self . client . get_block_filter ( & hash) ?. filter ;
177186 let filter = BlockFilter :: new ( & filter_bytes) ;
@@ -193,11 +202,11 @@ impl<C: RpcApi> Iterator for FilterIter<'_, C> {
193202
194203 // In case of a reorg, throw out any stale entries.
195204 if reorg_depth > 0 {
196- self . blocks . split_off ( & height) ;
205+ self . headers . split_off ( & height) ;
197206 self . matched . split_off ( & height) ;
198207 }
199208 // Record the scanned block
200- self . blocks . insert ( height, hash) ;
209+ self . headers . insert ( height, ( hash, header ) ) ;
201210 // Record the matching block
202211 if let Ok ( Some ( Event :: Block ( ..) ) ) = next_event {
203212 self . matched . insert ( height) ;
@@ -216,17 +225,21 @@ impl<C: RpcApi> FilterIter<'_, C> {
216225 fn find_base_with ( & mut self , mut cp : CheckPoint ) -> Result < BlockId , Error > {
217226 loop {
218227 let height = cp. height ( ) ;
219- let fetched_hash = match self . blocks . get ( & height) {
220- Some ( hash) => * hash,
221- None => self . client . get_block_hash ( height as u64 ) ?,
228+ let ( fetched_hash, header) = match self . headers . get ( & height) . copied ( ) {
229+ Some ( value) => value,
230+ None => {
231+ let hash = self . client . get_block_hash ( height as u64 ) ?;
232+ let header = self . client . get_block_header ( & hash) ?;
233+ ( hash, header)
234+ }
222235 } ;
223236 if cp. hash ( ) == fetched_hash {
224- // ensure this block also exists in self
225- self . blocks . insert ( height, cp . hash ( ) ) ;
237+ // Ensure this block also exists in ` self`.
238+ self . headers . insert ( height, ( fetched_hash , header ) ) ;
226239 return Ok ( cp. block_id ( ) ) ;
227240 }
228- // remember conflicts
229- self . blocks . insert ( height, fetched_hash) ;
241+ // Remember conflicts.
242+ self . headers . insert ( height, ( fetched_hash, header ) ) ;
230243 cp = cp. prev ( ) . ok_or ( Error :: ReorgDepthExceeded ) ?;
231244 }
232245 }
@@ -236,15 +249,15 @@ impl<C: RpcApi> FilterIter<'_, C> {
236249 /// Returns `None` if this [`FilterIter`] was not constructed using a [`CheckPoint`], or
237250 /// if not all events have been emitted (by calling `next`).
238251 pub fn chain_update ( & self ) -> Option < CheckPoint > {
239- if self . cp . is_none ( ) || self . blocks . is_empty ( ) || self . height <= self . stop {
252+ if self . cp . is_none ( ) || self . headers . is_empty ( ) || self . height <= self . stop {
240253 return None ;
241254 }
242255
243256 // We return blocks up to and including the initial height, all of the matching blocks,
244257 // and blocks in the terminal range.
245258 let tail_range = self . stop . saturating_sub ( 9 ) ..=self . stop ;
246259 Some (
247- CheckPoint :: from_block_ids ( self . blocks . iter ( ) . filter_map ( |( & height, & hash) | {
260+ CheckPoint :: from_block_ids ( self . headers . iter ( ) . filter_map ( |( & height, & ( hash, _ ) ) | {
248261 if height <= self . start
249262 || self . matched . contains ( & height)
250263 || tail_range. contains ( & height)
0 commit comments