@@ -768,8 +768,8 @@ impl<Env: Environment> Client<Env> {
768768 Ok ( ( ) )
769769 }
770770
771- /// Downloads and processes all confirmed block certificates that sent any message to this
772- /// chain, including their ancestors .
771+ /// Downloads and preprocesses all confirmed block certificates that sent any message to this
772+ /// chain.
773773 #[ instrument( level = "trace" , skip( self ) ) ]
774774 async fn synchronize_received_certificates_from_validator (
775775 & self ,
@@ -792,12 +792,12 @@ impl<Env: Environment> Client<Env> {
792792 let query = ChainInfoQuery :: new ( chain_id) . with_received_log_excluding_first_n ( tracker) ;
793793 let info = remote_node. handle_chain_info_query ( query) . await ?;
794794 let remote_log = info. requested_received_log ;
795- let remote_max_heights = Self :: max_height_per_chain ( & remote_log) ;
795+ let remote_heights = Self :: heights_per_chain ( & remote_log) ;
796796
797797 // Obtain the next block height we need in the local node, for each chain.
798798 let local_next_heights = self
799799 . local_node
800- . next_block_heights ( remote_max_heights . keys ( ) , chain_worker_limit)
800+ . next_outbox_heights ( remote_heights . keys ( ) , chain_worker_limit, chain_id )
801801 . await ?;
802802
803803 // We keep track of the height we've successfully downloaded and checked, per chain.
@@ -806,15 +806,17 @@ impl<Env: Environment> Client<Env> {
806806 // put all their sent messages into the inbox.
807807 let mut other_sender_chains = Vec :: new ( ) ;
808808
809- let certificate_hashes = future:: try_join_all ( remote_max_heights. into_iter ( ) . filter_map (
810- |( sender_chain_id, remote_height) | {
811- let local_next = * local_next_heights. get ( & sender_chain_id) ?;
809+ let certificate_hashes = future:: try_join_all ( remote_heights. into_iter ( ) . filter_map (
810+ |( sender_chain_id, remote_heights) | {
811+ let height0 = * remote_heights. first ( ) ?;
812+ let local_next = ( * local_next_heights. get ( & sender_chain_id) ?) . max ( height0) ;
812813 if let Ok ( height) = local_next. try_sub_one ( ) {
813814 downloaded_heights. insert ( sender_chain_id, height) ;
814815 }
815816
816- let Some ( diff) = remote_height. 0 . checked_sub ( local_next. 0 ) else {
817- // Our highest, locally-known block is higher than any block height
817+ let height1 = * remote_heights. last ( ) ?;
818+ let Some ( diff) = height1. 0 . checked_sub ( local_next. 0 ) else {
819+ // Our highest, locally executed block is higher than any block height
818820 // from the current batch. Skip this batch, but remember to wait for
819821 // the messages to be delivered to the inboxes.
820822 other_sender_chains. push ( sender_chain_id) ;
@@ -823,20 +825,61 @@ impl<Env: Environment> Client<Env> {
823825
824826 // Find the hashes of the blocks we need.
825827 let range = BlockHeightRange :: multi ( local_next, diff. saturating_add ( 1 ) ) ;
826- Some ( remote_node. fetch_sent_certificate_hashes ( sender_chain_id, range) )
828+ Some ( async move {
829+ let hashes = remote_node
830+ . fetch_sent_certificate_hashes ( sender_chain_id, range)
831+ . await ?;
832+ Ok :: < _ , ChainClientError > (
833+ remote_heights
834+ . into_iter ( )
835+ . map ( move |h| hashes[ ( h. 0 - local_next. 0 ) as usize ] ) ,
836+ )
837+ } )
827838 } ,
828839 ) )
829840 . await ?
830841 . into_iter ( )
831842 . flatten ( )
832- . collect ( ) ;
843+ . collect :: < Vec < _ > > ( ) ;
844+
845+ let local_certificates =
846+ future:: try_join_all ( certificate_hashes. iter ( ) . map ( |hash| async move {
847+ match self . storage_client ( ) . read_certificate ( * hash) . await {
848+ Ok ( certificate) => Ok ( Some ( certificate) ) ,
849+ Err ( ViewError :: NotFound ( _) ) => Ok ( None ) ,
850+ Err ( error) => Err ( error) ,
851+ }
852+ } ) )
853+ . await ?
854+ . into_iter ( )
855+ . flatten ( )
856+ . collect :: < Vec < _ > > ( ) ;
857+ let local_certificate_hashes = local_certificates
858+ . iter ( )
859+ . map ( |cert| cert. hash ( ) )
860+ . collect :: < HashSet < _ > > ( ) ;
833861
834862 // Download the block certificates.
835863 let remote_certificates = remote_node
836- . download_certificates ( certificate_hashes)
864+ . download_certificates (
865+ certificate_hashes
866+ . into_iter ( )
867+ . filter ( |hash| !local_certificate_hashes. contains ( hash) )
868+ . collect ( ) ,
869+ )
837870 . await ?;
838871 let mut certificates_by_height_by_chain = BTreeMap :: new ( ) ;
839872
873+ for confirmed_block_certificate in local_certificates {
874+ let block_header = & confirmed_block_certificate. inner ( ) . block ( ) . header ;
875+ let sender_chain_id = block_header. chain_id ;
876+ let height = block_header. height ;
877+ certificates_by_height_by_chain
878+ . entry ( sender_chain_id)
879+ . or_insert_with ( BTreeMap :: new)
880+ . insert ( height, confirmed_block_certificate) ;
881+ }
882+
840883 // Check the signatures and keep only the ones that are valid.
841884 for confirmed_block_certificate in remote_certificates {
842885 let block_header = & confirmed_block_certificate. inner ( ) . block ( ) . header ;
@@ -863,7 +906,7 @@ impl<Env: Environment> Client<Env> {
863906 certificates_by_height_by_chain
864907 . entry ( sender_chain_id)
865908 . or_insert_with ( BTreeMap :: new)
866- . insert ( height, confirmed_block_certificate. clone ( ) ) ;
909+ . insert ( height, confirmed_block_certificate) ;
867910 }
868911 }
869912 }
@@ -881,10 +924,9 @@ impl<Env: Environment> Client<Env> {
881924 }
882925
883926 for ( sender_chain_id, certs) in & mut certificates_by_height_by_chain {
884- if ! certs
927+ if certs
885928 . values ( )
886- . last ( )
887- . is_some_and ( |cert| cert. block ( ) . recipients ( ) . contains ( & chain_id) )
929+ . any ( |cert| !cert. block ( ) . recipients ( ) . contains ( & chain_id) )
888930 {
889931 warn ! (
890932 "Skipping received certificates from chain {sender_chain_id:.8}:
@@ -931,15 +973,17 @@ impl<Env: Environment> Client<Env> {
931973 }
932974
933975 /// Given a set of chain ID-block height pairs, returns a map that assigns to each chain ID
934- /// the highest height seen.
935- fn max_height_per_chain ( remote_log : & [ ChainAndHeight ] ) -> BTreeMap < ChainId , BlockHeight > {
976+ /// the set of heights. The returned map contains no empty values.
977+ fn heights_per_chain (
978+ remote_log : & [ ChainAndHeight ] ,
979+ ) -> BTreeMap < ChainId , BTreeSet < BlockHeight > > {
936980 remote_log. iter ( ) . fold (
937- BTreeMap :: < ChainId , BlockHeight > :: new ( ) ,
981+ BTreeMap :: < ChainId , BTreeSet < _ > > :: new ( ) ,
938982 |mut chain_to_info, entry| {
939983 chain_to_info
940984 . entry ( entry. chain_id )
941- . and_modify ( |h| * h = entry . height . max ( * h ) )
942- . or_insert ( entry. height ) ;
985+ . or_default ( )
986+ . insert ( entry. height ) ;
943987 chain_to_info
944988 } ,
945989 )
0 commit comments