@@ -9,6 +9,7 @@ use blockifier::context::{BlockContext, ChainInfo, FeeTokenAddresses};
9
9
use blockifier:: state:: cached_state:: { CommitmentStateDiff , StateMaps } ;
10
10
use blockifier:: state:: stateful_compression_test_utils:: decompress;
11
11
use blockifier:: test_utils:: ALIAS_CONTRACT_ADDRESS ;
12
+ use blockifier:: transaction:: objects:: TransactionExecutionInfo ;
12
13
use blockifier:: transaction:: transaction_execution:: Transaction as BlockifierTransaction ;
13
14
use blockifier_test_utils:: contracts:: FeatureContract ;
14
15
use itertools:: Itertools ;
@@ -87,12 +88,17 @@ pub(crate) struct TestParameters {
87
88
pub ( crate ) messages_to_l2 : Vec < MessageToL2 > ,
88
89
}
89
90
91
+ pub ( crate ) struct FlowTestTx {
92
+ tx : BlockifierTransaction ,
93
+ revert_reason : Option < String > ,
94
+ }
95
+
90
96
/// Manages the execution of flow tests by maintaining the initial state and transactions.
91
97
pub ( crate ) struct TestManager < S : FlowTestState > {
92
98
pub ( crate ) initial_state : InitialState < S > ,
93
99
pub ( crate ) execution_contracts : OsExecutionContracts ,
94
100
95
- per_block_transactions : Vec < Vec < BlockifierTransaction > > ,
101
+ per_block_transactions : Vec < Vec < FlowTestTx > > ,
96
102
}
97
103
98
104
pub ( crate ) struct OsTestExpectedValues {
@@ -267,7 +273,7 @@ impl<S: FlowTestState> TestManager<S> {
267
273
self . per_block_transactions . push ( vec ! [ ] ) ;
268
274
}
269
275
270
- fn last_block_txs_mut ( & mut self ) -> & mut Vec < BlockifierTransaction > {
276
+ fn last_block_txs_mut ( & mut self ) -> & mut Vec < FlowTestTx > {
271
277
self . per_block_transactions
272
278
. last_mut ( )
273
279
. expect ( "Always initialized with at least one tx list (at least one block)." )
@@ -283,9 +289,12 @@ impl<S: FlowTestState> TestManager<S> {
283
289
else {
284
290
panic ! ( "Expected a V1 contract class" ) ;
285
291
} ;
286
- self . last_block_txs_mut ( ) . push ( BlockifierTransaction :: new_for_sequencing (
287
- StarknetApiTransaction :: Account ( AccountTransaction :: Declare ( tx) ) ,
288
- ) ) ;
292
+ self . last_block_txs_mut ( ) . push ( FlowTestTx {
293
+ tx : BlockifierTransaction :: new_for_sequencing ( StarknetApiTransaction :: Account (
294
+ AccountTransaction :: Declare ( tx) ,
295
+ ) ) ,
296
+ revert_reason : None ,
297
+ } ) ;
289
298
290
299
self . execution_contracts
291
300
. declared_class_hash_to_component_hashes
@@ -297,14 +306,25 @@ impl<S: FlowTestState> TestManager<S> {
297
306
. insert ( compiled_class_hash, casm. clone ( ) ) ;
298
307
}
299
308
300
- pub ( crate ) fn add_invoke_tx ( & mut self , tx : InvokeTransaction ) {
301
- self . last_block_txs_mut ( ) . push ( BlockifierTransaction :: new_for_sequencing (
302
- StarknetApiTransaction :: Account ( AccountTransaction :: Invoke ( tx) ) ,
303
- ) ) ;
309
+ pub ( crate ) fn add_invoke_tx ( & mut self , tx : InvokeTransaction , revert_reason : Option < String > ) {
310
+ self . last_block_txs_mut ( ) . push ( FlowTestTx {
311
+ tx : BlockifierTransaction :: new_for_sequencing ( StarknetApiTransaction :: Account (
312
+ AccountTransaction :: Invoke ( tx) ,
313
+ ) ) ,
314
+ revert_reason,
315
+ } ) ;
304
316
}
305
317
306
- pub ( crate ) fn add_invoke_tx_from_args ( & mut self , args : InvokeTxArgs , chain_id : & ChainId ) {
307
- 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
+ ) ;
308
328
}
309
329
310
330
pub ( crate ) fn add_cairo0_declare_tx (
@@ -315,24 +335,36 @@ impl<S: FlowTestState> TestManager<S> {
315
335
let ContractClass :: V0 ( class) = tx. class_info . contract_class . clone ( ) else {
316
336
panic ! ( "Expected a V0 contract class" ) ;
317
337
} ;
318
- self . last_block_txs_mut ( ) . push ( BlockifierTransaction :: new_for_sequencing (
319
- StarknetApiTransaction :: Account ( AccountTransaction :: Declare ( tx) ) ,
320
- ) ) ;
338
+ self . last_block_txs_mut ( ) . push ( FlowTestTx {
339
+ tx : BlockifierTransaction :: new_for_sequencing ( StarknetApiTransaction :: Account (
340
+ AccountTransaction :: Declare ( tx) ,
341
+ ) ) ,
342
+ revert_reason : None ,
343
+ } ) ;
321
344
self . execution_contracts
322
345
. executed_contracts
323
346
. deprecated_contracts
324
347
. insert ( compiled_class_hash, class) ;
325
348
}
326
349
327
350
pub ( crate ) fn add_deploy_account_tx ( & mut self , tx : DeployAccountTransaction ) {
328
- self . last_block_txs_mut ( ) . push ( BlockifierTransaction :: new_for_sequencing (
329
- StarknetApiTransaction :: Account ( AccountTransaction :: DeployAccount ( tx) ) ,
330
- ) ) ;
351
+ self . last_block_txs_mut ( ) . push ( FlowTestTx {
352
+ tx : BlockifierTransaction :: new_for_sequencing ( StarknetApiTransaction :: Account (
353
+ AccountTransaction :: DeployAccount ( tx) ,
354
+ ) ) ,
355
+ revert_reason : None ,
356
+ } ) ;
331
357
}
332
358
333
- pub ( crate ) fn add_l1_handler_tx ( & mut self , tx : L1HandlerTransaction ) {
334
- self . last_block_txs_mut ( )
335
- . push ( BlockifierTransaction :: new_for_sequencing ( StarknetApiTransaction :: L1Handler ( tx) ) ) ;
359
+ pub ( crate ) fn add_l1_handler_tx (
360
+ & mut self ,
361
+ tx : L1HandlerTransaction ,
362
+ revert_reason : Option < String > ,
363
+ ) {
364
+ self . last_block_txs_mut ( ) . push ( FlowTestTx {
365
+ tx : BlockifierTransaction :: new_for_sequencing ( StarknetApiTransaction :: L1Handler ( tx) ) ,
366
+ revert_reason,
367
+ } ) ;
336
368
}
337
369
338
370
/// Executes the test using default block contexts, starting from the given block number.
@@ -407,6 +439,27 @@ impl<S: FlowTestState> TestManager<S> {
407
439
first_use_kzg_da
408
440
}
409
441
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
+ for ( revert_reason, ( execution_info, _) ) in
448
+ revert_reasons. iter ( ) . zip ( execution_outputs. iter ( ) )
449
+ {
450
+ if let Some ( revert_reason) = revert_reason {
451
+ let actual_revert_reason =
452
+ execution_info. revert_error . as_ref ( ) . unwrap ( ) . to_string ( ) ;
453
+ assert ! (
454
+ actual_revert_reason. contains( revert_reason) ,
455
+ "Expected '{revert_reason}' to be in revert string:\n '{actual_revert_reason}'"
456
+ ) ;
457
+ } else {
458
+ assert ! ( execution_info. revert_error. is_none( ) ) ;
459
+ }
460
+ }
461
+ }
462
+
410
463
/// Decompresses the state diff from the OS output using the given OS output, state and alias
411
464
/// keys.
412
465
fn get_decompressed_state_diff (
@@ -466,13 +519,19 @@ impl<S: FlowTestState> TestManager<S> {
466
519
"use_kzg_da flag in block contexts must match the test parameter."
467
520
) ;
468
521
let mut alias_keys = HashSet :: new ( ) ;
469
- for ( block_txs, block_context) in per_block_txs. into_iter ( ) . zip ( block_contexts. into_iter ( ) )
522
+ for ( block_txs_with_reason, block_context) in
523
+ per_block_txs. into_iter ( ) . zip ( block_contexts. into_iter ( ) )
470
524
{
471
525
// Clone the block info for later use.
526
+ let ( block_txs, revert_reasons) : ( Vec < _ > , Vec < _ > ) = block_txs_with_reason
527
+ . into_iter ( )
528
+ . map ( |flow_test_tx| ( flow_test_tx. tx , flow_test_tx. revert_reason ) )
529
+ . unzip ( ) ;
472
530
let block_info = block_context. block_info ( ) . clone ( ) ;
473
531
// Execute the transactions.
474
532
let ExecutionOutput { execution_outputs, block_summary, mut final_state } =
475
533
execute_transactions ( state, & block_txs, block_context) ;
534
+ Self :: verify_execution_outputs ( & revert_reasons, & execution_outputs) ;
476
535
let extended_state_diff = final_state. cache . borrow ( ) . extended_state_diff ( ) ;
477
536
// Update the wrapped state.
478
537
let state_diff = final_state. to_state_diff ( ) . unwrap ( ) ;
0 commit comments