@@ -9,6 +9,7 @@ use blockifier::context::{BlockContext, ChainInfo, FeeTokenAddresses};
99use blockifier:: state:: cached_state:: { CommitmentStateDiff , StateMaps } ;
1010use blockifier:: state:: stateful_compression_test_utils:: decompress;
1111use blockifier:: test_utils:: ALIAS_CONTRACT_ADDRESS ;
12+ use blockifier:: transaction:: objects:: TransactionExecutionInfo ;
1213use blockifier:: transaction:: transaction_execution:: Transaction as BlockifierTransaction ;
1314use blockifier_test_utils:: contracts:: FeatureContract ;
1415use itertools:: Itertools ;
@@ -87,12 +88,17 @@ pub(crate) struct TestParameters {
8788 pub ( crate ) messages_to_l2 : Vec < MessageToL2 > ,
8889}
8990
91+ pub ( crate ) struct FlowTestTx {
92+ tx : BlockifierTransaction ,
93+ expected_revert_reason : Option < String > ,
94+ }
95+
9096/// Manages the execution of flow tests by maintaining the initial state and transactions.
9197pub ( crate ) struct TestManager < S : FlowTestState > {
9298 pub ( crate ) initial_state : InitialState < S > ,
9399 pub ( crate ) execution_contracts : OsExecutionContracts ,
94100
95- per_block_transactions : Vec < Vec < BlockifierTransaction > > ,
101+ per_block_transactions : Vec < Vec < FlowTestTx > > ,
96102}
97103
98104pub ( crate ) struct OsTestExpectedValues {
@@ -263,7 +269,7 @@ impl<S: FlowTestState> TestManager<S> {
263269 self . per_block_transactions . push ( vec ! [ ] ) ;
264270 }
265271
266- fn last_block_txs_mut ( & mut self ) -> & mut Vec < BlockifierTransaction > {
272+ fn last_block_txs_mut ( & mut self ) -> & mut Vec < FlowTestTx > {
267273 self . per_block_transactions
268274 . last_mut ( )
269275 . expect ( "Always initialized with at least one tx list (at least one block)." )
@@ -279,9 +285,12 @@ impl<S: FlowTestState> TestManager<S> {
279285 else {
280286 panic ! ( "Expected a V1 contract class" ) ;
281287 } ;
282- self . last_block_txs_mut ( ) . push ( BlockifierTransaction :: new_for_sequencing (
283- StarknetApiTransaction :: Account ( AccountTransaction :: Declare ( tx) ) ,
284- ) ) ;
288+ self . last_block_txs_mut ( ) . push ( FlowTestTx {
289+ tx : BlockifierTransaction :: new_for_sequencing ( StarknetApiTransaction :: Account (
290+ AccountTransaction :: Declare ( tx) ,
291+ ) ) ,
292+ expected_revert_reason : None ,
293+ } ) ;
285294
286295 self . execution_contracts
287296 . declared_class_hash_to_component_hashes
@@ -293,14 +302,29 @@ impl<S: FlowTestState> TestManager<S> {
293302 . insert ( compiled_class_hash, casm. clone ( ) ) ;
294303 }
295304
296- pub ( crate ) fn add_invoke_tx ( & mut self , tx : InvokeTransaction ) {
297- self . last_block_txs_mut ( ) . push ( BlockifierTransaction :: new_for_sequencing (
298- StarknetApiTransaction :: Account ( AccountTransaction :: Invoke ( tx) ) ,
299- ) ) ;
305+ pub ( crate ) fn add_invoke_tx (
306+ & mut self ,
307+ tx : InvokeTransaction ,
308+ expected_revert_reason : Option < String > ,
309+ ) {
310+ self . last_block_txs_mut ( ) . push ( FlowTestTx {
311+ tx : BlockifierTransaction :: new_for_sequencing ( StarknetApiTransaction :: Account (
312+ AccountTransaction :: Invoke ( tx) ,
313+ ) ) ,
314+ expected_revert_reason,
315+ } ) ;
300316 }
301317
302- pub ( crate ) fn add_invoke_tx_from_args ( & mut self , args : InvokeTxArgs , chain_id : & ChainId ) {
303- self . add_invoke_tx ( InvokeTransaction :: create ( invoke_tx ( args) , chain_id) . unwrap ( ) ) ;
318+ pub ( crate ) fn add_invoke_tx_from_args (
319+ & mut self ,
320+ args : InvokeTxArgs ,
321+ chain_id : & ChainId ,
322+ revert_reason : Option < String > ,
323+ ) {
324+ self . add_invoke_tx (
325+ InvokeTransaction :: create ( invoke_tx ( args) , chain_id) . unwrap ( ) ,
326+ revert_reason,
327+ ) ;
304328 }
305329
306330 pub ( crate ) fn add_cairo0_declare_tx (
@@ -311,24 +335,36 @@ impl<S: FlowTestState> TestManager<S> {
311335 let ContractClass :: V0 ( class) = tx. class_info . contract_class . clone ( ) else {
312336 panic ! ( "Expected a V0 contract class" ) ;
313337 } ;
314- self . last_block_txs_mut ( ) . push ( BlockifierTransaction :: new_for_sequencing (
315- StarknetApiTransaction :: Account ( AccountTransaction :: Declare ( tx) ) ,
316- ) ) ;
338+ self . last_block_txs_mut ( ) . push ( FlowTestTx {
339+ tx : BlockifierTransaction :: new_for_sequencing ( StarknetApiTransaction :: Account (
340+ AccountTransaction :: Declare ( tx) ,
341+ ) ) ,
342+ expected_revert_reason : None ,
343+ } ) ;
317344 self . execution_contracts
318345 . executed_contracts
319346 . deprecated_contracts
320347 . insert ( compiled_class_hash, class) ;
321348 }
322349
323350 pub ( crate ) fn add_deploy_account_tx ( & mut self , tx : DeployAccountTransaction ) {
324- self . last_block_txs_mut ( ) . push ( BlockifierTransaction :: new_for_sequencing (
325- StarknetApiTransaction :: Account ( AccountTransaction :: DeployAccount ( tx) ) ,
326- ) ) ;
351+ self . last_block_txs_mut ( ) . push ( FlowTestTx {
352+ tx : BlockifierTransaction :: new_for_sequencing ( StarknetApiTransaction :: Account (
353+ AccountTransaction :: DeployAccount ( tx) ,
354+ ) ) ,
355+ expected_revert_reason : None ,
356+ } ) ;
327357 }
328358
329- pub ( crate ) fn add_l1_handler_tx ( & mut self , tx : L1HandlerTransaction ) {
330- self . last_block_txs_mut ( )
331- . push ( BlockifierTransaction :: new_for_sequencing ( StarknetApiTransaction :: L1Handler ( tx) ) ) ;
359+ pub ( crate ) fn add_l1_handler_tx (
360+ & mut self ,
361+ tx : L1HandlerTransaction ,
362+ expected_revert_reason : Option < String > ,
363+ ) {
364+ self . last_block_txs_mut ( ) . push ( FlowTestTx {
365+ tx : BlockifierTransaction :: new_for_sequencing ( StarknetApiTransaction :: L1Handler ( tx) ) ,
366+ expected_revert_reason,
367+ } ) ;
332368 }
333369
334370 /// Executes the test using default block contexts, starting from the given block number.
@@ -403,6 +439,28 @@ impl<S: FlowTestState> TestManager<S> {
403439 first_use_kzg_da
404440 }
405441
442+ /// Verifies all the execution outputs are as expected w.r.t. revert reasons.
443+ fn verify_execution_outputs (
444+ revert_reasons : & [ Option < String > ] ,
445+ execution_outputs : & [ ( TransactionExecutionInfo , StateMaps ) ] ,
446+ ) {
447+ assert_eq ! ( revert_reasons. len( ) , execution_outputs. len( ) ) ;
448+ for ( revert_reason, ( execution_info, _) ) in
449+ revert_reasons. iter ( ) . zip ( execution_outputs. iter ( ) )
450+ {
451+ if let Some ( revert_reason) = revert_reason {
452+ let actual_revert_reason =
453+ execution_info. revert_error . as_ref ( ) . unwrap ( ) . to_string ( ) ;
454+ assert ! (
455+ actual_revert_reason. contains( revert_reason) ,
456+ "Expected '{revert_reason}' to be in revert string:\n '{actual_revert_reason}'"
457+ ) ;
458+ } else {
459+ assert ! ( execution_info. revert_error. is_none( ) ) ;
460+ }
461+ }
462+ }
463+
406464 /// Decompresses the state diff from the OS output using the given OS output, state and alias
407465 /// keys.
408466 fn get_decompressed_state_diff (
@@ -465,13 +523,19 @@ impl<S: FlowTestState> TestManager<S> {
465523 "use_kzg_da flag in block contexts must match the test parameter."
466524 ) ;
467525 let mut alias_keys = HashSet :: new ( ) ;
468- for ( block_txs, block_context) in per_block_txs. into_iter ( ) . zip ( block_contexts. into_iter ( ) )
526+ for ( block_txs_with_reason, block_context) in
527+ per_block_txs. into_iter ( ) . zip ( block_contexts. into_iter ( ) )
469528 {
529+ let ( block_txs, revert_reasons) : ( Vec < _ > , Vec < _ > ) = block_txs_with_reason
530+ . into_iter ( )
531+ . map ( |flow_test_tx| ( flow_test_tx. tx , flow_test_tx. expected_revert_reason ) )
532+ . unzip ( ) ;
470533 // Clone the block info for later use.
471534 let block_info = block_context. block_info ( ) . clone ( ) ;
472535 // Execute the transactions.
473536 let ExecutionOutput { execution_outputs, block_summary, mut final_state } =
474537 execute_transactions ( state, & block_txs, block_context) ;
538+ Self :: verify_execution_outputs ( & revert_reasons, & execution_outputs) ;
475539 let extended_state_diff = final_state. cache . borrow ( ) . extended_state_diff ( ) ;
476540 // Update the wrapped state.
477541 let state_diff = final_state. to_state_diff ( ) . unwrap ( ) ;
0 commit comments