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,40 @@ 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 (
255+ & self , block_hash : & bitcoin:: hash_types:: BlockHash ,
256+ ) -> Option < & ValidatedBlockHeader > {
257+ self . 0 . look_up ( block_hash)
258+ }
259+
260+ fn insert_during_diff (
261+ & mut self , block_hash : bitcoin:: hash_types:: BlockHash , block_header : ValidatedBlockHeader ,
262+ ) {
263+ self . 0 . insert_during_diff ( block_hash, block_header) ;
264+ }
265+
266+ fn block_connected (
267+ & mut self , block_hash : bitcoin:: hash_types:: BlockHash , block_header : ValidatedBlockHeader ,
268+ ) {
269+ self . 0 . block_connected ( block_hash, block_header) ;
270+ }
271+
272+ fn blocks_disconnected ( & mut self , _fork_point : & ValidatedBlockHeader ) {
273+ // Intentionally ignore disconnections to retain blocks in cache
274+ }
275+ }
276+
245277#[ cfg( test) ]
246278mod tests {
247279 use super :: * ;
248280 use crate :: test_utils:: { Blockchain , MockChainListener } ;
281+ use crate :: Cache ;
249282
250283 #[ tokio:: test]
251284 async fn sync_from_same_chain ( ) {
@@ -266,7 +299,13 @@ mod tests {
266299 ( chain. best_block_at_height( 3 ) , & listener_3 as & dyn chain:: Listen ) ,
267300 ] ;
268301 match synchronize_listeners ( & chain, Network :: Bitcoin , listeners) . await {
269- Ok ( ( _, header) ) => assert_eq ! ( header, chain. tip( ) ) ,
302+ Ok ( ( cache, header) ) => {
303+ assert_eq ! ( header, chain. tip( ) ) ;
304+ assert ! ( cache. look_up( & chain. at_height( 1 ) . block_hash) . is_some( ) ) ;
305+ assert ! ( cache. look_up( & chain. at_height( 2 ) . block_hash) . is_some( ) ) ;
306+ assert ! ( cache. look_up( & chain. at_height( 3 ) . block_hash) . is_some( ) ) ;
307+ assert ! ( cache. look_up( & chain. at_height( 4 ) . block_hash) . is_some( ) ) ;
308+ } ,
270309 Err ( e) => panic ! ( "Unexpected error: {:?}" , e) ,
271310 }
272311 }
@@ -297,7 +336,15 @@ mod tests {
297336 ( fork_chain_3. best_block( ) , & listener_3 as & dyn chain:: Listen ) ,
298337 ] ;
299338 match synchronize_listeners ( & main_chain, Network :: Bitcoin , listeners) . await {
300- Ok ( ( _, header) ) => assert_eq ! ( header, main_chain. tip( ) ) ,
339+ Ok ( ( cache, header) ) => {
340+ assert_eq ! ( header, main_chain. tip( ) ) ;
341+ assert ! ( cache. look_up( & main_chain. at_height( 1 ) . block_hash) . is_some( ) ) ;
342+ assert ! ( cache. look_up( & main_chain. at_height( 2 ) . block_hash) . is_some( ) ) ;
343+ assert ! ( cache. look_up( & main_chain. at_height( 3 ) . block_hash) . is_some( ) ) ;
344+ assert ! ( cache. look_up( & fork_chain_1. at_height( 2 ) . block_hash) . is_none( ) ) ;
345+ assert ! ( cache. look_up( & fork_chain_2. at_height( 3 ) . block_hash) . is_none( ) ) ;
346+ assert ! ( cache. look_up( & fork_chain_3. at_height( 4 ) . block_hash) . is_none( ) ) ;
347+ } ,
301348 Err ( e) => panic ! ( "Unexpected error: {:?}" , e) ,
302349 }
303350 }
@@ -331,7 +378,16 @@ mod tests {
331378 ( fork_chain_3. best_block( ) , & listener_3 as & dyn chain:: Listen ) ,
332379 ] ;
333380 match synchronize_listeners ( & main_chain, Network :: Bitcoin , listeners) . await {
334- Ok ( ( _, header) ) => assert_eq ! ( header, main_chain. tip( ) ) ,
381+ Ok ( ( cache, header) ) => {
382+ assert_eq ! ( header, main_chain. tip( ) ) ;
383+ assert ! ( cache. look_up( & main_chain. at_height( 1 ) . block_hash) . is_some( ) ) ;
384+ assert ! ( cache. look_up( & main_chain. at_height( 2 ) . block_hash) . is_some( ) ) ;
385+ assert ! ( cache. look_up( & main_chain. at_height( 3 ) . block_hash) . is_some( ) ) ;
386+ assert ! ( cache. look_up( & main_chain. at_height( 4 ) . block_hash) . is_some( ) ) ;
387+ assert ! ( cache. look_up( & fork_chain_1. at_height( 2 ) . block_hash) . is_none( ) ) ;
388+ assert ! ( cache. look_up( & fork_chain_1. at_height( 3 ) . block_hash) . is_none( ) ) ;
389+ assert ! ( cache. look_up( & fork_chain_1. at_height( 4 ) . block_hash) . is_none( ) ) ;
390+ } ,
335391 Err ( e) => panic ! ( "Unexpected error: {:?}" , e) ,
336392 }
337393 }
0 commit comments