@@ -324,11 +324,23 @@ fn get_locator_heights(height: u64) -> Vec<u64> {
324324 heights
325325}
326326
327+ #[ derive( Clone , Debug ) ]
328+ struct BlockHashAndHeight {
329+ hash : CryptoHash ,
330+ height : BlockHeight ,
331+ }
332+
333+ impl BlockHashAndHeight {
334+ pub fn new ( hash : CryptoHash , height : BlockHeight ) -> Self {
335+ BlockHashAndHeight { hash, height }
336+ }
337+ }
338+
327339/// Cache for block sync that stores the hashes to request in insertion order.
328340/// It also maintains the last final block header to minimize the impact of reorgs.
329341#[ derive( Default ) ]
330342struct BlockSyncCache {
331- hashes : LinkedHashMap < CryptoHash , ( ) > ,
343+ hashes : LinkedHashMap < CryptoHash , BlockHeight > ,
332344 last_header : Option < BlockHeader > ,
333345}
334346
@@ -337,8 +349,8 @@ impl BlockSyncCache {
337349 self . hashes . len ( )
338350 }
339351
340- fn insert ( & mut self , block_hash : CryptoHash ) {
341- self . hashes . insert ( block_hash, ( ) ) ;
352+ fn insert ( & mut self , block_hash : CryptoHash , block_height : BlockHeight ) {
353+ self . hashes . insert ( block_hash, block_height ) ;
342354 }
343355
344356 fn remove ( & mut self , block_hash : & CryptoHash ) {
@@ -432,13 +444,13 @@ impl BlockSync {
432444
433445 fn compute_hashes_to_request (
434446 & mut self ,
435- new_hashes : & [ CryptoHash ] ,
447+ new_blocks : & [ BlockHashAndHeight ] ,
436448 chain : & mut Chain ,
437449 block_count : usize ,
438- ) -> Vec < CryptoHash > {
450+ ) -> Vec < BlockHashAndHeight > {
439451 let mut res = vec ! [ ] ;
440452 let mut hashes_to_remove = vec ! [ ] ;
441- for ( block_hash, _ ) in self . cache . hashes . iter ( ) {
453+ for ( block_hash, block_height ) in self . cache . hashes . iter ( ) {
442454 if res. len ( ) >= block_count {
443455 break ;
444456 }
@@ -451,14 +463,16 @@ impl BlockSync {
451463 if block_exists || chain. is_orphan ( block_hash) || chain. is_chunk_orphan ( block_hash) {
452464 continue ;
453465 } else {
454- res. push ( * block_hash) ;
466+ res. push ( BlockHashAndHeight :: new ( * block_hash, * block_height ) ) ;
455467 }
456468 }
457469 for hash in hashes_to_remove {
458470 self . cache . remove ( & hash) ;
459471 }
460- for hash in new_hashes. iter ( ) . rev ( ) . take ( block_count. saturating_sub ( res. len ( ) ) ) {
461- res. push ( * hash) ;
472+ for block_hash_and_height in
473+ new_blocks. iter ( ) . rev ( ) . take ( block_count. saturating_sub ( res. len ( ) ) )
474+ {
475+ res. push ( block_hash_and_height. clone ( ) ) ;
462476 }
463477 res
464478 }
@@ -468,7 +482,7 @@ impl BlockSync {
468482 & mut self ,
469483 chain : & mut Chain ,
470484 block_count : usize ,
471- ) -> Result < Vec < CryptoHash > , near_chain:: Error > {
485+ ) -> Result < Vec < BlockHashAndHeight > , near_chain:: Error > {
472486 let last_header = match self . cache . last_header {
473487 Some ( ref h) => h. clone ( ) ,
474488 None => chain. head_header ( ) ?. clone ( ) ,
@@ -496,14 +510,14 @@ impl BlockSync {
496510 }
497511 }
498512
499- hashes_to_request. push ( * header. hash ( ) ) ;
513+ hashes_to_request. push ( BlockHashAndHeight :: new ( * header. hash ( ) , header . height ( ) ) ) ;
500514 current = chain. get_previous_header ( & header) . map ( |h| h. clone ( ) ) ;
501515 }
502516 let res = self . compute_hashes_to_request ( & hashes_to_request, chain, block_count) ;
503517
504518 self . cache . hashes . reserve ( hashes_to_request. len ( ) ) ;
505- for hash in hashes_to_request. into_iter ( ) . rev ( ) {
506- self . cache . insert ( hash) ;
519+ for block_hash_and_height in hashes_to_request. into_iter ( ) . rev ( ) {
520+ self . cache . insert ( block_hash_and_height . hash , block_hash_and_height . height ) ;
507521 }
508522 self . cache . last_header =
509523 chain. get_block_header ( & header_head. last_block_hash ) . map ( |h| h. clone ( ) ) . ok ( ) ;
@@ -538,11 +552,22 @@ impl BlockSync {
538552 self . blocks_requested = 0 ;
539553 self . receive_timeout = Utc :: now ( ) + Duration :: seconds ( BLOCK_REQUEST_TIMEOUT ) ;
540554
541- let mut peers_iter = highest_height_peers. iter ( ) . cycle ( ) ;
542- for hash in hashes_to_request {
543- if let Some ( peer) = peers_iter. next ( ) {
555+ let gc_stop_height =
556+ chain. runtime_adapter . get_gc_stop_height ( & header_head. last_block_hash ) ;
557+ let mut archival_peer_iter =
558+ highest_height_peers. iter ( ) . filter ( |p| p. chain_info . archival ) . cycle ( ) ;
559+ let mut peer_iter = highest_height_peers. iter ( ) . cycle ( ) ;
560+ for block_hash_and_height in hashes_to_request {
561+ let request_from_archival =
562+ self . archive && block_hash_and_height. height < gc_stop_height;
563+ let peer = if request_from_archival {
564+ archival_peer_iter. next ( )
565+ } else {
566+ peer_iter. next ( )
567+ } ;
568+ if let Some ( peer) = peer {
544569 self . network_adapter . do_send ( NetworkRequests :: BlockRequest {
545- hash : hash . clone ( ) ,
570+ hash : block_hash_and_height . hash ,
546571 peer_id : peer. peer_info . id . clone ( ) ,
547572 } ) ;
548573 self . blocks_requested += 1 ;
@@ -1557,4 +1582,45 @@ mod test {
15571582 assert_eq ! ( block_sync. cache. len( ) , expected_block_hashes. len( ) ) ;
15581583 assert_eq ! ( block_sync. cache. last_header, Some ( fork_block. header( ) . clone( ) ) ) ;
15591584 }
1585+
1586+ #[ test]
1587+ fn test_block_sync_archival ( ) {
1588+ let network_adapter = Arc :: new ( MockNetworkAdapter :: default ( ) ) ;
1589+ let block_fetch_horizon = 10 ;
1590+ let mut block_sync = BlockSync :: new ( network_adapter. clone ( ) , block_fetch_horizon, true ) ;
1591+ let mut chain_genesis = ChainGenesis :: test ( ) ;
1592+ chain_genesis. epoch_length = 5 ;
1593+ let mut env = TestEnv :: new ( chain_genesis, 2 , 1 ) ;
1594+ let mut blocks = vec ! [ ] ;
1595+ for i in 1 ..31 {
1596+ let block = env. clients [ 0 ] . produce_block ( i) . unwrap ( ) . unwrap ( ) ;
1597+ blocks. push ( block. clone ( ) ) ;
1598+ env. process_block ( 0 , block, Provenance :: PRODUCED ) ;
1599+ }
1600+ let block_headers = blocks. iter ( ) . map ( |b| b. header ( ) . clone ( ) ) . collect :: < Vec < _ > > ( ) ;
1601+ let peer_infos = create_peer_infos ( 2 ) ;
1602+ env. clients [ 1 ] . chain . sync_block_headers ( block_headers, |_| unreachable ! ( ) ) . unwrap ( ) ;
1603+ let is_state_sync = block_sync. block_sync ( & mut env. clients [ 1 ] . chain , & peer_infos) . unwrap ( ) ;
1604+ assert ! ( !is_state_sync) ;
1605+ let requested_block_hashes = collect_hashes_from_network_adapter ( network_adapter. clone ( ) ) ;
1606+ assert_eq ! (
1607+ requested_block_hashes,
1608+ blocks[ 4 ..] . iter( ) . map( |b| * b. hash( ) ) . collect:: <HashSet <_>>( )
1609+ ) ;
1610+ let last_block_header = blocks. last ( ) . unwrap ( ) . header ( ) . clone ( ) ;
1611+ assert_eq ! ( block_sync. cache. len( ) as u64 , last_block_header. height( ) ) ;
1612+ assert_eq ! ( block_sync. cache. last_header, Some ( last_block_header. clone( ) ) ) ;
1613+
1614+ let mut peer_infos = create_peer_infos ( 2 ) ;
1615+ for peer in peer_infos. iter_mut ( ) {
1616+ peer. chain_info . archival = true ;
1617+ }
1618+ let is_state_sync = block_sync. block_sync ( & mut env. clients [ 1 ] . chain , & peer_infos) . unwrap ( ) ;
1619+ assert ! ( !is_state_sync) ;
1620+ let requested_block_hashes = collect_hashes_from_network_adapter ( network_adapter. clone ( ) ) ;
1621+ assert_eq ! (
1622+ requested_block_hashes,
1623+ blocks. iter( ) . map( |b| * b. hash( ) ) . collect:: <HashSet <_>>( )
1624+ ) ;
1625+ }
15601626}
0 commit comments