@@ -41,59 +41,40 @@ impl<'a> FilterIter<'a> {
41
41
}
42
42
}
43
43
44
- /// Find the agreement height with the remote node and return the corresponding
45
- /// header info.
44
+ /// Return the agreement header with the remote node.
46
45
///
47
- /// Error if no agreement height is found.
46
+ /// Error if no agreement header is found.
48
47
fn find_base ( & self ) -> Result < GetBlockHeaderResult , Error > {
49
48
for cp in self . cp . iter ( ) {
50
- let height = cp. height ( ) ;
51
-
52
- let fetched_hash = self . client . get_block_hash ( height as u64 ) ?;
53
-
54
- if fetched_hash == cp. hash ( ) {
55
- return Ok ( self . client . get_block_header_info ( & fetched_hash) ?) ;
49
+ match self . client . get_block_header_info ( & cp. hash ( ) ) {
50
+ Err ( e) if is_not_found ( & e) => continue ,
51
+ Ok ( header) if header. confirmations <= 0 => continue ,
52
+ Ok ( header) => return Ok ( header) ,
53
+ Err ( e) => return Err ( Error :: Rpc ( e) ) ,
56
54
}
57
55
}
58
-
59
56
Err ( Error :: ReorgDepthExceeded )
60
57
}
61
58
}
62
59
63
- /// Kind of event produced by `FilterIter`.
60
+ /// Event returned by [ `FilterIter`] .
64
61
#[ derive( Debug , Clone ) ]
65
- pub enum Event {
66
- /// Block
67
- Block {
68
- /// checkpoint
69
- cp : CheckPoint ,
70
- /// block
71
- block : Block ,
72
- } ,
73
- /// No match
74
- NoMatch {
75
- /// block id
76
- id : BlockId ,
77
- } ,
78
- /// Tip
79
- Tip {
80
- /// checkpoint
81
- cp : CheckPoint ,
82
- } ,
62
+ pub struct Event {
63
+ /// Checkpoint
64
+ pub cp : CheckPoint ,
65
+ /// Block, will be `Some(..)` for matching blocks
66
+ pub block : Option < Block > ,
83
67
}
84
68
85
69
impl Event {
86
70
/// Whether this event contains a matching block.
87
71
pub fn is_match ( & self ) -> bool {
88
- matches ! ( self , Event :: Block { .. } )
72
+ self . block . is_some ( )
89
73
}
90
74
91
75
/// Return the height of the event.
92
76
pub fn height ( & self ) -> u32 {
93
- match self {
94
- Self :: Block { cp, .. } | Self :: Tip { cp } => cp. height ( ) ,
95
- Self :: NoMatch { id } => id. height ,
96
- }
77
+ self . cp . height ( )
97
78
}
98
79
}
99
80
@@ -106,15 +87,9 @@ impl Iterator for FilterIter<'_> {
106
87
107
88
let header = match self . header . take ( ) {
108
89
Some ( header) => header,
109
- None => {
110
- // If no header is cached we need to locate a base of the local
111
- // checkpoint from which the scan may proceed.
112
- let header = self . find_base ( ) ?;
113
- let height: u32 = header. height . try_into ( ) ?;
114
- cp = cp. range ( ..=height) . next ( ) . expect ( "we found a base" ) ;
115
-
116
- header
117
- }
90
+ // If no header is cached we need to locate a base of the local
91
+ // checkpoint from which the scan may proceed.
92
+ None => self . find_base ( ) ?,
118
93
} ;
119
94
120
95
let mut next_hash = match header. next_block_hash {
@@ -126,58 +101,38 @@ impl Iterator for FilterIter<'_> {
126
101
127
102
// In case of a reorg, rewind by fetching headers of previous hashes until we find
128
103
// one with enough confirmations.
129
- let mut reorg_ct: i32 = 0 ;
130
104
while next_header. confirmations < 0 {
131
105
let prev_hash = next_header
132
106
. previous_block_hash
133
107
. ok_or ( Error :: ReorgDepthExceeded ) ?;
134
108
let prev_header = self . client . get_block_header_info ( & prev_hash) ?;
135
109
next_header = prev_header;
136
- reorg_ct += 1 ;
137
110
}
138
111
139
112
next_hash = next_header. hash ;
140
113
let next_height: u32 = next_header. height . try_into ( ) ?;
141
114
142
- // Purge any no longer valid checkpoints.
143
- if reorg_ct. is_positive ( ) {
144
- cp = cp
145
- . range ( ..=next_height)
146
- . next ( )
147
- . ok_or ( Error :: ReorgDepthExceeded ) ?;
148
- }
149
- let block_id = BlockId {
115
+ cp = cp. insert ( BlockId {
150
116
height : next_height,
151
117
hash : next_hash,
152
- } ;
153
- let filter_bytes = self . client . get_block_filter ( & next_hash) ?. filter ;
154
- let filter = BlockFilter :: new ( & filter_bytes) ;
118
+ } ) ;
155
119
156
- let next_event = if filter
120
+ let mut block = None ;
121
+ let filter =
122
+ BlockFilter :: new ( self . client . get_block_filter ( & next_hash) ?. filter . as_slice ( ) ) ;
123
+ if filter
157
124
. match_any ( & next_hash, self . spks . iter ( ) . map ( ScriptBuf :: as_ref) )
158
125
. map_err ( Error :: Bip158 ) ?
159
126
{
160
- let block = self . client . get_block ( & next_hash) ?;
161
- cp = cp. insert ( block_id) ;
162
-
163
- Ok ( Some ( Event :: Block {
164
- cp : cp. clone ( ) ,
165
- block,
166
- } ) )
167
- } else if next_header. next_block_hash . is_none ( ) {
168
- cp = cp. insert ( block_id) ;
169
-
170
- Ok ( Some ( Event :: Tip { cp : cp. clone ( ) } ) )
171
- } else {
172
- Ok ( Some ( Event :: NoMatch { id : block_id } ) )
173
- } ;
127
+ block = Some ( self . client . get_block ( & next_hash) ?) ;
128
+ }
174
129
175
130
// Store the next header
176
131
self . header = Some ( next_header) ;
177
132
// Update self.cp
178
- self . cp = cp;
133
+ self . cp = cp. clone ( ) ;
179
134
180
- next_event
135
+ Ok ( Some ( Event { cp , block } ) )
181
136
} ) ( )
182
137
. transpose ( )
183
138
}
@@ -221,3 +176,12 @@ impl From<core::num::TryFromIntError> for Error {
221
176
Self :: TryFromInt ( e)
222
177
}
223
178
}
179
+
180
+ /// Whether the RPC error is a "not found" error (code: `-5`).
181
+ fn is_not_found ( e : & bitcoincore_rpc:: Error ) -> bool {
182
+ matches ! (
183
+ e,
184
+ bitcoincore_rpc:: Error :: JsonRpc ( bitcoincore_rpc:: jsonrpc:: Error :: Rpc ( e) )
185
+ if e. code == -5
186
+ )
187
+ }
0 commit comments