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