@@ -2,6 +2,8 @@ use std::sync::{Arc, Mutex};
22use std:: time:: Duration ;
33use std:: vec;
44
5+ use apollo_batcher_types:: communication:: BatcherClientError ;
6+ use apollo_batcher_types:: errors:: BatcherError ;
57use apollo_config_manager_types:: communication:: MockConfigManagerClient ;
68use apollo_consensus_config:: config:: {
79 ConsensusConfig ,
@@ -39,7 +41,7 @@ use crate::test_utils::{
3941 NoOpHeightVotedStorage ,
4042 TestProposalPart ,
4143} ;
42- use crate :: types:: { Round , ValidatorId } ;
44+ use crate :: types:: { ConsensusError , Round , ValidatorId } ;
4345use crate :: votes_threshold:: QuorumType ;
4446use crate :: RunConsensusArguments ;
4547
@@ -166,7 +168,7 @@ async fn manager_multiple_heights_unordered(consensus_config: ConsensusConfig) {
166168 expect_validate_proposal ( & mut context, Felt :: ONE , 1 ) ;
167169 context. expect_validators ( ) . returning ( move |_| vec ! [ * PROPOSER_ID , * VALIDATOR_ID ] ) ;
168170 context. expect_proposer ( ) . returning ( move |_, _| * PROPOSER_ID ) ;
169- context. expect_set_height_and_round ( ) . returning ( move |_, _| ( ) ) ;
171+ context. expect_set_height_and_round ( ) . returning ( move |_, _| Ok ( ( ) ) ) ;
170172 context. expect_broadcast ( ) . returning ( move |_| Ok ( ( ) ) ) ;
171173 context
172174 . expect_decision_reached ( )
@@ -220,7 +222,7 @@ async fn run_consensus_sync(consensus_config: ConsensusConfig) {
220222 expect_validate_proposal ( & mut context, Felt :: TWO , 1 ) ;
221223 context. expect_validators ( ) . returning ( move |_| vec ! [ * PROPOSER_ID , * VALIDATOR_ID ] ) ;
222224 context. expect_proposer ( ) . returning ( move |_, _| * PROPOSER_ID ) ;
223- context. expect_set_height_and_round ( ) . returning ( move |_, _| ( ) ) ;
225+ context. expect_set_height_and_round ( ) . returning ( move |_, _| Ok ( ( ) ) ) ;
224226 context. expect_broadcast ( ) . returning ( move |_| Ok ( ( ) ) ) ;
225227 context
226228 . expect_decision_reached ( )
@@ -286,7 +288,7 @@ async fn test_timeouts(consensus_config: ConsensusConfig) {
286288 send ( & mut sender, precommit ( None , HEIGHT_1 , ROUND_0 , * VALIDATOR_ID_3 ) ) . await ;
287289
288290 let mut context = MockTestContext :: new ( ) ;
289- context. expect_set_height_and_round ( ) . returning ( move |_, _| ( ) ) ;
291+ context. expect_set_height_and_round ( ) . returning ( move |_, _| Ok ( ( ) ) ) ;
290292 expect_validate_proposal ( & mut context, Felt :: ONE , 2 ) ;
291293 context
292294 . expect_validators ( )
@@ -444,7 +446,7 @@ async fn future_height_limit_caching_and_dropping(mut consensus_config: Consensu
444446 expect_validate_proposal ( & mut context, Felt :: ONE , 1 ) ; // Height 1 validation
445447 context. expect_validators ( ) . returning ( move |_| vec ! [ * PROPOSER_ID , * VALIDATOR_ID ] ) ;
446448 context. expect_proposer ( ) . returning ( move |_, _| * PROPOSER_ID ) ;
447- context. expect_set_height_and_round ( ) . returning ( move |_, _| ( ) ) ;
449+ context. expect_set_height_and_round ( ) . returning ( move |_, _| Ok ( ( ) ) ) ;
448450 // Set up coordination to detect when node votes Nil for height 2 (indicating proposal was
449451 // dropped, so the node didn't received the proposal and votes Nil).
450452 let ( height2_nil_vote_trigger, height2_nil_vote_wait) = oneshot:: channel ( ) ;
@@ -583,16 +585,18 @@ async fn current_height_round_limit_caching_and_dropping(mut consensus_config: C
583585 . times ( 1 )
584586 . return_once ( |_, _| {
585587 round1_trigger. send ( ( ) ) . unwrap ( ) ;
588+ Ok ( ( ) )
586589 } ) ;
587590 context
588591 . expect_set_height_and_round ( )
589592 . withf ( |height, round| * height == HEIGHT_1 && * round == ROUND_2 )
590593 . times ( 1 )
591594 . return_once ( |_, _| {
592595 round2_trigger. send ( ( ) ) . unwrap ( ) ;
596+ Ok ( ( ) )
593597 } ) ;
594598 // Handle all other set_height_and_round calls normally.
595- context. expect_set_height_and_round ( ) . returning ( move |_, _| ( ) ) ;
599+ context. expect_set_height_and_round ( ) . returning ( move |_, _| Ok ( ( ) ) ) ;
596600 context
597601 . expect_decision_reached ( )
598602 . withf ( move |_, c| * c == ProposalCommitment ( Felt :: ONE ) )
@@ -667,7 +671,7 @@ async fn run_consensus_dynamic_client_updates_validator_between_heights(
667671 // Context with expectations: H1 we are the validator, learn height via sync; at H2 we are the
668672 // proposer.
669673 let mut context = MockTestContext :: new ( ) ;
670- context. expect_set_height_and_round ( ) . returning ( move |_, _| ( ) ) ;
674+ context. expect_set_height_and_round ( ) . returning ( move |_, _| Ok ( ( ) ) ) ;
671675 context. expect_validators ( ) . returning ( move |h : BlockNumber | {
672676 if h == HEIGHT_1 { vec ! [ * VALIDATOR_ID ] } else { vec ! [ * PROPOSER_ID ] }
673677 } ) ;
@@ -688,7 +692,7 @@ async fn run_consensus_dynamic_client_updates_validator_between_heights(
688692 . returning ( move |_, _| {
689693 let ( sender, receiver) = oneshot:: channel ( ) ;
690694 sender. send ( ProposalCommitment ( Felt :: TWO ) ) . unwrap ( ) ;
691- receiver
695+ Ok ( receiver)
692696 } )
693697 . times ( 1 ) ;
694698 // Expect a decision at height 2.
@@ -818,7 +822,7 @@ async fn manager_runs_normally_when_height_is_greater_than_last_voted_height(
818822 expect_validate_proposal ( & mut context, Felt :: ONE , 1 ) ;
819823 context. expect_validators ( ) . returning ( move |_| vec ! [ * PROPOSER_ID , * VALIDATOR_ID ] ) ;
820824 context. expect_proposer ( ) . returning ( move |_, _| * PROPOSER_ID ) ;
821- context. expect_set_height_and_round ( ) . returning ( move |_, _| ( ) ) ;
825+ context. expect_set_height_and_round ( ) . returning ( move |_, _| Ok ( ( ) ) ) ;
822826 context. expect_broadcast ( ) . returning ( move |_| Ok ( ( ) ) ) ;
823827 context
824828 . expect_decision_reached ( )
@@ -921,7 +925,7 @@ async fn writes_voted_height_to_storage(consensus_config: ConsensusConfig) {
921925 context
922926 . expect_validators ( )
923927 . returning ( move |_| vec ! [ * PROPOSER_ID , * VALIDATOR_ID , * VALIDATOR_ID_2 , * VALIDATOR_ID_3 ] ) ;
924- context. expect_set_height_and_round ( ) . returning ( move |_, _| ( ) ) ;
928+ context. expect_set_height_and_round ( ) . returning ( move |_, _| Ok ( ( ) ) ) ;
925929 context. expect_try_sync ( ) . returning ( |_| false ) ;
926930
927931 // Set up storage expectation for prevote - must happen before broadcast
@@ -1047,3 +1051,45 @@ async fn writes_voted_height_to_storage(consensus_config: ConsensusConfig) {
10471051
10481052 assert_decision ( decision, block_id. 0 , ROUND_0 ) ;
10491053}
1054+
1055+ #[ rstest]
1056+ #[ tokio:: test]
1057+ async fn manager_fallback_to_sync_on_height_level_errors ( consensus_config : ConsensusConfig ) {
1058+ let TestSubscriberChannels { mock_network : _mock_network, subscriber_channels } =
1059+ mock_register_broadcast_topic ( ) . unwrap ( ) ;
1060+
1061+ let ( mut _proposal_receiver_sender, mut proposal_receiver_receiver) =
1062+ mpsc:: channel ( CHANNEL_SIZE ) ;
1063+
1064+ let mut context = MockTestContext :: new ( ) ;
1065+ context. expect_validators ( ) . returning ( move |_| vec ! [ * PROPOSER_ID , * VALIDATOR_ID ] ) ;
1066+ context. expect_proposer ( ) . returning ( move |_, _| * PROPOSER_ID ) ;
1067+
1068+ // Sync should first fail, so consensus will try to run.
1069+ context. expect_try_sync ( ) . times ( 1 ) . returning ( |_| false ) ;
1070+
1071+ // Consensus should fail when context.set_height_and_round fails.
1072+ context. expect_set_height_and_round ( ) . times ( 1 ) . returning ( move |_, _| {
1073+ Err ( ConsensusError :: BatcherError ( BatcherClientError :: BatcherError (
1074+ BatcherError :: InternalError ,
1075+ ) ) )
1076+ } ) ;
1077+
1078+ // Now sync should be called and succeed.
1079+ context. expect_try_sync ( ) . withf ( move |height| * height == HEIGHT_1 ) . times ( 1 ) . returning ( |_| true ) ;
1080+
1081+ let mut manager = MultiHeightManager :: new (
1082+ consensus_config,
1083+ QuorumType :: Byzantine ,
1084+ Arc :: new ( Mutex :: new ( NoOpHeightVotedStorage ) ) ,
1085+ ) ;
1086+ let res = manager
1087+ . run_height (
1088+ & mut context,
1089+ HEIGHT_1 ,
1090+ & mut subscriber_channels. into ( ) ,
1091+ & mut proposal_receiver_receiver,
1092+ )
1093+ . await ;
1094+ assert_eq ! ( res, Ok ( RunHeightRes :: Sync ) ) ;
1095+ }
0 commit comments