@@ -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 ;
@@ -86,12 +87,17 @@ pub(crate) struct TestParameters {
86
87
pub ( crate ) messages_to_l2 : Vec < MessageToL2 > ,
87
88
}
88
89
90
+ pub ( crate ) struct FlowTestTx {
91
+ tx : BlockifierTransaction ,
92
+ revert_reason : Option < String > ,
93
+ }
94
+
89
95
/// Manages the execution of flow tests by maintaining the initial state and transactions.
90
96
pub ( crate ) struct TestManager < S : FlowTestState > {
91
97
pub ( crate ) initial_state : InitialState < S > ,
92
98
pub ( crate ) execution_contracts : OsExecutionContracts ,
93
99
94
- per_block_transactions : Vec < Vec < BlockifierTransaction > > ,
100
+ per_block_transactions : Vec < Vec < FlowTestTx > > ,
95
101
}
96
102
97
103
pub ( crate ) struct OsTestExpectedValues {
@@ -255,7 +261,7 @@ impl<S: FlowTestState> TestManager<S> {
255
261
self . per_block_transactions . push ( vec ! [ ] ) ;
256
262
}
257
263
258
- fn last_block_txs_mut ( & mut self ) -> & mut Vec < BlockifierTransaction > {
264
+ fn last_block_txs_mut ( & mut self ) -> & mut Vec < FlowTestTx > {
259
265
self . per_block_transactions
260
266
. last_mut ( )
261
267
. expect ( "Always initialized with at least one tx list (at least one block)." )
@@ -271,9 +277,12 @@ impl<S: FlowTestState> TestManager<S> {
271
277
else {
272
278
panic ! ( "Expected a V1 contract class" ) ;
273
279
} ;
274
- self . last_block_txs_mut ( ) . push ( BlockifierTransaction :: new_for_sequencing (
275
- StarknetApiTransaction :: Account ( AccountTransaction :: Declare ( tx) ) ,
276
- ) ) ;
280
+ self . last_block_txs_mut ( ) . push ( FlowTestTx {
281
+ tx : BlockifierTransaction :: new_for_sequencing ( StarknetApiTransaction :: Account (
282
+ AccountTransaction :: Declare ( tx) ,
283
+ ) ) ,
284
+ revert_reason : None ,
285
+ } ) ;
277
286
278
287
self . execution_contracts
279
288
. declared_class_hash_to_component_hashes
@@ -285,14 +294,25 @@ impl<S: FlowTestState> TestManager<S> {
285
294
. insert ( compiled_class_hash, casm. clone ( ) ) ;
286
295
}
287
296
288
- pub ( crate ) fn add_invoke_tx ( & mut self , tx : InvokeTransaction ) {
289
- self . last_block_txs_mut ( ) . push ( BlockifierTransaction :: new_for_sequencing (
290
- StarknetApiTransaction :: Account ( AccountTransaction :: Invoke ( tx) ) ,
291
- ) ) ;
297
+ pub ( crate ) fn add_invoke_tx ( & mut self , tx : InvokeTransaction , revert_reason : Option < String > ) {
298
+ self . last_block_txs_mut ( ) . push ( FlowTestTx {
299
+ tx : BlockifierTransaction :: new_for_sequencing ( StarknetApiTransaction :: Account (
300
+ AccountTransaction :: Invoke ( tx) ,
301
+ ) ) ,
302
+ revert_reason,
303
+ } ) ;
292
304
}
293
305
294
- pub ( crate ) fn add_invoke_tx_from_args ( & mut self , args : InvokeTxArgs , chain_id : & ChainId ) {
295
- self . add_invoke_tx ( InvokeTransaction :: create ( invoke_tx ( args) , chain_id) . unwrap ( ) ) ;
306
+ pub ( crate ) fn add_invoke_tx_from_args (
307
+ & mut self ,
308
+ args : InvokeTxArgs ,
309
+ chain_id : & ChainId ,
310
+ revert_reason : Option < String > ,
311
+ ) {
312
+ self . add_invoke_tx (
313
+ InvokeTransaction :: create ( invoke_tx ( args) , chain_id) . unwrap ( ) ,
314
+ revert_reason,
315
+ ) ;
296
316
}
297
317
298
318
pub ( crate ) fn add_cairo0_declare_tx (
@@ -303,24 +323,36 @@ impl<S: FlowTestState> TestManager<S> {
303
323
let ContractClass :: V0 ( class) = tx. class_info . contract_class . clone ( ) else {
304
324
panic ! ( "Expected a V0 contract class" ) ;
305
325
} ;
306
- self . last_block_txs_mut ( ) . push ( BlockifierTransaction :: new_for_sequencing (
307
- StarknetApiTransaction :: Account ( AccountTransaction :: Declare ( tx) ) ,
308
- ) ) ;
326
+ self . last_block_txs_mut ( ) . push ( FlowTestTx {
327
+ tx : BlockifierTransaction :: new_for_sequencing ( StarknetApiTransaction :: Account (
328
+ AccountTransaction :: Declare ( tx) ,
329
+ ) ) ,
330
+ revert_reason : None ,
331
+ } ) ;
309
332
self . execution_contracts
310
333
. executed_contracts
311
334
. deprecated_contracts
312
335
. insert ( compiled_class_hash, class) ;
313
336
}
314
337
315
338
pub ( crate ) fn add_deploy_account_tx ( & mut self , tx : DeployAccountTransaction ) {
316
- self . last_block_txs_mut ( ) . push ( BlockifierTransaction :: new_for_sequencing (
317
- StarknetApiTransaction :: Account ( AccountTransaction :: DeployAccount ( tx) ) ,
318
- ) ) ;
339
+ self . last_block_txs_mut ( ) . push ( FlowTestTx {
340
+ tx : BlockifierTransaction :: new_for_sequencing ( StarknetApiTransaction :: Account (
341
+ AccountTransaction :: DeployAccount ( tx) ,
342
+ ) ) ,
343
+ revert_reason : None ,
344
+ } ) ;
319
345
}
320
346
321
- pub ( crate ) fn add_l1_handler_tx ( & mut self , tx : L1HandlerTransaction ) {
322
- self . last_block_txs_mut ( )
323
- . push ( BlockifierTransaction :: new_for_sequencing ( StarknetApiTransaction :: L1Handler ( tx) ) ) ;
347
+ pub ( crate ) fn add_l1_handler_tx (
348
+ & mut self ,
349
+ tx : L1HandlerTransaction ,
350
+ revert_reason : Option < String > ,
351
+ ) {
352
+ self . last_block_txs_mut ( ) . push ( FlowTestTx {
353
+ tx : BlockifierTransaction :: new_for_sequencing ( StarknetApiTransaction :: L1Handler ( tx) ) ,
354
+ revert_reason,
355
+ } ) ;
324
356
}
325
357
326
358
/// Executes the test using default block contexts, starting from the given block number.
@@ -395,6 +427,27 @@ impl<S: FlowTestState> TestManager<S> {
395
427
first_use_kzg_da
396
428
}
397
429
430
+ /// Verifies all the execution outputs are as expected w.r.t. revert reasons.
431
+ fn verify_execution_outputs (
432
+ revert_reasons : & [ Option < String > ] ,
433
+ execution_outputs : & [ ( TransactionExecutionInfo , StateMaps ) ] ,
434
+ ) {
435
+ for ( revert_reason, ( execution_info, _) ) in
436
+ revert_reasons. iter ( ) . zip ( execution_outputs. iter ( ) )
437
+ {
438
+ if let Some ( revert_reason) = revert_reason {
439
+ let actual_revert_reason =
440
+ execution_info. revert_error . as_ref ( ) . unwrap ( ) . to_string ( ) ;
441
+ assert ! (
442
+ actual_revert_reason. contains( revert_reason) ,
443
+ "Expected '{revert_reason}' to be in revert string:\n '{actual_revert_reason}'"
444
+ ) ;
445
+ } else {
446
+ assert ! ( execution_info. revert_error. is_none( ) ) ;
447
+ }
448
+ }
449
+ }
450
+
398
451
/// Decompresses the state diff from the OS output using the given OS output, state and alias
399
452
/// keys.
400
453
fn get_decompressed_state_diff (
@@ -454,13 +507,19 @@ impl<S: FlowTestState> TestManager<S> {
454
507
"use_kzg_da flag in block contexts must match the test parameter."
455
508
) ;
456
509
let mut alias_keys = HashSet :: new ( ) ;
457
- for ( block_txs, block_context) in per_block_txs. into_iter ( ) . zip ( block_contexts. into_iter ( ) )
510
+ for ( block_txs_with_reason, block_context) in
511
+ per_block_txs. into_iter ( ) . zip ( block_contexts. into_iter ( ) )
458
512
{
459
513
// Clone the block info for later use.
514
+ let ( block_txs, revert_reasons) : ( Vec < _ > , Vec < _ > ) = block_txs_with_reason
515
+ . into_iter ( )
516
+ . map ( |flow_test_tx| ( flow_test_tx. tx , flow_test_tx. revert_reason ) )
517
+ . unzip ( ) ;
460
518
let block_info = block_context. block_info ( ) . clone ( ) ;
461
519
// Execute the transactions.
462
520
let ExecutionOutput { execution_outputs, block_summary, mut final_state } =
463
521
execute_transactions ( state, & block_txs, block_context) ;
522
+ Self :: verify_execution_outputs ( & revert_reasons, & execution_outputs) ;
464
523
let extended_state_diff = final_state. cache . borrow ( ) . extended_state_diff ( ) ;
465
524
// Update the wrapped state.
466
525
let state_diff = final_state. to_state_diff ( ) . unwrap ( ) ;
0 commit comments