@@ -1903,9 +1903,10 @@ where
19031903 async fn stage_block_execution_and_discard_failing_messages (
19041904 & self ,
19051905 mut block : ProposedBlock ,
1906+ round : Option < u32 > ,
19061907 ) -> Result < ( ExecutedBlock , ChainInfoResponse ) , ChainClientError > {
19071908 loop {
1908- let result = self . stage_block_execution ( block. clone ( ) ) . await ;
1909+ let result = self . stage_block_execution ( block. clone ( ) , round ) . await ;
19091910 if let Err ( ChainClientError :: LocalNodeError ( LocalNodeError :: WorkerError (
19101911 WorkerError :: ChainError ( chain_error) ,
19111912 ) ) ) = & result
@@ -1944,12 +1945,13 @@ where
19441945 async fn stage_block_execution (
19451946 & self ,
19461947 block : ProposedBlock ,
1948+ round : Option < u32 > ,
19471949 ) -> Result < ( ExecutedBlock , ChainInfoResponse ) , ChainClientError > {
19481950 loop {
19491951 let result = self
19501952 . client
19511953 . local_node
1952- . stage_block_execution ( block. clone ( ) )
1954+ . stage_block_execution ( block. clone ( ) , round )
19531955 . await ;
19541956 if let Err ( LocalNodeError :: BlobsNotFound ( blob_ids) ) = & result {
19551957 self . receive_certificates_for_blobs ( blob_ids. clone ( ) )
@@ -2122,8 +2124,18 @@ where
21222124 } ;
21232125 // Make sure every incoming message succeeds and otherwise remove them.
21242126 // Also, compute the final certified hash while we're at it.
2127+
2128+ let info = self . chain_info ( ) . await ?;
2129+ // Use the round number assuming there are oracle responses.
2130+ // Using the round number during execution counts as an oracle.
2131+ // Accessing the round number in single-leader rounds where we are not the leader
2132+ // is not currently supported.
2133+ let round = match Self :: round_for_new_proposal ( & info, & identity, & block, true ) ? {
2134+ Either :: Left ( round) => round. multi_leader ( ) ,
2135+ Either :: Right ( _) => None ,
2136+ } ;
21252137 let ( executed_block, _) = self
2126- . stage_block_execution_and_discard_failing_messages ( block)
2138+ . stage_block_execution_and_discard_failing_messages ( block, round )
21272139 . await ?;
21282140 let blobs = self
21292141 . read_local_blobs ( executed_block. required_blob_ids ( ) )
@@ -2270,7 +2282,7 @@ where
22702282 timestamp,
22712283 } ;
22722284 match self
2273- . stage_block_execution_and_discard_failing_messages ( block)
2285+ . stage_block_execution_and_discard_failing_messages ( block, None )
22742286 . await
22752287 {
22762288 Ok ( ( _, response) ) => Ok ( (
@@ -2424,6 +2436,7 @@ where
24242436 {
24252437 return self . finalize_locking_block ( info) . await ;
24262438 }
2439+ let identity = self . identity ( ) . await ?;
24272440
24282441 // Otherwise we have to re-propose the highest validated block, if there is one.
24292442 let pending: Option < ProposedBlock > = self . state ( ) . pending_proposal ( ) . clone ( ) ;
@@ -2432,18 +2445,28 @@ where
24322445 LockingBlock :: Regular ( certificate) => certificate. block ( ) . clone ( ) . into ( ) ,
24332446 LockingBlock :: Fast ( proposal) => {
24342447 let block = proposal. content . block . clone ( ) ;
2435- self . stage_block_execution ( block) . await ?. 0
2448+ self . stage_block_execution ( block, None ) . await ?. 0
24362449 }
24372450 }
24382451 } else if let Some ( block) = pending {
24392452 // Otherwise we are free to propose our own pending block.
2440- self . stage_block_execution ( block) . await ?. 0
2453+ // Use the round number assuming there are oracle responses.
2454+ // Using the round number during execution counts as an oracle.
2455+ let round = match Self :: round_for_new_proposal ( & info, & identity, & block, true ) ? {
2456+ Either :: Left ( round) => round. multi_leader ( ) ,
2457+ Either :: Right ( _) => None ,
2458+ } ;
2459+ self . stage_block_execution ( block, round) . await ?. 0
24412460 } else {
24422461 return Ok ( ClientOutcome :: Committed ( None ) ) ; // Nothing to do.
24432462 } ;
24442463
2445- let identity = self . identity ( ) . await ?;
2446- let round = match Self :: round_for_new_proposal ( & info, & identity, & executed_block) ? {
2464+ let round = match Self :: round_for_new_proposal (
2465+ & info,
2466+ & identity,
2467+ & executed_block. block ,
2468+ executed_block. outcome . has_oracle_responses ( ) ,
2469+ ) ? {
24472470 Either :: Left ( round) => round,
24482471 Either :: Right ( timeout) => return Ok ( ClientOutcome :: WaitForTimeout ( timeout) ) ,
24492472 } ;
@@ -2546,17 +2569,16 @@ where
25462569 fn round_for_new_proposal (
25472570 info : & ChainInfo ,
25482571 identity : & Owner ,
2549- executed_block : & ExecutedBlock ,
2572+ block : & ProposedBlock ,
2573+ has_oracle_responses : bool ,
25502574 ) -> Result < Either < Round , RoundTimeout > , ChainClientError > {
25512575 let manager = & info. manager ;
2552- let block = & executed_block. block ;
25532576 // If there is a conflicting proposal in the current round, we can only propose if the
25542577 // next round can be started without a timeout, i.e. if we are in a multi-leader round.
25552578 // Similarly, we cannot propose a block that uses oracles in the fast round.
25562579 let conflict = manager. requested_proposed . as_ref ( ) . is_some_and ( |proposal| {
25572580 proposal. content . round == manager. current_round && proposal. content . block != * block
2558- } ) || ( manager. current_round . is_fast ( )
2559- && executed_block. outcome . has_oracle_responses ( ) ) ;
2581+ } ) || ( manager. current_round . is_fast ( ) && has_oracle_responses) ;
25602582 let round = if !conflict {
25612583 manager. current_round
25622584 } else if let Some ( round) = manager
0 commit comments