@@ -6,14 +6,15 @@ use blockifier_test_utils::cairo_versions::{CairoVersion, RunnableCairo1};
66use blockifier_test_utils:: calldata:: create_calldata;
77use blockifier_test_utils:: contracts:: FeatureContract ;
88use chrono:: { Datelike , Utc } ;
9+ use expect_test:: { expect, Expect } ;
910use rand:: prelude:: IteratorRandom ;
1011use rand_chacha:: rand_core:: SeedableRng ;
1112use rand_chacha:: ChaCha8Rng ;
1213use rstest:: rstest;
1314use starknet_api:: core:: { calculate_contract_address, ClassHash , ContractAddress } ;
1415use starknet_api:: state:: StorageKey ;
1516use starknet_api:: transaction:: fields:: ContractAddressSalt ;
16- use starknet_api:: { calldata, invoke_tx_args} ;
17+ use starknet_api:: { calldata, felt , invoke_tx_args} ;
1718use starknet_committer:: block_committer:: input:: StarknetStorageValue ;
1819use starknet_types_core:: felt:: Felt ;
1920use strum:: { EnumIter , IntoEnumIterator } ;
@@ -46,6 +47,33 @@ static IS_CAIRO1: LazyLock<BTreeMap<ClassHash, bool>> = LazyLock::new(|| {
4647 ] )
4748} ) ;
4849
50+ /// Initial fuzz contract addresses.
51+ static FUZZ_ADDRESS_ORCHESTRATOR_EXPECT : Expect =
52+ expect ! [ "0x42a4e070a0336c42c1de292bc3de986ae479bc5187d86a6dca4c52c6e502d6f" ] ;
53+ static FUZZ_ADDRESS_CAIRO1_A_EXPECT : Expect =
54+ expect ! [ "0x4554a89a9bdca75b3e05f9818db7ac9f3ff0ed8a29d8a5b9c06120ea460fb1d" ] ;
55+ static FUZZ_ADDRESS_CAIRO1_B_EXPECT : Expect =
56+ expect ! [ "0x6499dd5a927d84defe08b2736e15c225db208091ab216ea2cef4f0197736353" ] ;
57+ static FUZZ_ADDRESS_CAIRO0_A_EXPECT : Expect =
58+ expect ! [ "0x64ab77c6fe5fbb6b4e47c13af2eb731f9302d3140e7f4fe7c42f84ed68327be" ] ;
59+ static FUZZ_ADDRESS_CAIRO0_B_EXPECT : Expect =
60+ expect ! [ "0x230d7401e20368dfd1098aa3c01da16a192350bad43c157da0adc5c4caffdeb" ] ;
61+ static FUZZ_ADDRESS_ORCHESTRATOR : LazyLock < ContractAddress > = LazyLock :: new ( || {
62+ ContractAddress :: try_from ( felt ! ( FUZZ_ADDRESS_ORCHESTRATOR_EXPECT . data( ) ) ) . unwrap ( )
63+ } ) ;
64+ static FUZZ_ADDRESS_CAIRO1_A : LazyLock < ContractAddress > = LazyLock :: new ( || {
65+ ContractAddress :: try_from ( felt ! ( FUZZ_ADDRESS_CAIRO1_A_EXPECT . data( ) ) ) . unwrap ( )
66+ } ) ;
67+ static FUZZ_ADDRESS_CAIRO1_B : LazyLock < ContractAddress > = LazyLock :: new ( || {
68+ ContractAddress :: try_from ( felt ! ( FUZZ_ADDRESS_CAIRO1_B_EXPECT . data( ) ) ) . unwrap ( )
69+ } ) ;
70+ static FUZZ_ADDRESS_CAIRO0_A : LazyLock < ContractAddress > = LazyLock :: new ( || {
71+ ContractAddress :: try_from ( felt ! ( FUZZ_ADDRESS_CAIRO0_A_EXPECT . data( ) ) ) . unwrap ( )
72+ } ) ;
73+ static FUZZ_ADDRESS_CAIRO0_B : LazyLock < ContractAddress > = LazyLock :: new ( || {
74+ ContractAddress :: try_from ( felt ! ( FUZZ_ADDRESS_CAIRO0_B_EXPECT . data( ) ) ) . unwrap ( )
75+ } ) ;
76+
4977/// Storage key that can be written to.
5078static VALID_STORAGE_KEYS : LazyLock < Vec < Felt > > =
5179 LazyLock :: new ( || vec ! [ Felt :: from( 1u16 << 8 ) , Felt :: from( 1u16 << 9 ) ] ) ;
@@ -325,14 +353,12 @@ struct FuzzTestContext {
325353 /// Next salt to use for a deploy operation.
326354 pub next_salt : ContractAddressSalt ,
327355
328- pub orchestrator_contract_address : ContractAddress ,
329356 pub rng : ChaCha8Rng ,
330357}
331358
332359impl FuzzTestContext {
333360 pub fn init (
334361 seed : u64 ,
335- orchestrator_contract_address : ContractAddress ,
336362 first_call : FuzzCallInfo ,
337363 deployed_fuzz_contracts : BTreeMap < ContractAddress , ClassHash > ,
338364 ) -> Self {
@@ -345,7 +371,6 @@ impl FuzzTestContext {
345371 class_replaced : false ,
346372 next_storage_write_value : StarknetStorageValue ( Felt :: from ( 1u16 << 12 ) ) ,
347373 next_salt : ContractAddressSalt ( Felt :: from ( 1u32 << 16 ) ) ,
348- orchestrator_contract_address,
349374 rng : ChaCha8Rng :: seed_from_u64 ( seed) ,
350375 }
351376 }
@@ -364,61 +389,70 @@ impl FuzzTestManager {
364389 // - an orchestrator contract.
365390 // - two cairo1 fuzz test contracts.
366391 // - two cairo0 fuzz test contracts.
367- let (
368- mut test_manager,
369- [
370- orchestrator_contract_address,
371- cairo1_contract_address_a,
372- cairo1_contract_address_b,
373- cairo0_contract_address_a,
374- cairo0_contract_address_b,
375- // We don't need an instance of the replacement class, but we do want it declared.
376- _replacement_address,
377- ] ,
378- ) = TestBuilder :: create_standard ( [
379- ( ORCHESTRATOR_CONTRACT , calldata ! [ ] ) ,
380- ( CAIRO1_CONTRACT , calldata ! [ Felt :: ZERO ] ) ,
381- ( CAIRO1_CONTRACT , calldata ! [ Felt :: ZERO ] ) ,
382- ( CAIRO0_CONTRACT , calldata ! [ Felt :: ZERO ] ) ,
383- ( CAIRO0_CONTRACT , calldata ! [ Felt :: ZERO ] ) ,
384- ( CAIRO1_REPLACEMENT_CONTRACT , calldata ! [ Felt :: ZERO ] ) ,
385- ] )
386- . await ;
392+ let mut test_manager = Self :: init_deployment ( false ) . await ;
387393
388394 let deployed_fuzz_contracts = BTreeMap :: from ( [
389- ( cairo1_contract_address_a , * CAIRO1_CONTRACT_CLASS_HASH ) ,
390- ( cairo1_contract_address_b , * CAIRO1_CONTRACT_CLASS_HASH ) ,
391- ( cairo0_contract_address_a , * CAIRO0_CONTRACT_CLASS_HASH ) ,
392- ( cairo0_contract_address_b , * CAIRO0_CONTRACT_CLASS_HASH ) ,
395+ ( * FUZZ_ADDRESS_CAIRO1_A , * CAIRO1_CONTRACT_CLASS_HASH ) ,
396+ ( * FUZZ_ADDRESS_CAIRO1_B , * CAIRO1_CONTRACT_CLASS_HASH ) ,
397+ ( * FUZZ_ADDRESS_CAIRO0_A , * CAIRO0_CONTRACT_CLASS_HASH ) ,
398+ ( * FUZZ_ADDRESS_CAIRO0_B , * CAIRO0_CONTRACT_CLASS_HASH ) ,
393399 ] ) ;
394400
395401 // Initialize the fuzz testing contracts with the orchestrator address.
396402 for address in deployed_fuzz_contracts. keys ( ) {
397- let calldata =
398- create_calldata ( * address, "initialize" , & [ * * orchestrator_contract_address] ) ;
403+ let calldata = create_calldata ( * address, "initialize" , & [ * * * FUZZ_ADDRESS_ORCHESTRATOR ] ) ;
399404 test_manager. add_funded_account_invoke ( invoke_tx_args ! { calldata } ) ;
400405 }
401406
402407 // First call is the orchestrator calling the first fuzz test contract.
403- let first_called_address = cairo1_contract_address_a ;
408+ let first_called_address = * FUZZ_ADDRESS_CAIRO1_A ;
404409 let first_call = FuzzCallInfo :: new_call (
405410 first_called_address,
406411 * CAIRO1_CONTRACT_CLASS_HASH ,
407412 // The orchestrator always starts the test in a catching context.
408413 ParentFailureBehavior :: Cairo1Catching ,
409414 ) ;
410415 Self {
411- context : FuzzTestContext :: init (
412- seed,
413- orchestrator_contract_address,
414- first_call,
415- deployed_fuzz_contracts,
416- ) ,
416+ context : FuzzTestContext :: init ( seed, first_call, deployed_fuzz_contracts) ,
417417 test_manager,
418418 first_called_address,
419419 }
420420 }
421421
422+ /// Initializes the deployment of the fuzz test contracts.
423+ /// Returns the test builder (after deployment).
424+ pub async fn init_deployment ( assert_expect : bool ) -> TestBuilder < DictStateReader > {
425+ let (
426+ test_manager,
427+ [
428+ orchestrator_contract_address,
429+ cairo1_contract_address_a,
430+ cairo1_contract_address_b,
431+ cairo0_contract_address_a,
432+ cairo0_contract_address_b,
433+ // We don't need an instance of the replacement class, but we do want it declared.
434+ _replacement_address,
435+ ] ,
436+ ) = TestBuilder :: create_standard ( [
437+ ( ORCHESTRATOR_CONTRACT , calldata ! [ ] ) ,
438+ ( CAIRO1_CONTRACT , calldata ! [ Felt :: ZERO ] ) ,
439+ ( CAIRO1_CONTRACT , calldata ! [ Felt :: ZERO ] ) ,
440+ ( CAIRO0_CONTRACT , calldata ! [ Felt :: ZERO ] ) ,
441+ ( CAIRO0_CONTRACT , calldata ! [ Felt :: ZERO ] ) ,
442+ ( CAIRO1_REPLACEMENT_CONTRACT , calldata ! [ Felt :: ZERO ] ) ,
443+ ] )
444+ . await ;
445+ if assert_expect {
446+ FUZZ_ADDRESS_ORCHESTRATOR_EXPECT
447+ . assert_eq ( & orchestrator_contract_address. to_hex_string ( ) ) ;
448+ FUZZ_ADDRESS_CAIRO1_A_EXPECT . assert_eq ( & cairo1_contract_address_a. to_hex_string ( ) ) ;
449+ FUZZ_ADDRESS_CAIRO1_B_EXPECT . assert_eq ( & cairo1_contract_address_b. to_hex_string ( ) ) ;
450+ FUZZ_ADDRESS_CAIRO0_A_EXPECT . assert_eq ( & cairo0_contract_address_a. to_hex_string ( ) ) ;
451+ FUZZ_ADDRESS_CAIRO0_B_EXPECT . assert_eq ( & cairo0_contract_address_b. to_hex_string ( ) ) ;
452+ }
453+ test_manager
454+ }
455+
422456 pub fn finalized ( & self ) -> bool {
423457 self . context . final_state . finalized ( )
424458 }
@@ -610,16 +644,12 @@ impl FuzzTestManager {
610644 }
611645
612646 /// Expected address of a deploy operation.
613- pub fn address_of_deploy (
614- & self ,
615- class_hash : ClassHash ,
616- salt : ContractAddressSalt ,
617- ) -> ContractAddress {
647+ pub fn address_of_deploy ( class_hash : ClassHash , salt : ContractAddressSalt ) -> ContractAddress {
618648 // Deployer address is always zero (for simplicity).
619649 calculate_contract_address (
620650 salt,
621651 class_hash,
622- & calldata ! [ * * self . context . orchestrator_contract_address ] ,
652+ & calldata ! [ * * * FUZZ_ADDRESS_ORCHESTRATOR ] ,
623653 ContractAddress :: default ( ) ,
624654 )
625655 . unwrap ( )
@@ -714,7 +744,7 @@ impl FuzzTestManager {
714744 // call-contract) should the code change be reflected.
715745 }
716746 FuzzOperationData :: Deploy { class_hash, salt } => {
717- let deployed_address = self . address_of_deploy ( class_hash, salt) ;
747+ let deployed_address = Self :: address_of_deploy ( class_hash, salt) ;
718748 // Increment the salt for the next deploy operation.
719749 self . context . next_salt . 0 += Felt :: ONE ;
720750 // Update the mapping from address to class hash.
@@ -881,7 +911,7 @@ impl FuzzTestManager {
881911 ]
882912 }
883913 FuzzOperationData :: Deploy { class_hash, salt } => {
884- let deployed_address = self . address_of_deploy ( * class_hash, * salt) ;
914+ let deployed_address = Self :: address_of_deploy ( * class_hash, * salt) ;
885915 let is_cairo1 = self . is_cairo1_class ( class_hash) ;
886916 vec ! [
887917 format!(
@@ -918,7 +948,7 @@ impl FuzzTestManager {
918948 // Initialize the orchestrator contract with the scenario data.
919949 let scenario_data = Self :: operations_to_scenario_data ( & self . context . operations ) ;
920950 let orchestrator_calldata = create_calldata (
921- self . context . orchestrator_contract_address ,
951+ * FUZZ_ADDRESS_ORCHESTRATOR ,
922952 "initialize" ,
923953 & [ vec ! [ Felt :: from( scenario_data. len( ) ) ] , scenario_data] . concat ( ) ,
924954 ) ;
@@ -927,7 +957,7 @@ impl FuzzTestManager {
927957
928958 // Invoke the test.
929959 let start_test_calldata = create_calldata (
930- self . context . orchestrator_contract_address ,
960+ * FUZZ_ADDRESS_ORCHESTRATOR ,
931961 "start_test" ,
932962 & [ * * self . first_called_address ] ,
933963 ) ;
@@ -973,6 +1003,13 @@ async fn fuzz_test_body(seed: u64, max_n_operations: usize) {
9731003 fuzz_tester. run_test ( ) . await ;
9741004}
9751005
1006+ /// Updates the expected fuzz contract addresses (if UPDATE_EXPECT env var is set).
1007+ #[ rstest]
1008+ #[ tokio:: test]
1009+ async fn test_fuzz_deployment_expect ( ) {
1010+ FuzzTestManager :: init_deployment ( true ) . await ;
1011+ }
1012+
9761013#[ rstest]
9771014#[ tokio:: test]
9781015async fn test_daily_fuzz_seed (
0 commit comments