@@ -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 ,
@@ -58,7 +59,9 @@ use starknet_api::transaction::fields::{
5859 ProofFacts ,
5960 Resource ,
6061 ResourceBounds ,
62+ SnosProofFacts ,
6163 ValidResourceBounds ,
64+ VIRTUAL_SNOS ,
6265} ;
6366use starknet_api:: transaction:: {
6467 DeclareTransaction ,
@@ -80,6 +83,7 @@ use starknet_api::{
8083} ;
8184use starknet_types_core:: felt:: Felt ;
8285
86+ use crate :: abi:: constants:: STORED_BLOCK_HASH_BUFFER ;
8387use crate :: context:: { BlockContext , TransactionContext } ;
8488use crate :: execution:: call_info:: CallInfo ;
8589use crate :: execution:: contract_class:: TrackedResource ;
@@ -2220,3 +2224,82 @@ fn test_invoke_tx_with_proof_facts(
22202224
22212225 assert ! ( !tx_execution_info. is_reverted( ) ) ;
22222226}
2227+
2228+ /// Converts SnosProofFacts to ProofFacts for testing.
2229+ fn snos_to_proof_facts ( snos : SnosProofFacts ) -> ProofFacts {
2230+ vec ! [
2231+ felt!( VIRTUAL_SNOS ) ,
2232+ snos. program_hash,
2233+ felt!( snos. block_number. 0 ) ,
2234+ snos. block_hash. 0 ,
2235+ snos. config_hash,
2236+ ]
2237+ . into ( )
2238+ }
2239+
2240+ /// Returns invalid proof_facts with a too recent block number (at the boundary).
2241+ fn too_recent_block_proof_facts ( ) -> ProofFacts {
2242+ let mut snos_proof_facts =
2243+ SnosProofFacts :: try_from ( ProofFacts :: snos_proof_facts_for_testing ( ) ) . unwrap ( ) ;
2244+ // Block number at the boundary: current - STORED_BLOCK_HASH_BUFFER, which is >= max_allowed.
2245+ snos_proof_facts. block_number = BlockNumber ( CURRENT_BLOCK_NUMBER - STORED_BLOCK_HASH_BUFFER ) ;
2246+ snos_to_proof_facts ( snos_proof_facts)
2247+ }
2248+
2249+ /// Returns invalid proof_facts with a mismatched block hash.
2250+ fn mismatched_hash_proof_facts ( ) -> ProofFacts {
2251+ let mut snos_proof_facts =
2252+ SnosProofFacts :: try_from ( ProofFacts :: snos_proof_facts_for_testing ( ) ) . unwrap ( ) ;
2253+ //
2254+ snos_proof_facts. block_hash = BlockHash ( snos_proof_facts. block_hash . 0 + 1 ) ;
2255+ snos_to_proof_facts ( snos_proof_facts)
2256+ }
2257+
2258+ /// Returns invalid proof_facts with a zero block hash.
2259+ fn zero_block_hash_proof_facts ( ) -> ProofFacts {
2260+ let mut snos_proof_facts = SnosProofFacts :: try_from ( ProofFacts :: snos_proof_facts_for_testing ( ) )
2261+ . expect ( "Invalid proof facts" ) ;
2262+ snos_proof_facts. block_hash = BlockHash ( Felt :: ZERO ) ;
2263+ snos_to_proof_facts ( snos_proof_facts)
2264+ }
2265+
2266+ /// Tests the `validate_proof_facts` function for Invoke V3 transactions.
2267+ /// Covers: valid proof facts, too recent block number, mismatched block hash, future block,
2268+ /// current block too small, and zero block hash.
2269+ #[ rstest]
2270+ #[ case:: valid_proof_facts( ProofFacts :: snos_proof_facts_for_testing( ) , CURRENT_BLOCK_NUMBER ) ]
2271+ #[ should_panic( expected = "is too recent. The maximum allowed" ) ]
2272+ #[ case:: too_recent_block( too_recent_block_proof_facts( ) , CURRENT_BLOCK_NUMBER ) ]
2273+ #[ should_panic( expected = "Block hash mismatch" ) ]
2274+ #[ case:: mismatched_block_hash( mismatched_hash_proof_facts( ) , CURRENT_BLOCK_NUMBER ) ]
2275+ #[ should_panic( expected = "is too recent to have a stored block hash" ) ]
2276+ #[ case:: current_block_too_small(
2277+ ProofFacts :: snos_proof_facts_for_testing( ) ,
2278+ STORED_BLOCK_HASH_BUFFER - 1 ,
2279+ ) ]
2280+ #[ should_panic( expected = "Stored block hash is zero" ) ]
2281+ #[ case:: zero_block_hash( zero_block_hash_proof_facts( ) , CURRENT_BLOCK_NUMBER ) ]
2282+ fn test_validate_proof_facts (
2283+ default_all_resource_bounds : ValidResourceBounds ,
2284+ #[ case] proof_facts : ProofFacts ,
2285+ #[ case] current_block_number : u64 ,
2286+ ) {
2287+ let mut block_context = BlockContext :: create_for_account_testing ( ) ;
2288+ block_context. block_info . block_number = BlockNumber ( current_block_number) ;
2289+
2290+ let chain_info = & block_context. chain_info ;
2291+ let account =
2292+ FeatureContract :: AccountWithoutValidations ( CairoVersion :: Cairo1 ( RunnableCairo1 :: Casm ) ) ;
2293+ let mut state = test_state ( chain_info, BALANCE , & [ ( account, 1u16 ) ] ) ;
2294+ let account_address = account. get_instance_address ( 0_u16 ) ;
2295+
2296+ let tx = invoke_tx_with_default_flags ( invoke_tx_args ! {
2297+ sender_address: account_address,
2298+ resource_bounds: default_all_resource_bounds,
2299+ proof_facts,
2300+ } ) ;
2301+
2302+ // Run only pre-validation stage (which includes proof facts validation).
2303+ let tx_context = block_context. to_tx_context ( & tx) ;
2304+ tx. perform_pre_validation_stage ( & mut state, & tx_context) . unwrap ( ) ;
2305+ }
0 commit comments