@@ -49,7 +49,10 @@ use starknet_api::test_utils::{
4949 DEFAULT_STRK_L2_GAS_PRICE ,
5050 TEST_SEQUENCER_ADDRESS ,
5151} ;
52- use starknet_api:: transaction:: constants:: DEPLOY_CONTRACT_FUNCTION_ENTRY_POINT_NAME ;
52+ use starknet_api:: transaction:: constants:: {
53+ DEPLOY_CONTRACT_FUNCTION_ENTRY_POINT_NAME ,
54+ EXECUTE_ENTRY_POINT_NAME ,
55+ } ;
5356use starknet_api:: transaction:: fields:: {
5457 AllResourceBounds ,
5558 Calldata ,
@@ -2598,3 +2601,207 @@ async fn test_direct_execute_call() {
25982601 test_output. assert_storage_diff_eq ( test_contract_address, HashMap :: default ( ) ) ;
25992602 test_output. assert_storage_diff_eq ( dummy_account_address, HashMap :: default ( ) ) ;
26002603}
2604+
2605+ #[ rstest]
2606+ #[ tokio:: test]
2607+ async fn test_meta_tx ( ) {
2608+ let meta_tx_contract = FeatureContract :: MetaTx ( RunnableCairo1 :: Casm ) ;
2609+ let tx_info_contract = FeatureContract :: TxInfoWriter ;
2610+ let ( mut test_manager, mut nonce_manager, [ meta_tx_contract_address, tx_info_contract_address] ) =
2611+ TestManager :: < DictStateReader > :: new_with_default_initial_state ( [
2612+ ( meta_tx_contract, calldata ! [ ] ) ,
2613+ ( tx_info_contract, calldata ! [ ] ) ,
2614+ ] )
2615+ . await ;
2616+
2617+ let argument = Felt :: from ( 1234 ) ;
2618+ let signature = vec ! [ Felt :: from( 5432 ) , Felt :: from( 100 ) ] ;
2619+
2620+ // Create and run an invoke tx.
2621+ let invoke_args = invoke_tx_args ! {
2622+ sender_address: * FUNDED_ACCOUNT_ADDRESS ,
2623+ nonce: nonce_manager. next( * FUNDED_ACCOUNT_ADDRESS ) ,
2624+ calldata: create_calldata(
2625+ meta_tx_contract_address,
2626+ "execute_meta_tx_v0" ,
2627+ & [
2628+ vec![
2629+ * * meta_tx_contract_address,
2630+ selector_from_name( EXECUTE_ENTRY_POINT_NAME ) . 0 ,
2631+ Felt :: ONE , // Calldata length.
2632+ argument,
2633+ signature. len( ) . into( )
2634+ ] ,
2635+ signature. clone( ) ,
2636+ vec![ false . into( ) ] , // Should revert.
2637+ ] . concat( )
2638+ ) ,
2639+ resource_bounds: * NON_TRIVIAL_RESOURCE_BOUNDS ,
2640+ } ;
2641+ let tx0 = InvokeTransaction :: create ( invoke_tx ( invoke_args) , & CHAIN_ID_FOR_TESTS ) . unwrap ( ) ;
2642+ let tx0_hash = tx0. tx_hash ( ) ;
2643+ let tx0_nonce = tx0. nonce ( ) ;
2644+ assert ! ( tx0. nonce( ) != Nonce ( Felt :: ZERO ) ) ;
2645+ test_manager. add_invoke_tx ( tx0, None ) ;
2646+
2647+ // Compute the meta-tx hash.
2648+ let meta_tx_hash0 = InvokeTransaction :: create (
2649+ invoke_tx ( invoke_tx_args ! {
2650+ version: TransactionVersion :: ZERO ,
2651+ sender_address: meta_tx_contract_address,
2652+ calldata: calldata![ argument] ,
2653+ max_fee: Fee ( 0 ) ,
2654+ } ) ,
2655+ & CHAIN_ID_FOR_TESTS ,
2656+ )
2657+ . unwrap ( )
2658+ . tx_hash ( ) ;
2659+
2660+ // Call `tx_info_writer` with a meta transaction.
2661+ let argument1 = Felt :: ONE ;
2662+ let invoke_args = invoke_tx_args ! {
2663+ sender_address: * FUNDED_ACCOUNT_ADDRESS ,
2664+ nonce: nonce_manager. next( * FUNDED_ACCOUNT_ADDRESS ) ,
2665+ calldata: create_calldata(
2666+ meta_tx_contract_address,
2667+ "execute_meta_tx_v0" ,
2668+ & [
2669+ vec![
2670+ * * tx_info_contract_address,
2671+ selector_from_name( EXECUTE_ENTRY_POINT_NAME ) . 0 ,
2672+ Felt :: ONE , // Calldata length.
2673+ argument1,
2674+ signature. len( ) . into( ) ,
2675+ ] ,
2676+ signature. clone( ) ,
2677+ vec![ false . into( ) ] , // Should revert.
2678+ ] . concat( )
2679+ ) ,
2680+ resource_bounds: * NON_TRIVIAL_RESOURCE_BOUNDS ,
2681+ } ;
2682+ let tx1 = InvokeTransaction :: create ( invoke_tx ( invoke_args) , & CHAIN_ID_FOR_TESTS ) . unwrap ( ) ;
2683+ assert ! ( tx1. nonce( ) != Nonce ( Felt :: ZERO ) ) ;
2684+ let tx1_hash = tx1. tx_hash ( ) ;
2685+ let tx1_nonce = tx1. nonce ( ) ;
2686+ test_manager. add_invoke_tx ( tx1, None ) ;
2687+
2688+ // Compute the meta-tx hash.
2689+ let meta_tx_hash1 = InvokeTransaction :: create (
2690+ invoke_tx ( invoke_tx_args ! {
2691+ version: TransactionVersion :: ZERO ,
2692+ sender_address: tx_info_contract_address,
2693+ calldata: calldata![ argument1] ,
2694+ max_fee: Fee ( 0 ) ,
2695+ } ) ,
2696+ & CHAIN_ID_FOR_TESTS ,
2697+ )
2698+ . unwrap ( )
2699+ . tx_hash ( ) ;
2700+
2701+ // Check that calling an entry point other than '__execute__` fails.
2702+ let invoke_args = invoke_tx_args ! {
2703+ sender_address: * FUNDED_ACCOUNT_ADDRESS ,
2704+ nonce: nonce_manager. next( * FUNDED_ACCOUNT_ADDRESS ) ,
2705+ calldata: create_calldata(
2706+ meta_tx_contract_address,
2707+ "execute_meta_tx_v0" ,
2708+ & [
2709+ vec![
2710+ * * meta_tx_contract_address,
2711+ selector_from_name( "foo" ) . 0 ,
2712+ Felt :: ZERO ,
2713+ signature. len( ) . into( )
2714+ ] ,
2715+ signature. clone( ) ,
2716+ vec![ true . into( ) ] // Should revert.
2717+ ] . concat( )
2718+ ) ,
2719+ resource_bounds: * NON_TRIVIAL_RESOURCE_BOUNDS ,
2720+ } ;
2721+ let tx2 = InvokeTransaction :: create ( invoke_tx ( invoke_args) , & CHAIN_ID_FOR_TESTS ) . unwrap ( ) ;
2722+ assert ! ( tx2. nonce( ) != Nonce ( Felt :: ZERO ) ) ;
2723+ let tx2_hash = tx2. tx_hash ( ) ;
2724+ let tx2_nonce = tx2. nonce ( ) ;
2725+ test_manager. add_invoke_tx ( tx2, None ) ;
2726+
2727+ // Construct the expected storage diff for each of the two contracts.
2728+ // All zero-valued keys should be filtered out (as they don't appear in the state diff).
2729+ let calldata_key = selector_from_name ( "call_data" ) . 0 ;
2730+ let calldata_item_keys: Vec < Felt > =
2731+ ( 0 ..4u8 ) . map ( |i| Pedersen :: hash ( & calldata_key, & i. into ( ) ) ) . collect ( ) ;
2732+ let no_argument = Felt :: from_bytes_be_slice ( b"NO_ARGUMENT" ) ;
2733+ let no_signature = Felt :: from_bytes_be_slice ( b"NO_SIGNATURE" ) ;
2734+ let expected_meta_tx_contract_diffs: HashMap < Felt , Felt > = HashMap :: from_iter ( [
2735+ ( calldata_key, Felt :: from ( 4 ) ) , // Size of `call_data` vector.
2736+ // Inside the meta-tx.
2737+ ( calldata_item_keys[ 0 ] , Felt :: ZERO ) , // caller_address.
2738+ ( calldata_item_keys[ 0 ] + Felt :: ONE , * * meta_tx_contract_address) , /* account_contract_address. */
2739+ ( calldata_item_keys[ 0 ] + Felt :: TWO , Felt :: ZERO ) , // tx_version.
2740+ ( calldata_item_keys[ 0 ] + Felt :: THREE , argument) , // Argument.
2741+ ( calldata_item_keys[ 0 ] + Felt :: from ( 4u8 ) , * meta_tx_hash0) , // transaction_hash.
2742+ ( calldata_item_keys[ 0 ] + Felt :: from ( 5u8 ) , signature[ 0 ] ) , // signature.
2743+ ( calldata_item_keys[ 0 ] + Felt :: from ( 6u8 ) , Felt :: ZERO ) , // max_fee.
2744+ ( calldata_item_keys[ 0 ] + Felt :: from ( 7u8 ) , Felt :: ZERO ) , // resource_bound_len.
2745+ ( calldata_item_keys[ 0 ] + Felt :: from ( 8u8 ) , Felt :: ZERO ) , // nonce.
2746+ // Outside the meta-tx.
2747+ ( calldata_item_keys[ 1 ] , * * * FUNDED_ACCOUNT_ADDRESS ) , // caller_address.
2748+ ( calldata_item_keys[ 1 ] + Felt :: ONE , * * * FUNDED_ACCOUNT_ADDRESS ) , // account_contract_address.
2749+ ( calldata_item_keys[ 1 ] + Felt :: TWO , Felt :: THREE ) , // tx_version.
2750+ ( calldata_item_keys[ 1 ] + Felt :: THREE , no_argument) , // Argument.
2751+ ( calldata_item_keys[ 1 ] + Felt :: from ( 4u8 ) , * tx0_hash) , // transaction_hash.
2752+ ( calldata_item_keys[ 1 ] + Felt :: from ( 5u8 ) , no_signature) , // signature.
2753+ ( calldata_item_keys[ 1 ] + Felt :: from ( 6u8 ) , Felt :: ZERO ) , // max_fee.
2754+ ( calldata_item_keys[ 1 ] + Felt :: from ( 7u8 ) , Felt :: THREE ) , // resource_bound_len.
2755+ ( calldata_item_keys[ 1 ] + Felt :: from ( 8u8 ) , * tx0_nonce) , // nonce.
2756+ // Outside the meta-tx (second tx).
2757+ ( calldata_item_keys[ 2 ] , * * * FUNDED_ACCOUNT_ADDRESS ) , // caller_address.
2758+ ( calldata_item_keys[ 2 ] + Felt :: ONE , * * * FUNDED_ACCOUNT_ADDRESS ) , // account_contract_address.
2759+ ( calldata_item_keys[ 2 ] + Felt :: TWO , Felt :: THREE ) , // tx_version.
2760+ ( calldata_item_keys[ 2 ] + Felt :: THREE , no_argument) , // Argument.
2761+ ( calldata_item_keys[ 2 ] + Felt :: from ( 4u8 ) , * tx1_hash) , // transaction_hash.
2762+ ( calldata_item_keys[ 2 ] + Felt :: from ( 5u8 ) , no_signature) , // signature.
2763+ ( calldata_item_keys[ 2 ] + Felt :: from ( 6u8 ) , Felt :: ZERO ) , // max_fee.
2764+ ( calldata_item_keys[ 2 ] + Felt :: from ( 7u8 ) , Felt :: THREE ) , // resource_bound_len.
2765+ ( calldata_item_keys[ 2 ] + Felt :: from ( 8u8 ) , * tx1_nonce) , // nonce.
2766+ // Outside the meta-tx (third tx).
2767+ ( calldata_item_keys[ 3 ] , * * * FUNDED_ACCOUNT_ADDRESS ) , // caller_address.
2768+ ( calldata_item_keys[ 3 ] + Felt :: ONE , * * * FUNDED_ACCOUNT_ADDRESS ) , // account_contract_address.
2769+ ( calldata_item_keys[ 3 ] + Felt :: TWO , Felt :: THREE ) , // tx_version.
2770+ ( calldata_item_keys[ 3 ] + Felt :: THREE , no_argument) , // Argument.
2771+ ( calldata_item_keys[ 3 ] + Felt :: from ( 4u8 ) , * tx2_hash) , // transaction_hash.
2772+ ( calldata_item_keys[ 3 ] + Felt :: from ( 5u8 ) , no_signature) , // signature.
2773+ ( calldata_item_keys[ 3 ] + Felt :: from ( 6u8 ) , Felt :: ZERO ) , // max_fee.
2774+ ( calldata_item_keys[ 3 ] + Felt :: from ( 7u8 ) , Felt :: THREE ) , // resource_bound_len.
2775+ ( calldata_item_keys[ 3 ] + Felt :: from ( 8u8 ) , * tx2_nonce) , // nonce.
2776+ ] . into_iter ( ) . filter ( |( _, v) | * v != Felt :: ZERO ) ) ;
2777+ let expected_tx_info_writer_diffs: HashMap < Felt , Felt > = HashMap :: from_iter (
2778+ [
2779+ ( * * get_storage_var_address ( "version" , & [ Felt :: ZERO ] ) , Felt :: ZERO ) ,
2780+ (
2781+ * * get_storage_var_address ( "account_contract_address" , & [ Felt :: ZERO ] ) ,
2782+ * * tx_info_contract_address,
2783+ ) ,
2784+ ( * * get_storage_var_address ( "max_fee" , & [ Felt :: ZERO ] ) , Felt :: ZERO ) ,
2785+ ( * * get_storage_var_address ( "signature_len" , & [ Felt :: ZERO ] ) , Felt :: TWO ) ,
2786+ ( * * get_storage_var_address ( "transaction_hash" , & [ Felt :: ZERO ] ) , * meta_tx_hash1) ,
2787+ (
2788+ * * get_storage_var_address ( "chain_id" , & [ Felt :: ZERO ] ) ,
2789+ Felt :: try_from ( & * CHAIN_ID_FOR_TESTS ) . unwrap ( ) ,
2790+ ) ,
2791+ ( * * get_storage_var_address ( "nonce" , & [ Felt :: ZERO ] ) , Felt :: ZERO ) ,
2792+ ]
2793+ . into_iter ( )
2794+ . filter ( |( _, v) | * v != Felt :: ZERO ) ,
2795+ ) ;
2796+
2797+ // Run the test and verify the storage changes.
2798+ let test_output = test_manager
2799+ . execute_test_with_default_block_contexts ( & TestParameters {
2800+ use_kzg_da : true ,
2801+ ..Default :: default ( )
2802+ } )
2803+ . await ;
2804+ test_output. perform_default_validations ( ) ;
2805+ test_output. assert_storage_diff_eq ( meta_tx_contract_address, expected_meta_tx_contract_diffs) ;
2806+ test_output. assert_storage_diff_eq ( tx_info_contract_address, expected_tx_info_writer_diffs) ;
2807+ }
0 commit comments