@@ -194,12 +194,17 @@ struct ChainNotifier<C: Cache> {
194
194
header_cache : C ,
195
195
}
196
196
197
- /// Steps outlining changes needed to be made to the chain in order to transform it from having one
198
- /// chain tip to another.
199
- enum ForkStep {
200
- ForkPoint ( ValidatedBlockHeader ) ,
201
- DisconnectBlock ( ValidatedBlockHeader ) ,
202
- ConnectBlock ( ValidatedBlockHeader ) ,
197
+ /// Changes made to the chain between subsequent polls that transformed it from having one chain tip
198
+ /// to another.
199
+ ///
200
+ /// Blocks are given in height-descending order. Therefore, blocks are first disconnected in order
201
+ /// before new blocks are connected in reverse order.
202
+ struct ChainDifference {
203
+ /// Blocks that were disconnected from the chain since the last poll.
204
+ disconnected_blocks : Vec < ValidatedBlockHeader > ,
205
+
206
+ /// Blocks that were connected to the chain since the last poll.
207
+ connected_blocks : Vec < ValidatedBlockHeader > ,
203
208
}
204
209
205
210
impl < C : Cache > ChainNotifier < C > {
@@ -217,81 +222,51 @@ impl<C: Cache> ChainNotifier<C> {
217
222
chain_poller : & mut P ,
218
223
chain_listener : & mut L ,
219
224
) -> Result < ( ) , ( BlockSourceError , Option < ValidatedBlockHeader > ) > {
220
- let mut events = self . find_fork ( new_header, old_header, chain_poller) . await . map_err ( |e| ( e, None ) ) ?;
221
-
222
- let mut last_disconnect_tip = None ;
223
- let mut new_tip = None ;
224
- for event in events. iter ( ) {
225
- match & event {
226
- & ForkStep :: DisconnectBlock ( ref header) => {
227
- println ! ( "Disconnecting block {}" , header. block_hash) ;
228
- if let Some ( cached_header) = self . header_cache . block_disconnected ( & header. block_hash ) {
229
- assert_eq ! ( cached_header, * header) ;
230
- }
231
- chain_listener. block_disconnected ( & header. header , header. height ) ;
232
- last_disconnect_tip = Some ( header. header . prev_blockhash ) ;
233
- } ,
234
- & ForkStep :: ForkPoint ( ref header) => {
235
- new_tip = Some ( * header) ;
236
- } ,
237
- _ => { } ,
225
+ let mut difference = self . find_difference ( new_header, old_header, chain_poller) . await
226
+ . map_err ( |e| ( e, None ) ) ?;
227
+
228
+ let mut new_tip = * old_header;
229
+ for header in difference. disconnected_blocks . drain ( ..) {
230
+ println ! ( "Disconnecting block {}" , header. block_hash) ;
231
+ if let Some ( cached_header) = self . header_cache . block_disconnected ( & header. block_hash ) {
232
+ assert_eq ! ( cached_header, header) ;
238
233
}
234
+ chain_listener. block_disconnected ( & header. header , header. height ) ;
235
+ new_tip = header;
239
236
}
240
237
241
- // If blocks were disconnected, new blocks will connect starting from the fork point.
242
- // Otherwise, there was no fork, so new blocks connect starting from the old tip.
243
- assert_eq ! ( last_disconnect_tip. is_some( ) , new_tip. is_some( ) ) ;
244
- if let & Some ( ref tip_header) = & new_tip {
245
- debug_assert_eq ! ( tip_header. header. block_hash( ) , * last_disconnect_tip. as_ref( ) . unwrap( ) ) ;
246
- } else {
247
- new_tip = Some ( * old_header) ;
248
- }
238
+ for header in difference. connected_blocks . drain ( ..) . rev ( ) {
239
+ let block = chain_poller
240
+ . fetch_block ( & header) . await
241
+ . or_else ( |e| Err ( ( e, Some ( new_tip) ) ) ) ?;
242
+ debug_assert_eq ! ( block. block_hash, header. block_hash) ;
249
243
250
- for event in events. drain ( ..) . rev ( ) {
251
- if let ForkStep :: ConnectBlock ( header) = event {
252
- let block = chain_poller
253
- . fetch_block ( & header) . await
254
- . or_else ( |e| Err ( ( e, new_tip) ) ) ?;
255
- debug_assert_eq ! ( block. block_hash, header. block_hash) ;
256
-
257
- println ! ( "Connecting block {}" , header. block_hash) ;
258
- self . header_cache . block_connected ( header. block_hash , header) ;
259
- chain_listener. block_connected ( & block, header. height ) ;
260
- new_tip = Some ( header) ;
261
- }
244
+ println ! ( "Connecting block {}" , header. block_hash) ;
245
+ self . header_cache . block_connected ( header. block_hash , header) ;
246
+ chain_listener. block_connected ( & block, header. height ) ;
247
+ new_tip = header;
262
248
}
249
+
263
250
Ok ( ( ) )
264
251
}
265
252
253
+ /// Returns the changes needed to produce the chain with `current_header` as its tip from the
254
+ /// chain with `prev_header` as its tip.
255
+ ///
266
256
/// Walks backwards from `current_header` and `prev_header`, finding the common ancestor.
267
- /// Returns the steps needed to produce the chain with `current_header` as its tip from the
268
- /// chain with `prev_header` as its tip. There is no ordering guarantee between different
269
- /// `ForkStep` types, but `DisconnectBlock` and `ConnectBlock` are each returned in
270
- /// height-descending order.
271
- async fn find_fork < P : Poll > (
257
+ async fn find_difference < P : Poll > (
272
258
& self ,
273
259
current_header : ValidatedBlockHeader ,
274
260
prev_header : & ValidatedBlockHeader ,
275
261
chain_poller : & mut P ,
276
- ) -> BlockSourceResult < Vec < ForkStep > > {
277
- let mut steps = Vec :: new ( ) ;
262
+ ) -> BlockSourceResult < ChainDifference > {
263
+ let mut disconnected_blocks = Vec :: new ( ) ;
264
+ let mut connected_blocks = Vec :: new ( ) ;
278
265
let mut current = current_header;
279
266
let mut previous = * prev_header;
280
267
loop {
281
- // Found the parent block.
282
- if current. header . prev_blockhash == previous. block_hash {
283
- debug_assert_eq ! ( current. height, previous. height + 1 ) ;
284
- steps. push ( ForkStep :: ConnectBlock ( current) ) ;
285
- break ;
286
- }
287
-
288
- // Found a chain fork.
289
- if current. header . prev_blockhash == previous. header . prev_blockhash {
290
- debug_assert_eq ! ( current. height, previous. height) ;
291
- let fork_point = self . look_up_previous_header ( chain_poller, & previous) . await ?;
292
- steps. push ( ForkStep :: DisconnectBlock ( previous) ) ;
293
- steps. push ( ForkStep :: ConnectBlock ( current) ) ;
294
- steps. push ( ForkStep :: ForkPoint ( fork_point) ) ;
268
+ // Found the common ancestor.
269
+ if current. block_hash == previous. block_hash {
295
270
break ;
296
271
}
297
272
@@ -300,16 +275,16 @@ impl<C: Cache> ChainNotifier<C> {
300
275
let current_height = current. height ;
301
276
let previous_height = previous. height ;
302
277
if current_height <= previous_height {
303
- steps . push ( ForkStep :: DisconnectBlock ( previous) ) ;
278
+ disconnected_blocks . push ( previous) ;
304
279
previous = self . look_up_previous_header ( chain_poller, & previous) . await ?;
305
280
}
306
281
if current_height >= previous_height {
307
- steps . push ( ForkStep :: ConnectBlock ( current) ) ;
282
+ connected_blocks . push ( current) ;
308
283
current = self . look_up_previous_header ( chain_poller, & current) . await ?;
309
284
}
310
285
}
311
286
312
- Ok ( steps )
287
+ Ok ( ChainDifference { disconnected_blocks , connected_blocks } )
313
288
}
314
289
315
290
/// Returns the previous header for the given header, either by looking it up in the cache or
0 commit comments