@@ -17,7 +17,7 @@ use starknet_api::abi::abi_utils::{
1717 get_storage_var_address,
1818 selector_from_name,
1919} ;
20- use starknet_api:: block:: { FeeType , GasPrice } ;
20+ use starknet_api:: block:: { BlockHash , BlockNumber , FeeType , GasPrice } ;
2121use starknet_api:: contract_class:: compiled_class_hash:: { HashVersion , HashableCompiledClass } ;
2222use starknet_api:: contract_class:: ContractClass ;
2323use starknet_api:: core:: {
@@ -41,6 +41,7 @@ use starknet_api::test_utils::deploy_account::executable_deploy_account_tx;
4141use starknet_api:: test_utils:: invoke:: { executable_invoke_tx, InvokeTxArgs } ;
4242use starknet_api:: test_utils:: {
4343 NonceManager ,
44+ CURRENT_BLOCK_NUMBER ,
4445 DEFAULT_L1_DATA_GAS_MAX_AMOUNT ,
4546 DEFAULT_L1_GAS_AMOUNT ,
4647 DEFAULT_L2_GAS_MAX_AMOUNT ,
@@ -55,9 +56,12 @@ use starknet_api::transaction::fields::{
5556 ContractAddressSalt ,
5657 Fee ,
5758 GasVectorComputationMode ,
59+ ProofFacts ,
5860 Resource ,
5961 ResourceBounds ,
62+ SnosProofFacts ,
6063 ValidResourceBounds ,
64+ VIRTUAL_SNOS ,
6165} ;
6266use starknet_api:: transaction:: {
6367 DeclareTransaction ,
@@ -79,6 +83,7 @@ use starknet_api::{
7983} ;
8084use starknet_types_core:: felt:: Felt ;
8185
86+ use crate :: abi:: constants:: STORED_BLOCK_HASH_BUFFER ;
8287use crate :: context:: { BlockContext , TransactionContext } ;
8388use crate :: execution:: call_info:: CallInfo ;
8489use crate :: execution:: contract_class:: TrackedResource ;
@@ -2191,3 +2196,82 @@ fn test_missing_validate_entrypoint_rejects(
21912196 if ret == retdata![ Felt :: from_hex( ENTRYPOINT_NOT_FOUND_ERROR ) . unwrap( ) ]
21922197 ) ;
21932198}
2199+
2200+ /// Converts SnosProofFacts to ProofFacts for testing.
2201+ fn snos_to_proof_facts ( snos : SnosProofFacts ) -> ProofFacts {
2202+ vec ! [
2203+ felt!( VIRTUAL_SNOS ) ,
2204+ snos. program_hash,
2205+ felt!( snos. block_number. 0 ) ,
2206+ snos. block_hash. 0 ,
2207+ snos. config_hash,
2208+ ]
2209+ . into ( )
2210+ }
2211+
2212+ /// Returns invalid proof_facts with a too recent block number (at the boundary).
2213+ fn too_recent_block_proof_facts ( ) -> ProofFacts {
2214+ let mut snos_proof_facts =
2215+ SnosProofFacts :: try_from ( ProofFacts :: snos_proof_facts_for_testing ( ) ) . unwrap ( ) ;
2216+ // Block number at the boundary: current - STORED_BLOCK_HASH_BUFFER, which is >= max_allowed.
2217+ snos_proof_facts. block_number = BlockNumber ( CURRENT_BLOCK_NUMBER - STORED_BLOCK_HASH_BUFFER ) ;
2218+ snos_to_proof_facts ( snos_proof_facts)
2219+ }
2220+
2221+ /// Returns invalid proof_facts with a mismatched block hash.
2222+ fn mismatched_hash_proof_facts ( ) -> ProofFacts {
2223+ let mut snos_proof_facts =
2224+ SnosProofFacts :: try_from ( ProofFacts :: snos_proof_facts_for_testing ( ) ) . unwrap ( ) ;
2225+ //
2226+ snos_proof_facts. block_hash = BlockHash ( snos_proof_facts. block_hash . 0 + 1 ) ;
2227+ snos_to_proof_facts ( snos_proof_facts)
2228+ }
2229+
2230+ /// Returns invalid proof_facts with a zero block hash.
2231+ fn zero_block_hash_proof_facts ( ) -> ProofFacts {
2232+ let mut snos_proof_facts = SnosProofFacts :: try_from ( ProofFacts :: snos_proof_facts_for_testing ( ) )
2233+ . expect ( "Invalid proof facts" ) ;
2234+ snos_proof_facts. block_hash = BlockHash ( Felt :: ZERO ) ;
2235+ snos_to_proof_facts ( snos_proof_facts)
2236+ }
2237+
2238+ /// Tests the `validate_proof_facts` function for Invoke V3 transactions.
2239+ /// Covers: valid proof facts, too recent block number, mismatched block hash, future block,
2240+ /// current block too small, and zero block hash.
2241+ #[ rstest]
2242+ #[ case:: valid_proof_facts( ProofFacts :: snos_proof_facts_for_testing( ) , CURRENT_BLOCK_NUMBER ) ]
2243+ #[ should_panic( expected = "is too recent. The maximum allowed" ) ]
2244+ #[ case:: too_recent_block( too_recent_block_proof_facts( ) , CURRENT_BLOCK_NUMBER ) ]
2245+ #[ should_panic( expected = "Block hash mismatch" ) ]
2246+ #[ case:: mismatched_block_hash( mismatched_hash_proof_facts( ) , CURRENT_BLOCK_NUMBER ) ]
2247+ #[ should_panic( expected = "is too recent to have a stored block hash" ) ]
2248+ #[ case:: current_block_too_small(
2249+ ProofFacts :: snos_proof_facts_for_testing( ) ,
2250+ STORED_BLOCK_HASH_BUFFER - 1 ,
2251+ ) ]
2252+ #[ should_panic( expected = "Stored block hash is zero" ) ]
2253+ #[ case:: zero_block_hash( zero_block_hash_proof_facts( ) , CURRENT_BLOCK_NUMBER ) ]
2254+ fn test_validate_proof_facts (
2255+ default_all_resource_bounds : ValidResourceBounds ,
2256+ #[ case] proof_facts : ProofFacts ,
2257+ #[ case] current_block_number : u64 ,
2258+ ) {
2259+ let mut block_context = BlockContext :: create_for_account_testing ( ) ;
2260+ block_context. block_info . block_number = BlockNumber ( current_block_number) ;
2261+
2262+ let chain_info = & block_context. chain_info ;
2263+ let account =
2264+ FeatureContract :: AccountWithoutValidations ( CairoVersion :: Cairo1 ( RunnableCairo1 :: Casm ) ) ;
2265+ let mut state = test_state ( chain_info, BALANCE , & [ ( account, 1u16 ) ] ) ;
2266+ let account_address = account. get_instance_address ( 0_u16 ) ;
2267+
2268+ let tx = invoke_tx_with_default_flags ( invoke_tx_args ! {
2269+ sender_address: account_address,
2270+ resource_bounds: default_all_resource_bounds,
2271+ proof_facts,
2272+ } ) ;
2273+
2274+ // Run only pre-validation stage (which includes proof facts validation).
2275+ let tx_context = block_context. to_tx_context ( & tx) ;
2276+ tx. perform_pre_validation_stage ( & mut state, & tx_context) . unwrap ( ) ;
2277+ }
0 commit comments