@@ -46,7 +46,10 @@ use starknet_api::test_utils::{
4646 DEFAULT_STRK_L2_GAS_PRICE ,
4747 TEST_SEQUENCER_ADDRESS ,
4848} ;
49- use starknet_api:: transaction:: constants:: DEPLOY_CONTRACT_FUNCTION_ENTRY_POINT_NAME ;
49+ use starknet_api:: transaction:: constants:: {
50+ DEPLOY_CONTRACT_FUNCTION_ENTRY_POINT_NAME ,
51+ EXECUTE_ENTRY_POINT_NAME ,
52+ } ;
5053use starknet_api:: transaction:: fields:: {
5154 AllResourceBounds ,
5255 Calldata ,
@@ -2433,3 +2436,207 @@ async fn test_direct_execute_call() {
24332436 test_output. assert_storage_diff_eq ( test_contract_address, HashMap :: default ( ) ) ;
24342437 test_output. assert_storage_diff_eq ( dummy_account_address, HashMap :: default ( ) ) ;
24352438}
2439+
2440+ #[ rstest]
2441+ #[ tokio:: test]
2442+ async fn test_meta_tx ( ) {
2443+ let meta_tx_contract = FeatureContract :: MetaTx ( RunnableCairo1 :: Casm ) ;
2444+ let tx_info_contract = FeatureContract :: TxInfoWriter ;
2445+ let ( mut test_manager, [ meta_tx_contract_address, tx_info_contract_address] ) =
2446+ TestManager :: < DictStateReader > :: new_with_default_initial_state ( [
2447+ ( meta_tx_contract, calldata ! [ ] ) ,
2448+ ( tx_info_contract, calldata ! [ ] ) ,
2449+ ] )
2450+ . await ;
2451+
2452+ let argument = Felt :: from ( 1234 ) ;
2453+ let signature = vec ! [ Felt :: from( 5432 ) , Felt :: from( 100 ) ] ;
2454+
2455+ // Create and run an invoke tx.
2456+ let invoke_args = invoke_tx_args ! {
2457+ sender_address: * FUNDED_ACCOUNT_ADDRESS ,
2458+ nonce: test_manager. next_nonce( * FUNDED_ACCOUNT_ADDRESS ) ,
2459+ calldata: create_calldata(
2460+ meta_tx_contract_address,
2461+ "execute_meta_tx_v0" ,
2462+ & [
2463+ vec![
2464+ * * meta_tx_contract_address,
2465+ selector_from_name( EXECUTE_ENTRY_POINT_NAME ) . 0 ,
2466+ Felt :: ONE , // Calldata length.
2467+ argument,
2468+ signature. len( ) . into( )
2469+ ] ,
2470+ signature. clone( ) ,
2471+ vec![ false . into( ) ] , // Should revert.
2472+ ] . concat( )
2473+ ) ,
2474+ resource_bounds: * NON_TRIVIAL_RESOURCE_BOUNDS ,
2475+ } ;
2476+ let tx0 = InvokeTransaction :: create ( invoke_tx ( invoke_args) , & CHAIN_ID_FOR_TESTS ) . unwrap ( ) ;
2477+ let tx0_hash = tx0. tx_hash ( ) ;
2478+ let tx0_nonce = tx0. nonce ( ) ;
2479+ assert ! ( tx0. nonce( ) != Nonce ( Felt :: ZERO ) ) ;
2480+ test_manager. add_invoke_tx ( tx0, None ) ;
2481+
2482+ // Compute the meta-tx hash.
2483+ let meta_tx_hash0 = InvokeTransaction :: create (
2484+ invoke_tx ( invoke_tx_args ! {
2485+ version: TransactionVersion :: ZERO ,
2486+ sender_address: meta_tx_contract_address,
2487+ calldata: calldata![ argument] ,
2488+ max_fee: Fee ( 0 ) ,
2489+ } ) ,
2490+ & CHAIN_ID_FOR_TESTS ,
2491+ )
2492+ . unwrap ( )
2493+ . tx_hash ( ) ;
2494+
2495+ // Call `tx_info_writer` with a meta transaction.
2496+ let argument1 = Felt :: ONE ;
2497+ let invoke_args = invoke_tx_args ! {
2498+ sender_address: * FUNDED_ACCOUNT_ADDRESS ,
2499+ nonce: test_manager. next_nonce( * FUNDED_ACCOUNT_ADDRESS ) ,
2500+ calldata: create_calldata(
2501+ meta_tx_contract_address,
2502+ "execute_meta_tx_v0" ,
2503+ & [
2504+ vec![
2505+ * * tx_info_contract_address,
2506+ selector_from_name( EXECUTE_ENTRY_POINT_NAME ) . 0 ,
2507+ Felt :: ONE , // Calldata length.
2508+ argument1,
2509+ signature. len( ) . into( ) ,
2510+ ] ,
2511+ signature. clone( ) ,
2512+ vec![ false . into( ) ] , // Should revert.
2513+ ] . concat( )
2514+ ) ,
2515+ resource_bounds: * NON_TRIVIAL_RESOURCE_BOUNDS ,
2516+ } ;
2517+ let tx1 = InvokeTransaction :: create ( invoke_tx ( invoke_args) , & CHAIN_ID_FOR_TESTS ) . unwrap ( ) ;
2518+ assert ! ( tx1. nonce( ) != Nonce ( Felt :: ZERO ) ) ;
2519+ let tx1_hash = tx1. tx_hash ( ) ;
2520+ let tx1_nonce = tx1. nonce ( ) ;
2521+ test_manager. add_invoke_tx ( tx1, None ) ;
2522+
2523+ // Compute the meta-tx hash.
2524+ let meta_tx_hash1 = InvokeTransaction :: create (
2525+ invoke_tx ( invoke_tx_args ! {
2526+ version: TransactionVersion :: ZERO ,
2527+ sender_address: tx_info_contract_address,
2528+ calldata: calldata![ argument1] ,
2529+ max_fee: Fee ( 0 ) ,
2530+ } ) ,
2531+ & CHAIN_ID_FOR_TESTS ,
2532+ )
2533+ . unwrap ( )
2534+ . tx_hash ( ) ;
2535+
2536+ // Check that calling an entry point other than '__execute__` fails.
2537+ let invoke_args = invoke_tx_args ! {
2538+ sender_address: * FUNDED_ACCOUNT_ADDRESS ,
2539+ nonce: test_manager. next_nonce( * FUNDED_ACCOUNT_ADDRESS ) ,
2540+ calldata: create_calldata(
2541+ meta_tx_contract_address,
2542+ "execute_meta_tx_v0" ,
2543+ & [
2544+ vec![
2545+ * * meta_tx_contract_address,
2546+ selector_from_name( "foo" ) . 0 ,
2547+ Felt :: ZERO ,
2548+ signature. len( ) . into( )
2549+ ] ,
2550+ signature. clone( ) ,
2551+ vec![ true . into( ) ] // Should revert.
2552+ ] . concat( )
2553+ ) ,
2554+ resource_bounds: * NON_TRIVIAL_RESOURCE_BOUNDS ,
2555+ } ;
2556+ let tx2 = InvokeTransaction :: create ( invoke_tx ( invoke_args) , & CHAIN_ID_FOR_TESTS ) . unwrap ( ) ;
2557+ assert ! ( tx2. nonce( ) != Nonce ( Felt :: ZERO ) ) ;
2558+ let tx2_hash = tx2. tx_hash ( ) ;
2559+ let tx2_nonce = tx2. nonce ( ) ;
2560+ test_manager. add_invoke_tx ( tx2, None ) ;
2561+
2562+ // Construct the expected storage diff for each of the two contracts.
2563+ // All zero-valued keys should be filtered out (as they don't appear in the state diff).
2564+ let calldata_key = selector_from_name ( "call_data" ) . 0 ;
2565+ let calldata_item_keys: Vec < Felt > =
2566+ ( 0 ..4u8 ) . map ( |i| Pedersen :: hash ( & calldata_key, & i. into ( ) ) ) . collect ( ) ;
2567+ let no_argument = Felt :: from_bytes_be_slice ( b"NO_ARGUMENT" ) ;
2568+ let no_signature = Felt :: from_bytes_be_slice ( b"NO_SIGNATURE" ) ;
2569+ let expected_meta_tx_contract_diffs: HashMap < Felt , Felt > = HashMap :: from_iter ( [
2570+ ( calldata_key, Felt :: from ( 4 ) ) , // Size of `call_data` vector.
2571+ // Inside the meta-tx.
2572+ ( calldata_item_keys[ 0 ] , Felt :: ZERO ) , // caller_address.
2573+ ( calldata_item_keys[ 0 ] + Felt :: ONE , * * meta_tx_contract_address) , /* account_contract_address. */
2574+ ( calldata_item_keys[ 0 ] + Felt :: TWO , Felt :: ZERO ) , // tx_version.
2575+ ( calldata_item_keys[ 0 ] + Felt :: THREE , argument) , // Argument.
2576+ ( calldata_item_keys[ 0 ] + Felt :: from ( 4u8 ) , * meta_tx_hash0) , // transaction_hash.
2577+ ( calldata_item_keys[ 0 ] + Felt :: from ( 5u8 ) , signature[ 0 ] ) , // signature.
2578+ ( calldata_item_keys[ 0 ] + Felt :: from ( 6u8 ) , Felt :: ZERO ) , // max_fee.
2579+ ( calldata_item_keys[ 0 ] + Felt :: from ( 7u8 ) , Felt :: ZERO ) , // resource_bound_len.
2580+ ( calldata_item_keys[ 0 ] + Felt :: from ( 8u8 ) , Felt :: ZERO ) , // nonce.
2581+ // Outside the meta-tx.
2582+ ( calldata_item_keys[ 1 ] , * * * FUNDED_ACCOUNT_ADDRESS ) , // caller_address.
2583+ ( calldata_item_keys[ 1 ] + Felt :: ONE , * * * FUNDED_ACCOUNT_ADDRESS ) , // account_contract_address.
2584+ ( calldata_item_keys[ 1 ] + Felt :: TWO , Felt :: THREE ) , // tx_version.
2585+ ( calldata_item_keys[ 1 ] + Felt :: THREE , no_argument) , // Argument.
2586+ ( calldata_item_keys[ 1 ] + Felt :: from ( 4u8 ) , * tx0_hash) , // transaction_hash.
2587+ ( calldata_item_keys[ 1 ] + Felt :: from ( 5u8 ) , no_signature) , // signature.
2588+ ( calldata_item_keys[ 1 ] + Felt :: from ( 6u8 ) , Felt :: ZERO ) , // max_fee.
2589+ ( calldata_item_keys[ 1 ] + Felt :: from ( 7u8 ) , Felt :: THREE ) , // resource_bound_len.
2590+ ( calldata_item_keys[ 1 ] + Felt :: from ( 8u8 ) , * tx0_nonce) , // nonce.
2591+ // Outside the meta-tx (second tx).
2592+ ( calldata_item_keys[ 2 ] , * * * FUNDED_ACCOUNT_ADDRESS ) , // caller_address.
2593+ ( calldata_item_keys[ 2 ] + Felt :: ONE , * * * FUNDED_ACCOUNT_ADDRESS ) , // account_contract_address.
2594+ ( calldata_item_keys[ 2 ] + Felt :: TWO , Felt :: THREE ) , // tx_version.
2595+ ( calldata_item_keys[ 2 ] + Felt :: THREE , no_argument) , // Argument.
2596+ ( calldata_item_keys[ 2 ] + Felt :: from ( 4u8 ) , * tx1_hash) , // transaction_hash.
2597+ ( calldata_item_keys[ 2 ] + Felt :: from ( 5u8 ) , no_signature) , // signature.
2598+ ( calldata_item_keys[ 2 ] + Felt :: from ( 6u8 ) , Felt :: ZERO ) , // max_fee.
2599+ ( calldata_item_keys[ 2 ] + Felt :: from ( 7u8 ) , Felt :: THREE ) , // resource_bound_len.
2600+ ( calldata_item_keys[ 2 ] + Felt :: from ( 8u8 ) , * tx1_nonce) , // nonce.
2601+ // Outside the meta-tx (third tx).
2602+ ( calldata_item_keys[ 3 ] , * * * FUNDED_ACCOUNT_ADDRESS ) , // caller_address.
2603+ ( calldata_item_keys[ 3 ] + Felt :: ONE , * * * FUNDED_ACCOUNT_ADDRESS ) , // account_contract_address.
2604+ ( calldata_item_keys[ 3 ] + Felt :: TWO , Felt :: THREE ) , // tx_version.
2605+ ( calldata_item_keys[ 3 ] + Felt :: THREE , no_argument) , // Argument.
2606+ ( calldata_item_keys[ 3 ] + Felt :: from ( 4u8 ) , * tx2_hash) , // transaction_hash.
2607+ ( calldata_item_keys[ 3 ] + Felt :: from ( 5u8 ) , no_signature) , // signature.
2608+ ( calldata_item_keys[ 3 ] + Felt :: from ( 6u8 ) , Felt :: ZERO ) , // max_fee.
2609+ ( calldata_item_keys[ 3 ] + Felt :: from ( 7u8 ) , Felt :: THREE ) , // resource_bound_len.
2610+ ( calldata_item_keys[ 3 ] + Felt :: from ( 8u8 ) , * tx2_nonce) , // nonce.
2611+ ] . into_iter ( ) . filter ( |( _, v) | * v != Felt :: ZERO ) ) ;
2612+ let expected_tx_info_writer_diffs: HashMap < Felt , Felt > = HashMap :: from_iter (
2613+ [
2614+ ( * * get_storage_var_address ( "version" , & [ Felt :: ZERO ] ) , Felt :: ZERO ) ,
2615+ (
2616+ * * get_storage_var_address ( "account_contract_address" , & [ Felt :: ZERO ] ) ,
2617+ * * tx_info_contract_address,
2618+ ) ,
2619+ ( * * get_storage_var_address ( "max_fee" , & [ Felt :: ZERO ] ) , Felt :: ZERO ) ,
2620+ ( * * get_storage_var_address ( "signature_len" , & [ Felt :: ZERO ] ) , Felt :: TWO ) ,
2621+ ( * * get_storage_var_address ( "transaction_hash" , & [ Felt :: ZERO ] ) , * meta_tx_hash1) ,
2622+ (
2623+ * * get_storage_var_address ( "chain_id" , & [ Felt :: ZERO ] ) ,
2624+ Felt :: try_from ( & * CHAIN_ID_FOR_TESTS ) . unwrap ( ) ,
2625+ ) ,
2626+ ( * * get_storage_var_address ( "nonce" , & [ Felt :: ZERO ] ) , Felt :: ZERO ) ,
2627+ ]
2628+ . into_iter ( )
2629+ . filter ( |( _, v) | * v != Felt :: ZERO ) ,
2630+ ) ;
2631+
2632+ // Run the test and verify the storage changes.
2633+ let test_output = test_manager
2634+ . execute_test_with_default_block_contexts ( & TestParameters {
2635+ use_kzg_da : true ,
2636+ ..Default :: default ( )
2637+ } )
2638+ . await ;
2639+ test_output. perform_default_validations ( ) ;
2640+ test_output. assert_storage_diff_eq ( meta_tx_contract_address, expected_meta_tx_contract_diffs) ;
2641+ test_output. assert_storage_diff_eq ( tx_info_contract_address, expected_tx_info_writer_diffs) ;
2642+ }
0 commit comments