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 ;
@@ -156,8 +156,9 @@ where
156156 // Disconnect any stale blocks, but keep them in the cache for the next iteration.
157157 let ( common_ancestor, connected_blocks) = {
158158 let chain_listener = & DynamicChainListener ( chain_listener) ;
159+ let mut cache_wrapper = HeaderCacheNoDisconnect ( & mut header_cache) ;
159160 let mut chain_notifier =
160- ChainNotifier { header_cache : & mut header_cache , chain_listener } ;
161+ ChainNotifier { header_cache : & mut cache_wrapper , chain_listener } ;
161162 let difference = chain_notifier
162163 . find_difference_from_best_block ( best_header, old_best_block, & mut chain_poller)
163164 . await ?;
@@ -192,7 +193,9 @@ where
192193 const NO_BLOCK : Option < ( u32 , crate :: poll:: ValidatedBlock ) > = None ;
193194 let mut fetched_blocks = [ NO_BLOCK ; MAX_BLOCKS_AT_ONCE ] ;
194195 for ( ( header, block_res) , result) in results. into_iter ( ) . zip ( fetched_blocks. iter_mut ( ) ) {
195- * result = Some ( ( header. height , block_res?) ) ;
196+ let block = block_res?;
197+ header_cache. block_connected ( header. block_hash , * header) ;
198+ * result = Some ( ( header. height , block) ) ;
196199 }
197200 debug_assert ! ( fetched_blocks. iter( ) . take( most_connected_blocks. len( ) ) . all( |r| r. is_some( ) ) ) ;
198201 // TODO: When our MSRV is 1.82, use is_sorted_by_key
@@ -243,10 +246,40 @@ impl<'a, L: chain::Listen + ?Sized> chain::Listen for DynamicChainListener<'a, L
243246 }
244247}
245248
249+ /// Wrapper around HeaderCache that ignores `blocks_disconnected` calls, retaining disconnected
250+ /// blocks in the cache. This is useful during initial sync to keep headers available across
251+ /// multiple listeners.
252+ struct HeaderCacheNoDisconnect < ' a > ( & ' a mut HeaderCache ) ;
253+
254+ impl < ' a > crate :: Cache for & mut HeaderCacheNoDisconnect < ' a > {
255+ fn look_up (
256+ & self , block_hash : & bitcoin:: hash_types:: BlockHash ,
257+ ) -> Option < & ValidatedBlockHeader > {
258+ self . 0 . look_up ( block_hash)
259+ }
260+
261+ fn insert_during_diff (
262+ & mut self , block_hash : bitcoin:: hash_types:: BlockHash , block_header : ValidatedBlockHeader ,
263+ ) {
264+ self . 0 . insert_during_diff ( block_hash, block_header) ;
265+ }
266+
267+ fn block_connected (
268+ & mut self , block_hash : bitcoin:: hash_types:: BlockHash , block_header : ValidatedBlockHeader ,
269+ ) {
270+ self . 0 . block_connected ( block_hash, block_header) ;
271+ }
272+
273+ fn blocks_disconnected ( & mut self , _fork_point : & ValidatedBlockHeader ) {
274+ // Intentionally ignore disconnections to retain blocks in cache
275+ }
276+ }
277+
246278#[ cfg( test) ]
247279mod tests {
248280 use super :: * ;
249281 use crate :: test_utils:: { Blockchain , MockChainListener } ;
282+ use crate :: Cache ;
250283
251284 #[ tokio:: test]
252285 async fn sync_from_same_chain ( ) {
@@ -267,7 +300,13 @@ mod tests {
267300 ( chain. best_block_at_height( 3 ) , & listener_3 as & dyn chain:: Listen ) ,
268301 ] ;
269302 match synchronize_listeners ( & chain, Network :: Bitcoin , listeners) . await {
270- Ok ( ( _, header) ) => assert_eq ! ( header, chain. tip( ) ) ,
303+ Ok ( ( cache, header) ) => {
304+ assert_eq ! ( header, chain. tip( ) ) ;
305+ assert ! ( cache. look_up( & chain. at_height( 1 ) . block_hash) . is_some( ) ) ;
306+ assert ! ( cache. look_up( & chain. at_height( 2 ) . block_hash) . is_some( ) ) ;
307+ assert ! ( cache. look_up( & chain. at_height( 3 ) . block_hash) . is_some( ) ) ;
308+ assert ! ( cache. look_up( & chain. at_height( 4 ) . block_hash) . is_some( ) ) ;
309+ } ,
271310 Err ( e) => panic ! ( "Unexpected error: {:?}" , e) ,
272311 }
273312 }
@@ -298,7 +337,15 @@ mod tests {
298337 ( fork_chain_3. best_block( ) , & listener_3 as & dyn chain:: Listen ) ,
299338 ] ;
300339 match synchronize_listeners ( & main_chain, Network :: Bitcoin , listeners) . await {
301- Ok ( ( _, header) ) => assert_eq ! ( header, main_chain. tip( ) ) ,
340+ Ok ( ( cache, header) ) => {
341+ assert_eq ! ( header, main_chain. tip( ) ) ;
342+ assert ! ( cache. look_up( & main_chain. at_height( 1 ) . block_hash) . is_some( ) ) ;
343+ assert ! ( cache. look_up( & main_chain. at_height( 2 ) . block_hash) . is_some( ) ) ;
344+ assert ! ( cache. look_up( & main_chain. at_height( 3 ) . block_hash) . is_some( ) ) ;
345+ assert ! ( cache. look_up( & fork_chain_1. at_height( 2 ) . block_hash) . is_none( ) ) ;
346+ assert ! ( cache. look_up( & fork_chain_2. at_height( 3 ) . block_hash) . is_none( ) ) ;
347+ assert ! ( cache. look_up( & fork_chain_3. at_height( 4 ) . block_hash) . is_none( ) ) ;
348+ } ,
302349 Err ( e) => panic ! ( "Unexpected error: {:?}" , e) ,
303350 }
304351 }
@@ -332,7 +379,16 @@ mod tests {
332379 ( fork_chain_3. best_block( ) , & listener_3 as & dyn chain:: Listen ) ,
333380 ] ;
334381 match synchronize_listeners ( & main_chain, Network :: Bitcoin , listeners) . await {
335- Ok ( ( _, header) ) => assert_eq ! ( header, main_chain. tip( ) ) ,
382+ Ok ( ( cache, header) ) => {
383+ assert_eq ! ( header, main_chain. tip( ) ) ;
384+ assert ! ( cache. look_up( & main_chain. at_height( 1 ) . block_hash) . is_some( ) ) ;
385+ assert ! ( cache. look_up( & main_chain. at_height( 2 ) . block_hash) . is_some( ) ) ;
386+ assert ! ( cache. look_up( & main_chain. at_height( 3 ) . block_hash) . is_some( ) ) ;
387+ assert ! ( cache. look_up( & main_chain. at_height( 4 ) . block_hash) . is_some( ) ) ;
388+ assert ! ( cache. look_up( & fork_chain_1. at_height( 2 ) . block_hash) . is_none( ) ) ;
389+ assert ! ( cache. look_up( & fork_chain_1. at_height( 3 ) . block_hash) . is_none( ) ) ;
390+ assert ! ( cache. look_up( & fork_chain_1. at_height( 4 ) . block_hash) . is_none( ) ) ;
391+ } ,
336392 Err ( e) => panic ! ( "Unexpected error: {:?}" , e) ,
337393 }
338394 }
0 commit comments