From ef8318be50c2851c3ef05fbb906097cdd3bea3da Mon Sep 17 00:00:00 2001 From: Bohdan Ohorodnii Date: Tue, 6 Aug 2024 19:00:20 +0300 Subject: [PATCH 1/6] refactor: split syscalls into separate files --- .gitignore | 1 + .../blockifier/src/execution/syscalls/mod.rs | 3 +- .../syscalls/syscall_tests/call_contract.rs | 60 ++ .../syscalls/syscall_tests/consts.rs | 3 + .../syscalls/syscall_tests/deploy.rs | 172 +++ .../syscalls/syscall_tests/emit_event.rs | 122 +++ .../syscalls/syscall_tests/get_block_hash.rs | 105 ++ .../syscall_tests/get_execution_info.rs | 257 +++++ .../syscalls/syscall_tests/keccak.rs | 29 + .../syscalls/syscall_tests/library_call.rs | 204 ++++ .../execution/syscalls/syscall_tests/mod.rs | 15 + .../syscalls/syscall_tests/out_of_gas.rs | 29 + .../syscalls/syscall_tests/replace_class.rs | 72 ++ .../execution/syscalls/syscall_tests/secp.rs | 46 + .../syscall_tests/send_message_to_l1.rs | 51 + .../syscalls/syscall_tests/sha256.rs | 29 + .../syscall_tests/storage_read_write.rs | 50 + .../execution/syscalls/syscall_tests/utils.rs | 27 + .../src/execution/syscalls/syscalls_test.rs | 986 ------------------ 19 files changed, 1273 insertions(+), 988 deletions(-) create mode 100644 crates/blockifier/src/execution/syscalls/syscall_tests/call_contract.rs create mode 100644 crates/blockifier/src/execution/syscalls/syscall_tests/consts.rs create mode 100644 crates/blockifier/src/execution/syscalls/syscall_tests/deploy.rs create mode 100644 crates/blockifier/src/execution/syscalls/syscall_tests/emit_event.rs create mode 100644 crates/blockifier/src/execution/syscalls/syscall_tests/get_block_hash.rs create mode 100644 crates/blockifier/src/execution/syscalls/syscall_tests/get_execution_info.rs create mode 100644 crates/blockifier/src/execution/syscalls/syscall_tests/keccak.rs create mode 100644 crates/blockifier/src/execution/syscalls/syscall_tests/library_call.rs create mode 100644 crates/blockifier/src/execution/syscalls/syscall_tests/mod.rs create mode 100644 crates/blockifier/src/execution/syscalls/syscall_tests/out_of_gas.rs create mode 100644 crates/blockifier/src/execution/syscalls/syscall_tests/replace_class.rs create mode 100644 crates/blockifier/src/execution/syscalls/syscall_tests/secp.rs create mode 100644 crates/blockifier/src/execution/syscalls/syscall_tests/send_message_to_l1.rs create mode 100644 crates/blockifier/src/execution/syscalls/syscall_tests/sha256.rs create mode 100644 crates/blockifier/src/execution/syscalls/syscall_tests/storage_read_write.rs create mode 100644 crates/blockifier/src/execution/syscalls/syscall_tests/utils.rs delete mode 100644 crates/blockifier/src/execution/syscalls/syscalls_test.rs diff --git a/.gitignore b/.gitignore index bc8e9a4262..32bbb4b2fd 100644 --- a/.gitignore +++ b/.gitignore @@ -23,6 +23,7 @@ tmp_venv/* /.vscode # Git hooks /.husky +/.idea # Python artifacts. scripts/__pycache__ diff --git a/crates/blockifier/src/execution/syscalls/mod.rs b/crates/blockifier/src/execution/syscalls/mod.rs index 9e31c9ab9b..7e253f247b 100644 --- a/crates/blockifier/src/execution/syscalls/mod.rs +++ b/crates/blockifier/src/execution/syscalls/mod.rs @@ -55,8 +55,7 @@ pub mod hint_processor; mod secp; #[cfg(test)] -#[path = "syscalls_test.rs"] -pub mod syscalls_test; +pub mod syscall_tests; pub type SyscallResult = Result; pub type WriteResponseResult = SyscallResult<()>; diff --git a/crates/blockifier/src/execution/syscalls/syscall_tests/call_contract.rs b/crates/blockifier/src/execution/syscalls/syscall_tests/call_contract.rs new file mode 100644 index 0000000000..39d97e5e68 --- /dev/null +++ b/crates/blockifier/src/execution/syscalls/syscall_tests/call_contract.rs @@ -0,0 +1,60 @@ +use pretty_assertions::assert_eq; +use starknet_api::felt; +use test_case::test_case; + +use super::consts::REQUIRED_GAS_CALL_CONTRACT_TEST; +use crate::abi::abi_utils::selector_from_name; +use crate::context::ChainInfo; +use crate::execution::call_info::{CallExecution, Retdata}; +use crate::execution::entry_point::CallEntryPoint; +use crate::execution::syscalls::syscall_tests::utils::assert_consistent_contract_version; +use crate::retdata; +use crate::test_utils::contracts::FeatureContract; +use crate::test_utils::initial_test_state::test_state; +use crate::test_utils::{create_calldata, trivial_external_entry_point_new, CairoVersion, BALANCE}; + +#[test_case( + FeatureContract::TestContract(CairoVersion::Cairo1), + FeatureContract::TestContract(CairoVersion::Cairo1), + REQUIRED_GAS_CALL_CONTRACT_TEST; + "Call Contract between two contracts using VM" +)] +fn test_call_contract( + outer_contract: FeatureContract, + inner_contract: FeatureContract, + expected_gas: u64, +) { + let chain_info = &ChainInfo::create_for_testing(); + let mut state = test_state(chain_info, BALANCE, &[(outer_contract, 1), (inner_contract, 1)]); + + assert_consistent_contract_version(outer_contract, &state); + assert_consistent_contract_version(inner_contract, &state); + + let outer_entry_point_selector = selector_from_name("test_call_contract"); + let calldata = create_calldata( + inner_contract.get_instance_address(0), + "test_storage_read_write", + &[ + felt!(405_u16), // Calldata: address. + felt!(48_u8), // Calldata: value. + ], + ); + let entry_point_call = CallEntryPoint { + entry_point_selector: outer_entry_point_selector, + calldata, + ..trivial_external_entry_point_new(outer_contract) + }; + + assert_eq!( + entry_point_call.execute_directly(&mut state).unwrap().execution, + CallExecution { + retdata: retdata![felt!(48_u8)], + gas_consumed: expected_gas, + ..CallExecution::default() + } + ); + + // ensure that the fallback system didn't replace the contract + assert_consistent_contract_version(outer_contract, &state); + assert_consistent_contract_version(inner_contract, &state); +} diff --git a/crates/blockifier/src/execution/syscalls/syscall_tests/consts.rs b/crates/blockifier/src/execution/syscalls/syscall_tests/consts.rs new file mode 100644 index 0000000000..94c378a074 --- /dev/null +++ b/crates/blockifier/src/execution/syscalls/syscall_tests/consts.rs @@ -0,0 +1,3 @@ +pub const REQUIRED_GAS_CALL_CONTRACT_TEST: u64 = 105680; +pub const REQUIRED_GAS_STORAGE_READ_WRITE_TEST: u64 = 27150; +pub const REQUIRED_GAS_LIBRARY_CALL_TEST: u64 = REQUIRED_GAS_CALL_CONTRACT_TEST; diff --git a/crates/blockifier/src/execution/syscalls/syscall_tests/deploy.rs b/crates/blockifier/src/execution/syscalls/syscall_tests/deploy.rs new file mode 100644 index 0000000000..8f4b9570dd --- /dev/null +++ b/crates/blockifier/src/execution/syscalls/syscall_tests/deploy.rs @@ -0,0 +1,172 @@ +use pretty_assertions::assert_eq; +use starknet_api::core::calculate_contract_address; +use starknet_api::transaction::{Calldata, ContractAddressSalt}; +use starknet_api::{calldata, felt}; +use test_case::test_case; + +use crate::abi::abi_utils::selector_from_name; +use crate::context::ChainInfo; +use crate::execution::call_info::{CallExecution, Retdata}; +use crate::execution::entry_point::CallEntryPoint; +use crate::execution::syscalls::syscall_tests::utils::assert_consistent_contract_version; +use crate::retdata; +use crate::state::state_api::StateReader; +use crate::test_utils::contracts::FeatureContract; +use crate::test_utils::initial_test_state::test_state; +use crate::test_utils::{calldata_for_deploy_test, trivial_external_entry_point_new, CairoVersion}; + +#[test_case(FeatureContract::TestContract(CairoVersion::Cairo1);"VM")] +fn no_constructor(deployer_contract: FeatureContract) { + let empty_contract = FeatureContract::Empty(CairoVersion::Cairo1); + let class_hash = empty_contract.get_class_hash(); + + let mut state = test_state( + &ChainInfo::create_for_testing(), + 0, + &[(deployer_contract, 1), (empty_contract, 0)], + ); + + assert_consistent_contract_version(deployer_contract, &state); + assert_consistent_contract_version(empty_contract, &state); + + let calldata = calldata_for_deploy_test(class_hash, &[], true); + let entry_point_call = CallEntryPoint { + entry_point_selector: selector_from_name("test_deploy"), + calldata, + ..trivial_external_entry_point_new(deployer_contract) + }; + let deployed_contract_address = calculate_contract_address( + ContractAddressSalt::default(), + class_hash, + &calldata![], + deployer_contract.get_instance_address(0), + ) + .unwrap(); + + let deploy_call = &entry_point_call.execute_directly(&mut state).unwrap().inner_calls[0]; + + assert_eq!(deploy_call.call.storage_address, deployed_contract_address); + assert_eq!( + deploy_call.execution, + CallExecution { retdata: retdata![], gas_consumed: 0, ..CallExecution::default() } + ); + assert_eq!(state.get_class_hash_at(deployed_contract_address).unwrap(), class_hash); + + assert_consistent_contract_version(deployer_contract, &state); + assert_consistent_contract_version(empty_contract, &state); +} + +#[test_case(FeatureContract::TestContract(CairoVersion::Cairo1);"VM")] +fn no_constructor_nonempty_calldata(deployer_contract: FeatureContract) { + let empty_contract = FeatureContract::Empty(CairoVersion::Cairo1); + let class_hash = empty_contract.get_class_hash(); + + let mut state = test_state( + &ChainInfo::create_for_testing(), + 0, + &[(deployer_contract, 1), (empty_contract, 0)], + ); + assert_consistent_contract_version(deployer_contract, &state); + assert_consistent_contract_version(empty_contract, &state); + + let calldata = calldata_for_deploy_test(class_hash, &[felt!(1_u8), felt!(1_u8)], true); + + let entry_point_call = CallEntryPoint { + entry_point_selector: selector_from_name("test_deploy"), + calldata, + ..trivial_external_entry_point_new(deployer_contract) + }; + + let error = entry_point_call.execute_directly(&mut state).unwrap_err().to_string(); + assert!(error.contains( + "Invalid input: constructor_calldata; Cannot pass calldata to a contract with no \ + constructor." + )); + + assert_consistent_contract_version(deployer_contract, &state); + assert_consistent_contract_version(empty_contract, &state); +} + +#[test_case(FeatureContract::TestContract(CairoVersion::Cairo1), 10140;"VM")] +fn with_constructor(deployer_contract: FeatureContract, expected_gas: u64) { + let empty_contract = FeatureContract::Empty(CairoVersion::Cairo1); + let mut state = test_state( + &ChainInfo::create_for_testing(), + 0, + &[(deployer_contract, 1), (empty_contract, 0)], + ); + assert_consistent_contract_version(deployer_contract, &state); + assert_consistent_contract_version(empty_contract, &state); + + let class_hash = deployer_contract.get_class_hash(); + let constructor_calldata = vec![ + felt!(1_u8), // Calldata: address. + felt!(1_u8), // Calldata: value. + ]; + + let calldata = calldata_for_deploy_test(class_hash, &constructor_calldata, true); + + let entry_point_call = CallEntryPoint { + entry_point_selector: selector_from_name("test_deploy"), + calldata, + ..trivial_external_entry_point_new(deployer_contract) + }; + + // No errors expected. + let contract_address = calculate_contract_address( + ContractAddressSalt::default(), + class_hash, + &Calldata(constructor_calldata.clone().into()), + deployer_contract.get_instance_address(0), + ) + .unwrap(); + let deploy_call = &entry_point_call.execute_directly(&mut state).unwrap().inner_calls[0]; + + assert_eq!(deploy_call.call.storage_address, contract_address); + assert_eq!( + deploy_call.execution, + CallExecution { + retdata: retdata![constructor_calldata[0]], + gas_consumed: expected_gas, + ..CallExecution::default() + } + ); + assert_eq!(state.get_class_hash_at(contract_address).unwrap(), class_hash); + + assert_consistent_contract_version(deployer_contract, &state); + assert_consistent_contract_version(empty_contract, &state); +} + +#[test_case(FeatureContract::TestContract(CairoVersion::Cairo1);"VM")] +fn to_unavailable_address(deployer_contract: FeatureContract) { + let empty_contract = FeatureContract::Empty(CairoVersion::Cairo1); + let mut state = test_state( + &ChainInfo::create_for_testing(), + 0, + &[(deployer_contract, 1), (empty_contract, 0)], + ); + assert_consistent_contract_version(deployer_contract, &state); + assert_consistent_contract_version(empty_contract, &state); + + let class_hash = deployer_contract.get_class_hash(); + let constructor_calldata = vec![ + felt!(1_u8), // Calldata: address. + felt!(1_u8), // Calldata: value. + ]; + + let calldata = calldata_for_deploy_test(class_hash, &constructor_calldata, true); + + let entry_point_call = CallEntryPoint { + entry_point_selector: selector_from_name("test_deploy"), + calldata, + ..trivial_external_entry_point_new(deployer_contract) + }; + + entry_point_call.clone().execute_directly(&mut state).unwrap(); + let error = entry_point_call.execute_directly(&mut state).unwrap_err().to_string(); + + assert!(error.contains("is unavailable for deployment.")); + + assert_consistent_contract_version(deployer_contract, &state); + assert_consistent_contract_version(empty_contract, &state); +} diff --git a/crates/blockifier/src/execution/syscalls/syscall_tests/emit_event.rs b/crates/blockifier/src/execution/syscalls/syscall_tests/emit_event.rs new file mode 100644 index 0000000000..8c6a2679fc --- /dev/null +++ b/crates/blockifier/src/execution/syscalls/syscall_tests/emit_event.rs @@ -0,0 +1,122 @@ +use itertools::concat; +use pretty_assertions::assert_eq; +use starknet_api::felt; +use starknet_api::transaction::{Calldata, EventContent, EventData, EventKey}; +use starknet_types_core::felt::Felt; +use test_case::test_case; + +use super::utils::assert_consistent_contract_version; +use crate::abi::abi_utils::selector_from_name; +use crate::context::ChainInfo; +use crate::execution::call_info::{CallExecution, CallInfo, OrderedEvent}; +use crate::execution::entry_point::CallEntryPoint; +use crate::execution::errors::EntryPointExecutionError; +use crate::execution::syscalls::hint_processor::EmitEventError; +use crate::test_utils::contracts::FeatureContract; +use crate::test_utils::initial_test_state::test_state; +use crate::test_utils::{trivial_external_entry_point_new, CairoVersion, BALANCE}; +use crate::versioned_constants::VersionedConstants; + +const KEYS: [Felt; 2] = [Felt::from_hex_unchecked("0x2019"), Felt::from_hex_unchecked("0x2020")]; +const DATA: [Felt; 3] = [ + Felt::from_hex_unchecked("0x2021"), + Felt::from_hex_unchecked("0x2022"), + Felt::from_hex_unchecked("0x2023"), +]; +const N_EMITTED_EVENTS: [Felt; 1] = [Felt::from_hex_unchecked("0x1")]; + +#[test_case(FeatureContract::TestContract(CairoVersion::Cairo1), 49860; "VM")] +fn positive_flow(test_contract: FeatureContract, expected_gas: u64) { + // TODO(Ori, 1/2/2024): Write an indicative expect message explaining why the conversion + // works. + let call_info = emit_events(test_contract, &N_EMITTED_EVENTS, &KEYS, &DATA).unwrap(); + let event = EventContent { + keys: KEYS.into_iter().map(EventKey).collect(), + data: EventData(DATA.to_vec()), + }; + + assert_eq!( + call_info.execution, + CallExecution { + events: vec![OrderedEvent { order: 0, event }], + gas_consumed: expected_gas, + ..Default::default() + } + ); +} + +#[test_case(FeatureContract::TestContract(CairoVersion::Cairo1); "VM")] +fn data_length_exceeds_limit(test_contract: FeatureContract) { + let versioned_constants = VersionedConstants::create_for_testing(); + + let max_event_data_length = versioned_constants.tx_event_limits.max_data_length; + let data_too_long = vec![felt!(2_u16); max_event_data_length + 1]; + let error = emit_events(test_contract, &N_EMITTED_EVENTS, &KEYS, &data_too_long).unwrap_err(); + let expected_error = EmitEventError::ExceedsMaxDataLength { + data_length: max_event_data_length + 1, + max_data_length: max_event_data_length, + }; + assert!(error.to_string().contains(&expected_error.to_string())); +} + +#[test_case(FeatureContract::TestContract(CairoVersion::Cairo1); "VM")] +fn keys_length_exceeds_limit(test_contract: FeatureContract) { + let versioned_constants = VersionedConstants::create_for_testing(); + + let max_event_keys_length = versioned_constants.tx_event_limits.max_keys_length; + let keys_too_long = vec![felt!(1_u16); max_event_keys_length + 1]; + let error = emit_events(test_contract, &N_EMITTED_EVENTS, &keys_too_long, &DATA).unwrap_err(); + let expected_error = EmitEventError::ExceedsMaxKeysLength { + keys_length: max_event_keys_length + 1, + max_keys_length: max_event_keys_length, + }; + + assert!(error.to_string().contains(&expected_error.to_string())); +} + +#[test_case(FeatureContract::TestContract(CairoVersion::Cairo1); "VM")] +fn event_number_exceeds_limit(test_contract: FeatureContract) { + let versioned_constants = VersionedConstants::create_for_testing(); + + let max_n_emitted_events = versioned_constants.tx_event_limits.max_n_emitted_events; + let n_emitted_events_too_big = vec![felt!( + u16::try_from(max_n_emitted_events + 1).expect("Failed to convert usize to u16.") + )]; + let error = emit_events(test_contract, &n_emitted_events_too_big, &KEYS, &DATA).unwrap_err(); + let expected_error = EmitEventError::ExceedsMaxNumberOfEmittedEvents { + n_emitted_events: max_n_emitted_events + 1, + max_n_emitted_events, + }; + assert!(error.to_string().contains(&expected_error.to_string())); +} + +fn emit_events( + test_contract: FeatureContract, + n_emitted_events: &[Felt], + keys: &[Felt], + data: &[Felt], +) -> Result { + let chain_info = &ChainInfo::create_for_testing(); + let mut state = test_state(chain_info, BALANCE, &[(test_contract, 1)]); + assert_consistent_contract_version(test_contract, &state); + let calldata = Calldata( + concat(vec![ + n_emitted_events.to_owned(), + vec![felt!(u16::try_from(keys.len()).expect("Failed to convert usize to u16."))], + keys.to_vec(), + vec![felt!(u16::try_from(data.len()).expect("Failed to convert usize to u16."))], + data.to_vec(), + ]) + .into(), + ); + + let entry_point_call = CallEntryPoint { + entry_point_selector: selector_from_name("test_emit_events"), + calldata, + ..trivial_external_entry_point_new(test_contract) + }; + + let result = entry_point_call.execute_directly(&mut state); + assert_consistent_contract_version(test_contract, &state); + result +} diff --git a/crates/blockifier/src/execution/syscalls/syscall_tests/get_block_hash.rs b/crates/blockifier/src/execution/syscalls/syscall_tests/get_block_hash.rs new file mode 100644 index 0000000000..69cef2fdda --- /dev/null +++ b/crates/blockifier/src/execution/syscalls/syscall_tests/get_block_hash.rs @@ -0,0 +1,105 @@ +use pretty_assertions::assert_eq; +use starknet_api::core::ContractAddress; +use starknet_api::state::StorageKey; +use starknet_api::transaction::Calldata; +use starknet_api::{calldata, felt}; +use starknet_types_core::felt::Felt; +use test_case::test_case; + +use super::utils::assert_consistent_contract_version; +use crate::abi::abi_utils::selector_from_name; +use crate::abi::constants; +use crate::context::ChainInfo; +use crate::execution::call_info::{CallExecution, Retdata}; +use crate::execution::entry_point::CallEntryPoint; +use crate::state::cached_state::CachedState; +use crate::state::state_api::State; +use crate::test_utils::contracts::FeatureContract; +use crate::test_utils::dict_state_reader::DictStateReader; +use crate::test_utils::initial_test_state::test_state; +use crate::test_utils::{ + trivial_external_entry_point_new, CairoVersion, BALANCE, CURRENT_BLOCK_NUMBER, +}; +use crate::{check_entry_point_execution_error_for_custom_hint, retdata}; + +fn initialize_state(test_contract: FeatureContract) -> (CachedState, Felt, Felt) { + let chain_info = &ChainInfo::create_for_testing(); + let mut state = test_state(chain_info, BALANCE, &[(test_contract, 1)]); + assert_consistent_contract_version(test_contract, &state); + + // Initialize block number -> block hash entry. + let upper_bound_block_number = CURRENT_BLOCK_NUMBER - constants::STORED_BLOCK_HASH_BUFFER; + let block_number = felt!(upper_bound_block_number); + let block_hash = felt!(66_u64); + let key = StorageKey::try_from(block_number).unwrap(); + let block_hash_contract_address = + ContractAddress::try_from(Felt::from(constants::BLOCK_HASH_CONTRACT_ADDRESS)).unwrap(); + state.set_storage_at(block_hash_contract_address, key, block_hash).unwrap(); + + (state, block_number, block_hash) +} + +#[test_case(FeatureContract::TestContract(CairoVersion::Cairo1), 9680; "VM")] +fn positive_flow(test_contract: FeatureContract, expected_gas: u64) { + let (mut state, block_number, block_hash) = initialize_state(test_contract); + + let calldata = calldata![block_number]; + let entry_point_call = CallEntryPoint { + entry_point_selector: selector_from_name("test_get_block_hash"), + calldata, + ..trivial_external_entry_point_new(test_contract) + }; + + assert_eq!( + entry_point_call.clone().execute_directly(&mut state).unwrap().execution, + CallExecution { + gas_consumed: expected_gas, + ..CallExecution::from_retdata(retdata![block_hash]) + } + ); + + assert_consistent_contract_version(test_contract, &state); +} + +#[test_case(FeatureContract::TestContract(CairoVersion::Cairo1); "VM")] +fn negative_flow_execution_mode_validate(test_contract: FeatureContract) { + let (mut state, block_number, _) = initialize_state(test_contract); + + let calldata = calldata![block_number]; + let entry_point_call = CallEntryPoint { + entry_point_selector: selector_from_name("test_get_block_hash"), + calldata, + ..trivial_external_entry_point_new(test_contract) + }; + + let error = entry_point_call.execute_directly_in_validate_mode(&mut state).unwrap_err(); + + check_entry_point_execution_error_for_custom_hint!( + &error, + "Unauthorized syscall get_block_hash in execution mode Validate.", + ); + + assert!(error + .to_string() + .contains("Unauthorized syscall get_block_hash in execution mode Validate")); + + assert_consistent_contract_version(test_contract, &state); +} + +#[test_case(FeatureContract::TestContract(CairoVersion::Cairo1); "VM")] +fn negative_flow_block_number_out_of_range(test_contract: FeatureContract) { + let (mut state, _, _) = initialize_state(test_contract); + + let requested_block_number = CURRENT_BLOCK_NUMBER - constants::STORED_BLOCK_HASH_BUFFER + 1; + let block_number = felt!(requested_block_number); + let calldata = calldata![block_number]; + let entry_point_call = CallEntryPoint { + entry_point_selector: selector_from_name("test_get_block_hash"), + calldata, + ..trivial_external_entry_point_new(test_contract) + }; + + let error = entry_point_call.execute_directly(&mut state).unwrap_err().to_string(); + assert!(error.contains("Block number out of range")); + assert_consistent_contract_version(test_contract, &state); +} diff --git a/crates/blockifier/src/execution/syscalls/syscall_tests/get_execution_info.rs b/crates/blockifier/src/execution/syscalls/syscall_tests/get_execution_info.rs new file mode 100644 index 0000000000..43570183df --- /dev/null +++ b/crates/blockifier/src/execution/syscalls/syscall_tests/get_execution_info.rs @@ -0,0 +1,257 @@ +use std::collections::BTreeMap; + +use cairo_vm::Felt252; +use num_traits::Pow; +use starknet_api::core::ChainId; +use starknet_api::data_availability::DataAvailabilityMode; +use starknet_api::felt; +use starknet_api::transaction::{ + AccountDeploymentData, Calldata, Fee, PaymasterData, Resource, ResourceBounds, + ResourceBoundsMapping, Tip, TransactionHash, TransactionVersion, +}; +use starknet_types_core::felt::Felt; +use test_case::test_case; + +use crate::abi::abi_utils::selector_from_name; +use crate::context::ChainInfo; +use crate::execution::common_hints::ExecutionMode; +use crate::execution::entry_point::CallEntryPoint; +use crate::execution::syscalls::hint_processor::{L1_GAS, L2_GAS}; +use crate::execution::syscalls::syscall_tests::utils::assert_consistent_contract_version; +use crate::nonce; +use crate::test_utils::contracts::FeatureContract; +use crate::test_utils::initial_test_state::test_state; +use crate::test_utils::{ + trivial_external_entry_point_with_address, CairoVersion, BALANCE, CHAIN_ID_NAME, + CURRENT_BLOCK_NUMBER, CURRENT_BLOCK_NUMBER_FOR_VALIDATE, CURRENT_BLOCK_TIMESTAMP, + CURRENT_BLOCK_TIMESTAMP_FOR_VALIDATE, TEST_SEQUENCER_ADDRESS, +}; +use crate::transaction::constants::QUERY_VERSION_BASE_BIT; +use crate::transaction::objects::{ + CommonAccountFields, CurrentTransactionInfo, DeprecatedTransactionInfo, TransactionInfo, +}; + +#[test_case( + FeatureContract::TestContract(CairoVersion::Cairo1), + ExecutionMode::Validate, + TransactionVersion::ONE, + false; + "Validate execution mode: block info fields should be zeroed. Transaction V1.")] +#[test_case( + FeatureContract::TestContract(CairoVersion::Cairo1), + ExecutionMode::Execute, + TransactionVersion::ONE, + false; + "Execute execution mode: block info should be as usual. Transaction V1.")] +#[test_case( + FeatureContract::TestContract(CairoVersion::Cairo1), + ExecutionMode::Validate, + TransactionVersion::THREE, + false; + "Validate execution mode: block info fields should be zeroed. Transaction V3.")] +#[test_case( + FeatureContract::TestContract(CairoVersion::Cairo1), + ExecutionMode::Execute, + TransactionVersion::THREE, + false; + "Execute execution mode: block info should be as usual. Transaction V3.")] +#[test_case( + FeatureContract::LegacyTestContract, + ExecutionMode::Execute, + TransactionVersion::ONE, + false; + "Legacy contract. Execute execution mode: block info should be as usual. Transaction V1.")] +#[test_case( + FeatureContract::LegacyTestContract, + ExecutionMode::Execute, + TransactionVersion::THREE, + false; + "Legacy contract. Execute execution mode: block info should be as usual. Transaction V3.")] +#[test_case( + FeatureContract::TestContract(CairoVersion::Cairo1), + ExecutionMode::Execute, + TransactionVersion::THREE, + true; + "Execute execution mode: block info should be as usual. Transaction V3. Query.")] +fn test_get_execution_info( + test_contract: FeatureContract, + execution_mode: ExecutionMode, + mut version: TransactionVersion, + only_query: bool, +) { + let state = &mut test_state(&ChainInfo::create_for_testing(), BALANCE, &[(test_contract, 1)]); + assert_consistent_contract_version(test_contract, state); + let expected_block_info = match execution_mode { + ExecutionMode::Validate => [ + // Rounded block number. + felt!(CURRENT_BLOCK_NUMBER_FOR_VALIDATE), + // Rounded timestamp. + felt!(CURRENT_BLOCK_TIMESTAMP_FOR_VALIDATE), + Felt::ZERO, + ], + ExecutionMode::Execute => [ + felt!(CURRENT_BLOCK_NUMBER), // Block number. + felt!(CURRENT_BLOCK_TIMESTAMP), // Block timestamp. + Felt::from_hex(TEST_SEQUENCER_ADDRESS).unwrap(), + ], + }; + + let test_contract_address = test_contract.get_instance_address(0); + + let expected_unsupported_fields = match test_contract { + FeatureContract::LegacyTestContract => { + // Read and parse file content. + let raw_contract: serde_json::Value = + serde_json::from_str(&test_contract.get_raw_class()).expect("Error parsing JSON"); + // Verify version. + if let Some(compiler_version) = raw_contract["compiler_version"].as_str() { + assert_eq!(compiler_version, "2.1.0"); + } else { + panic!("'compiler_version' not found or not a valid string in JSON."); + }; + vec![] + } + _ => { + vec![ + Felt::ZERO, // Tip. + Felt::ZERO, // Paymaster data. + Felt::ZERO, // Nonce DA. + Felt::ZERO, // Fee DA. + Felt::ZERO, // Account data. + ] + } + }; + + if only_query { + let simulate_version_base = Pow::pow(Felt252::from(2_u8), QUERY_VERSION_BASE_BIT); + let query_version = simulate_version_base + version.0; + version = TransactionVersion(query_version); + } + + let tx_hash = TransactionHash(felt!(1991_u16)); + let max_fee = Fee(42); + let nonce = nonce!(3_u16); + let sender_address = test_contract_address; + + let max_amount = Fee(13); + let max_price_per_unit = Fee(61); + + let expected_resource_bounds: Vec = match (test_contract, version) { + (FeatureContract::LegacyTestContract, _) => vec![], + (_, version) if version == TransactionVersion(Felt::from_hex("0x1").unwrap()) => vec![ + felt!(0_u16), // Length of resource bounds array. + ], + (_, _) => vec![ + Felt::from(2u32), // Length of ResourceBounds array. + felt!(L1_GAS), // Resource. + felt!(max_amount.0), // Max amount. + felt!(max_price_per_unit.0), // Max price per unit. + felt!(L2_GAS), // Resource. + Felt::ZERO, // Max amount. + Felt::ZERO, // Max price per unit. + ], + }; + + let expected_tx_info: Vec; + let tx_info: TransactionInfo; + if version == TransactionVersion(Felt::from_hex("0x1").unwrap()) { + expected_tx_info = vec![ + version.0, /* Transaction + * version. */ + *sender_address.0.key(), // Account address. + felt!(max_fee.0), // Max fee. + Felt::ZERO, // Signature. + tx_hash.0, // Transaction hash. + felt!(&*ChainId::Other(CHAIN_ID_NAME.to_string()).as_hex()), // Chain ID. + nonce.0, // Nonce. + ]; + + tx_info = TransactionInfo::Deprecated(DeprecatedTransactionInfo { + common_fields: CommonAccountFields { + transaction_hash: tx_hash, + version: TransactionVersion::ONE, + nonce, + sender_address, + only_query, + ..Default::default() + }, + max_fee, + }); + } else { + expected_tx_info = vec![ + version.0, /* Transaction + * version. */ + *sender_address.0.key(), // Account address. + Felt::ZERO, // Max fee. + Felt::ZERO, // Signature. + tx_hash.0, // Transaction hash. + felt!(&*ChainId::Other(CHAIN_ID_NAME.to_string()).as_hex()), // Chain ID. + nonce.0, // Nonce. + ]; + + tx_info = TransactionInfo::Current(CurrentTransactionInfo { + common_fields: CommonAccountFields { + transaction_hash: tx_hash, + version: TransactionVersion::THREE, + nonce, + sender_address, + only_query, + ..Default::default() + }, + resource_bounds: ResourceBoundsMapping(BTreeMap::from([ + ( + Resource::L1Gas, + // TODO(Ori, 1/2/2024): Write an indicative expect message explaining why + // the convertion works. + ResourceBounds { + max_amount: max_amount + .0 + .try_into() + .expect("Failed to convert u128 to u64."), + max_price_per_unit: max_price_per_unit.0, + }, + ), + (Resource::L2Gas, ResourceBounds { max_amount: 0, max_price_per_unit: 0 }), + ])), + tip: Tip::default(), + nonce_data_availability_mode: DataAvailabilityMode::L1, + fee_data_availability_mode: DataAvailabilityMode::L1, + paymaster_data: PaymasterData::default(), + account_deployment_data: AccountDeploymentData::default(), + }); + } + + let entry_point_selector = selector_from_name("test_get_execution_info"); + let expected_call_info = vec![ + felt!(0_u16), // Caller address. + *test_contract_address.0.key(), // Storage address. + entry_point_selector.0, // Entry point selector. + ]; + let entry_point_call = CallEntryPoint { + entry_point_selector, + code_address: None, + calldata: Calldata( + [ + expected_block_info.to_vec(), + expected_tx_info, + expected_resource_bounds.into_iter().chain(expected_unsupported_fields).collect(), + expected_call_info, + ] + .concat() + .into(), + ), + ..trivial_external_entry_point_with_address(test_contract_address) + }; + + let result = match execution_mode { + ExecutionMode::Validate => { + entry_point_call.execute_directly_given_tx_info_in_validate_mode(state, tx_info, false) + } + ExecutionMode::Execute => { + entry_point_call.execute_directly_given_tx_info(state, tx_info, false) + } + }; + + assert!(!result.unwrap().execution.failed); + assert_consistent_contract_version(test_contract, state); +} diff --git a/crates/blockifier/src/execution/syscalls/syscall_tests/keccak.rs b/crates/blockifier/src/execution/syscalls/syscall_tests/keccak.rs new file mode 100644 index 0000000000..db7cfdc33b --- /dev/null +++ b/crates/blockifier/src/execution/syscalls/syscall_tests/keccak.rs @@ -0,0 +1,29 @@ +use starknet_api::transaction::Calldata; +use test_case::test_case; + +use crate::abi::abi_utils::selector_from_name; +use crate::context::ChainInfo; +use crate::execution::call_info::{CallExecution, Retdata}; +use crate::execution::entry_point::CallEntryPoint; +use crate::retdata; +use crate::test_utils::contracts::FeatureContract; +use crate::test_utils::initial_test_state::test_state; +use crate::test_utils::{trivial_external_entry_point_new, CairoVersion, BALANCE}; + +#[test_case(FeatureContract::TestContract(CairoVersion::Cairo1), 256250; "VM")] +fn test_keccak(test_contract: FeatureContract, expected_gas: u64) { + let chain_info = &ChainInfo::create_for_testing(); + let mut state = test_state(chain_info, BALANCE, &[(test_contract, 1)]); + + let calldata = Calldata(vec![].into()); + let entry_point_call = CallEntryPoint { + entry_point_selector: selector_from_name("test_keccak"), + calldata, + ..trivial_external_entry_point_new(test_contract) + }; + + assert_eq!( + entry_point_call.execute_directly(&mut state).unwrap().execution, + CallExecution { gas_consumed: expected_gas, ..CallExecution::from_retdata(retdata![]) } + ); +} diff --git a/crates/blockifier/src/execution/syscalls/syscall_tests/library_call.rs b/crates/blockifier/src/execution/syscalls/syscall_tests/library_call.rs new file mode 100644 index 0000000000..63574545f0 --- /dev/null +++ b/crates/blockifier/src/execution/syscalls/syscall_tests/library_call.rs @@ -0,0 +1,204 @@ +use std::collections::{HashMap, HashSet}; + +use cairo_vm::types::builtin_name::BuiltinName; +use cairo_vm::vm::runners::cairo_runner::ExecutionResources; +use pretty_assertions::assert_eq; +use starknet_api::core::PatriciaKey; +use starknet_api::state::StorageKey; +use starknet_api::transaction::Calldata; +use starknet_api::{calldata, felt, patricia_key}; +use test_case::test_case; + +use crate::abi::abi_utils::selector_from_name; +use crate::context::ChainInfo; +use crate::execution::call_info::{CallExecution, CallInfo, Retdata}; +use crate::execution::entry_point::{CallEntryPoint, CallType}; +use crate::execution::syscalls::syscall_tests::consts::{ + REQUIRED_GAS_LIBRARY_CALL_TEST, REQUIRED_GAS_STORAGE_READ_WRITE_TEST, +}; +use crate::execution::syscalls::SyscallSelector; +use crate::retdata; +use crate::test_utils::contracts::FeatureContract; +use crate::test_utils::initial_test_state::test_state; +use crate::test_utils::{ + get_syscall_resources, trivial_external_entry_point_new, CairoVersion, BALANCE, +}; + +#[test_case(FeatureContract::TestContract(CairoVersion::Cairo1), REQUIRED_GAS_LIBRARY_CALL_TEST; "VM")] +fn test_library_call(test_contract: FeatureContract, expected_gas: u64) { + let chain_info = &ChainInfo::create_for_testing(); + let mut state = test_state(chain_info, BALANCE, &[(test_contract, 1)]); + + let inner_entry_point_selector = selector_from_name("test_storage_read_write"); + let calldata = calldata![ + test_contract.get_class_hash().0, // Class hash. + inner_entry_point_selector.0, // Function selector. + felt!(2_u8), // Calldata length. + felt!(1234_u16), // Calldata: address. + felt!(91_u8) // Calldata: value. + ]; + + let entry_point_call = CallEntryPoint { + entry_point_selector: selector_from_name("test_library_call"), + calldata, + class_hash: Some(test_contract.get_class_hash()), + ..trivial_external_entry_point_new(test_contract) + }; + + assert_eq!( + entry_point_call.execute_directly(&mut state).unwrap().execution, + CallExecution { + retdata: retdata![felt!(91_u16)], + gas_consumed: expected_gas, + ..Default::default() + } + ); +} + +#[test_case(FeatureContract::TestContract(CairoVersion::Cairo1); "VM")] +fn test_library_call_assert_fails(test_contract: FeatureContract) { + let chain_info = &ChainInfo::create_for_testing(); + let mut state = test_state(chain_info, BALANCE, &[(test_contract, 1)]); + let inner_entry_point_selector = selector_from_name("assert_eq"); + let calldata = calldata![ + test_contract.get_class_hash().0, // Class hash. + inner_entry_point_selector.0, // Function selector. + felt!(2_u8), // Calldata length. + felt!(0_u8), // Calldata: first assert value. + felt!(1_u8) // Calldata: second assert value. + ]; + let entry_point_call = CallEntryPoint { + entry_point_selector: selector_from_name("test_library_call"), + calldata, + class_hash: Some(test_contract.get_class_hash()), + ..trivial_external_entry_point_new(test_contract) + }; + + let err = entry_point_call.execute_directly(&mut state).unwrap_err(); + assert!(err.to_string().contains("x != y")); +} + +#[test_case(FeatureContract::TestContract(CairoVersion::Cairo1), 276880; "VM")] +fn test_nested_library_call(test_contract: FeatureContract, expected_gas: u64) { + let chain_info = &ChainInfo::create_for_testing(); + let mut state = test_state(chain_info, BALANCE, &[(test_contract, 1)]); + + let (key, value) = (255_u64, 44_u64); + let outer_entry_point_selector = selector_from_name("test_library_call"); + let inner_entry_point_selector = selector_from_name("test_storage_read_write"); + let test_class_hash = test_contract.get_class_hash(); + let main_entry_point_calldata = calldata![ + test_class_hash.0, // Class hash. + outer_entry_point_selector.0, // Library call function selector. + inner_entry_point_selector.0, // Storage function selector. + felt!(key), // Calldata: address. + felt!(value) // Calldata: value. + ]; + + // Create expected call info tree. + let main_entry_point = CallEntryPoint { + entry_point_selector: selector_from_name("test_nested_library_call"), + calldata: main_entry_point_calldata, + class_hash: Some(test_class_hash), + initial_gas: 9999906600, + ..trivial_external_entry_point_new(test_contract) + }; + let nested_storage_entry_point = CallEntryPoint { + entry_point_selector: inner_entry_point_selector, + calldata: calldata![felt!(key + 1), felt!(value + 1)], + class_hash: Some(test_class_hash), + code_address: None, + call_type: CallType::Delegate, + initial_gas: 9999745020, + ..trivial_external_entry_point_new(test_contract) + }; + let library_entry_point = CallEntryPoint { + entry_point_selector: outer_entry_point_selector, + calldata: calldata![ + test_class_hash.0, // Class hash. + inner_entry_point_selector.0, // Storage function selector. + felt!(2_u8), // Calldata: address. + felt!(key + 1), // Calldata: address. + felt!(value + 1) // Calldata: value. + ], + class_hash: Some(test_class_hash), + code_address: None, + call_type: CallType::Delegate, + initial_gas: 9999823550, + ..trivial_external_entry_point_new(test_contract) + }; + let storage_entry_point = CallEntryPoint { + calldata: calldata![felt!(key), felt!(value)], + initial_gas: 9999656870, + ..nested_storage_entry_point + }; + + let storage_entry_point_resources = ExecutionResources { + n_steps: 243, + n_memory_holes: 0, + builtin_instance_counter: HashMap::from([(BuiltinName::range_check, 7)]), + }; + let nested_storage_call_info = CallInfo { + call: nested_storage_entry_point, + execution: CallExecution { + retdata: retdata![felt!(value + 1)], + gas_consumed: REQUIRED_GAS_STORAGE_READ_WRITE_TEST, + ..CallExecution::default() + }, + resources: storage_entry_point_resources.clone(), + storage_read_values: vec![felt!(value + 1)], + accessed_storage_keys: HashSet::from([StorageKey(patricia_key!(key + 1))]), + ..Default::default() + }; + + let library_call_resources = &get_syscall_resources(SyscallSelector::LibraryCall) + + &ExecutionResources { + n_steps: 388, + n_memory_holes: 0, + builtin_instance_counter: HashMap::from([(BuiltinName::range_check, 15)]), + }; + let library_call_info = CallInfo { + call: library_entry_point, + execution: CallExecution { + retdata: retdata![felt!(value + 1)], + gas_consumed: REQUIRED_GAS_LIBRARY_CALL_TEST, + ..CallExecution::default() + }, + resources: library_call_resources, + inner_calls: vec![nested_storage_call_info], + ..Default::default() + }; + + let storage_call_info = CallInfo { + call: storage_entry_point, + execution: CallExecution { + retdata: retdata![felt!(value)], + gas_consumed: REQUIRED_GAS_STORAGE_READ_WRITE_TEST, + ..CallExecution::default() + }, + resources: storage_entry_point_resources, + storage_read_values: vec![felt!(value)], + accessed_storage_keys: HashSet::from([StorageKey(patricia_key!(key))]), + ..Default::default() + }; + + let main_call_resources = &(&get_syscall_resources(SyscallSelector::LibraryCall) * 3) + + &ExecutionResources { + n_steps: 749, + n_memory_holes: 2, + builtin_instance_counter: HashMap::from([(BuiltinName::range_check, 27)]), + }; + let expected_call_info = CallInfo { + call: main_entry_point.clone(), + execution: CallExecution { + retdata: retdata![felt!(value)], + gas_consumed: expected_gas, + ..CallExecution::default() + }, + resources: main_call_resources, + inner_calls: vec![library_call_info, storage_call_info], + ..Default::default() + }; + + assert_eq!(main_entry_point.execute_directly(&mut state).unwrap(), expected_call_info); +} diff --git a/crates/blockifier/src/execution/syscalls/syscall_tests/mod.rs b/crates/blockifier/src/execution/syscalls/syscall_tests/mod.rs new file mode 100644 index 0000000000..0e39a50057 --- /dev/null +++ b/crates/blockifier/src/execution/syscalls/syscall_tests/mod.rs @@ -0,0 +1,15 @@ +mod call_contract; +mod consts; +mod deploy; +mod emit_event; +mod get_block_hash; +mod get_execution_info; +mod keccak; +mod library_call; +mod out_of_gas; +mod replace_class; +mod secp; +mod send_message_to_l1; +mod sha256; +mod storage_read_write; +mod utils; diff --git a/crates/blockifier/src/execution/syscalls/syscall_tests/out_of_gas.rs b/crates/blockifier/src/execution/syscalls/syscall_tests/out_of_gas.rs new file mode 100644 index 0000000000..1ac010fc06 --- /dev/null +++ b/crates/blockifier/src/execution/syscalls/syscall_tests/out_of_gas.rs @@ -0,0 +1,29 @@ +use starknet_api::transaction::Calldata; +use starknet_api::{calldata, felt}; +use test_case::test_case; + +use crate::abi::abi_utils::selector_from_name; +use crate::context::ChainInfo; +use crate::execution::entry_point::CallEntryPoint; +use crate::execution::syscalls::syscall_tests::consts::REQUIRED_GAS_STORAGE_READ_WRITE_TEST; +use crate::test_utils::contracts::FeatureContract; +use crate::test_utils::initial_test_state::test_state; +use crate::test_utils::{trivial_external_entry_point_new, CairoVersion, BALANCE}; + +#[test_case(FeatureContract::TestContract(CairoVersion::Cairo1); "VM")] +fn test_out_of_gas(test_contract: FeatureContract) { + let chain_info = &ChainInfo::create_for_testing(); + let mut state = test_state(chain_info, BALANCE, &[(test_contract, 1)]); + + let key = felt!(1234_u16); + let value = felt!(18_u8); + let calldata = calldata![key, value]; + let entry_point_call = CallEntryPoint { + calldata, + entry_point_selector: selector_from_name("test_storage_read_write"), + initial_gas: REQUIRED_GAS_STORAGE_READ_WRITE_TEST - 1, + ..trivial_external_entry_point_new(test_contract) + }; + let error = entry_point_call.execute_directly(&mut state).unwrap_err().to_string(); + assert!(error.contains("Out of gas")); +} diff --git a/crates/blockifier/src/execution/syscalls/syscall_tests/replace_class.rs b/crates/blockifier/src/execution/syscalls/syscall_tests/replace_class.rs new file mode 100644 index 0000000000..31f689695f --- /dev/null +++ b/crates/blockifier/src/execution/syscalls/syscall_tests/replace_class.rs @@ -0,0 +1,72 @@ +use starknet_api::transaction::Calldata; +use starknet_api::{calldata, felt}; +use test_case::test_case; + +use crate::abi::abi_utils::selector_from_name; +use crate::context::ChainInfo; +use crate::execution::call_info::CallExecution; +use crate::execution::entry_point::CallEntryPoint; +use crate::state::state_api::StateReader; +use crate::test_utils::contracts::FeatureContract; +use crate::test_utils::initial_test_state::test_state; +use crate::test_utils::{trivial_external_entry_point_new, CairoVersion, BALANCE}; + +#[test_case(FeatureContract::TestContract(CairoVersion::Cairo1); "VM")] +fn undeclared_class_hash(test_contract: FeatureContract) { + let mut state = test_state(&ChainInfo::create_for_testing(), BALANCE, &[(test_contract, 1)]); + + let entry_point_call = CallEntryPoint { + calldata: calldata![felt!(1234_u16)], + entry_point_selector: selector_from_name("test_replace_class"), + ..trivial_external_entry_point_new(test_contract) + }; + let error = entry_point_call.execute_directly(&mut state).unwrap_err().to_string(); + assert!(error.contains("is not declared")); +} + +#[test_case(FeatureContract::TestContract(CairoVersion::Cairo1); "VM")] +fn cairo0_class_hash(test_contract: FeatureContract) { + let empty_contract_cairo0 = FeatureContract::Empty(CairoVersion::Cairo0); + let mut state = test_state( + &ChainInfo::create_for_testing(), + BALANCE, + &[(test_contract, 1), (empty_contract_cairo0, 0)], + ); + + // Replace with Cairo 0 class hash. + let v0_class_hash = empty_contract_cairo0.get_class_hash(); + + let entry_point_call = CallEntryPoint { + calldata: calldata![v0_class_hash.0], + entry_point_selector: selector_from_name("test_replace_class"), + ..trivial_external_entry_point_new(test_contract) + }; + let error = entry_point_call.execute_directly(&mut state).unwrap_err().to_string(); + assert!(error.contains("Cannot replace V1 class hash with V0 class hash")); +} + +#[test_case(FeatureContract::TestContract(CairoVersion::Cairo1), 9750; "VM")] +fn positive_flow(test_contract: FeatureContract, gas_consumed: u64) { + let empty_contract = FeatureContract::Empty(CairoVersion::Cairo1); + let empty_contract_cairo0 = FeatureContract::Empty(CairoVersion::Cairo0); + let mut state = test_state( + &ChainInfo::create_for_testing(), + BALANCE, + &[(test_contract, 1), (empty_contract, 0), (empty_contract_cairo0, 0)], + ); + let contract_address = test_contract.get_instance_address(0); + + let old_class_hash = test_contract.get_class_hash(); + let new_class_hash = empty_contract.get_class_hash(); + assert_eq!(state.get_class_hash_at(contract_address).unwrap(), old_class_hash); + let entry_point_call = CallEntryPoint { + calldata: calldata![new_class_hash.0], + entry_point_selector: selector_from_name("test_replace_class"), + ..trivial_external_entry_point_new(test_contract) + }; + assert_eq!( + entry_point_call.execute_directly(&mut state).unwrap().execution, + CallExecution { gas_consumed, ..Default::default() } + ); + assert_eq!(state.get_class_hash_at(contract_address).unwrap(), new_class_hash); +} diff --git a/crates/blockifier/src/execution/syscalls/syscall_tests/secp.rs b/crates/blockifier/src/execution/syscalls/syscall_tests/secp.rs new file mode 100644 index 0000000000..0066067c13 --- /dev/null +++ b/crates/blockifier/src/execution/syscalls/syscall_tests/secp.rs @@ -0,0 +1,46 @@ +use starknet_api::transaction::Calldata; +use test_case::test_case; + +use crate::abi::abi_utils::selector_from_name; +use crate::context::ChainInfo; +use crate::execution::call_info::CallExecution; +use crate::execution::entry_point::CallEntryPoint; +use crate::test_utils::contracts::FeatureContract; +use crate::test_utils::initial_test_state::test_state; +use crate::test_utils::{trivial_external_entry_point_new, CairoVersion, BALANCE}; + +#[test_case(FeatureContract::TestContract(CairoVersion::Cairo1), 17033810; "VM")] +fn test_secp256k1(test_contract: FeatureContract, expected_gas: u64) { + let chain_info = &ChainInfo::create_for_testing(); + let mut state = test_state(chain_info, BALANCE, &[(test_contract, 1)]); + + let calldata = Calldata(vec![].into()); + let entry_point_call = CallEntryPoint { + entry_point_selector: selector_from_name("test_secp256k1"), + calldata, + ..trivial_external_entry_point_new(test_contract) + }; + + pretty_assertions::assert_eq!( + entry_point_call.execute_directly(&mut state).unwrap().execution, + CallExecution { gas_consumed: expected_gas, ..Default::default() } + ); +} + +#[test_case(FeatureContract::TestContract(CairoVersion::Cairo1), 27582260; "VM")] +fn test_secp256r1(test_contract: FeatureContract, expected_gas: u64) { + let chain_info = &ChainInfo::create_for_testing(); + let mut state = test_state(chain_info, BALANCE, &[(test_contract, 1)]); + + let calldata = Calldata(vec![].into()); + let entry_point_call = CallEntryPoint { + entry_point_selector: selector_from_name("test_secp256r1"), + calldata, + ..trivial_external_entry_point_new(test_contract) + }; + + pretty_assertions::assert_eq!( + entry_point_call.execute_directly(&mut state).unwrap().execution, + CallExecution { gas_consumed: expected_gas, ..Default::default() } + ); +} diff --git a/crates/blockifier/src/execution/syscalls/syscall_tests/send_message_to_l1.rs b/crates/blockifier/src/execution/syscalls/syscall_tests/send_message_to_l1.rs new file mode 100644 index 0000000000..64cde18bc7 --- /dev/null +++ b/crates/blockifier/src/execution/syscalls/syscall_tests/send_message_to_l1.rs @@ -0,0 +1,51 @@ +use itertools::concat; +use starknet_api::core::EthAddress; +use starknet_api::felt; +use starknet_api::transaction::{Calldata, L2ToL1Payload}; +use test_case::test_case; + +use crate::abi::abi_utils::selector_from_name; +use crate::context::ChainInfo; +use crate::execution::call_info::{CallExecution, MessageToL1, OrderedL2ToL1Message}; +use crate::execution::entry_point::CallEntryPoint; +use crate::test_utils::contracts::FeatureContract; +use crate::test_utils::initial_test_state::test_state; +use crate::test_utils::{trivial_external_entry_point_new, CairoVersion, BALANCE}; + +#[test_case(FeatureContract::TestContract(CairoVersion::Cairo1), 22990; "VM")] +fn test_send_message_to_l1(test_contract: FeatureContract, expected_gas: u64) { + let chain_info = &ChainInfo::create_for_testing(); + let mut state = test_state(chain_info, BALANCE, &[(test_contract, 1)]); + + let to_address = felt!(1234_u16); + let payload = vec![felt!(2019_u16), felt!(2020_u16), felt!(2021_u16)]; + let calldata = Calldata( + concat(vec![ + vec![ + to_address, + // TODO(Ori, 1/2/2024): Write an indicative expect message explaining why the + // convertion works. + felt!(u64::try_from(payload.len()).expect("Failed to convert usize to u64.")), + ], + payload.clone(), + ]) + .into(), + ); + let entry_point_call = CallEntryPoint { + entry_point_selector: selector_from_name("test_send_message_to_l1"), + calldata, + ..trivial_external_entry_point_new(test_contract) + }; + + let to_address = EthAddress::try_from(to_address).unwrap(); + let message = MessageToL1 { to_address, payload: L2ToL1Payload(payload) }; + + pretty_assertions::assert_eq!( + entry_point_call.execute_directly(&mut state).unwrap().execution, + CallExecution { + l2_to_l1_messages: vec![OrderedL2ToL1Message { order: 0, message }], + gas_consumed: expected_gas, + ..Default::default() + } + ); +} diff --git a/crates/blockifier/src/execution/syscalls/syscall_tests/sha256.rs b/crates/blockifier/src/execution/syscalls/syscall_tests/sha256.rs new file mode 100644 index 0000000000..2f239c49c0 --- /dev/null +++ b/crates/blockifier/src/execution/syscalls/syscall_tests/sha256.rs @@ -0,0 +1,29 @@ +use starknet_api::transaction::Calldata; +use test_case::test_case; + +use crate::abi::abi_utils::selector_from_name; +use crate::context::ChainInfo; +use crate::execution::call_info::{CallExecution, Retdata}; +use crate::execution::entry_point::CallEntryPoint; +use crate::retdata; +use crate::test_utils::contracts::FeatureContract; +use crate::test_utils::initial_test_state::test_state; +use crate::test_utils::{trivial_external_entry_point_new, CairoVersion, BALANCE}; + +#[test_case(FeatureContract::TestContract(CairoVersion::Cairo1), 892990; "VM")] +fn test_sha256(test_contract: FeatureContract, gas_consumed: u64) { + let chain_info = &ChainInfo::create_for_testing(); + let mut state = test_state(chain_info, BALANCE, &[(test_contract, 1)]); + + let calldata = Calldata(vec![].into()); + let entry_point_call = CallEntryPoint { + entry_point_selector: selector_from_name("test_sha256"), + calldata, + ..trivial_external_entry_point_new(test_contract) + }; + + assert_eq!( + entry_point_call.execute_directly(&mut state).unwrap().execution, + CallExecution { gas_consumed, ..CallExecution::from_retdata(retdata![]) } + ); +} diff --git a/crates/blockifier/src/execution/syscalls/syscall_tests/storage_read_write.rs b/crates/blockifier/src/execution/syscalls/syscall_tests/storage_read_write.rs new file mode 100644 index 0000000000..36fb0df04f --- /dev/null +++ b/crates/blockifier/src/execution/syscalls/syscall_tests/storage_read_write.rs @@ -0,0 +1,50 @@ +use starknet_api::state::StorageKey; +use starknet_api::transaction::Calldata; +use starknet_api::{calldata, felt}; +use test_case::test_case; + +use crate::abi::abi_utils::selector_from_name; +use crate::context::ChainInfo; +use crate::execution::call_info::{CallExecution, Retdata}; +use crate::execution::entry_point::CallEntryPoint; +use crate::execution::syscalls::syscall_tests::consts::REQUIRED_GAS_STORAGE_READ_WRITE_TEST; +use crate::execution::syscalls::syscall_tests::utils::assert_consistent_contract_version; +use crate::retdata; +use crate::state::state_api::StateReader; +use crate::test_utils::contracts::FeatureContract; +use crate::test_utils::initial_test_state::test_state; +use crate::test_utils::{trivial_external_entry_point_new, CairoVersion, BALANCE}; + +#[test_case(FeatureContract::TestContract(CairoVersion::Cairo1), REQUIRED_GAS_STORAGE_READ_WRITE_TEST; "VM")] +fn test_storage_read_write(test_contract: FeatureContract, expected_gas: u64) { + let chain_info = &ChainInfo::create_for_testing(); + let mut state = test_state(chain_info, BALANCE, &[(test_contract, 1)]); + + assert_consistent_contract_version(test_contract, &state); + + let key = felt!(1234_u16); + let value = felt!(18_u8); + let calldata = calldata![key, value]; + let entry_point_call = CallEntryPoint { + calldata, + entry_point_selector: selector_from_name("test_storage_read_write"), + ..trivial_external_entry_point_new(test_contract) + }; + let storage_address = entry_point_call.storage_address; + assert_eq!( + entry_point_call.execute_directly(&mut state).unwrap().execution, + CallExecution { + retdata: retdata![value], + gas_consumed: expected_gas, + ..CallExecution::default() + } + ); + + // Verify that the state has changed. + let value_from_state = + state.get_storage_at(storage_address, StorageKey::try_from(key).unwrap()).unwrap(); + assert_eq!(value_from_state, value); + + // ensure that the fallback system didn't replace the contract + assert_consistent_contract_version(test_contract, &state); +} diff --git a/crates/blockifier/src/execution/syscalls/syscall_tests/utils.rs b/crates/blockifier/src/execution/syscalls/syscall_tests/utils.rs new file mode 100644 index 0000000000..ef61800b0c --- /dev/null +++ b/crates/blockifier/src/execution/syscalls/syscall_tests/utils.rs @@ -0,0 +1,27 @@ +use assert_matches::assert_matches; + +use crate::execution::contract_class::ContractClass; +use crate::state::state_api::State; +use crate::test_utils::contracts::FeatureContract; + +pub fn assert_consistent_contract_version(contract: FeatureContract, state: &dyn State) { + let hash = contract.get_class_hash(); + match contract { + FeatureContract::SecurityTests + | FeatureContract::ERC20(_) + | FeatureContract::LegacyTestContract + | FeatureContract::AccountWithLongValidate(_) + | FeatureContract::AccountWithoutValidations(_) + | FeatureContract::Empty(_) + | FeatureContract::FaultyAccount(_) + | FeatureContract::TestContract(_) => { + // Assert contract uses VM + assert_matches!( + state + .get_compiled_contract_class(hash) + .unwrap_or_else(|_| panic!("Expected contract class at {hash}")), + ContractClass::V1(_) | ContractClass::V0(_) + ) + } + } +} diff --git a/crates/blockifier/src/execution/syscalls/syscalls_test.rs b/crates/blockifier/src/execution/syscalls/syscalls_test.rs deleted file mode 100644 index a5cb569630..0000000000 --- a/crates/blockifier/src/execution/syscalls/syscalls_test.rs +++ /dev/null @@ -1,986 +0,0 @@ -use std::collections::{BTreeMap, HashMap, HashSet}; - -use assert_matches::assert_matches; -use cairo_lang_utils::byte_array::BYTE_ARRAY_MAGIC; -use cairo_vm::types::builtin_name::BuiltinName; -use cairo_vm::vm::runners::cairo_runner::ExecutionResources; -use num_traits::Pow; -use pretty_assertions::assert_eq; -use rstest::rstest; -use starknet_api::core::{ - calculate_contract_address, - ChainId, - ContractAddress, - EthAddress, - PatriciaKey, -}; -use starknet_api::data_availability::DataAvailabilityMode; -use starknet_api::state::StorageKey; -use starknet_api::transaction::{ - AccountDeploymentData, - Calldata, - ContractAddressSalt, - EventContent, - EventData, - EventKey, - Fee, - L2ToL1Payload, - PaymasterData, - Resource, - ResourceBounds, - ResourceBoundsMapping, - Tip, - TransactionHash, - TransactionVersion, -}; -use starknet_api::{calldata, felt}; -use starknet_types_core::felt::Felt; -use test_case::test_case; - -use crate::abi::abi_utils::selector_from_name; -use crate::abi::constants; -use crate::context::ChainInfo; -use crate::execution::call_info::{ - CallExecution, - CallInfo, - MessageToL1, - OrderedEvent, - OrderedL2ToL1Message, - Retdata, -}; -use crate::execution::common_hints::ExecutionMode; -use crate::execution::entry_point::{CallEntryPoint, CallType}; -use crate::execution::errors::EntryPointExecutionError; -use crate::execution::syscalls::hint_processor::{ - EmitEventError, - BLOCK_NUMBER_OUT_OF_RANGE_ERROR, - L1_GAS, - L2_GAS, - OUT_OF_GAS_ERROR, -}; -use crate::execution::syscalls::SyscallSelector; -use crate::state::state_api::{State, StateReader}; -use crate::test_utils::contracts::FeatureContract; -use crate::test_utils::initial_test_state::test_state; -use crate::test_utils::{ - calldata_for_deploy_test, - create_calldata, - get_syscall_resources, - trivial_external_entry_point_new, - trivial_external_entry_point_with_address, - CairoVersion, - BALANCE, - CHAIN_ID_NAME, - CURRENT_BLOCK_NUMBER, - CURRENT_BLOCK_NUMBER_FOR_VALIDATE, - CURRENT_BLOCK_TIMESTAMP, - CURRENT_BLOCK_TIMESTAMP_FOR_VALIDATE, - TEST_SEQUENCER_ADDRESS, -}; -use crate::transaction::constants::QUERY_VERSION_BASE_BIT; -use crate::transaction::objects::{ - CommonAccountFields, - CurrentTransactionInfo, - DeprecatedTransactionInfo, - TransactionInfo, -}; -use crate::versioned_constants::VersionedConstants; -use crate::{check_entry_point_execution_error_for_custom_hint, nonce, retdata, storage_key}; -pub const REQUIRED_GAS_STORAGE_READ_WRITE_TEST: u64 = 27150; -pub const REQUIRED_GAS_CALL_CONTRACT_TEST: u64 = 105680; -pub const REQUIRED_GAS_LIBRARY_CALL_TEST: u64 = REQUIRED_GAS_CALL_CONTRACT_TEST; - -#[test] -fn test_storage_read_write() { - let test_contract = FeatureContract::TestContract(CairoVersion::Cairo1); - let chain_info = &ChainInfo::create_for_testing(); - let mut state = test_state(chain_info, BALANCE, &[(test_contract, 1)]); - - let key = felt!(1234_u16); - let value = felt!(18_u8); - let calldata = calldata![key, value]; - let entry_point_call = CallEntryPoint { - calldata, - entry_point_selector: selector_from_name("test_storage_read_write"), - ..trivial_external_entry_point_new(test_contract) - }; - let storage_address = entry_point_call.storage_address; - assert_eq!( - entry_point_call.execute_directly(&mut state).unwrap().execution, - CallExecution { - retdata: retdata![value], - gas_consumed: REQUIRED_GAS_STORAGE_READ_WRITE_TEST, - ..CallExecution::default() - } - ); - // Verify that the state has changed. - let value_from_state = - state.get_storage_at(storage_address, StorageKey::try_from(key).unwrap()).unwrap(); - assert_eq!(value_from_state, value); -} - -#[test] -fn test_call_contract() { - let test_contract = FeatureContract::TestContract(CairoVersion::Cairo1); - let chain_info = &ChainInfo::create_for_testing(); - let mut state = test_state(chain_info, BALANCE, &[(test_contract, 1)]); - - let outer_entry_point_selector = selector_from_name("test_call_contract"); - let calldata = create_calldata( - FeatureContract::TestContract(CairoVersion::Cairo1).get_instance_address(0), - "test_storage_read_write", - &[ - felt!(405_u16), // Calldata: address. - felt!(48_u8), // Calldata: value. - ], - ); - let entry_point_call = CallEntryPoint { - entry_point_selector: outer_entry_point_selector, - calldata, - ..trivial_external_entry_point_new(test_contract) - }; - assert_eq!( - entry_point_call.execute_directly(&mut state).unwrap().execution, - CallExecution { - retdata: retdata![felt!(48_u8)], - gas_consumed: REQUIRED_GAS_CALL_CONTRACT_TEST, - ..CallExecution::default() - } - ); -} - -#[test] -fn test_emit_event() { - let versioned_constants = VersionedConstants::create_for_testing(); - // Positive flow. - let keys = vec![felt!(2019_u16), felt!(2020_u16)]; - let data = vec![felt!(2021_u16), felt!(2022_u16), felt!(2023_u16)]; - // TODO(Ori, 1/2/2024): Write an indicative expect message explaining why the conversion works. - let n_emitted_events = vec![felt!(1_u16)]; - let call_info = emit_events(&n_emitted_events, &keys, &data).unwrap(); - let event = EventContent { - keys: keys.clone().into_iter().map(EventKey).collect(), - data: EventData(data.clone()), - }; - assert_eq!( - call_info.execution, - CallExecution { - events: vec![OrderedEvent { order: 0, event }], - gas_consumed: 49860, - ..Default::default() - } - ); - - // Negative flow, the data length exceeds the limit. - let max_event_data_length = versioned_constants.tx_event_limits.max_data_length; - let data_too_long = vec![felt!(2_u16); max_event_data_length + 1]; - let error = emit_events(&n_emitted_events, &keys, &data_too_long).unwrap_err(); - let expected_error = EmitEventError::ExceedsMaxDataLength { - data_length: max_event_data_length + 1, - max_data_length: max_event_data_length, - }; - assert!(error.to_string().contains(format!("{}", expected_error).as_str())); - - // Negative flow, the keys length exceeds the limit. - let max_event_keys_length = versioned_constants.tx_event_limits.max_keys_length; - let keys_too_long = vec![felt!(1_u16); max_event_keys_length + 1]; - let error = emit_events(&n_emitted_events, &keys_too_long, &data).unwrap_err(); - let expected_error = EmitEventError::ExceedsMaxKeysLength { - keys_length: max_event_keys_length + 1, - max_keys_length: max_event_keys_length, - }; - assert!(error.to_string().contains(format!("{}", expected_error).as_str())); - - // Negative flow, the number of events exceeds the limit. - let max_n_emitted_events = versioned_constants.tx_event_limits.max_n_emitted_events; - let n_emitted_events_too_big = vec![felt!( - u16::try_from(max_n_emitted_events + 1).expect("Failed to convert usize to u16.") - )]; - let error = emit_events(&n_emitted_events_too_big, &keys, &data).unwrap_err(); - let expected_error = EmitEventError::ExceedsMaxNumberOfEmittedEvents { - n_emitted_events: max_n_emitted_events + 1, - max_n_emitted_events, - }; - assert!(error.to_string().contains(format!("{}", expected_error).as_str())); -} - -fn emit_events( - n_emitted_events: &[Felt], - keys: &[Felt], - data: &[Felt], -) -> Result { - let test_contract = FeatureContract::TestContract(CairoVersion::Cairo1); - let chain_info = &ChainInfo::create_for_testing(); - let mut state = test_state(chain_info, BALANCE, &[(test_contract, 1)]); - let calldata = Calldata( - [ - n_emitted_events.to_owned(), - vec![felt!(u16::try_from(keys.len()).expect("Failed to convert usize to u16."))], - keys.to_vec(), - vec![felt!(u16::try_from(data.len()).expect("Failed to convert usize to u16."))], - data.to_vec(), - ] - .concat() - .into(), - ); - - let entry_point_call = CallEntryPoint { - entry_point_selector: selector_from_name("test_emit_events"), - calldata, - ..trivial_external_entry_point_new(test_contract) - }; - - entry_point_call.execute_directly(&mut state) -} - -#[test] -fn test_get_block_hash() { - let test_contract = FeatureContract::TestContract(CairoVersion::Cairo1); - let chain_info = &ChainInfo::create_for_testing(); - let mut state = test_state(chain_info, BALANCE, &[(test_contract, 1)]); - - // Initialize block number -> block hash entry. - let upper_bound_block_number = CURRENT_BLOCK_NUMBER - constants::STORED_BLOCK_HASH_BUFFER; - let block_number = felt!(upper_bound_block_number); - let block_hash = felt!(66_u64); - let key = StorageKey::try_from(block_number).unwrap(); - let block_hash_contract_address = - ContractAddress::try_from(Felt::from(constants::BLOCK_HASH_CONTRACT_ADDRESS)).unwrap(); - state.set_storage_at(block_hash_contract_address, key, block_hash).unwrap(); - - // Positive flow. - let calldata = calldata![block_number]; - let entry_point_call = CallEntryPoint { - entry_point_selector: selector_from_name("test_get_block_hash"), - calldata, - ..trivial_external_entry_point_new(test_contract) - }; - - assert_eq!( - entry_point_call.clone().execute_directly(&mut state).unwrap().execution, - CallExecution { gas_consumed: 9680, ..CallExecution::from_retdata(retdata![block_hash]) } - ); - - // Negative flow. Execution mode is Validate. - let error = entry_point_call.execute_directly_in_validate_mode(&mut state).unwrap_err(); - check_entry_point_execution_error_for_custom_hint!( - &error, - "Unauthorized syscall get_block_hash in execution mode Validate.", - ); - - // Negative flow: Block number out of range. - let requested_block_number = CURRENT_BLOCK_NUMBER - constants::STORED_BLOCK_HASH_BUFFER + 1; - let block_number = felt!(requested_block_number); - let calldata = calldata![block_number]; - let entry_point_call = CallEntryPoint { - entry_point_selector: selector_from_name("test_get_block_hash"), - calldata, - ..trivial_external_entry_point_new(test_contract) - }; - let error = entry_point_call.execute_directly(&mut state).unwrap_err(); - assert_matches!(error, EntryPointExecutionError::ExecutionFailed{ error_data } - if error_data == vec![felt!(BLOCK_NUMBER_OUT_OF_RANGE_ERROR)]); -} - -#[test] -fn test_keccak() { - let test_contract = FeatureContract::TestContract(CairoVersion::Cairo1); - let chain_info = &ChainInfo::create_for_testing(); - let mut state = test_state(chain_info, BALANCE, &[(test_contract, 1)]); - - let calldata = Calldata(vec![].into()); - let entry_point_call = CallEntryPoint { - entry_point_selector: selector_from_name("test_keccak"), - calldata, - ..trivial_external_entry_point_new(test_contract) - }; - - assert_eq!( - entry_point_call.execute_directly(&mut state).unwrap().execution, - CallExecution { gas_consumed: 256250, ..CallExecution::from_retdata(retdata![]) } - ); -} - -#[test] -fn test_sha256() { - let test_contract = FeatureContract::TestContract(CairoVersion::Cairo1); - let chain_info = &ChainInfo::create_for_testing(); - let mut state = test_state(chain_info, BALANCE, &[(test_contract, 1)]); - - let calldata = Calldata(vec![].into()); - let entry_point_call = CallEntryPoint { - entry_point_selector: selector_from_name("test_sha256"), - calldata, - ..trivial_external_entry_point_new(test_contract) - }; - - assert_eq!( - entry_point_call.execute_directly(&mut state).unwrap().execution, - CallExecution { gas_consumed: 892990, ..CallExecution::from_retdata(retdata![]) } - ); -} - -fn verify_compiler_version(contract: FeatureContract, expected_version: &str) { - // Read and parse file content. - let raw_contract: serde_json::Value = - serde_json::from_str(&contract.get_raw_class()).expect("Error parsing JSON"); - - // Verify version. - if let Some(compiler_version) = raw_contract["compiler_version"].as_str() { - assert_eq!(compiler_version, expected_version); - } else { - panic!("'compiler_version' not found or not a valid string in JSON."); - } -} - -#[test_case( - ExecutionMode::Validate, - TransactionVersion::ONE, - false, - false; - "Validate execution mode: block info fields should be zeroed. Transaction V1.")] -#[test_case( - ExecutionMode::Execute, - TransactionVersion::ONE, - false, - false; - "Execute execution mode: block info should be as usual. Transaction V1.")] -#[test_case( - ExecutionMode::Validate, - TransactionVersion::THREE, - false, - false; - "Validate execution mode: block info fields should be zeroed. Transaction V3.")] -#[test_case( - ExecutionMode::Execute, - TransactionVersion::THREE, - false, - false; - "Execute execution mode: block info should be as usual. Transaction V3.")] -#[test_case( - ExecutionMode::Execute, - TransactionVersion::ONE, - true, - false; - "Legacy contract. Execute execution mode: block info should be as usual. Transaction V1.")] -#[test_case( - ExecutionMode::Execute, - TransactionVersion::THREE, - true, - false; - "Legacy contract. Execute execution mode: block info should be as usual. Transaction V3.")] -#[test_case( - ExecutionMode::Execute, - TransactionVersion::THREE, - false, - true; - "Execute execution mode: block info should be as usual. Transaction V3. Query.")] -fn test_get_execution_info( - execution_mode: ExecutionMode, - mut version: TransactionVersion, - is_legacy: bool, - only_query: bool, -) { - let legacy_contract = FeatureContract::LegacyTestContract; - let test_contract = FeatureContract::TestContract(CairoVersion::Cairo1); - let state = &mut test_state( - &ChainInfo::create_for_testing(), - BALANCE, - &[(legacy_contract, 1), (test_contract, 1)], - ); - let expected_block_info = match execution_mode { - ExecutionMode::Validate => [ - // Rounded block number. - felt!(CURRENT_BLOCK_NUMBER_FOR_VALIDATE), - // Rounded timestamp. - felt!(CURRENT_BLOCK_TIMESTAMP_FOR_VALIDATE), - Felt::ZERO, - ], - ExecutionMode::Execute => [ - felt!(CURRENT_BLOCK_NUMBER), // Block number. - felt!(CURRENT_BLOCK_TIMESTAMP), // Block timestamp. - Felt::from_hex(TEST_SEQUENCER_ADDRESS).unwrap(), - ], - }; - - let (test_contract_address, expected_unsupported_fields) = if is_legacy { - verify_compiler_version(legacy_contract, "2.1.0"); - (legacy_contract.get_instance_address(0), vec![]) - } else { - ( - test_contract.get_instance_address(0), - vec![ - Felt::ZERO, // Tip. - Felt::ZERO, // Paymaster data. - Felt::ZERO, // Nonce DA. - Felt::ZERO, // Fee DA. - Felt::ZERO, // Account data. - ], - ) - }; - - if only_query { - let simulate_version_base = Pow::pow(Felt::from(2_u8), QUERY_VERSION_BASE_BIT); - let query_version = simulate_version_base + version.0; - version = TransactionVersion(query_version); - } - - let tx_hash = TransactionHash(felt!(1991_u16)); - let max_fee = Fee(42); - let nonce = nonce!(3_u16); - let sender_address = test_contract_address; - - let expected_tx_info: Vec; - let mut expected_resource_bounds: Vec = vec![]; - let tx_info: TransactionInfo; - if version == TransactionVersion::ONE { - expected_tx_info = vec![ - version.0, // Transaction version. - *sender_address.0.key(), // Account address. - felt!(max_fee.0), // Max fee. - Felt::ZERO, // Signature. - tx_hash.0, // Transaction hash. - felt!(&*ChainId::Other(CHAIN_ID_NAME.to_string()).as_hex()), // Chain ID. - nonce.0, // Nonce. - ]; - if !is_legacy { - expected_resource_bounds = vec![ - felt!(0_u16), // Length of resource bounds array. - ]; - } - tx_info = TransactionInfo::Deprecated(DeprecatedTransactionInfo { - common_fields: CommonAccountFields { - transaction_hash: tx_hash, - version: TransactionVersion::ONE, - nonce, - sender_address, - only_query, - ..Default::default() - }, - max_fee, - }); - } else { - let max_amount = Fee(13); - let max_price_per_unit = Fee(61); - expected_tx_info = vec![ - version.0, // Transaction version. - *sender_address.0.key(), // Account address. - Felt::ZERO, // Max fee. - Felt::ZERO, // Signature. - tx_hash.0, // Transaction hash. - felt!(&*ChainId::Other(CHAIN_ID_NAME.to_string()).as_hex()), // Chain ID. - nonce.0, // Nonce. - ]; - if !is_legacy { - expected_resource_bounds = vec![ - Felt::from(2u32), // Length of ResourceBounds array. - felt!(L1_GAS), // Resource. - felt!(max_amount.0), // Max amount. - felt!(max_price_per_unit.0), // Max price per unit. - felt!(L2_GAS), // Resource. - Felt::ZERO, // Max amount. - Felt::ZERO, // Max price per unit. - ]; - } - tx_info = TransactionInfo::Current(CurrentTransactionInfo { - common_fields: CommonAccountFields { - transaction_hash: tx_hash, - version: TransactionVersion::THREE, - nonce, - sender_address, - only_query, - ..Default::default() - }, - resource_bounds: ResourceBoundsMapping(BTreeMap::from([ - ( - Resource::L1Gas, - // TODO(Ori, 1/2/2024): Write an indicative expect message explaining why the - // convertion works. - ResourceBounds { - max_amount: max_amount - .0 - .try_into() - .expect("Failed to convert u128 to u64."), - max_price_per_unit: max_price_per_unit.0, - }, - ), - (Resource::L2Gas, ResourceBounds { max_amount: 0, max_price_per_unit: 0 }), - ])), - tip: Tip::default(), - nonce_data_availability_mode: DataAvailabilityMode::L1, - fee_data_availability_mode: DataAvailabilityMode::L1, - paymaster_data: PaymasterData::default(), - account_deployment_data: AccountDeploymentData::default(), - }); - } - - let entry_point_selector = selector_from_name("test_get_execution_info"); - let expected_call_info = vec![ - felt!(0_u16), // Caller address. - *test_contract_address.0.key(), // Storage address. - entry_point_selector.0, // Entry point selector. - ]; - let entry_point_call = CallEntryPoint { - entry_point_selector, - code_address: None, - calldata: Calldata( - [ - expected_block_info.to_vec(), - expected_tx_info, - expected_resource_bounds, - expected_unsupported_fields, - expected_call_info, - ] - .concat() - .into(), - ), - ..trivial_external_entry_point_with_address(test_contract_address) - }; - - let result = match execution_mode { - ExecutionMode::Validate => { - entry_point_call.execute_directly_given_tx_info_in_validate_mode(state, tx_info, false) - } - ExecutionMode::Execute => { - entry_point_call.execute_directly_given_tx_info(state, tx_info, false) - } - }; - - assert!(!result.unwrap().execution.failed); -} - -#[test] -fn test_library_call() { - let test_contract = FeatureContract::TestContract(CairoVersion::Cairo1); - let chain_info = &ChainInfo::create_for_testing(); - let mut state = test_state(chain_info, BALANCE, &[(test_contract, 1)]); - - let inner_entry_point_selector = selector_from_name("test_storage_read_write"); - let test_contract = FeatureContract::TestContract(CairoVersion::Cairo1); - let calldata = calldata![ - test_contract.get_class_hash().0, // Class hash. - inner_entry_point_selector.0, // Function selector. - felt!(2_u8), // Calldata length. - felt!(1234_u16), // Calldata: address. - felt!(91_u8) // Calldata: value. - ]; - let entry_point_call = CallEntryPoint { - entry_point_selector: selector_from_name("test_library_call"), - calldata, - class_hash: Some(test_contract.get_class_hash()), - ..trivial_external_entry_point_new(test_contract) - }; - - assert_eq!( - entry_point_call.execute_directly(&mut state).unwrap().execution, - CallExecution { - retdata: retdata![felt!(91_u16)], - gas_consumed: REQUIRED_GAS_LIBRARY_CALL_TEST, - ..Default::default() - } - ); -} - -#[test] -fn test_library_call_assert_fails() { - let test_contract = FeatureContract::TestContract(CairoVersion::Cairo1); - let chain_info = &ChainInfo::create_for_testing(); - let mut state = test_state(chain_info, BALANCE, &[(test_contract, 1)]); - let inner_entry_point_selector = selector_from_name("assert_eq"); - let calldata = calldata![ - test_contract.get_class_hash().0, // Class hash. - inner_entry_point_selector.0, // Function selector. - felt!(2_u8), // Calldata length. - felt!(0_u8), // Calldata: first assert value. - felt!(1_u8) // Calldata: second assert value. - ]; - let entry_point_call = CallEntryPoint { - entry_point_selector: selector_from_name("test_library_call"), - calldata, - class_hash: Some(test_contract.get_class_hash()), - ..trivial_external_entry_point_new(test_contract) - }; - - assert!( - entry_point_call.execute_directly(&mut state).unwrap_err().to_string().contains("x != y") - ); -} - -#[test] -fn test_nested_library_call() { - let test_contract = FeatureContract::TestContract(CairoVersion::Cairo1); - let chain_info = &ChainInfo::create_for_testing(); - let mut state = test_state(chain_info, BALANCE, &[(test_contract, 1)]); - - let (key, value) = (255_u64, 44_u64); - let outer_entry_point_selector = selector_from_name("test_library_call"); - let inner_entry_point_selector = selector_from_name("test_storage_read_write"); - let test_class_hash = test_contract.get_class_hash(); - let main_entry_point_calldata = calldata![ - test_class_hash.0, // Class hash. - outer_entry_point_selector.0, // Library call function selector. - inner_entry_point_selector.0, // Storage function selector. - felt!(key), // Calldata: address. - felt!(value) // Calldata: value. - ]; - - // Create expected call info tree. - let main_entry_point = CallEntryPoint { - entry_point_selector: selector_from_name("test_nested_library_call"), - calldata: main_entry_point_calldata, - class_hash: Some(test_class_hash), - initial_gas: 9999906600, - ..trivial_external_entry_point_new(test_contract) - }; - let nested_storage_entry_point = CallEntryPoint { - entry_point_selector: inner_entry_point_selector, - calldata: calldata![felt!(key + 1), felt!(value + 1)], - class_hash: Some(test_class_hash), - code_address: None, - call_type: CallType::Delegate, - initial_gas: 9999745020, - ..trivial_external_entry_point_new(test_contract) - }; - let library_entry_point = CallEntryPoint { - entry_point_selector: outer_entry_point_selector, - calldata: calldata![ - test_class_hash.0, // Class hash. - inner_entry_point_selector.0, // Storage function selector. - felt!(2_u8), // Calldata: address. - felt!(key + 1), // Calldata: address. - felt!(value + 1) // Calldata: value. - ], - class_hash: Some(test_class_hash), - code_address: None, - call_type: CallType::Delegate, - initial_gas: 9999823550, - ..trivial_external_entry_point_new(test_contract) - }; - let storage_entry_point = CallEntryPoint { - calldata: calldata![felt!(key), felt!(value)], - initial_gas: 9999656870, - ..nested_storage_entry_point - }; - let storage_entry_point_resources = ExecutionResources { - n_steps: 243, - n_memory_holes: 0, - builtin_instance_counter: HashMap::from([(BuiltinName::range_check, 7)]), - }; - let nested_storage_call_info = CallInfo { - call: nested_storage_entry_point, - execution: CallExecution { - retdata: retdata![felt!(value + 1)], - gas_consumed: REQUIRED_GAS_STORAGE_READ_WRITE_TEST, - ..CallExecution::default() - }, - resources: storage_entry_point_resources.clone(), - storage_read_values: vec![felt!(value + 1)], - accessed_storage_keys: HashSet::from([storage_key!(key + 1)]), - ..Default::default() - }; - let library_call_resources = &get_syscall_resources(SyscallSelector::LibraryCall) - + &ExecutionResources { - n_steps: 388, - n_memory_holes: 0, - builtin_instance_counter: HashMap::from([(BuiltinName::range_check, 15)]), - }; - let library_call_info = CallInfo { - call: library_entry_point, - execution: CallExecution { - retdata: retdata![felt!(value + 1)], - gas_consumed: REQUIRED_GAS_LIBRARY_CALL_TEST, - ..CallExecution::default() - }, - resources: library_call_resources, - inner_calls: vec![nested_storage_call_info], - ..Default::default() - }; - let storage_call_info = CallInfo { - call: storage_entry_point, - execution: CallExecution { - retdata: retdata![felt!(value)], - gas_consumed: REQUIRED_GAS_STORAGE_READ_WRITE_TEST, - ..CallExecution::default() - }, - resources: storage_entry_point_resources, - storage_read_values: vec![felt!(value)], - accessed_storage_keys: HashSet::from([storage_key!(key)]), - ..Default::default() - }; - - let main_call_resources = &(&get_syscall_resources(SyscallSelector::LibraryCall) * 3) - + &ExecutionResources { - n_steps: 749, - n_memory_holes: 2, - builtin_instance_counter: HashMap::from([(BuiltinName::range_check, 27)]), - }; - let expected_call_info = CallInfo { - call: main_entry_point.clone(), - execution: CallExecution { - retdata: retdata![felt!(value)], - gas_consumed: 276880, - ..CallExecution::default() - }, - resources: main_call_resources, - inner_calls: vec![library_call_info, storage_call_info], - ..Default::default() - }; - - assert_eq!(main_entry_point.execute_directly(&mut state).unwrap(), expected_call_info); -} - -#[test] -fn test_replace_class() { - let test_contract = FeatureContract::TestContract(CairoVersion::Cairo1); - let empty_contract = FeatureContract::Empty(CairoVersion::Cairo1); - let empty_contract_cairo0 = FeatureContract::Empty(CairoVersion::Cairo0); - let mut state = test_state( - &ChainInfo::create_for_testing(), - BALANCE, - &[(test_contract, 1), (empty_contract, 0), (empty_contract_cairo0, 0)], - ); - let contract_address = test_contract.get_instance_address(0); - - // Negative flow. - - // Replace with undeclared class hash. - let entry_point_call = CallEntryPoint { - calldata: calldata![felt!(1234_u16)], - entry_point_selector: selector_from_name("test_replace_class"), - ..trivial_external_entry_point_new(test_contract) - }; - let error = entry_point_call.execute_directly(&mut state).unwrap_err().to_string(); - assert!(error.contains("is not declared")); - - // Replace with Cairo 0 class hash. - let v0_class_hash = empty_contract_cairo0.get_class_hash(); - - let entry_point_call = CallEntryPoint { - calldata: calldata![v0_class_hash.0], - entry_point_selector: selector_from_name("test_replace_class"), - ..trivial_external_entry_point_new(test_contract) - }; - let error = entry_point_call.execute_directly(&mut state).unwrap_err().to_string(); - assert!(error.contains("Cannot replace V1 class hash with V0 class hash")); - - // Positive flow. - let old_class_hash = test_contract.get_class_hash(); - let new_class_hash = empty_contract.get_class_hash(); - assert_eq!(state.get_class_hash_at(contract_address).unwrap(), old_class_hash); - let entry_point_call = CallEntryPoint { - calldata: calldata![new_class_hash.0], - entry_point_selector: selector_from_name("test_replace_class"), - ..trivial_external_entry_point_new(test_contract) - }; - assert_eq!( - entry_point_call.execute_directly(&mut state).unwrap().execution, - CallExecution { gas_consumed: 9750, ..Default::default() } - ); - assert_eq!(state.get_class_hash_at(contract_address).unwrap(), new_class_hash); -} - -#[test] -fn test_secp256k1() { - let test_contract = FeatureContract::TestContract(CairoVersion::Cairo1); - let chain_info = &ChainInfo::create_for_testing(); - let mut state = test_state(chain_info, BALANCE, &[(test_contract, 1)]); - - let calldata = Calldata(vec![].into()); - let entry_point_call = CallEntryPoint { - entry_point_selector: selector_from_name("test_secp256k1"), - calldata, - ..trivial_external_entry_point_new(test_contract) - }; - - assert_eq!( - entry_point_call.execute_directly(&mut state).unwrap().execution, - CallExecution { gas_consumed: 17033810_u64, ..Default::default() } - ); -} - -#[test] -fn test_secp256r1() { - let test_contract = FeatureContract::TestContract(CairoVersion::Cairo1); - let chain_info = &ChainInfo::create_for_testing(); - let mut state = test_state(chain_info, BALANCE, &[(test_contract, 1)]); - - let calldata = Calldata(vec![].into()); - let entry_point_call = CallEntryPoint { - entry_point_selector: selector_from_name("test_secp256r1"), - calldata, - ..trivial_external_entry_point_new(test_contract) - }; - - assert_eq!( - entry_point_call.execute_directly(&mut state).unwrap().execution, - CallExecution { gas_consumed: 27582260_u64, ..Default::default() } - ); -} - -#[test] -fn test_send_message_to_l1() { - let test_contract = FeatureContract::TestContract(CairoVersion::Cairo1); - let chain_info = &ChainInfo::create_for_testing(); - let mut state = test_state(chain_info, BALANCE, &[(test_contract, 1)]); - - let to_address = felt!(1234_u16); - let payload = vec![felt!(2019_u16), felt!(2020_u16), felt!(2021_u16)]; - let calldata = Calldata( - [ - vec![ - to_address, - // TODO(Ori, 1/2/2024): Write an indicative expect message explaining why the - // convertion works. - felt!(u64::try_from(payload.len()).expect("Failed to convert usize to u64.")), - ], - payload.clone(), - ] - .concat() - .into(), - ); - let entry_point_call = CallEntryPoint { - entry_point_selector: selector_from_name("test_send_message_to_l1"), - calldata, - ..trivial_external_entry_point_new(test_contract) - }; - - let to_address = EthAddress::try_from(to_address).unwrap(); - let message = MessageToL1 { to_address, payload: L2ToL1Payload(payload) }; - - assert_eq!( - entry_point_call.execute_directly(&mut state).unwrap().execution, - CallExecution { - l2_to_l1_messages: vec![OrderedL2ToL1Message { order: 0, message }], - gas_consumed: 22990, - ..Default::default() - } - ); -} - -#[rstest] -#[case::no_constructor( - false, false, true, None - // No constructor, trivial calldata, address available; Positive flow. -)] -#[case::no_constructor_nonempty_calldata( - false, true, true, - Some( - "Invalid input: constructor_calldata; Cannot pass calldata to a contract with no constructor.".to_string() - ) - // No constructor, nontrivial calldata, address available; Negative flow. -)] -#[case::with_constructor( - true, true, true, None - // With constructor, nontrivial calldata, address available; Positive flow. -)] -#[case::deploy_to_unavailable_address( - true, true, false, - Some("is unavailable for deployment.".to_string()) - // With constructor, nontrivial calldata, address unavailable; Negative flow. -)] -fn test_deploy( - #[case] constructor_exists: bool, - #[case] supply_constructor_calldata: bool, - #[case] available_for_deployment: bool, - #[case] expected_error: Option, -) { - let test_contract = FeatureContract::TestContract(CairoVersion::Cairo1); - let empty_contract = FeatureContract::Empty(CairoVersion::Cairo1); - let mut state = - test_state(&ChainInfo::create_for_testing(), 0, &[(empty_contract, 0), (test_contract, 1)]); - - let class_hash = if constructor_exists { - test_contract.get_class_hash() - } else { - empty_contract.get_class_hash() - }; - let constructor_calldata = if supply_constructor_calldata { - vec![ - felt!(1_u8), // Calldata: address. - felt!(1_u8), // Calldata: value. - ] - } else { - vec![] - }; - - let calldata = calldata_for_deploy_test(class_hash, &constructor_calldata, true); - - let entry_point_call = CallEntryPoint { - entry_point_selector: selector_from_name("test_deploy"), - calldata, - ..trivial_external_entry_point_new(test_contract) - }; - - if !available_for_deployment { - // Deploy an instance of the contract for the scenario: deploy_to_unavailable_address. - entry_point_call.clone().execute_directly(&mut state).unwrap(); - } - - if let Some(expected_error) = expected_error { - let error = entry_point_call.execute_directly(&mut state).unwrap_err().to_string(); - assert!(error.contains(expected_error.as_str())); - return; - } - - // No errors expected. - let contract_address = calculate_contract_address( - ContractAddressSalt::default(), - class_hash, - &Calldata(constructor_calldata.clone().into()), - test_contract.get_instance_address(0), - ) - .unwrap(); - let deploy_call = &entry_point_call.execute_directly(&mut state).unwrap().inner_calls[0]; - assert_eq!(deploy_call.call.storage_address, contract_address); - let mut retdata = retdata![]; - let gas_consumed = if constructor_calldata.is_empty() { - 0 - } else { - retdata.0.push(constructor_calldata[0]); - 10140 - }; - assert_eq!( - deploy_call.execution, - CallExecution { retdata, gas_consumed, ..CallExecution::default() } - ); - assert_eq!(state.get_class_hash_at(contract_address).unwrap(), class_hash); -} - -#[test] -fn test_out_of_gas() { - let test_contract = FeatureContract::TestContract(CairoVersion::Cairo1); - let chain_info = &ChainInfo::create_for_testing(); - let mut state = test_state(chain_info, BALANCE, &[(test_contract, 1)]); - - let key = felt!(1234_u16); - let value = felt!(18_u8); - let calldata = calldata![key, value]; - let entry_point_call = CallEntryPoint { - calldata, - entry_point_selector: selector_from_name("test_storage_read_write"), - initial_gas: REQUIRED_GAS_STORAGE_READ_WRITE_TEST - 1, - ..trivial_external_entry_point_new(test_contract) - }; - let error = entry_point_call.execute_directly(&mut state).unwrap_err(); - assert_matches!(error, EntryPointExecutionError::ExecutionFailed{ error_data } - if error_data == vec![felt!(OUT_OF_GAS_ERROR)]); -} - -#[test] -fn test_syscall_failure_format() { - let error_data = vec![ - // Magic to indicate that this is a byte array. - BYTE_ARRAY_MAGIC, - // the number of full words in the byte array. - "0x00", - // The pending word of the byte array: "Execution failure" - "0x457865637574696f6e206661696c757265", - // The length of the pending word. - "0x11", - ] - .into_iter() - .map(|x| Felt::from_hex(x).unwrap()) - .collect(); - let error = EntryPointExecutionError::ExecutionFailed { error_data }; - assert_eq!(error.to_string(), "Execution failed. Failure reason: \"Execution failure\"."); -} From 956639e82389cffed372399047c7cbcae48ea30d Mon Sep 17 00:00:00 2001 From: Bohdan Ohorodnii Date: Tue, 6 Aug 2024 19:20:21 +0300 Subject: [PATCH 2/6] fix: apply cargo-fmt --- .../syscalls/syscall_tests/get_block_hash.rs | 13 ++++++--- .../syscall_tests/get_execution_info.rs | 29 +++++++++++++++---- .../syscalls/syscall_tests/library_call.rs | 8 +++-- 3 files changed, 38 insertions(+), 12 deletions(-) diff --git a/crates/blockifier/src/execution/syscalls/syscall_tests/get_block_hash.rs b/crates/blockifier/src/execution/syscalls/syscall_tests/get_block_hash.rs index 69cef2fdda..f014d076e7 100644 --- a/crates/blockifier/src/execution/syscalls/syscall_tests/get_block_hash.rs +++ b/crates/blockifier/src/execution/syscalls/syscall_tests/get_block_hash.rs @@ -18,7 +18,10 @@ use crate::test_utils::contracts::FeatureContract; use crate::test_utils::dict_state_reader::DictStateReader; use crate::test_utils::initial_test_state::test_state; use crate::test_utils::{ - trivial_external_entry_point_new, CairoVersion, BALANCE, CURRENT_BLOCK_NUMBER, + trivial_external_entry_point_new, + CairoVersion, + BALANCE, + CURRENT_BLOCK_NUMBER, }; use crate::{check_entry_point_execution_error_for_custom_hint, retdata}; @@ -79,9 +82,11 @@ fn negative_flow_execution_mode_validate(test_contract: FeatureContract) { "Unauthorized syscall get_block_hash in execution mode Validate.", ); - assert!(error - .to_string() - .contains("Unauthorized syscall get_block_hash in execution mode Validate")); + assert!( + error + .to_string() + .contains("Unauthorized syscall get_block_hash in execution mode Validate") + ); assert_consistent_contract_version(test_contract, &state); } diff --git a/crates/blockifier/src/execution/syscalls/syscall_tests/get_execution_info.rs b/crates/blockifier/src/execution/syscalls/syscall_tests/get_execution_info.rs index 43570183df..89501aa6af 100644 --- a/crates/blockifier/src/execution/syscalls/syscall_tests/get_execution_info.rs +++ b/crates/blockifier/src/execution/syscalls/syscall_tests/get_execution_info.rs @@ -6,8 +6,16 @@ use starknet_api::core::ChainId; use starknet_api::data_availability::DataAvailabilityMode; use starknet_api::felt; use starknet_api::transaction::{ - AccountDeploymentData, Calldata, Fee, PaymasterData, Resource, ResourceBounds, - ResourceBoundsMapping, Tip, TransactionHash, TransactionVersion, + AccountDeploymentData, + Calldata, + Fee, + PaymasterData, + Resource, + ResourceBounds, + ResourceBoundsMapping, + Tip, + TransactionHash, + TransactionVersion, }; use starknet_types_core::felt::Felt; use test_case::test_case; @@ -22,13 +30,22 @@ use crate::nonce; use crate::test_utils::contracts::FeatureContract; use crate::test_utils::initial_test_state::test_state; use crate::test_utils::{ - trivial_external_entry_point_with_address, CairoVersion, BALANCE, CHAIN_ID_NAME, - CURRENT_BLOCK_NUMBER, CURRENT_BLOCK_NUMBER_FOR_VALIDATE, CURRENT_BLOCK_TIMESTAMP, - CURRENT_BLOCK_TIMESTAMP_FOR_VALIDATE, TEST_SEQUENCER_ADDRESS, + trivial_external_entry_point_with_address, + CairoVersion, + BALANCE, + CHAIN_ID_NAME, + CURRENT_BLOCK_NUMBER, + CURRENT_BLOCK_NUMBER_FOR_VALIDATE, + CURRENT_BLOCK_TIMESTAMP, + CURRENT_BLOCK_TIMESTAMP_FOR_VALIDATE, + TEST_SEQUENCER_ADDRESS, }; use crate::transaction::constants::QUERY_VERSION_BASE_BIT; use crate::transaction::objects::{ - CommonAccountFields, CurrentTransactionInfo, DeprecatedTransactionInfo, TransactionInfo, + CommonAccountFields, + CurrentTransactionInfo, + DeprecatedTransactionInfo, + TransactionInfo, }; #[test_case( diff --git a/crates/blockifier/src/execution/syscalls/syscall_tests/library_call.rs b/crates/blockifier/src/execution/syscalls/syscall_tests/library_call.rs index 63574545f0..1d13bde93e 100644 --- a/crates/blockifier/src/execution/syscalls/syscall_tests/library_call.rs +++ b/crates/blockifier/src/execution/syscalls/syscall_tests/library_call.rs @@ -14,14 +14,18 @@ use crate::context::ChainInfo; use crate::execution::call_info::{CallExecution, CallInfo, Retdata}; use crate::execution::entry_point::{CallEntryPoint, CallType}; use crate::execution::syscalls::syscall_tests::consts::{ - REQUIRED_GAS_LIBRARY_CALL_TEST, REQUIRED_GAS_STORAGE_READ_WRITE_TEST, + REQUIRED_GAS_LIBRARY_CALL_TEST, + REQUIRED_GAS_STORAGE_READ_WRITE_TEST, }; use crate::execution::syscalls::SyscallSelector; use crate::retdata; use crate::test_utils::contracts::FeatureContract; use crate::test_utils::initial_test_state::test_state; use crate::test_utils::{ - get_syscall_resources, trivial_external_entry_point_new, CairoVersion, BALANCE, + get_syscall_resources, + trivial_external_entry_point_new, + CairoVersion, + BALANCE, }; #[test_case(FeatureContract::TestContract(CairoVersion::Cairo1), REQUIRED_GAS_LIBRARY_CALL_TEST; "VM")] From 47f3557fb359fa7f62391c1569af3fc3ce2b5fd5 Mon Sep 17 00:00:00 2001 From: Bohdan Ohorodnii Date: Wed, 7 Aug 2024 19:46:52 +0300 Subject: [PATCH 3/6] fix: address review comments --- .../syscalls/syscall_tests/call_contract.rs | 10 +------ .../syscall_tests/{consts.rs => constants.rs} | 0 .../syscalls/syscall_tests/deploy.rs | 24 ++--------------- .../syscalls/syscall_tests/emit_event.rs | 3 --- .../syscalls/syscall_tests/get_block_hash.rs | 13 --------- .../syscall_tests/get_execution_info.rs | 7 ++--- .../syscalls/syscall_tests/library_call.rs | 2 +- .../execution/syscalls/syscall_tests/mod.rs | 3 +-- .../syscalls/syscall_tests/out_of_gas.rs | 2 +- .../syscall_tests/storage_read_write.rs | 8 +----- .../execution/syscalls/syscall_tests/utils.rs | 27 ------------------- 11 files changed, 9 insertions(+), 90 deletions(-) rename crates/blockifier/src/execution/syscalls/syscall_tests/{consts.rs => constants.rs} (100%) delete mode 100644 crates/blockifier/src/execution/syscalls/syscall_tests/utils.rs diff --git a/crates/blockifier/src/execution/syscalls/syscall_tests/call_contract.rs b/crates/blockifier/src/execution/syscalls/syscall_tests/call_contract.rs index 39d97e5e68..f73b04027b 100644 --- a/crates/blockifier/src/execution/syscalls/syscall_tests/call_contract.rs +++ b/crates/blockifier/src/execution/syscalls/syscall_tests/call_contract.rs @@ -2,12 +2,11 @@ use pretty_assertions::assert_eq; use starknet_api::felt; use test_case::test_case; -use super::consts::REQUIRED_GAS_CALL_CONTRACT_TEST; +use super::constants::REQUIRED_GAS_CALL_CONTRACT_TEST; use crate::abi::abi_utils::selector_from_name; use crate::context::ChainInfo; use crate::execution::call_info::{CallExecution, Retdata}; use crate::execution::entry_point::CallEntryPoint; -use crate::execution::syscalls::syscall_tests::utils::assert_consistent_contract_version; use crate::retdata; use crate::test_utils::contracts::FeatureContract; use crate::test_utils::initial_test_state::test_state; @@ -27,9 +26,6 @@ fn test_call_contract( let chain_info = &ChainInfo::create_for_testing(); let mut state = test_state(chain_info, BALANCE, &[(outer_contract, 1), (inner_contract, 1)]); - assert_consistent_contract_version(outer_contract, &state); - assert_consistent_contract_version(inner_contract, &state); - let outer_entry_point_selector = selector_from_name("test_call_contract"); let calldata = create_calldata( inner_contract.get_instance_address(0), @@ -53,8 +49,4 @@ fn test_call_contract( ..CallExecution::default() } ); - - // ensure that the fallback system didn't replace the contract - assert_consistent_contract_version(outer_contract, &state); - assert_consistent_contract_version(inner_contract, &state); } diff --git a/crates/blockifier/src/execution/syscalls/syscall_tests/consts.rs b/crates/blockifier/src/execution/syscalls/syscall_tests/constants.rs similarity index 100% rename from crates/blockifier/src/execution/syscalls/syscall_tests/consts.rs rename to crates/blockifier/src/execution/syscalls/syscall_tests/constants.rs diff --git a/crates/blockifier/src/execution/syscalls/syscall_tests/deploy.rs b/crates/blockifier/src/execution/syscalls/syscall_tests/deploy.rs index 8f4b9570dd..6381d4f945 100644 --- a/crates/blockifier/src/execution/syscalls/syscall_tests/deploy.rs +++ b/crates/blockifier/src/execution/syscalls/syscall_tests/deploy.rs @@ -8,7 +8,6 @@ use crate::abi::abi_utils::selector_from_name; use crate::context::ChainInfo; use crate::execution::call_info::{CallExecution, Retdata}; use crate::execution::entry_point::CallEntryPoint; -use crate::execution::syscalls::syscall_tests::utils::assert_consistent_contract_version; use crate::retdata; use crate::state::state_api::StateReader; use crate::test_utils::contracts::FeatureContract; @@ -17,6 +16,8 @@ use crate::test_utils::{calldata_for_deploy_test, trivial_external_entry_point_n #[test_case(FeatureContract::TestContract(CairoVersion::Cairo1);"VM")] fn no_constructor(deployer_contract: FeatureContract) { + // TODO(Yoni): share the init code of the tests in this file. + let empty_contract = FeatureContract::Empty(CairoVersion::Cairo1); let class_hash = empty_contract.get_class_hash(); @@ -26,9 +27,6 @@ fn no_constructor(deployer_contract: FeatureContract) { &[(deployer_contract, 1), (empty_contract, 0)], ); - assert_consistent_contract_version(deployer_contract, &state); - assert_consistent_contract_version(empty_contract, &state); - let calldata = calldata_for_deploy_test(class_hash, &[], true); let entry_point_call = CallEntryPoint { entry_point_selector: selector_from_name("test_deploy"), @@ -51,9 +49,6 @@ fn no_constructor(deployer_contract: FeatureContract) { CallExecution { retdata: retdata![], gas_consumed: 0, ..CallExecution::default() } ); assert_eq!(state.get_class_hash_at(deployed_contract_address).unwrap(), class_hash); - - assert_consistent_contract_version(deployer_contract, &state); - assert_consistent_contract_version(empty_contract, &state); } #[test_case(FeatureContract::TestContract(CairoVersion::Cairo1);"VM")] @@ -66,8 +61,6 @@ fn no_constructor_nonempty_calldata(deployer_contract: FeatureContract) { 0, &[(deployer_contract, 1), (empty_contract, 0)], ); - assert_consistent_contract_version(deployer_contract, &state); - assert_consistent_contract_version(empty_contract, &state); let calldata = calldata_for_deploy_test(class_hash, &[felt!(1_u8), felt!(1_u8)], true); @@ -82,9 +75,6 @@ fn no_constructor_nonempty_calldata(deployer_contract: FeatureContract) { "Invalid input: constructor_calldata; Cannot pass calldata to a contract with no \ constructor." )); - - assert_consistent_contract_version(deployer_contract, &state); - assert_consistent_contract_version(empty_contract, &state); } #[test_case(FeatureContract::TestContract(CairoVersion::Cairo1), 10140;"VM")] @@ -95,8 +85,6 @@ fn with_constructor(deployer_contract: FeatureContract, expected_gas: u64) { 0, &[(deployer_contract, 1), (empty_contract, 0)], ); - assert_consistent_contract_version(deployer_contract, &state); - assert_consistent_contract_version(empty_contract, &state); let class_hash = deployer_contract.get_class_hash(); let constructor_calldata = vec![ @@ -132,9 +120,6 @@ fn with_constructor(deployer_contract: FeatureContract, expected_gas: u64) { } ); assert_eq!(state.get_class_hash_at(contract_address).unwrap(), class_hash); - - assert_consistent_contract_version(deployer_contract, &state); - assert_consistent_contract_version(empty_contract, &state); } #[test_case(FeatureContract::TestContract(CairoVersion::Cairo1);"VM")] @@ -145,8 +130,6 @@ fn to_unavailable_address(deployer_contract: FeatureContract) { 0, &[(deployer_contract, 1), (empty_contract, 0)], ); - assert_consistent_contract_version(deployer_contract, &state); - assert_consistent_contract_version(empty_contract, &state); let class_hash = deployer_contract.get_class_hash(); let constructor_calldata = vec![ @@ -166,7 +149,4 @@ fn to_unavailable_address(deployer_contract: FeatureContract) { let error = entry_point_call.execute_directly(&mut state).unwrap_err().to_string(); assert!(error.contains("is unavailable for deployment.")); - - assert_consistent_contract_version(deployer_contract, &state); - assert_consistent_contract_version(empty_contract, &state); } diff --git a/crates/blockifier/src/execution/syscalls/syscall_tests/emit_event.rs b/crates/blockifier/src/execution/syscalls/syscall_tests/emit_event.rs index 8c6a2679fc..46c594e59f 100644 --- a/crates/blockifier/src/execution/syscalls/syscall_tests/emit_event.rs +++ b/crates/blockifier/src/execution/syscalls/syscall_tests/emit_event.rs @@ -5,7 +5,6 @@ use starknet_api::transaction::{Calldata, EventContent, EventData, EventKey}; use starknet_types_core::felt::Felt; use test_case::test_case; -use super::utils::assert_consistent_contract_version; use crate::abi::abi_utils::selector_from_name; use crate::context::ChainInfo; use crate::execution::call_info::{CallExecution, CallInfo, OrderedEvent}; @@ -98,7 +97,6 @@ fn emit_events( ) -> Result { let chain_info = &ChainInfo::create_for_testing(); let mut state = test_state(chain_info, BALANCE, &[(test_contract, 1)]); - assert_consistent_contract_version(test_contract, &state); let calldata = Calldata( concat(vec![ n_emitted_events.to_owned(), @@ -117,6 +115,5 @@ fn emit_events( }; let result = entry_point_call.execute_directly(&mut state); - assert_consistent_contract_version(test_contract, &state); result } diff --git a/crates/blockifier/src/execution/syscalls/syscall_tests/get_block_hash.rs b/crates/blockifier/src/execution/syscalls/syscall_tests/get_block_hash.rs index f014d076e7..163526dba9 100644 --- a/crates/blockifier/src/execution/syscalls/syscall_tests/get_block_hash.rs +++ b/crates/blockifier/src/execution/syscalls/syscall_tests/get_block_hash.rs @@ -6,7 +6,6 @@ use starknet_api::{calldata, felt}; use starknet_types_core::felt::Felt; use test_case::test_case; -use super::utils::assert_consistent_contract_version; use crate::abi::abi_utils::selector_from_name; use crate::abi::constants; use crate::context::ChainInfo; @@ -28,7 +27,6 @@ use crate::{check_entry_point_execution_error_for_custom_hint, retdata}; fn initialize_state(test_contract: FeatureContract) -> (CachedState, Felt, Felt) { let chain_info = &ChainInfo::create_for_testing(); let mut state = test_state(chain_info, BALANCE, &[(test_contract, 1)]); - assert_consistent_contract_version(test_contract, &state); // Initialize block number -> block hash entry. let upper_bound_block_number = CURRENT_BLOCK_NUMBER - constants::STORED_BLOCK_HASH_BUFFER; @@ -60,8 +58,6 @@ fn positive_flow(test_contract: FeatureContract, expected_gas: u64) { ..CallExecution::from_retdata(retdata![block_hash]) } ); - - assert_consistent_contract_version(test_contract, &state); } #[test_case(FeatureContract::TestContract(CairoVersion::Cairo1); "VM")] @@ -81,14 +77,6 @@ fn negative_flow_execution_mode_validate(test_contract: FeatureContract) { &error, "Unauthorized syscall get_block_hash in execution mode Validate.", ); - - assert!( - error - .to_string() - .contains("Unauthorized syscall get_block_hash in execution mode Validate") - ); - - assert_consistent_contract_version(test_contract, &state); } #[test_case(FeatureContract::TestContract(CairoVersion::Cairo1); "VM")] @@ -106,5 +94,4 @@ fn negative_flow_block_number_out_of_range(test_contract: FeatureContract) { let error = entry_point_call.execute_directly(&mut state).unwrap_err().to_string(); assert!(error.contains("Block number out of range")); - assert_consistent_contract_version(test_contract, &state); } diff --git a/crates/blockifier/src/execution/syscalls/syscall_tests/get_execution_info.rs b/crates/blockifier/src/execution/syscalls/syscall_tests/get_execution_info.rs index 89501aa6af..02e4f37dc9 100644 --- a/crates/blockifier/src/execution/syscalls/syscall_tests/get_execution_info.rs +++ b/crates/blockifier/src/execution/syscalls/syscall_tests/get_execution_info.rs @@ -25,7 +25,6 @@ use crate::context::ChainInfo; use crate::execution::common_hints::ExecutionMode; use crate::execution::entry_point::CallEntryPoint; use crate::execution::syscalls::hint_processor::{L1_GAS, L2_GAS}; -use crate::execution::syscalls::syscall_tests::utils::assert_consistent_contract_version; use crate::nonce; use crate::test_utils::contracts::FeatureContract; use crate::test_utils::initial_test_state::test_state; @@ -97,7 +96,6 @@ fn test_get_execution_info( only_query: bool, ) { let state = &mut test_state(&ChainInfo::create_for_testing(), BALANCE, &[(test_contract, 1)]); - assert_consistent_contract_version(test_contract, state); let expected_block_info = match execution_mode { ExecutionMode::Validate => [ // Rounded block number. @@ -155,7 +153,7 @@ fn test_get_execution_info( let expected_resource_bounds: Vec = match (test_contract, version) { (FeatureContract::LegacyTestContract, _) => vec![], - (_, version) if version == TransactionVersion(Felt::from_hex("0x1").unwrap()) => vec![ + (_, version) if version == TransactionVersion::ONE => vec![ felt!(0_u16), // Length of resource bounds array. ], (_, _) => vec![ @@ -171,7 +169,7 @@ fn test_get_execution_info( let expected_tx_info: Vec; let tx_info: TransactionInfo; - if version == TransactionVersion(Felt::from_hex("0x1").unwrap()) { + if version == TransactionVersion::ONE { expected_tx_info = vec![ version.0, /* Transaction * version. */ @@ -270,5 +268,4 @@ fn test_get_execution_info( }; assert!(!result.unwrap().execution.failed); - assert_consistent_contract_version(test_contract, state); } diff --git a/crates/blockifier/src/execution/syscalls/syscall_tests/library_call.rs b/crates/blockifier/src/execution/syscalls/syscall_tests/library_call.rs index 1d13bde93e..d8c71bd4ba 100644 --- a/crates/blockifier/src/execution/syscalls/syscall_tests/library_call.rs +++ b/crates/blockifier/src/execution/syscalls/syscall_tests/library_call.rs @@ -13,7 +13,7 @@ use crate::abi::abi_utils::selector_from_name; use crate::context::ChainInfo; use crate::execution::call_info::{CallExecution, CallInfo, Retdata}; use crate::execution::entry_point::{CallEntryPoint, CallType}; -use crate::execution::syscalls::syscall_tests::consts::{ +use crate::execution::syscalls::syscall_tests::constants::{ REQUIRED_GAS_LIBRARY_CALL_TEST, REQUIRED_GAS_STORAGE_READ_WRITE_TEST, }; diff --git a/crates/blockifier/src/execution/syscalls/syscall_tests/mod.rs b/crates/blockifier/src/execution/syscalls/syscall_tests/mod.rs index 0e39a50057..3f048e319a 100644 --- a/crates/blockifier/src/execution/syscalls/syscall_tests/mod.rs +++ b/crates/blockifier/src/execution/syscalls/syscall_tests/mod.rs @@ -1,5 +1,5 @@ mod call_contract; -mod consts; +mod constants; mod deploy; mod emit_event; mod get_block_hash; @@ -12,4 +12,3 @@ mod secp; mod send_message_to_l1; mod sha256; mod storage_read_write; -mod utils; diff --git a/crates/blockifier/src/execution/syscalls/syscall_tests/out_of_gas.rs b/crates/blockifier/src/execution/syscalls/syscall_tests/out_of_gas.rs index 1ac010fc06..9f7a9e7c1a 100644 --- a/crates/blockifier/src/execution/syscalls/syscall_tests/out_of_gas.rs +++ b/crates/blockifier/src/execution/syscalls/syscall_tests/out_of_gas.rs @@ -5,7 +5,7 @@ use test_case::test_case; use crate::abi::abi_utils::selector_from_name; use crate::context::ChainInfo; use crate::execution::entry_point::CallEntryPoint; -use crate::execution::syscalls::syscall_tests::consts::REQUIRED_GAS_STORAGE_READ_WRITE_TEST; +use crate::execution::syscalls::syscall_tests::constants::REQUIRED_GAS_STORAGE_READ_WRITE_TEST; use crate::test_utils::contracts::FeatureContract; use crate::test_utils::initial_test_state::test_state; use crate::test_utils::{trivial_external_entry_point_new, CairoVersion, BALANCE}; diff --git a/crates/blockifier/src/execution/syscalls/syscall_tests/storage_read_write.rs b/crates/blockifier/src/execution/syscalls/syscall_tests/storage_read_write.rs index 36fb0df04f..bffb68bb18 100644 --- a/crates/blockifier/src/execution/syscalls/syscall_tests/storage_read_write.rs +++ b/crates/blockifier/src/execution/syscalls/syscall_tests/storage_read_write.rs @@ -7,8 +7,7 @@ use crate::abi::abi_utils::selector_from_name; use crate::context::ChainInfo; use crate::execution::call_info::{CallExecution, Retdata}; use crate::execution::entry_point::CallEntryPoint; -use crate::execution::syscalls::syscall_tests::consts::REQUIRED_GAS_STORAGE_READ_WRITE_TEST; -use crate::execution::syscalls::syscall_tests::utils::assert_consistent_contract_version; +use crate::execution::syscalls::syscall_tests::constants::REQUIRED_GAS_STORAGE_READ_WRITE_TEST; use crate::retdata; use crate::state::state_api::StateReader; use crate::test_utils::contracts::FeatureContract; @@ -20,8 +19,6 @@ fn test_storage_read_write(test_contract: FeatureContract, expected_gas: u64) { let chain_info = &ChainInfo::create_for_testing(); let mut state = test_state(chain_info, BALANCE, &[(test_contract, 1)]); - assert_consistent_contract_version(test_contract, &state); - let key = felt!(1234_u16); let value = felt!(18_u8); let calldata = calldata![key, value]; @@ -44,7 +41,4 @@ fn test_storage_read_write(test_contract: FeatureContract, expected_gas: u64) { let value_from_state = state.get_storage_at(storage_address, StorageKey::try_from(key).unwrap()).unwrap(); assert_eq!(value_from_state, value); - - // ensure that the fallback system didn't replace the contract - assert_consistent_contract_version(test_contract, &state); } diff --git a/crates/blockifier/src/execution/syscalls/syscall_tests/utils.rs b/crates/blockifier/src/execution/syscalls/syscall_tests/utils.rs deleted file mode 100644 index ef61800b0c..0000000000 --- a/crates/blockifier/src/execution/syscalls/syscall_tests/utils.rs +++ /dev/null @@ -1,27 +0,0 @@ -use assert_matches::assert_matches; - -use crate::execution::contract_class::ContractClass; -use crate::state::state_api::State; -use crate::test_utils::contracts::FeatureContract; - -pub fn assert_consistent_contract_version(contract: FeatureContract, state: &dyn State) { - let hash = contract.get_class_hash(); - match contract { - FeatureContract::SecurityTests - | FeatureContract::ERC20(_) - | FeatureContract::LegacyTestContract - | FeatureContract::AccountWithLongValidate(_) - | FeatureContract::AccountWithoutValidations(_) - | FeatureContract::Empty(_) - | FeatureContract::FaultyAccount(_) - | FeatureContract::TestContract(_) => { - // Assert contract uses VM - assert_matches!( - state - .get_compiled_contract_class(hash) - .unwrap_or_else(|_| panic!("Expected contract class at {hash}")), - ContractClass::V1(_) | ContractClass::V0(_) - ) - } - } -} From 47e696958403926ecc403d9c9113efb0b34ab683 Mon Sep 17 00:00:00 2001 From: Bohdan Ohorodnii Date: Thu, 8 Aug 2024 12:01:06 +0300 Subject: [PATCH 4/6] fix: conflicts after merge --- .../blockifier/src/execution/syscalls/syscall_tests/keccak.rs | 2 +- crates/blockifier/src/execution/syscalls/syscall_tests/secp.rs | 2 +- .../blockifier/src/execution/syscalls/syscall_tests/sha256.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/blockifier/src/execution/syscalls/syscall_tests/keccak.rs b/crates/blockifier/src/execution/syscalls/syscall_tests/keccak.rs index db7cfdc33b..585187db9c 100644 --- a/crates/blockifier/src/execution/syscalls/syscall_tests/keccak.rs +++ b/crates/blockifier/src/execution/syscalls/syscall_tests/keccak.rs @@ -10,7 +10,7 @@ use crate::test_utils::contracts::FeatureContract; use crate::test_utils::initial_test_state::test_state; use crate::test_utils::{trivial_external_entry_point_new, CairoVersion, BALANCE}; -#[test_case(FeatureContract::TestContract(CairoVersion::Cairo1), 256250; "VM")] +#[test_case(FeatureContract::TestContract(CairoVersion::Cairo1), 255110; "VM")] fn test_keccak(test_contract: FeatureContract, expected_gas: u64) { let chain_info = &ChainInfo::create_for_testing(); let mut state = test_state(chain_info, BALANCE, &[(test_contract, 1)]); diff --git a/crates/blockifier/src/execution/syscalls/syscall_tests/secp.rs b/crates/blockifier/src/execution/syscalls/syscall_tests/secp.rs index 0066067c13..9bb21473cc 100644 --- a/crates/blockifier/src/execution/syscalls/syscall_tests/secp.rs +++ b/crates/blockifier/src/execution/syscalls/syscall_tests/secp.rs @@ -9,7 +9,7 @@ use crate::test_utils::contracts::FeatureContract; use crate::test_utils::initial_test_state::test_state; use crate::test_utils::{trivial_external_entry_point_new, CairoVersion, BALANCE}; -#[test_case(FeatureContract::TestContract(CairoVersion::Cairo1), 17033810; "VM")] +#[test_case(FeatureContract::TestContract(CairoVersion::Cairo1), 17032670; "VM")] fn test_secp256k1(test_contract: FeatureContract, expected_gas: u64) { let chain_info = &ChainInfo::create_for_testing(); let mut state = test_state(chain_info, BALANCE, &[(test_contract, 1)]); diff --git a/crates/blockifier/src/execution/syscalls/syscall_tests/sha256.rs b/crates/blockifier/src/execution/syscalls/syscall_tests/sha256.rs index 2f239c49c0..4d60eff586 100644 --- a/crates/blockifier/src/execution/syscalls/syscall_tests/sha256.rs +++ b/crates/blockifier/src/execution/syscalls/syscall_tests/sha256.rs @@ -10,7 +10,7 @@ use crate::test_utils::contracts::FeatureContract; use crate::test_utils::initial_test_state::test_state; use crate::test_utils::{trivial_external_entry_point_new, CairoVersion, BALANCE}; -#[test_case(FeatureContract::TestContract(CairoVersion::Cairo1), 892990; "VM")] +#[test_case(FeatureContract::TestContract(CairoVersion::Cairo1), 893590; "VM")] fn test_sha256(test_contract: FeatureContract, gas_consumed: u64) { let chain_info = &ChainInfo::create_for_testing(); let mut state = test_state(chain_info, BALANCE, &[(test_contract, 1)]); From 86df83bb266f793c8ba318a44c36b61d10d87c6d Mon Sep 17 00:00:00 2001 From: Bohdan Ohorodnii Date: Thu, 8 Aug 2024 12:31:24 +0300 Subject: [PATCH 5/6] fix: clippy warnings --- .../src/execution/syscalls/syscall_tests/emit_event.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crates/blockifier/src/execution/syscalls/syscall_tests/emit_event.rs b/crates/blockifier/src/execution/syscalls/syscall_tests/emit_event.rs index 46c594e59f..cd7a0a3c1e 100644 --- a/crates/blockifier/src/execution/syscalls/syscall_tests/emit_event.rs +++ b/crates/blockifier/src/execution/syscalls/syscall_tests/emit_event.rs @@ -114,6 +114,5 @@ fn emit_events( ..trivial_external_entry_point_new(test_contract) }; - let result = entry_point_call.execute_directly(&mut state); - result + entry_point_call.execute_directly(&mut state) } From 32c4400f94aebd40e87ede986017604dff81d308 Mon Sep 17 00:00:00 2001 From: Bohdan Ohorodnii Date: Mon, 12 Aug 2024 12:56:21 +0300 Subject: [PATCH 6/6] feat: add syscall failure format --- .../syscalls/syscall_tests/failure_format.rs | 23 +++++++++++++++++++ .../execution/syscalls/syscall_tests/mod.rs | 1 + 2 files changed, 24 insertions(+) create mode 100644 crates/blockifier/src/execution/syscalls/syscall_tests/failure_format.rs diff --git a/crates/blockifier/src/execution/syscalls/syscall_tests/failure_format.rs b/crates/blockifier/src/execution/syscalls/syscall_tests/failure_format.rs new file mode 100644 index 0000000000..27891c2f2d --- /dev/null +++ b/crates/blockifier/src/execution/syscalls/syscall_tests/failure_format.rs @@ -0,0 +1,23 @@ +use cairo_lang_utils::byte_array::BYTE_ARRAY_MAGIC; +use starknet_types_core::felt::Felt; + +use crate::execution::errors::EntryPointExecutionError; + +#[test] +fn test_syscall_failure_format() { + let error_data = vec![ + // Magic to indicate that this is a byte array. + BYTE_ARRAY_MAGIC, + // The number of full words in the byte array. + "0x00", + // The pending word of the byte array: "Execution failure" + "0x457865637574696f6e206661696c757265", + // The length of the pending word. + "0x11", + ] + .into_iter() + .map(|x| Felt::from_hex(x).unwrap()) + .collect(); + let error = EntryPointExecutionError::ExecutionFailed { error_data }; + assert_eq!(error.to_string(), "Execution failed. Failure reason: \"Execution failure\"."); +} diff --git a/crates/blockifier/src/execution/syscalls/syscall_tests/mod.rs b/crates/blockifier/src/execution/syscalls/syscall_tests/mod.rs index 3f048e319a..fbebf14ba8 100644 --- a/crates/blockifier/src/execution/syscalls/syscall_tests/mod.rs +++ b/crates/blockifier/src/execution/syscalls/syscall_tests/mod.rs @@ -2,6 +2,7 @@ mod call_contract; mod constants; mod deploy; mod emit_event; +mod failure_format; mod get_block_hash; mod get_execution_info; mod keccak;