33
44use crate :: async_poll:: { MultiResultFuturePoller , ResultFuture } ;
55use crate :: poll:: { ChainPoller , Poll , Validate , ValidatedBlockHeader } ;
6- use crate :: { BlockData , BlockSource , BlockSourceResult , ChainNotifier , HeaderCache } ;
6+ use crate :: { BlockData , BlockSource , BlockSourceResult , Cache , ChainNotifier , HeaderCache } ;
77
88use bitcoin:: block:: Header ;
99use bitcoin:: network:: Network ;
@@ -153,8 +153,9 @@ where
153153 // Disconnect any stale blocks, but keep them in the cache for the next iteration.
154154 let ( common_ancestor, connected_blocks) = {
155155 let chain_listener = & DynamicChainListener ( chain_listener) ;
156+ let mut cache_wrapper = HeaderCacheNoDisconnect ( & mut header_cache) ;
156157 let mut chain_notifier =
157- ChainNotifier { header_cache : & mut header_cache , chain_listener } ;
158+ ChainNotifier { header_cache : & mut cache_wrapper , chain_listener } ;
158159 let difference = chain_notifier
159160 . find_difference_from_best_block ( best_header, old_best_block, & mut chain_poller)
160161 . await ?;
@@ -189,7 +190,9 @@ where
189190 const NO_BLOCK : Option < ( u32 , crate :: poll:: ValidatedBlock ) > = None ;
190191 let mut fetched_blocks = [ NO_BLOCK ; MAX_BLOCKS_AT_ONCE ] ;
191192 for ( ( header, block_res) , result) in results. into_iter ( ) . zip ( fetched_blocks. iter_mut ( ) ) {
192- * result = Some ( ( header. height , block_res?) ) ;
193+ let block = block_res?;
194+ header_cache. block_connected ( header. block_hash , * header) ;
195+ * result = Some ( ( header. height , block) ) ;
193196 }
194197 debug_assert ! ( fetched_blocks. iter( ) . take( most_connected_blocks. len( ) ) . all( |r| r. is_some( ) ) ) ;
195198 // TODO: When our MSRV is 1.82, use is_sorted_by_key
@@ -242,10 +245,34 @@ impl<'a, L: chain::Listen + ?Sized> chain::Listen for DynamicChainListener<'a, L
242245 }
243246}
244247
248+ /// Wrapper around HeaderCache that ignores `blocks_disconnected` calls, retaining disconnected
249+ /// blocks in the cache. This is useful during initial sync to keep headers available across
250+ /// multiple listeners.
251+ struct HeaderCacheNoDisconnect < ' a > ( & ' a mut HeaderCache ) ;
252+
253+ impl < ' a > crate :: Cache for & mut HeaderCacheNoDisconnect < ' a > {
254+ fn look_up ( & self , block_hash : & bitcoin:: hash_types:: BlockHash ) -> Option < & ValidatedBlockHeader > {
255+ self . 0 . look_up ( block_hash)
256+ }
257+
258+ fn insert_during_diff ( & mut self , block_hash : bitcoin:: hash_types:: BlockHash , block_header : ValidatedBlockHeader ) {
259+ self . 0 . insert_during_diff ( block_hash, block_header) ;
260+ }
261+
262+ fn block_connected ( & mut self , block_hash : bitcoin:: hash_types:: BlockHash , block_header : ValidatedBlockHeader ) {
263+ self . 0 . block_connected ( block_hash, block_header) ;
264+ }
265+
266+ fn blocks_disconnected ( & mut self , _fork_point : & ValidatedBlockHeader ) {
267+ // Intentionally ignore disconnections to retain blocks in cache
268+ }
269+ }
270+
245271#[ cfg( test) ]
246272mod tests {
247273 use super :: * ;
248274 use crate :: test_utils:: { Blockchain , MockChainListener } ;
275+ use crate :: Cache ;
249276
250277 #[ tokio:: test]
251278 async fn sync_from_same_chain ( ) {
@@ -266,7 +293,13 @@ mod tests {
266293 ( chain. best_block_at_height( 3 ) , & listener_3 as & dyn chain:: Listen ) ,
267294 ] ;
268295 match synchronize_listeners ( & chain, Network :: Bitcoin , listeners) . await {
269- Ok ( ( _, header) ) => assert_eq ! ( header, chain. tip( ) ) ,
296+ Ok ( ( cache, header) ) => {
297+ assert_eq ! ( header, chain. tip( ) ) ;
298+ assert ! ( cache. look_up( & chain. at_height( 1 ) . block_hash) . is_some( ) ) ;
299+ assert ! ( cache. look_up( & chain. at_height( 2 ) . block_hash) . is_some( ) ) ;
300+ assert ! ( cache. look_up( & chain. at_height( 3 ) . block_hash) . is_some( ) ) ;
301+ assert ! ( cache. look_up( & chain. at_height( 4 ) . block_hash) . is_some( ) ) ;
302+ } ,
270303 Err ( e) => panic ! ( "Unexpected error: {:?}" , e) ,
271304 }
272305 }
@@ -297,7 +330,15 @@ mod tests {
297330 ( fork_chain_3. best_block( ) , & listener_3 as & dyn chain:: Listen ) ,
298331 ] ;
299332 match synchronize_listeners ( & main_chain, Network :: Bitcoin , listeners) . await {
300- Ok ( ( _, header) ) => assert_eq ! ( header, main_chain. tip( ) ) ,
333+ Ok ( ( cache, header) ) => {
334+ assert_eq ! ( header, main_chain. tip( ) ) ;
335+ assert ! ( cache. look_up( & main_chain. at_height( 1 ) . block_hash) . is_some( ) ) ;
336+ assert ! ( cache. look_up( & main_chain. at_height( 2 ) . block_hash) . is_some( ) ) ;
337+ assert ! ( cache. look_up( & main_chain. at_height( 3 ) . block_hash) . is_some( ) ) ;
338+ assert ! ( cache. look_up( & fork_chain_1. at_height( 2 ) . block_hash) . is_none( ) ) ;
339+ assert ! ( cache. look_up( & fork_chain_2. at_height( 3 ) . block_hash) . is_none( ) ) ;
340+ assert ! ( cache. look_up( & fork_chain_3. at_height( 4 ) . block_hash) . is_none( ) ) ;
341+ } ,
301342 Err ( e) => panic ! ( "Unexpected error: {:?}" , e) ,
302343 }
303344 }
@@ -331,7 +372,16 @@ mod tests {
331372 ( fork_chain_3. best_block( ) , & listener_3 as & dyn chain:: Listen ) ,
332373 ] ;
333374 match synchronize_listeners ( & main_chain, Network :: Bitcoin , listeners) . await {
334- Ok ( ( _, header) ) => assert_eq ! ( header, main_chain. tip( ) ) ,
375+ Ok ( ( cache, header) ) => {
376+ assert_eq ! ( header, main_chain. tip( ) ) ;
377+ assert ! ( cache. look_up( & main_chain. at_height( 1 ) . block_hash) . is_some( ) ) ;
378+ assert ! ( cache. look_up( & main_chain. at_height( 2 ) . block_hash) . is_some( ) ) ;
379+ assert ! ( cache. look_up( & main_chain. at_height( 3 ) . block_hash) . is_some( ) ) ;
380+ assert ! ( cache. look_up( & main_chain. at_height( 4 ) . block_hash) . is_some( ) ) ;
381+ assert ! ( cache. look_up( & fork_chain_1. at_height( 2 ) . block_hash) . is_none( ) ) ;
382+ assert ! ( cache. look_up( & fork_chain_1. at_height( 3 ) . block_hash) . is_none( ) ) ;
383+ assert ! ( cache. look_up( & fork_chain_1. at_height( 4 ) . block_hash) . is_none( ) ) ;
384+ } ,
335385 Err ( e) => panic ! ( "Unexpected error: {:?}" , e) ,
336386 }
337387 }
0 commit comments