@@ -33,8 +33,6 @@ pub struct FilterIter<'c, C> {
33
33
client : & ' c C ,
34
34
// SPK inventory
35
35
spks : Vec < ScriptBuf > ,
36
- // local cp
37
- cp : Option < CheckPoint > ,
38
36
// block headers
39
37
headers : BTreeMap < Height , HashedHeader > ,
40
38
// heights of matching blocks
@@ -58,7 +56,6 @@ impl<'c, C: RpcApi> FilterIter<'c, C> {
58
56
Self {
59
57
client,
60
58
spks : vec ! [ ] ,
61
- cp : None ,
62
59
headers : BTreeMap :: new ( ) ,
63
60
matched : BTreeSet :: new ( ) ,
64
61
height,
@@ -68,10 +65,19 @@ impl<'c, C: RpcApi> FilterIter<'c, C> {
68
65
}
69
66
70
67
/// Construct [`FilterIter`] from a given `client` and [`CheckPoint`].
71
- pub fn new_with_checkpoint ( client : & ' c C , cp : CheckPoint ) -> Self {
72
- let mut filter_iter = Self :: new_with_height ( client, cp. height ( ) ) ;
73
- filter_iter. cp = Some ( cp) ;
74
- filter_iter
68
+ ///
69
+ /// # Errors
70
+ ///
71
+ /// If no point of agreement is found between `cp` and the remote node, then
72
+ /// a [`Error::ReorgDepthExceeded`] error is returned.
73
+ pub fn new_with_checkpoint ( client : & ' c C , cp : CheckPoint ) -> Result < Self , Error > {
74
+ let mut iter = Self :: new_with_height ( client, cp. height ( ) ) ;
75
+
76
+ // Start scanning from point of agreement + 1.
77
+ let base = iter. find_base ( cp. clone ( ) ) ?;
78
+ iter. height = base. height . saturating_add ( 1 ) ;
79
+
80
+ Ok ( iter)
75
81
}
76
82
77
83
/// Extends `self` with an iterator of spks.
@@ -86,7 +92,9 @@ impl<'c, C: RpcApi> FilterIter<'c, C> {
86
92
87
93
/// Get the remote tip.
88
94
///
89
- /// Returns `None` if the remote height is less than the height of this [`FilterIter`].
95
+ /// This will set the stop height to that of the new tip.
96
+ ///
97
+ /// Returns `None` if the remote height is not at least the height of this [`FilterIter`].
90
98
pub fn get_tip ( & mut self ) -> Result < Option < BlockId > , Error > {
91
99
let tip_hash = self . client . get_best_block_hash ( ) ?;
92
100
let header = self . client . get_block_header_info ( & tip_hash) ?;
@@ -95,12 +103,6 @@ impl<'c, C: RpcApi> FilterIter<'c, C> {
95
103
return Ok ( None ) ;
96
104
}
97
105
98
- // start scanning from point of agreement + 1
99
- if let Some ( cp) = self . cp . as_ref ( ) {
100
- let base = self . find_base_with ( cp. clone ( ) ) ?;
101
- self . height = base. height . saturating_add ( 1 ) ;
102
- }
103
-
104
106
self . stop = tip_height;
105
107
106
108
Ok ( Some ( BlockId {
@@ -223,8 +225,14 @@ impl<C: RpcApi> Iterator for FilterIter<'_, C> {
223
225
}
224
226
225
227
impl < C : RpcApi > FilterIter < ' _ , C > {
226
- /// Returns the point of agreement between `self` and the given `cp`.
227
- fn find_base_with ( & mut self , mut cp : CheckPoint ) -> Result < BlockId , Error > {
228
+ /// Returns the point of agreement (PoA) between `self` and the given `cp`.
229
+ ///
230
+ /// This ensures that the scan may proceed from a block that still exists
231
+ /// in the best chain.
232
+ ///
233
+ /// If no PoA is found between `cp` and the remote node, then a [`Error::ReorgDepthExceeded`]
234
+ /// error is returned.
235
+ fn find_base ( & mut self , mut cp : CheckPoint ) -> Result < BlockId , Error > {
228
236
loop {
229
237
let height = cp. height ( ) ;
230
238
let ( fetched_hash, header) = match self . headers . get ( & height) . copied ( ) {
@@ -240,24 +248,24 @@ impl<C: RpcApi> FilterIter<'_, C> {
240
248
self . headers . insert ( height, ( fetched_hash, header) ) ;
241
249
return Ok ( cp. block_id ( ) ) ;
242
250
}
243
- // Remember conflicts.
244
- self . headers . insert ( height, ( fetched_hash, header) ) ;
245
251
cp = cp. prev ( ) . ok_or ( Error :: ReorgDepthExceeded ) ?;
246
252
}
247
253
}
248
254
249
255
/// Returns a chain update from the newly scanned blocks.
250
256
///
251
- /// Returns `None` if this [`FilterIter`] was not constructed using a [`CheckPoint`], or
252
- /// if not all events have been emitted (by calling `next`).
257
+ /// This should only be called once all events have been consumed (by calling `next`).
258
+ ///
259
+ /// Returns `None` if the height of this `FilterIter` is not yet past the stop height.
253
260
pub fn chain_update ( & self ) -> Option < CheckPoint > {
254
- if self . cp . is_none ( ) || self . headers . is_empty ( ) || self . height <= self . stop {
261
+ if self . headers . is_empty ( ) || self . height <= self . stop {
255
262
return None ;
256
263
}
257
264
258
- // We return blocks up to and including the initial height, all of the matching blocks,
265
+ // We return blocks up to the initial height, all of the matching blocks,
259
266
// and blocks in the terminal range.
260
267
let tail_range = ( self . stop + 1 ) . saturating_sub ( Self :: CHAIN_SUFFIX_LEN ) ..=self . stop ;
268
+
261
269
Some (
262
270
CheckPoint :: from_block_ids ( self . headers . iter ( ) . filter_map ( |( & height, & ( hash, _) ) | {
263
271
if height <= self . start
0 commit comments