From 3fa71d8fbf30e6c447d9765c03b6d000d3cd36c2 Mon Sep 17 00:00:00 2001 From: Edgar Luque Date: Tue, 19 Sep 2023 15:11:42 +0200 Subject: [PATCH] remove testing, move erc20 test, update fibonacci bin --- examples/contract_execution/main.rs | 100 ++- src/bin/deploy.rs | 42 +- src/bin/deploy_invoke.rs | 109 ++- src/bin/fibonacci.rs | 145 ++-- src/bin/invoke.rs | 93 +-- src/lib.rs | 9 +- ...ch_integration.cpython-39-pytest-7.2.1.pyc | Bin 936 -> 0 bytes src/testing/bench_integration.rs | 101 --- src/testing/mod.rs | 165 ---- src/testing/state.rs | 733 ------------------ src/testing/state_error.rs | 20 - src/testing/type_utils.rs | 25 - src/utils.rs | 164 ++++ .../complex_contracts}/erc20.rs | 44 +- tests/complex_contracts/mod.rs | 1 + 15 files changed, 498 insertions(+), 1253 deletions(-) delete mode 100644 src/testing/__pycache__/bench_integration.cpython-39-pytest-7.2.1.pyc delete mode 100644 src/testing/bench_integration.rs delete mode 100644 src/testing/mod.rs delete mode 100644 src/testing/state.rs delete mode 100644 src/testing/state_error.rs delete mode 100644 src/testing/type_utils.rs rename {src/testing => tests/complex_contracts}/erc20.rs (85%) diff --git a/examples/contract_execution/main.rs b/examples/contract_execution/main.rs index b735362d4..2e6e21086 100644 --- a/examples/contract_execution/main.rs +++ b/examples/contract_execution/main.rs @@ -11,18 +11,24 @@ use cairo_vm::felt::Felt252; use starknet_in_rust::{ - services::api::contract_classes::deprecated_contract_class::ContractClass, - testing::state::StarknetState, + definitions::{block_context::BlockContext, constants::TRANSACTION_VERSION}, + services::api::contract_classes::{ + compiled_class::CompiledClass, deprecated_contract_class::ContractClass, + }, + state::{ + cached_state::CachedState, in_memory_state_reader::InMemoryStateReader, state_api::State, + }, + transaction::{Declare, Deploy, InvokeFunction, Transaction}, utils::{calculate_sn_keccak, Address}, }; -use std::path::Path; +use std::{collections::HashMap, path::Path, sync::Arc}; fn main() { // replace this with the path to your compiled contract - let contract_path = "starknet_programs/factorial.json"; + let contract_path = "starknet_programs/fibonacci.json"; // replace this with the name of your entrypoint - let entry_point: &str = "factorial"; + let entry_point: &str = "fib"; // replace this with the arguments for the entrypoint let calldata: Vec = [1.into(), 1.into(), 10.into()].to_vec(); @@ -42,12 +48,21 @@ fn main() { fn test_contract( contract_path: impl AsRef, entry_point: &str, - calldata: Vec, + call_data: Vec, ) -> Vec { + //* -------------------------------------------- + //* Initialize needed variables + //* -------------------------------------------- + let block_context = BlockContext::default(); + let chain_id = block_context.starknet_os_config().chain_id().clone(); + let sender_address = Address(1.into()); + let signature = vec![]; + //* -------------------------------------------- //* Initialize state //* -------------------------------------------- - let mut state = StarknetState::new(None); + let state_reader = Arc::new(InMemoryStateReader::default()); + let mut state = CachedState::new(state_reader, HashMap::new()); //* -------------------------------------------- //* Read contract from file @@ -58,37 +73,74 @@ fn test_contract( //* -------------------------------------------- //* Declare new contract class //* -------------------------------------------- - state - .declare(contract_class.clone()) - .expect("Could not declare the contract class"); + let declare_tx = Declare::new( + contract_class.clone(), + chain_id.clone(), + sender_address, + 0, // max fee + 0.into(), + signature.clone(), + 0.into(), // nonce + ) + .expect("couldn't create declare transaction"); + + declare_tx + .execute(&mut state, &block_context) + .expect("could not declare the contract class"); //* -------------------------------------------- //* Deploy new contract class instance //* -------------------------------------------- - let (contract_address, _) = state - .deploy(contract_class, vec![], Default::default(), None, 0) - .expect("Could not deploy contract"); + + let deploy = Deploy::new( + Default::default(), // salt + contract_class.clone(), + vec![], // call data + block_context.starknet_os_config().chain_id().clone(), + TRANSACTION_VERSION.clone(), + ) + .unwrap(); + + state + .set_contract_class( + &deploy.contract_hash, + &CompiledClass::Deprecated(Arc::new(contract_class)), + ) + .unwrap(); + let contract_address = deploy.contract_address.clone(); + + let tx = Transaction::Deploy(deploy); + + tx.execute(&mut state, &block_context, 0) + .expect("could not deploy contract"); //* -------------------------------------------- //* Execute contract entrypoint //* -------------------------------------------- let entry_point_selector = Felt252::from_bytes_be(&calculate_sn_keccak(entry_point.as_bytes())); - let caller_address = Address::default(); - - let callinfo = state - .execute_entry_point_raw( - contract_address, - entry_point_selector, - calldata, - caller_address, - ) - .expect("Could not execute entry point"); + let invoke_tx = InvokeFunction::new( + contract_address, + entry_point_selector, + 0, + TRANSACTION_VERSION.clone(), + call_data, + signature, + chain_id, + Some(0.into()), + ) + .unwrap(); + + let tx = Transaction::InvokeFunction(invoke_tx); + let tx_exec_info = tx.execute(&mut state, &block_context, 0).unwrap(); //* -------------------------------------------- //* Extract return values //* -------------------------------------------- - callinfo.retdata + tx_exec_info + .call_info + .expect("call info should exist") + .retdata } #[test] diff --git a/src/bin/deploy.rs b/src/bin/deploy.rs index 1b58d386a..f8ac4e455 100644 --- a/src/bin/deploy.rs +++ b/src/bin/deploy.rs @@ -1,7 +1,15 @@ +use std::{collections::HashMap, sync::Arc}; + use lazy_static::lazy_static; use starknet_in_rust::{ - services::api::contract_classes::deprecated_contract_class::ContractClass, - testing::state::StarknetState, + definitions::{block_context::BlockContext, constants::TRANSACTION_VERSION}, + services::api::contract_classes::{ + compiled_class::CompiledClass, deprecated_contract_class::ContractClass, + }, + state::{ + cached_state::CachedState, in_memory_state_reader::InMemoryStateReader, state_api::State, + }, + transaction::{Deploy, Transaction}, }; #[cfg(feature = "with_mimalloc")] @@ -20,19 +28,33 @@ lazy_static! { fn main() { const RUNS: usize = 100; - let mut starknet_state = StarknetState::new(None); + + let block_context = BlockContext::default(); + let state_reader = Arc::new(InMemoryStateReader::default()); + + let mut state = CachedState::new(state_reader, HashMap::new()); + let call_data = vec![]; for n in 0..RUNS { let contract_address_salt = n.into(); - starknet_state - .deploy( - CONTRACT_CLASS.clone(), - vec![], - contract_address_salt, - None, - 0, + let deploy = Deploy::new( + contract_address_salt, + CONTRACT_CLASS.clone(), + call_data.clone(), + block_context.starknet_os_config().chain_id().clone(), + TRANSACTION_VERSION.clone(), + ) + .unwrap(); + + state + .set_contract_class( + &deploy.contract_hash, + &CompiledClass::Deprecated(Arc::new(CONTRACT_CLASS.clone())), ) .unwrap(); + let tx = Transaction::Deploy(deploy); + + tx.execute(&mut state, &block_context, 0).unwrap(); } } diff --git a/src/bin/deploy_invoke.rs b/src/bin/deploy_invoke.rs index 1036a6496..b35da65f9 100644 --- a/src/bin/deploy_invoke.rs +++ b/src/bin/deploy_invoke.rs @@ -1,11 +1,18 @@ -use std::path::PathBuf; +use std::{collections::HashMap, path::PathBuf, sync::Arc}; use cairo_vm::felt::{felt_str, Felt252}; use num_traits::Zero; use starknet_in_rust::{ - services::api::contract_classes::deprecated_contract_class::ContractClass, - testing::state::StarknetState, utils::Address, + definitions::{block_context::BlockContext, constants::TRANSACTION_VERSION}, + services::api::contract_classes::{ + compiled_class::CompiledClass, deprecated_contract_class::ContractClass, + }, + state::{ + cached_state::CachedState, in_memory_state_reader::InMemoryStateReader, state_api::State, + }, + transaction::{Deploy, InvokeFunction, Transaction}, + utils::Address, }; use lazy_static::lazy_static; @@ -36,52 +43,76 @@ lazy_static! { fn main() { const RUNS: usize = 10000; - let mut starknet_state = StarknetState::new(None); - let contract_address_salt = 1.into(); - let (contract_address, _exec_info) = starknet_state - .deploy( - CONTRACT_CLASS.to_owned(), - vec![], - contract_address_salt, - None, - 0, + let block_context = BlockContext::default(); + let state_reader = Arc::new(InMemoryStateReader::default()); + let mut state = CachedState::new(state_reader, HashMap::new()); + + let call_data = vec![]; + let contract_address_salt = 1.into(); + let chain_id = block_context.starknet_os_config().chain_id().clone(); + + let deploy = Deploy::new( + contract_address_salt, + CONTRACT_CLASS.clone(), + call_data, + block_context.starknet_os_config().chain_id().clone(), + TRANSACTION_VERSION.clone(), + ) + .unwrap(); + + let contract_address = deploy.contract_address.clone(); + state + .set_contract_class( + &deploy.contract_hash, + &CompiledClass::Deprecated(Arc::new(CONTRACT_CLASS.clone())), ) .unwrap(); + let deploy_tx = Transaction::Deploy(deploy); + + let _tx_exec_info = deploy_tx.execute(&mut state, &block_context, 0).unwrap(); + + let signature = Vec::new(); // Statement **not** in blockifier. - starknet_state - .state + state .cache_mut() .nonce_initial_values_mut() .insert(contract_address.clone(), Felt252::zero()); for i in 0..RUNS { - starknet_state - .invoke_raw( - contract_address.clone(), - INCREASE_BALANCE_SELECTOR.clone(), - vec![1000.into()], - 0, - Some(Vec::new()), - Some(Felt252::from(i * 2)), - None, - 0, - ) - .unwrap(); - - let tx_exec_info = starknet_state - .invoke_raw( - contract_address.clone(), - GET_BALANCE_SELECTOR.clone(), - vec![], - 0, - Some(Vec::new()), - Some(Felt252::from((i * 2) + 1)), - None, - 0, - ) - .unwrap(); + let nonce_first = Felt252::from(i * 2); + let nonce_second = Felt252::from((i * 2) + 1); + + let invoke_first = InvokeFunction::new( + contract_address.clone(), + INCREASE_BALANCE_SELECTOR.clone(), + 0, + TRANSACTION_VERSION.clone(), + vec![1000.into()], + signature.clone(), + chain_id.clone(), + Some(nonce_first), + ) + .unwrap(); + + let tx = Transaction::InvokeFunction(invoke_first); + tx.execute(&mut state, &block_context, 0).unwrap(); + + let invoke_second = InvokeFunction::new( + contract_address.clone(), + GET_BALANCE_SELECTOR.clone(), + 0, + TRANSACTION_VERSION.clone(), + vec![], + signature.clone(), + chain_id.clone(), + Some(nonce_second), + ) + .unwrap(); + + let tx = Transaction::InvokeFunction(invoke_second); + let tx_exec_info = tx.execute(&mut state, &block_context, 0).unwrap(); assert_eq!( tx_exec_info.call_info.unwrap().retdata, diff --git a/src/bin/fibonacci.rs b/src/bin/fibonacci.rs index df61410cf..6017bfc8a 100644 --- a/src/bin/fibonacci.rs +++ b/src/bin/fibonacci.rs @@ -5,13 +5,17 @@ use num_traits::Zero; use lazy_static::lazy_static; use starknet_in_rust::{ + definitions::{block_context::BlockContext, constants::TRANSACTION_VERSION}, + execution::{ + execution_entry_point::ExecutionEntryPoint, CallType, TransactionExecutionContext, + }, services::api::contract_classes::{ compiled_class::CompiledClass, deprecated_contract_class::ContractClass, }, state::cached_state::CachedState, - state::in_memory_state_reader::InMemoryStateReader, - testing::state::StarknetState, + state::{in_memory_state_reader::InMemoryStateReader, ExecutionResourcesManager}, utils::Address, + EntryPointType, }; #[cfg(feature = "with_mimalloc")] @@ -40,60 +44,97 @@ lazy_static! { fn main() { const RUNS: usize = 1000; - let cached_state = create_initial_state(); - - let mut starknet_state = StarknetState::new_with_states(Default::default(), cached_state); - - starknet_state - .state - .cache_mut() - .nonce_initial_values_mut() - .insert(CONTRACT_ADDRESS.clone(), Felt252::zero()); - - for i in 0..RUNS { - let tx_exec_info = starknet_state - .invoke_raw( - CONTRACT_ADDRESS.clone(), - FIB_SELECTOR.clone(), - [1.into(), 1.into(), 1000.into()].into(), - 0, - Some(Vec::new()), - Some(Felt252::from(i)), - None, - 0, + + let contract_class = ContractClass::from_path(&*CONTRACT_PATH).unwrap(); + let entry_points_by_type = contract_class.entry_points_by_type().clone(); + + let fib_entrypoint_selector = entry_points_by_type + .get(&EntryPointType::External) + .unwrap() + .get(0) + .unwrap() + .selector() + .clone(); + + //* -------------------------------------------- + //* Create state reader with class hash data + //* -------------------------------------------- + + let mut contract_class_cache = HashMap::new(); + + // ------------ contract data -------------------- + + let contract_address = CONTRACT_ADDRESS.clone(); + let class_hash = *CONTRACT_CLASS_HASH; + let nonce = Felt252::zero(); + + contract_class_cache.insert( + class_hash, + CompiledClass::Deprecated(Arc::new(contract_class)), + ); + let mut state_reader = InMemoryStateReader::default(); + state_reader + .address_to_class_hash_mut() + .insert(contract_address.clone(), class_hash); + state_reader + .address_to_nonce_mut() + .insert(contract_address.clone(), nonce); + + //* --------------------------------------- + //* Create state with previous data + //* --------------------------------------- + + let mut state = CachedState::new(Arc::new(state_reader), contract_class_cache); + + //* ------------------------------------ + //* Create execution entry point + //* ------------------------------------ + + let calldata = [1.into(), 1.into(), 1000.into()].to_vec(); + let caller_address = Address(0000.into()); + let entry_point_type = EntryPointType::External; + + for nonce in 0..RUNS { + let exec_entry_point = ExecutionEntryPoint::new( + contract_address.clone(), + calldata.clone(), + fib_entrypoint_selector.clone(), + caller_address.clone(), + entry_point_type, + Some(CallType::Delegate), + Some(class_hash), + 0, + ); + + //* -------------------- + //* Execute contract + //* --------------------- + let block_context = BlockContext::default(); + let mut tx_execution_context = TransactionExecutionContext::new( + Address(0.into()), + Felt252::zero(), + Vec::new(), + 0, + nonce.into(), + block_context.invoke_tx_max_n_steps(), + TRANSACTION_VERSION.clone(), + ); + let mut resources_manager = ExecutionResourcesManager::default(); + + let tx_exec_result = exec_entry_point + .execute( + &mut state, + &block_context, + &mut resources_manager, + &mut tx_execution_context, + false, + block_context.invoke_tx_max_n_steps(), ) .unwrap(); assert_eq!( - tx_exec_info.call_info.unwrap().retdata, + tx_exec_result.call_info.unwrap().retdata, vec![EXPECTED_RES.clone()] - ) + ); } } - -fn create_initial_state() -> CachedState { - let cached_state = CachedState::new( - { - let mut state_reader = InMemoryStateReader::default(); - state_reader - .address_to_class_hash_mut() - .insert(CONTRACT_ADDRESS.clone(), *CONTRACT_CLASS_HASH); - - state_reader - .address_to_nonce_mut() - .insert(CONTRACT_ADDRESS.clone(), Felt252::zero()); - state_reader.class_hash_to_compiled_class_mut().insert( - *CONTRACT_CLASS_HASH, - CompiledClass::Deprecated(Arc::new(CONTRACT_CLASS.clone())), - ); - - state_reader - .address_to_storage_mut() - .insert((CONTRACT_ADDRESS.clone(), [0; 32]), Felt252::zero()); - Arc::new(state_reader) - }, - HashMap::new(), - ); - - cached_state -} diff --git a/src/bin/invoke.rs b/src/bin/invoke.rs index f29a78ad0..c98649987 100644 --- a/src/bin/invoke.rs +++ b/src/bin/invoke.rs @@ -4,12 +4,13 @@ use cairo_vm::felt::{felt_str, Felt252}; use num_traits::Zero; use starknet_in_rust::{ + definitions::{block_context::BlockContext, constants::TRANSACTION_VERSION}, services::api::contract_classes::{ compiled_class::CompiledClass, deprecated_contract_class::ContractClass, }, state::cached_state::CachedState, state::in_memory_state_reader::InMemoryStateReader, - testing::state::StarknetState, + transaction::{InvokeFunction, Transaction}, utils::Address, }; @@ -41,52 +42,10 @@ lazy_static! { fn main() { const RUNS: usize = 10000; - let cached_state = create_initial_state(); - let mut starknet_state = StarknetState::new_with_states(Default::default(), cached_state); + let block_context = BlockContext::default(); - starknet_state - .state - .cache_mut() - .nonce_initial_values_mut() - .insert(CONTRACT_ADDRESS.clone(), Felt252::zero()); - - for i in 0..RUNS { - starknet_state - .invoke_raw( - CONTRACT_ADDRESS.clone(), - INCREASE_BALANCE_SELECTOR.clone(), - vec![1000.into()], - 0, - Some(Vec::new()), - Some(Felt252::from(i * 2)), - None, - 0, - ) - .unwrap(); - - let tx_exec_info = starknet_state - .invoke_raw( - CONTRACT_ADDRESS.clone(), - GET_BALANCE_SELECTOR.clone(), - vec![], - 0, - Some(Vec::new()), - Some(Felt252::from((i * 2) + 1)), - None, - 0, - ) - .unwrap(); - - assert_eq!( - tx_exec_info.call_info.unwrap().retdata, - vec![((1000 * i) + 1000).into()] - ); - } -} - -fn create_initial_state() -> CachedState { - let cached_state = CachedState::new( + let mut state = CachedState::new( { let mut state_reader = InMemoryStateReader::default(); state_reader @@ -108,6 +67,48 @@ fn create_initial_state() -> CachedState { }, HashMap::new(), ); + let chain_id = block_context.starknet_os_config().chain_id().clone(); + let signature = Vec::new(); + + state + .cache_mut() + .nonce_initial_values_mut() + .insert(CONTRACT_ADDRESS.clone(), Felt252::zero()); + + for i in 0..RUNS { + let invoke_first = InvokeFunction::new( + CONTRACT_ADDRESS.clone(), + INCREASE_BALANCE_SELECTOR.clone(), + 0, + TRANSACTION_VERSION.clone(), + vec![1000.into()], + signature.clone(), + chain_id.clone(), + Some(Felt252::from(i * 2)), + ) + .unwrap(); + + let tx = Transaction::InvokeFunction(invoke_first); + tx.execute(&mut state, &block_context, 0).unwrap(); + + let invoke_second = InvokeFunction::new( + CONTRACT_ADDRESS.clone(), + GET_BALANCE_SELECTOR.clone(), + 0, + TRANSACTION_VERSION.clone(), + vec![], + signature.clone(), + chain_id.clone(), + Some(Felt252::from((i * 2) + 1)), + ) + .unwrap(); + + let tx = Transaction::InvokeFunction(invoke_second); + let tx_exec_info = tx.execute(&mut state, &block_context, 0).unwrap(); - cached_state + assert_eq!( + tx_exec_info.call_info.unwrap().retdata, + vec![((1000 * i) + 1000).into()] + ); + } } diff --git a/src/lib.rs b/src/lib.rs index 6af73ef40..fd8747a73 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -46,7 +46,6 @@ pub mod serde_structs; pub mod services; pub mod state; pub mod syscalls; -pub mod testing; pub mod transaction; pub mod utils; @@ -224,14 +223,14 @@ mod test { use crate::services::api::contract_classes::deprecated_contract_class::ContractClass; use crate::services::api::contract_classes::deprecated_contract_class::EntryPointType; use crate::state::state_api::State; - use crate::testing::{ - create_account_tx_test_state, TEST_ACCOUNT_CONTRACT_ADDRESS, TEST_CONTRACT_ADDRESS, - TEST_CONTRACT_PATH, TEST_FIB_COMPILED_CONTRACT_CLASS_HASH, - }; use crate::transaction::{ Declare, DeclareV2, Deploy, DeployAccount, InvokeFunction, L1Handler, Transaction, }; use crate::utils::felt_to_hash; + use crate::utils::test_utils::{ + create_account_tx_test_state, TEST_ACCOUNT_CONTRACT_ADDRESS, TEST_CONTRACT_ADDRESS, + TEST_CONTRACT_PATH, TEST_FIB_COMPILED_CONTRACT_CLASS_HASH, + }; use cairo_lang_starknet::casm_contract_class::CasmContractClass; use cairo_lang_starknet::contract_class::ContractClass as SierraContractClass; use cairo_vm::felt::{felt_str, Felt252}; diff --git a/src/testing/__pycache__/bench_integration.cpython-39-pytest-7.2.1.pyc b/src/testing/__pycache__/bench_integration.cpython-39-pytest-7.2.1.pyc deleted file mode 100644 index d856d68e7a2d0edecef1a5bafa5a5ef66abcb2c7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 936 zcmaJ+o$=bB*22A1#hf!%t{=hU14G@#ikl46Hg2;=#;x2K5?J$bE6I}Nn z+9SV%f8i?^_zRqPNt>|~R{Wgr^Lx+leKs8odI-jo{av5T-U@7-Bd> zF>Y3pcL>5Lcj7Ky?YObq?0B))tbXjnO0tc-7xx;UPS($ZIKYUz)4^ic*iAlKV&*JK zyv4og_Vga>GWQ$$isSnXpQ5q%8%{K6(mH259Qdi{519Hr7>2KrK?}S@$I#hJbdBeDN=%258@y(S zapq9tGxTonx-%!!F6%Jo1~1$;2BSGycuRDb`MAdrbksc&qg{lcdRG^fO1b#eSwWf? zl{8~t0YCsv8;`r5b+f`Ifcsvp^Rh(*`oYRcTlv|H~ z=4oZP?N7LA*|B3CRY@KDtw7dqC9yd9j?^X``R5>dtGUvVrqYOiS_+w{N}EWlG%{Qp zAt%u}m+6N@NW(#9BMKRoGuy9sf&5fl@_sF600t2U5Aik*@D5g6fX5H4e_n|U@@N|z zmb2s*Jxt13og<_g3Te_Rex(GovvEsVujP6W+#E@jC55)`3ff^y>zPbN5kGFazM_hU zZU5oAk+79P!TU%5^=v~|*W;Abe6Y^65Yl=~C`of}{Uo^%8BY@BLpJN=@M5h;S7kKK hH$vYrquS5k&kI&%`~U;eLoknsk9`v0fb0+#{{;#y4-)_Y diff --git a/src/testing/bench_integration.rs b/src/testing/bench_integration.rs deleted file mode 100644 index dcdbf6479..000000000 --- a/src/testing/bench_integration.rs +++ /dev/null @@ -1,101 +0,0 @@ -use std::{collections::HashMap, path::PathBuf}; - -use felt::{felt_str, Felt}; -use num_traits::Zero; - -use crate::{ - services::api::contract_classes::deprecated_contract_class::ContractClass, - state::cached_state::CachedState, state::in_memory_state_reader::InMemoryStateReader, - testing::starknet_state::StarknetState, utils::Address, -}; - -use lazy_static::lazy_static; - -lazy_static! { - // include_str! doesn't seem to work in CI - static ref CONTRACT_CLASS: ContractClass = ContractClass::new_from_path( - "starknet_programs/first_contract.json", - ).unwrap(); - - static ref CONTRACT_PATH: PathBuf = PathBuf::from("starknet_programs/first_contract.json"); - - static ref CONTRACT_CLASS_HASH: [u8; 32] = [1; 32]; - - static ref CONTRACT_ADDRESS: Address = Address(1.into()); - - static ref INCREASE_BALANCE_SELECTOR: Felt = felt_str!("1530486729947006463063166157847785599120665941190480211966374137237989315360"); - - static ref GET_BALANCE_SELECTOR: Felt = felt_str!("1636223440827086009537493065587328807418413867743950350615962740049133672085"); -} - -#[test] -fn main() { - const RUNS: usize = 1000; - let cached_state = create_initial_state(); - - let mut starknet_state = StarknetState { - state: cached_state, - ..Default::default() - }; - - starknet_state - .state - .cache_mut() - .nonce_initial_values_mut() - .insert(CONTRACT_ADDRESS.clone(), Felt::zero()); - - for i in 0..RUNS { - starknet_state - .invoke_raw( - CONTRACT_ADDRESS.clone(), - INCREASE_BALANCE_SELECTOR.clone(), - vec![1000.into()], - 0, - Some(Vec::new()), - Some(Felt::from(i * 2)), - ) - .unwrap(); - - let tx_exec_info = starknet_state - .invoke_raw( - CONTRACT_ADDRESS.clone(), - GET_BALANCE_SELECTOR.clone(), - vec![], - 0, - Some(Vec::new()), - Some(Felt::from((i * 2) + 1)), - ) - .unwrap(); - - assert_eq!( - tx_exec_info.call_info.unwrap().retdata, - vec![((1000 * i) + 1000).into()] - ); - } -} - -fn create_initial_state() -> CachedState { - let cached_state = CachedState::new( - { - let mut state_reader = InMemoryStateReader::default(); - state_reader - .address_to_class_hash_mut() - .insert(CONTRACT_ADDRESS.clone(), CONTRACT_CLASS_HASH.clone()); - - state_reader - .address_to_nonce_mut() - .insert(CONTRACT_ADDRESS.clone(), Felt::zero()); - state_reader - .class_hash_to_contract_class_mut() - .insert(CONTRACT_CLASS_HASH.clone(), CONTRACT_CLASS.clone()); - - state_reader - .address_to_storage_mut() - .insert((CONTRACT_ADDRESS.clone(), [0; 32]), Felt::zero()); - state_reader - }, - Some(HashMap::new()), - ); - - cached_state -} diff --git a/src/testing/mod.rs b/src/testing/mod.rs deleted file mode 100644 index 018082643..000000000 --- a/src/testing/mod.rs +++ /dev/null @@ -1,165 +0,0 @@ -pub mod erc20; -pub mod state; -pub mod state_error; -pub mod type_utils; - -use std::{collections::HashMap, sync::Arc}; - -use cairo_vm::felt::{felt_str, Felt252}; -use lazy_static::lazy_static; -use num_traits::Zero; - -use crate::{ - definitions::{ - block_context::{BlockContext, StarknetChainId, StarknetOsConfig}, - constants::DEFAULT_CAIRO_RESOURCE_FEE_WEIGHTS, - }, - services::api::contract_classes::{ - compiled_class::CompiledClass, deprecated_contract_class::ContractClass, - }, - state::{ - cached_state::CachedState, in_memory_state_reader::InMemoryStateReader, - state_cache::StorageEntry, BlockInfo, - }, - utils::{felt_to_hash, Address, ClassHash}, -}; - -pub const ACCOUNT_CONTRACT_PATH: &str = "starknet_programs/account_without_validation.json"; -pub const ERC20_CONTRACT_PATH: &str = "starknet_programs/ERC20.json"; -pub const TEST_CONTRACT_PATH: &str = "starknet_programs/fibonacci.json"; - -lazy_static! { - // Addresses. - pub static ref TEST_ACCOUNT_CONTRACT_ADDRESS: Address = Address(felt_str!("257")); - pub static ref TEST_CONTRACT_ADDRESS: Address = Address(felt_str!("256")); - pub static ref TEST_SEQUENCER_ADDRESS: Address = - Address(felt_str!("4096")); - pub static ref TEST_ERC20_CONTRACT_ADDRESS: Address = - Address(felt_str!("4097")); - - - // Class hashes. - pub static ref TEST_ACCOUNT_CONTRACT_CLASS_HASH: Felt252 = felt_str!("273"); - pub static ref TEST_CLASS_HASH: Felt252 = felt_str!("272"); - pub static ref TEST_EMPTY_CONTRACT_CLASS_HASH: Felt252 = felt_str!("274"); - pub static ref TEST_ERC20_CONTRACT_CLASS_HASH: Felt252 = felt_str!("4112"); - pub static ref TEST_FIB_COMPILED_CONTRACT_CLASS_HASH: Felt252 = felt_str!("1948962768849191111780391610229754715773924969841143100991524171924131413970"); - - // Storage keys. - pub static ref TEST_ERC20_ACCOUNT_BALANCE_KEY: Felt252 = - felt_str!("1192211877881866289306604115402199097887041303917861778777990838480655617515"); - pub static ref TEST_ERC20_SEQUENCER_BALANCE_KEY: Felt252 = - felt_str!("3229073099929281304021185011369329892856197542079132996799046100564060768274"); - pub static ref TEST_ERC20_BALANCE_KEY_1: Felt252 = - felt_str!("1192211877881866289306604115402199097887041303917861778777990838480655617516"); - pub static ref TEST_ERC20_BALANCE_KEY_2: Felt252 = - felt_str!("3229073099929281304021185011369329892856197542079132996799046100564060768275"); - - pub static ref TEST_ERC20_DEPLOYED_ACCOUNT_BALANCE_KEY: Felt252 = - felt_str!("2542253978940891427830343982984992363331567580652119103860970381451088310289"); - - // Others. - // Blockifier had this value hardcoded to 2. - pub static ref ACTUAL_FEE: Felt252 = Felt252::from(10000000); -} - -pub fn new_starknet_block_context_for_testing() -> BlockContext { - BlockContext::new( - StarknetOsConfig::new( - StarknetChainId::TestNet.to_felt(), - TEST_ERC20_CONTRACT_ADDRESS.clone(), - 1, - ), - 0, - 0, - DEFAULT_CAIRO_RESOURCE_FEE_WEIGHTS.clone(), - 1_000_000, - 0, - BlockInfo::empty(TEST_SEQUENCER_ADDRESS.clone()), - HashMap::default(), - true, - ) -} - -pub fn create_account_tx_test_state( -) -> Result<(BlockContext, CachedState), Box> { - let block_context = new_starknet_block_context_for_testing(); - - let test_contract_class_hash = felt_to_hash(&TEST_CLASS_HASH.clone()); - let test_account_contract_class_hash = felt_to_hash(&TEST_ACCOUNT_CONTRACT_CLASS_HASH.clone()); - let test_erc20_class_hash = felt_to_hash(&TEST_ERC20_CONTRACT_CLASS_HASH.clone()); - let class_hash_to_class = HashMap::from([ - ( - test_account_contract_class_hash, - ContractClass::from_path(ACCOUNT_CONTRACT_PATH)?, - ), - ( - test_contract_class_hash, - ContractClass::from_path(TEST_CONTRACT_PATH)?, - ), - ( - test_erc20_class_hash, - ContractClass::from_path(ERC20_CONTRACT_PATH)?, - ), - ]); - - let test_contract_address = TEST_CONTRACT_ADDRESS.clone(); - let test_account_contract_address = TEST_ACCOUNT_CONTRACT_ADDRESS.clone(); - let test_erc20_address = block_context - .starknet_os_config() - .fee_token_address() - .clone(); - let address_to_class_hash = HashMap::from([ - (test_contract_address, test_contract_class_hash), - ( - test_account_contract_address, - test_account_contract_class_hash, - ), - (test_erc20_address.clone(), test_erc20_class_hash), - ]); - - let test_erc20_account_balance_key = TEST_ERC20_ACCOUNT_BALANCE_KEY.clone(); - - let storage_view = HashMap::from([( - (test_erc20_address, test_erc20_account_balance_key), - ACTUAL_FEE.clone(), - )]); - - let cached_state = CachedState::new( - { - let mut state_reader = InMemoryStateReader::default(); - for (contract_address, class_hash) in address_to_class_hash { - let storage_keys: HashMap<(Address, ClassHash), Felt252> = storage_view - .iter() - .filter_map(|((address, storage_key), storage_value)| { - (address == &contract_address).then_some(( - (address.clone(), felt_to_hash(storage_key)), - storage_value.clone(), - )) - }) - .collect(); - - let stored: HashMap = storage_keys; - - state_reader - .address_to_class_hash_mut() - .insert(contract_address.clone(), class_hash); - - state_reader - .address_to_nonce_mut() - .insert(contract_address.clone(), Felt252::zero()); - state_reader.address_to_storage_mut().extend(stored); - } - for (class_hash, contract_class) in class_hash_to_class { - state_reader.class_hash_to_compiled_class_mut().insert( - class_hash, - CompiledClass::Deprecated(Arc::new(contract_class)), - ); - } - Arc::new(state_reader) - }, - HashMap::new(), - ); - - Ok((block_context, cached_state)) -} diff --git a/src/testing/state.rs b/src/testing/state.rs deleted file mode 100644 index 2fbbaec87..000000000 --- a/src/testing/state.rs +++ /dev/null @@ -1,733 +0,0 @@ -use super::{state_error::StarknetStateError, type_utils::ExecutionInfo}; -use crate::execution::execution_entry_point::ExecutionResult; -use crate::services::api::contract_classes::compiled_class::CompiledClass; -use crate::services::api::contract_classes::deprecated_contract_class::EntryPointType; -use crate::{ - definitions::{block_context::BlockContext, constants::TRANSACTION_VERSION}, - execution::{ - execution_entry_point::ExecutionEntryPoint, CallInfo, Event, TransactionExecutionContext, - TransactionExecutionInfo, - }, - services::api::{ - contract_classes::deprecated_contract_class::ContractClass, messages::StarknetMessageToL1, - }, - state::{ - cached_state::CachedState, - state_api::{State, StateReader}, - }, - state::{in_memory_state_reader::InMemoryStateReader, ExecutionResourcesManager}, - transaction::{ - error::TransactionError, invoke_function::InvokeFunction, Declare, Deploy, Transaction, - }, - utils::{Address, ClassHash}, -}; -use cairo_vm::felt::Felt252; -use num_traits::{One, Zero}; -use std::collections::HashMap; -use std::sync::Arc; - -// --------------------------------------------------------------------- -/// StarkNet testing object. Represents a state of a StarkNet network. -pub struct StarknetState { - pub state: CachedState, - pub(crate) block_context: BlockContext, - l2_to_l1_messages: HashMap, usize>, - l2_to_l1_messages_log: Vec, - events: Vec, -} - -impl StarknetState { - pub fn new(context: Option) -> Self { - let block_context = context.unwrap_or_default(); - let state_reader = Arc::new(InMemoryStateReader::default()); - - let state = CachedState::new(state_reader, HashMap::new()); - - let l2_to_l1_messages = HashMap::new(); - let l2_to_l1_messages_log = Vec::new(); - - let events = Vec::new(); - StarknetState { - state, - block_context, - l2_to_l1_messages, - l2_to_l1_messages_log, - events, - } - } - - pub fn new_with_states( - block_context: Option, - state: CachedState, - ) -> Self { - let block_context = block_context.unwrap_or_default(); - let l2_to_l1_messages = HashMap::new(); - let l2_to_l1_messages_log = Vec::new(); - - let events = Vec::new(); - StarknetState { - state, - block_context, - l2_to_l1_messages, - l2_to_l1_messages_log, - events, - } - } - - // ------------------------------------------------------------------------------------ - /// Declares a contract class. - /// Returns the class hash and the execution info. - /// Args: - /// contract_class - a compiled StarkNet contract - pub fn declare( - &mut self, - contract_class: ContractClass, - ) -> Result<(ClassHash, TransactionExecutionInfo), TransactionError> { - let tx = Declare::new( - contract_class, - self.chain_id(), - Address(Felt252::one()), - 0, - 0.into(), - Vec::new(), - 0.into(), - )?; - - let tx_execution_info = tx.execute(&mut self.state, &self.block_context)?; - - Ok((tx.class_hash, tx_execution_info)) - } - - /// Invokes a contract function. Returns the execution info. - - #[allow(clippy::too_many_arguments)] - pub fn invoke_raw( - &mut self, - contract_address: Address, - selector: Felt252, - calldata: Vec, - max_fee: u128, - signature: Option>, - nonce: Option, - hash_value: Option, - remaining_gas: u128, - ) -> Result { - let tx = self.create_invoke_function( - contract_address, - selector, - calldata, - max_fee, - signature, - nonce, - hash_value, - )?; - - let mut tx = Transaction::InvokeFunction(tx); - self.execute_tx(&mut tx, remaining_gas) - } - - /// Builds the transaction execution context and executes the entry point. - /// Returns the CallInfo. - pub fn execute_entry_point_raw( - &mut self, - contract_address: Address, - entry_point_selector: Felt252, - calldata: Vec, - caller_address: Address, - ) -> Result { - let call = ExecutionEntryPoint::new( - contract_address, - calldata, - entry_point_selector, - caller_address, - EntryPointType::External, - None, - None, - 0, - ); - - let mut resources_manager = ExecutionResourcesManager::default(); - - let mut tx_execution_context = TransactionExecutionContext::default(); - let ExecutionResult { call_info, .. } = call.execute( - &mut self.state, - &self.block_context, - &mut resources_manager, - &mut tx_execution_context, - false, - self.block_context.invoke_tx_max_n_steps, - )?; - - let call_info = call_info.ok_or(StarknetStateError::Transaction( - TransactionError::CallInfoIsNone, - ))?; - - let exec_info = ExecutionInfo::Call(Box::new(call_info.clone())); - self.add_messages_and_events(&exec_info)?; - - Ok(call_info) - } - - /// Deploys a contract. Returns the contract address and the execution info. - /// Args: - /// contract_class - a compiled StarkNet contract - /// contract_address_salt - /// the salt to use for deploying. Otherwise, the salt is randomized. - pub fn deploy( - &mut self, - contract_class: ContractClass, - constructor_calldata: Vec, - contract_address_salt: Felt252, - hash_value: Option, - remaining_gas: u128, - ) -> Result<(Address, TransactionExecutionInfo), StarknetStateError> { - let chain_id = self.block_context.starknet_os_config.chain_id.clone(); - let deploy = match hash_value { - None => Deploy::new( - contract_address_salt, - contract_class.clone(), - constructor_calldata, - chain_id, - TRANSACTION_VERSION.clone(), - )?, - Some(hash_value) => Deploy::new_with_tx_hash( - contract_address_salt, - contract_class.clone(), - constructor_calldata, - TRANSACTION_VERSION.clone(), - hash_value, - )?, - }; - let contract_address = deploy.contract_address.clone(); - let contract_hash = deploy.contract_hash; - let mut tx = Transaction::Deploy(deploy); - - self.state.set_contract_class( - &contract_hash, - &CompiledClass::Deprecated(Arc::new(contract_class)), - )?; - - let tx_execution_info = self.execute_tx(&mut tx, remaining_gas)?; - Ok((contract_address, tx_execution_info)) - } - - pub fn execute_tx( - &mut self, - tx: &mut Transaction, - remaining_gas: u128, - ) -> Result { - let tx = tx.execute(&mut self.state, &self.block_context, remaining_gas)?; - let tx_execution_info = ExecutionInfo::Transaction(Box::new(tx.clone())); - self.add_messages_and_events(&tx_execution_info)?; - Ok(tx) - } - - pub fn add_messages_and_events( - &mut self, - exec_info: &ExecutionInfo, - ) -> Result<(), StarknetStateError> { - for msg in exec_info.get_sorted_l2_to_l1_messages()? { - let starknet_message = - StarknetMessageToL1::new(msg.from_address, msg.to_address, msg.payload); - - self.l2_to_l1_messages_log.push(starknet_message.clone()); - let message_hash = starknet_message.get_hash(); - - if self.l2_to_l1_messages.contains_key(&message_hash) { - let val = self.l2_to_l1_messages.get(&message_hash).unwrap(); - self.l2_to_l1_messages.insert(message_hash, val + 1); - } else { - self.l2_to_l1_messages.insert(message_hash, 1); - } - } - - let mut events = exec_info.get_sorted_events()?; - self.events.append(&mut events); - Ok(()) - } - - /// Consumes the given message hash. - pub fn consume_message_hash( - &mut self, - message_hash: Vec, - ) -> Result<(), StarknetStateError> { - let val = self - .l2_to_l1_messages - .get(&message_hash) - .ok_or(StarknetStateError::InvalidMessageHash)?; - - if val.is_zero() { - Err(StarknetStateError::InvalidMessageHash) - } else { - self.l2_to_l1_messages.insert(message_hash, val - 1); - Ok(()) - } - } - - // ------------------------ - // Private functions - // ------------------------ - - fn chain_id(&self) -> Felt252 { - self.block_context.starknet_os_config.chain_id.clone() - } - - #[allow(clippy::too_many_arguments)] - fn create_invoke_function( - &mut self, - contract_address: Address, - entry_point_selector: Felt252, - calldata: Vec, - max_fee: u128, - signature: Option>, - nonce: Option, - hash_value: Option, - ) -> Result { - let signature = match signature { - Some(sign) => sign, - None => Vec::new(), - }; - - let nonce = match nonce { - Some(n) => n, - None => self.state.get_nonce_at(&contract_address)?, - }; - - match hash_value { - None => InvokeFunction::new( - contract_address, - entry_point_selector, - max_fee, - TRANSACTION_VERSION.clone(), - calldata, - signature, - self.chain_id(), - Some(nonce), - ), - Some(hash_value) => InvokeFunction::new_with_tx_hash( - contract_address, - entry_point_selector, - max_fee, - TRANSACTION_VERSION.clone(), - calldata, - signature, - Some(nonce), - hash_value, - ), - } - } -} - -#[cfg(test)] -mod tests { - use std::path::PathBuf; - - use cairo_vm::vm::runners::cairo_runner::ExecutionResources; - use num_traits::Num; - use pretty_assertions_sorted::assert_eq_sorted; - - use super::*; - use crate::{ - core::contract_address::compute_deprecated_class_hash, - definitions::{ - constants::CONSTRUCTOR_ENTRY_POINT_SELECTOR, transaction_type::TransactionType, - }, - execution::{CallType, OrderedL2ToL1Message}, - hash_utils::calculate_contract_address, - services::api::contract_classes::compiled_class::CompiledClass, - state::state_cache::StorageEntry, - utils::{calculate_sn_keccak, felt_to_hash}, - }; - - #[test] - fn test_deploy() { - let mut starknet_state = StarknetState::new(None); - - let contract_class = ContractClass::from_path("starknet_programs/fibonacci.json").unwrap(); - - let contract_address_salt: Felt252 = 1.into(); - - // expected results - - // ----- calculate fib class hash --------- - let hash = compute_deprecated_class_hash(&contract_class).unwrap(); - let class_hash = felt_to_hash(&hash); - - let address = calculate_contract_address( - &contract_address_salt, - &hash, - &[], - Address(Felt252::zero()), - ) - .unwrap(); - - let mut actual_resources = HashMap::new(); - actual_resources.insert("l1_gas_usage".to_string(), 2448); - actual_resources.insert("n_steps".to_string(), 0); - - let transaction_exec_info = TransactionExecutionInfo { - validate_info: None, - call_info: Some(CallInfo { - caller_address: Address(0.into()), - call_type: Some(CallType::Call), - contract_address: Address(address.clone()), - code_address: None, - class_hash: Some(class_hash), - entry_point_selector: Some(CONSTRUCTOR_ENTRY_POINT_SELECTOR.clone()), - entry_point_type: Some(EntryPointType::Constructor), - ..Default::default() - }), - revert_error: None, - fee_transfer_info: None, - actual_fee: 0, - actual_resources, - tx_type: Some(TransactionType::Deploy), - }; - - // check result is correct - let exec = (Address(address), transaction_exec_info); - assert_eq!( - starknet_state - .deploy( - contract_class.clone(), - vec![], - contract_address_salt, - None, - 0 - ) - .unwrap(), - exec - ); - - // check that properly stored contract class - assert_eq!( - starknet_state - .state - .contract_classes - .get(&class_hash) - .unwrap() - .to_owned(), - CompiledClass::Deprecated(Arc::new(contract_class)) - ); - } - - #[test] - fn test_declare() { - let path = PathBuf::from("starknet_programs/account_without_validation.json"); - let contract_class = ContractClass::from_path(path).unwrap(); - - // Instantiate CachedState - let mut contract_class_cache = HashMap::new(); - - // ------------ contract data -------------------- - // hack store account contract - let hash = compute_deprecated_class_hash(&contract_class).unwrap(); - let class_hash = felt_to_hash(&hash); - contract_class_cache.insert( - class_hash, - CompiledClass::Deprecated(Arc::new(contract_class.clone())), - ); - - // store sender_address - let sender_address = Address(1.into()); - // this is not conceptually correct as the sender address would be an - // Account contract (not the contract that we are currently declaring) - // but for testing reasons its ok - let nonce = Felt252::zero(); - let storage_entry: StorageEntry = (sender_address.clone(), [19; 32]); - let storage = Felt252::zero(); - - let mut state_reader = InMemoryStateReader::default(); - state_reader - .address_to_class_hash_mut() - .insert(sender_address.clone(), class_hash); - state_reader - .address_to_nonce_mut() - .insert(sender_address.clone(), nonce.clone()); - state_reader - .address_to_storage_mut() - .insert(storage_entry.clone(), storage.clone()); - state_reader.class_hash_to_compiled_class_mut().insert( - class_hash, - CompiledClass::Deprecated(Arc::new(contract_class.clone())), - ); - - let state = CachedState::new(Arc::new(state_reader), contract_class_cache); - - //* -------------------------------------------- - //* Create starknet state with previous data - //* -------------------------------------------- - - let mut starknet_state = StarknetState::new(None); - - starknet_state.state = state; - starknet_state - .state - .set_class_hash_at(sender_address.clone(), class_hash) - .unwrap(); - - starknet_state - .state - .cache - .nonce_writes - .insert(sender_address.clone(), nonce); - - starknet_state.state.set_storage_at(&storage_entry, storage); - - starknet_state - .state - .set_contract_class( - &class_hash, - &CompiledClass::Deprecated(Arc::new(contract_class)), - ) - .unwrap(); - - // -------------------------------------------- - // Test declare with starknet state - // -------------------------------------------- - let fib_contract_class = - ContractClass::from_path("starknet_programs/fibonacci.json").unwrap(); - - let (ret_class_hash, _exec_info) = - starknet_state.declare(fib_contract_class.clone()).unwrap(); - - //* --------------------------------------- - // Expected result - //* --------------------------------------- - - // ----- calculate fib class hash --------- - let hash = compute_deprecated_class_hash(&fib_contract_class).unwrap(); - let fib_class_hash = felt_to_hash(&hash); - - // check that it return the correct clash hash - assert_eq!(ret_class_hash, fib_class_hash); - - // check that state has store has store accounts class hash - assert_eq!( - starknet_state - .state - .get_class_hash_at(&sender_address) - .unwrap() - .to_owned(), - class_hash - ); - // check that state has store fib class hash - assert_eq!( - TryInto::::try_into( - starknet_state - .state - .get_contract_class(&fib_class_hash) - .unwrap() - ) - .unwrap(), - fib_contract_class - ); - } - - #[test] - fn test_invoke() { - // 1) deploy fibonacci - // 2) invoke call over fibonacci - - let mut starknet_state = StarknetState::new(None); - let contract_class = ContractClass::from_path("starknet_programs/fibonacci.json").unwrap(); - let calldata = [1.into(), 1.into(), 10.into()].to_vec(); - let contract_address_salt: Felt252 = 1.into(); - - let (contract_address, _exec_info) = starknet_state - .deploy( - contract_class.clone(), - vec![], - contract_address_salt.clone(), - None, - 0, - ) - .unwrap(); - - // fibonacci selector - let selector = Felt252::from_str_radix( - "112e35f48499939272000bd72eb840e502ca4c3aefa8800992e8defb746e0c9", - 16, - ) - .unwrap(); - - // Statement **not** in blockifier. - starknet_state - .state - .cache_mut() - .nonce_initial_values_mut() - .insert(contract_address.clone(), Felt252::zero()); - - let tx_info = starknet_state - .invoke_raw( - contract_address, - selector.clone(), - calldata, - 0, - Some(Vec::new()), - Some(Felt252::zero()), - None, - 0, - ) - .unwrap(); - - // expected result - // ----- calculate fib class hash --------- - let hash = compute_deprecated_class_hash(&contract_class).unwrap(); - let fib_class_hash = felt_to_hash(&hash); - - let address = calculate_contract_address( - &contract_address_salt, - &hash, - &[], - Address(Felt252::zero()), - ) - .unwrap(); - let actual_resources = HashMap::from([ - ("n_steps".to_string(), 3457), - ("l1_gas_usage".to_string(), 2448), - ("range_check_builtin".to_string(), 80), - ("pedersen_builtin".to_string(), 16), - ]); - - let expected_info = TransactionExecutionInfo { - validate_info: None, - call_info: Some(CallInfo { - caller_address: Address(Felt252::zero()), - call_type: Some(CallType::Call), - contract_address: Address(address), - code_address: None, - class_hash: Some(fib_class_hash), - entry_point_selector: Some(selector), - entry_point_type: Some(EntryPointType::External), - calldata: vec![1.into(), 1.into(), 10.into()], - retdata: vec![144.into()], - execution_resources: ExecutionResources { - n_steps: 94, - n_memory_holes: 0, - builtin_instance_counter: HashMap::default(), - }, - ..Default::default() - }), - actual_resources, - tx_type: Some(TransactionType::InvokeFunction), - ..Default::default() - }; - - assert_eq_sorted!(tx_info, expected_info); - } - - #[test] - fn test_execute_entry_point_raw() { - let mut starknet_state = StarknetState::new(None); - let path = PathBuf::from("starknet_programs/fibonacci.json"); - let contract_class = ContractClass::from_path(path).unwrap(); - let contract_address_salt = 1.into(); - - let (contract_address, _exec_info) = starknet_state - .deploy(contract_class, vec![], contract_address_salt, None, 0) - .unwrap(); - - // fibonacci selector - let entrypoint_selector = Felt252::from_bytes_be(&calculate_sn_keccak(b"fib")); - let result = starknet_state - .execute_entry_point_raw( - contract_address, - entrypoint_selector, - vec![1.into(), 1.into(), 10.into()], - Address(0.into()), - ) - .unwrap() - .retdata; - assert_eq!(result, vec![144.into()]); - } - - #[test] - fn test_add_messages_and_events() { - let mut starknet_state = StarknetState::new(None); - let test_msg_1 = OrderedL2ToL1Message { - order: 0, - to_address: Address(0.into()), - payload: vec![0.into()], - }; - let test_msg_2 = OrderedL2ToL1Message { - order: 1, - to_address: Address(0.into()), - payload: vec![0.into()], - }; - - let exec_info = ExecutionInfo::Call(Box::new(CallInfo { - l2_to_l1_messages: vec![test_msg_1, test_msg_2], - ..Default::default() - })); - - starknet_state.add_messages_and_events(&exec_info).unwrap(); - let msg_hash = - StarknetMessageToL1::new(Address(0.into()), Address(0.into()), vec![0.into()]) - .get_hash(); - - let messages = starknet_state.l2_to_l1_messages; - let mut expected_messages = HashMap::new(); - expected_messages.insert(msg_hash, 2); - assert_eq!(messages, expected_messages); - } - - #[test] - fn test_consume_message_hash() { - let mut starknet_state = StarknetState::new(None); - let test_msg_1 = OrderedL2ToL1Message { - order: 0, - to_address: Address(0.into()), - payload: vec![0.into()], - }; - let test_msg_2 = OrderedL2ToL1Message { - order: 1, - to_address: Address(0.into()), - payload: vec![0.into()], - }; - - let exec_info = ExecutionInfo::Call(Box::new(CallInfo { - l2_to_l1_messages: vec![test_msg_1, test_msg_2], - ..Default::default() - })); - - starknet_state.add_messages_and_events(&exec_info).unwrap(); - let msg_hash = - StarknetMessageToL1::new(Address(0.into()), Address(0.into()), vec![0.into()]) - .get_hash(); - - starknet_state - .consume_message_hash(msg_hash.clone()) - .unwrap(); - let messages = starknet_state.l2_to_l1_messages; - let mut expected_messages = HashMap::new(); - expected_messages.insert(msg_hash, 1); - assert_eq!(messages, expected_messages); - } - - #[test] - fn test_consume_message_hash_twice_should_fail() { - let mut starknet_state = StarknetState::new(None); - let test_msg = OrderedL2ToL1Message { - order: 0, - to_address: Address(0.into()), - payload: vec![0.into()], - }; - - let exec_info = ExecutionInfo::Call(Box::new(CallInfo { - l2_to_l1_messages: vec![test_msg], - ..Default::default() - })); - - starknet_state.add_messages_and_events(&exec_info).unwrap(); - let msg_hash = - StarknetMessageToL1::new(Address(0.into()), Address(0.into()), vec![0.into()]) - .get_hash(); - - starknet_state - .consume_message_hash(msg_hash.clone()) - .unwrap(); - let err = starknet_state.consume_message_hash(msg_hash).unwrap_err(); - assert_matches!(err, StarknetStateError::InvalidMessageHash); - } -} diff --git a/src/testing/state_error.rs b/src/testing/state_error.rs deleted file mode 100644 index c2e8ec705..000000000 --- a/src/testing/state_error.rs +++ /dev/null @@ -1,20 +0,0 @@ -use thiserror::Error; - -use crate::{ - core::errors::hash_errors::HashError, core::errors::state_errors::StateError, - syscalls::syscall_handler_errors::SyscallHandlerError, transaction::error::TransactionError, -}; - -#[derive(Debug, Error)] -pub enum StarknetStateError { - #[error("Invalid message hash key passed to l2 messages")] - InvalidMessageHash, - #[error(transparent)] - Syscall(#[from] SyscallHandlerError), - #[error(transparent)] - State(#[from] StateError), - #[error(transparent)] - Transaction(#[from] TransactionError), - #[error(transparent)] - HashError(#[from] HashError), -} diff --git a/src/testing/type_utils.rs b/src/testing/type_utils.rs deleted file mode 100644 index 488212c2e..000000000 --- a/src/testing/type_utils.rs +++ /dev/null @@ -1,25 +0,0 @@ -use crate::{ - execution::{CallInfo, Event, L2toL1MessageInfo, TransactionExecutionInfo}, - transaction::error::TransactionError, -}; - -pub enum ExecutionInfo { - Transaction(Box), - Call(Box), -} - -impl ExecutionInfo { - pub fn get_sorted_l2_to_l1_messages(&self) -> Result, TransactionError> { - match self { - ExecutionInfo::Transaction(tx) => tx.get_sorted_l2_to_l1_messages(), - ExecutionInfo::Call(call) => call.get_sorted_l2_to_l1_messages(), - } - } - - pub fn get_sorted_events(&self) -> Result, TransactionError> { - match self { - ExecutionInfo::Transaction(tx) => tx.get_sorted_events(), - ExecutionInfo::Call(call) => call.get_sorted_events(), - } - } -} diff --git a/src/utils.rs b/src/utils.rs index 15b70cbf9..9e12b47ae 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -436,12 +436,33 @@ pub fn parse_felt_array(felt_strings: &[Value]) -> Vec { pub mod test_utils { #![allow(unused_imports)] + use crate::{ + definitions::{ + block_context::{BlockContext, StarknetChainId, StarknetOsConfig}, + constants::DEFAULT_CAIRO_RESOURCE_FEE_WEIGHTS, + }, + services::api::contract_classes::{ + compiled_class::CompiledClass, deprecated_contract_class::ContractClass, + }, + state::{ + cached_state::CachedState, in_memory_state_reader::InMemoryStateReader, + state_cache::StorageEntry, BlockInfo, + }, + utils::Address, + }; + use cairo_vm::felt::{felt_str, Felt252}; + use num_traits::Zero; + use std::{collections::HashMap, sync::Arc}; + + use super::{felt_to_hash, ClassHash}; + #[macro_export] macro_rules! any_box { ($val : expr) => { Box::new($val) as Box }; } + pub(crate) use any_box; macro_rules! references { @@ -461,6 +482,7 @@ pub mod test_utils { references }}; } + pub(crate) use references; macro_rules! ids_data { @@ -617,6 +639,148 @@ pub mod test_utils { }}; } pub(crate) use run_syscall_hint; + + pub(crate) const ACCOUNT_CONTRACT_PATH: &str = + "starknet_programs/account_without_validation.json"; + pub(crate) const ERC20_CONTRACT_PATH: &str = "starknet_programs/ERC20.json"; + pub(crate) const TEST_CONTRACT_PATH: &str = "starknet_programs/fibonacci.json"; + + lazy_static::lazy_static! { + // Addresses. + pub(crate) static ref TEST_ACCOUNT_CONTRACT_ADDRESS: Address = Address(felt_str!("257")); + pub(crate) static ref TEST_CONTRACT_ADDRESS: Address = Address(felt_str!("256")); + pub(crate) static ref TEST_SEQUENCER_ADDRESS: Address = + Address(felt_str!("4096")); + pub(crate) static ref TEST_ERC20_CONTRACT_ADDRESS: Address = + Address(felt_str!("4097")); + + + // Class hashes. + pub(crate) static ref TEST_ACCOUNT_CONTRACT_CLASS_HASH: Felt252 = felt_str!("273"); + pub(crate) static ref TEST_CLASS_HASH: Felt252 = felt_str!("272"); + pub(crate) static ref TEST_EMPTY_CONTRACT_CLASS_HASH: Felt252 = felt_str!("274"); + pub(crate) static ref TEST_ERC20_CONTRACT_CLASS_HASH: Felt252 = felt_str!("4112"); + pub(crate) static ref TEST_FIB_COMPILED_CONTRACT_CLASS_HASH: Felt252 = felt_str!("1948962768849191111780391610229754715773924969841143100991524171924131413970"); + + // Storage keys. + pub(crate) static ref TEST_ERC20_ACCOUNT_BALANCE_KEY: Felt252 = + felt_str!("1192211877881866289306604115402199097887041303917861778777990838480655617515"); + pub(crate) static ref TEST_ERC20_SEQUENCER_BALANCE_KEY: Felt252 = + felt_str!("3229073099929281304021185011369329892856197542079132996799046100564060768274"); + pub(crate) static ref TEST_ERC20_BALANCE_KEY_1: Felt252 = + felt_str!("1192211877881866289306604115402199097887041303917861778777990838480655617516"); + pub(crate) static ref TEST_ERC20_BALANCE_KEY_2: Felt252 = + felt_str!("3229073099929281304021185011369329892856197542079132996799046100564060768275"); + + pub(crate) static ref TEST_ERC20_DEPLOYED_ACCOUNT_BALANCE_KEY: Felt252 = + felt_str!("2542253978940891427830343982984992363331567580652119103860970381451088310289"); + + // Others. + // Blockifier had this value hardcoded to 2. + pub(crate) static ref ACTUAL_FEE: Felt252 = Felt252::from(10000000); + } + + pub(crate) fn new_starknet_block_context_for_testing() -> BlockContext { + BlockContext::new( + StarknetOsConfig::new( + StarknetChainId::TestNet.to_felt(), + TEST_ERC20_CONTRACT_ADDRESS.clone(), + 1, + ), + 0, + 0, + DEFAULT_CAIRO_RESOURCE_FEE_WEIGHTS.clone(), + 1_000_000, + 0, + BlockInfo::empty(TEST_SEQUENCER_ADDRESS.clone()), + HashMap::default(), + true, + ) + } + + pub(crate) fn create_account_tx_test_state( + ) -> Result<(BlockContext, CachedState), Box> { + let block_context = new_starknet_block_context_for_testing(); + + let test_contract_class_hash = felt_to_hash(&TEST_CLASS_HASH.clone()); + let test_account_contract_class_hash = + felt_to_hash(&TEST_ACCOUNT_CONTRACT_CLASS_HASH.clone()); + let test_erc20_class_hash = felt_to_hash(&TEST_ERC20_CONTRACT_CLASS_HASH.clone()); + let class_hash_to_class = HashMap::from([ + ( + test_account_contract_class_hash, + ContractClass::from_path(ACCOUNT_CONTRACT_PATH)?, + ), + ( + test_contract_class_hash, + ContractClass::from_path(TEST_CONTRACT_PATH)?, + ), + ( + test_erc20_class_hash, + ContractClass::from_path(ERC20_CONTRACT_PATH)?, + ), + ]); + + let test_contract_address = TEST_CONTRACT_ADDRESS.clone(); + let test_account_contract_address = TEST_ACCOUNT_CONTRACT_ADDRESS.clone(); + let test_erc20_address = block_context + .starknet_os_config() + .fee_token_address() + .clone(); + let address_to_class_hash = HashMap::from([ + (test_contract_address, test_contract_class_hash), + ( + test_account_contract_address, + test_account_contract_class_hash, + ), + (test_erc20_address.clone(), test_erc20_class_hash), + ]); + + let test_erc20_account_balance_key = TEST_ERC20_ACCOUNT_BALANCE_KEY.clone(); + + let storage_view = HashMap::from([( + (test_erc20_address, test_erc20_account_balance_key), + ACTUAL_FEE.clone(), + )]); + + let cached_state = CachedState::new( + { + let mut state_reader = InMemoryStateReader::default(); + for (contract_address, class_hash) in address_to_class_hash { + let storage_keys: HashMap<(Address, ClassHash), Felt252> = storage_view + .iter() + .filter_map(|((address, storage_key), storage_value)| { + (address == &contract_address).then_some(( + (address.clone(), felt_to_hash(storage_key)), + storage_value.clone(), + )) + }) + .collect(); + + let stored: HashMap = storage_keys; + + state_reader + .address_to_class_hash_mut() + .insert(contract_address.clone(), class_hash); + + state_reader + .address_to_nonce_mut() + .insert(contract_address.clone(), Felt252::zero()); + state_reader.address_to_storage_mut().extend(stored); + } + for (class_hash, contract_class) in class_hash_to_class { + state_reader.class_hash_to_compiled_class_mut().insert( + class_hash, + CompiledClass::Deprecated(Arc::new(contract_class)), + ); + } + Arc::new(state_reader) + }, + HashMap::new(), + ); + + Ok((block_context, cached_state)) + } } #[cfg(test)] diff --git a/src/testing/erc20.rs b/tests/complex_contracts/erc20.rs similarity index 85% rename from src/testing/erc20.rs rename to tests/complex_contracts/erc20.rs index f29f94b0b..dc249032a 100644 --- a/src/testing/erc20.rs +++ b/tests/complex_contracts/erc20.rs @@ -1,43 +1,21 @@ -#![allow(unused_imports)] -use std::{collections::HashMap, io::Bytes, path::Path, sync::Arc}; +use std::{collections::HashMap, sync::Arc}; -use crate::{ +use cairo_vm::felt::{felt_str, Felt252}; +use num_traits::Zero; +use starknet_in_rust::{ call_contract, - definitions::{ - block_context::{BlockContext, StarknetChainId}, - constants::CONSTRUCTOR_ENTRY_POINT_SELECTOR, - }, + definitions::block_context::{BlockContext, StarknetChainId}, execution::{ execution_entry_point::ExecutionEntryPoint, CallType, TransactionExecutionContext, }, - services::api::contract_classes::{ - compiled_class::CompiledClass, deprecated_contract_class::ContractClass, - }, + services::api::contract_classes::compiled_class::CompiledClass, state::{ - cached_state::CachedState, - in_memory_state_reader::InMemoryStateReader, - state_api::{State, StateReader}, + cached_state::CachedState, in_memory_state_reader::InMemoryStateReader, state_api::State, ExecutionResourcesManager, }, - transaction::{error::TransactionError, DeployAccount, InvokeFunction}, - utils::calculate_sn_keccak, - EntryPointType, Felt252, -}; -use cairo_lang_starknet::casm_contract_class::CasmContractClass; -use cairo_vm::felt::felt_str; -use lazy_static::lazy_static; -use num_traits::Zero; -pub const ERC20_CONTRACT_PATH: &str = "starknet_programs/cairo2/ERC20.casm"; -use crate::{ - state::state_cache::StorageEntry, - utils::{felt_to_hash, Address, ClassHash}, -}; - -use super::{ - new_starknet_block_context_for_testing, ACCOUNT_CONTRACT_PATH, ACTUAL_FEE, - TEST_ACCOUNT_CONTRACT_ADDRESS, TEST_ACCOUNT_CONTRACT_CLASS_HASH, TEST_CLASS_HASH, - TEST_CONTRACT_ADDRESS, TEST_CONTRACT_PATH, TEST_ERC20_ACCOUNT_BALANCE_KEY, - TEST_ERC20_CONTRACT_CLASS_HASH, + transaction::DeployAccount, + utils::{calculate_sn_keccak, Address, ClassHash}, + CasmContractClass, EntryPointType, }; #[test] @@ -130,7 +108,7 @@ fn test_erc20_cairo2() { &mut resources_manager, &mut tx_execution_context, false, - block_context.invoke_tx_max_n_steps, + block_context.invoke_tx_max_n_steps(), ) .unwrap(); let erc20_address = call_info.call_info.unwrap().retdata.get(0).unwrap().clone(); diff --git a/tests/complex_contracts/mod.rs b/tests/complex_contracts/mod.rs index c6000a3a9..1131126f3 100644 --- a/tests/complex_contracts/mod.rs +++ b/tests/complex_contracts/mod.rs @@ -1,3 +1,4 @@ pub mod amm_contracts; +pub mod erc20; pub mod nft; pub mod utils;