diff --git a/rpc_state_reader/src/rpc_state.rs b/rpc_state_reader/src/rpc_state.rs index 76bdd4922..cb5b0808f 100644 --- a/rpc_state_reader/src/rpc_state.rs +++ b/rpc_state_reader/src/rpc_state.rs @@ -401,12 +401,12 @@ impl RpcState { } } - pub fn get_contract_class(&self, class_hash: &ClassHash) -> SNContractClass { + pub fn get_contract_class(&self, class_hash: &ClassHash) -> Option { self.rpc_call_result( "starknet_getClass", &json!([self.block.to_value().unwrap(), class_hash.0.to_string()]), ) - .unwrap() + .ok() } pub fn get_class_hash_at(&self, contract_address: &ContractAddress) -> ClassHash { diff --git a/rpc_state_reader/src/utils.rs b/rpc_state_reader/src/utils.rs index 59c1d9121..9a1fce09b 100644 --- a/rpc_state_reader/src/utils.rs +++ b/rpc_state_reader/src/utils.rs @@ -11,7 +11,7 @@ use starknet_api::{ core::EntryPointSelector, deprecated_contract_class::{EntryPoint, EntryPointOffset, EntryPointType}, hash::{StarkFelt, StarkHash}, - transaction::{InvokeTransaction, Transaction}, + transaction::{DeclareTransaction, InvokeTransaction, Transaction}, }; #[derive(Debug, Deserialize)] @@ -85,6 +85,20 @@ pub fn deserialize_transaction_json( "DEPLOY_ACCOUNT" => Ok(Transaction::DeployAccount(serde_json::from_value( transaction, )?)), + "DECLARE" => match tx_version.as_str() { + "0x0" => Ok(Transaction::Declare(DeclareTransaction::V0( + serde_json::from_value(transaction)?, + ))), + "0x1" => Ok(Transaction::Declare(DeclareTransaction::V1( + serde_json::from_value(transaction)?, + ))), + "0x2" => Ok(Transaction::Declare(DeclareTransaction::V2( + serde_json::from_value(transaction)?, + ))), + x => Err(serde::de::Error::custom(format!( + "unimplemented declare version: {x}" + ))), + }, x => Err(serde::de::Error::custom(format!( "unimplemented transaction type deserialization: {x}" ))), diff --git a/rpc_state_reader/tests/blockifier_tests.rs b/rpc_state_reader/tests/blockifier_tests.rs index 0bcb17f0e..a516ff693 100644 --- a/rpc_state_reader/tests/blockifier_tests.rs +++ b/rpc_state_reader/tests/blockifier_tests.rs @@ -3,12 +3,13 @@ use blockifier::{ execution::{contract_class::ContractClass, entry_point::CallInfo}, state::{ cached_state::{CachedState, GlobalContractCache}, + errors::StateError, state_api::{StateReader, StateResult}, }, transaction::{ account_transaction::AccountTransaction, objects::TransactionExecutionInfo, - transactions::{DeployAccountTransaction, ExecutableTransaction}, + transactions::{DeclareTransaction, DeployAccountTransaction, ExecutableTransaction}, }, }; use blockifier::{ @@ -66,7 +67,7 @@ impl StateReader for RpcStateReader { class_hash: &ClassHash, ) -> StateResult { Ok(match self.0.get_contract_class(class_hash) { - SNContractClass::Legacy(compressed_legacy_cc) => { + Some(SNContractClass::Legacy(compressed_legacy_cc)) => { let as_str = utils::decode_reader(compressed_legacy_cc.program).unwrap(); let program = Program::from_bytes(as_str.as_bytes(), None).unwrap(); let entry_points_by_type = utils::map_entry_points_by_type_legacy( @@ -78,7 +79,7 @@ impl StateReader for RpcStateReader { }); BlockifierContractClass::V0(ContractClassV0(inner)) } - SNContractClass::Sierra(flattened_sierra_cc) => { + Some(SNContractClass::Sierra(flattened_sierra_cc)) => { let middle_sierra: utils::MiddleSierraContractClass = { let v = serde_json::to_value(flattened_sierra_cc).unwrap(); serde_json::from_value(v).unwrap() @@ -93,6 +94,7 @@ impl StateReader for RpcStateReader { let casm_cc = CasmContractClass::from_contract_class(sierra_cc, false).unwrap(); BlockifierContractClass::V1(casm_cc.try_into().unwrap()) } + None => return Err(StateError::UndeclaredClassHash(*class_hash)), }) } @@ -194,6 +196,17 @@ pub fn execute_tx( contract_address, }) } + SNTransaction::Declare(tx) => { + // Fetch the contract_class from the next block (as we don't have it in the previous one) + let mut next_block_state_reader = + RpcStateReader(RpcState::new_infura(network, (block_number.next()).into())); + let contract_class = next_block_state_reader + .get_compiled_contract_class(&tx.class_hash()) + .unwrap(); + + let declare = DeclareTransaction::new(tx, tx_hash, contract_class).unwrap(); + AccountTransaction::Declare(declare) + } _ => unimplemented!(), }; @@ -385,3 +398,38 @@ fn blockifier_test_case_reverted_tx(hash: &str, block_number: u64, chain: RpcCha ); } } + +#[test_case( + // Declare tx + "0x60506c49e65d84e2cdd0e9142dc43832a0a59cb6a9cbcce1ab4f57c20ba4afb", + 347899, // real block 347900 + RpcChain::MainNet +)] +#[test_case( + // Declare tx + "0x1088aa18785779e1e8eef406dc495654ad42a9729b57969ad0dbf2189c40bee", + 271887, // real block 271888 + RpcChain::MainNet +)] +fn blockifier_test_case_declare_tx(hash: &str, block_number: u64, chain: RpcChain) { + let (tx_info, _trace, receipt) = execute_tx(hash, chain, BlockNumber(block_number)); + let TransactionExecutionInfo { + execute_call_info, + actual_fee, + .. + } = tx_info; + + assert!(execute_call_info.is_none()); + + let actual_fee = actual_fee.0; + if receipt.actual_fee != actual_fee { + let diff = 100 * receipt.actual_fee.abs_diff(actual_fee) / receipt.actual_fee; + + if diff >= 5 { + assert_eq!( + actual_fee, receipt.actual_fee, + "actual_fee mismatch differs from the baseline by more than 5% ({diff}%)", + ); + } + } +} diff --git a/rpc_state_reader/tests/sir_tests.rs b/rpc_state_reader/tests/sir_tests.rs index 4fdbcbe12..8f1dca76f 100644 --- a/rpc_state_reader/tests/sir_tests.rs +++ b/rpc_state_reader/tests/sir_tests.rs @@ -8,10 +8,10 @@ use starknet_api::{ hash::{StarkFelt, StarkHash}, stark_felt, state::StorageKey, - transaction::{Transaction as SNTransaction, TransactionHash}, + transaction::{Transaction as SNTransaction, TransactionHash, TransactionVersion}, }; use starknet_in_rust::{ - core::errors::state_errors::StateError, + core::{contract_address::compute_casm_class_hash, errors::state_errors::StateError}, definitions::{ block_context::{BlockContext, StarknetChainId, StarknetOsConfig}, constants::{ @@ -28,7 +28,7 @@ use starknet_in_rust::{ state_cache::StorageEntry, BlockInfo, }, - transaction::{DeployAccount, InvokeFunction}, + transaction::{Declare, DeclareV2, DeployAccount, InvokeFunction}, utils::{Address, ClassHash}, }; @@ -42,7 +42,9 @@ pub struct RpcStateReader(RpcState); impl StateReader for RpcStateReader { fn get_contract_class(&self, class_hash: &ClassHash) -> Result { let hash = SNClassHash(StarkHash::new(*class_hash).unwrap()); - Ok(CompiledClass::from(self.0.get_contract_class(&hash))) + Ok(CompiledClass::from( + self.0.get_contract_class(&hash).unwrap(), + )) } fn get_class_hash_at(&self, contract_address: &Address) -> Result { @@ -148,6 +150,64 @@ pub fn execute_tx_configurable( .unwrap() .create_for_simulation(skip_validate, false, false, false) } + SNTransaction::Declare(tx) => { + // Fetch the contract_class from the next block (as we don't have it in the previous one) + let next_block_state_reader = + RpcStateReader(RpcState::new_infura(network, (block_number.next()).into())); + let contract_class = next_block_state_reader + .get_contract_class(tx.class_hash().0.bytes().try_into().unwrap()) + .unwrap(); + + if tx.version() != TransactionVersion(2_u8.into()) { + let contract_class = match contract_class { + CompiledClass::Deprecated(cc) => cc.as_ref().clone(), + _ => unreachable!(), + }; + + let declare = Declare::new_with_tx_and_class_hash( + contract_class, + Address(Felt252::from_bytes_be(tx.sender_address().0.key().bytes())), + tx.max_fee().0, + Felt252::from_bytes_be(tx.version().0.bytes()), + tx.signature() + .0 + .iter() + .map(|f| Felt252::from_bytes_be(f.bytes())) + .collect(), + Felt252::from_bytes_be(tx.nonce().0.bytes()), + Felt252::from_bytes_be(tx_hash.0.bytes()), + tx.class_hash().0.bytes().try_into().unwrap(), + ) + .unwrap(); + declare.create_for_simulation(skip_validate, false, false, false) + } else { + let contract_class = match contract_class { + CompiledClass::Casm(cc) => cc.as_ref().clone(), + _ => unreachable!(), + }; + + let compiled_class_hash = compute_casm_class_hash(&contract_class).unwrap(); + + let declare = DeclareV2::new_with_sierra_class_hash_and_tx_hash( + None, + Felt252::from_bytes_be(tx.class_hash().0.bytes()), + Some(contract_class), + compiled_class_hash, + Address(Felt252::from_bytes_be(tx.sender_address().0.key().bytes())), + tx.max_fee().0, + Felt252::from_bytes_be(tx.version().0.bytes()), + tx.signature() + .0 + .iter() + .map(|f| Felt252::from_bytes_be(f.bytes())) + .collect(), + Felt252::from_bytes_be(tx.nonce().0.bytes()), + Felt252::from_bytes_be(tx_hash.0.bytes()), + ) + .unwrap(); + declare.create_for_simulation(skip_validate, false, false, false) + } + } _ => unimplemented!(), }; @@ -421,3 +481,38 @@ fn test_validate_fee(hash: &str, block_number: u64, chain: RpcChain) { assert_eq!(tx_info.actual_fee, receipt.actual_fee); assert!(tx_info_without_fee.actual_fee < tx_info.actual_fee); } + +#[test_case( + // Declare tx + "0x60506c49e65d84e2cdd0e9142dc43832a0a59cb6a9cbcce1ab4f57c20ba4afb", + 347899, // real block 347900 + RpcChain::MainNet +)] +#[test_case( + // Declare tx + "0x1088aa18785779e1e8eef406dc495654ad42a9729b57969ad0dbf2189c40bee", + 271887, // real block 271888 + RpcChain::MainNet +)] +fn starknet_in_rust_test_case_declare_tx(hash: &str, block_number: u64, chain: RpcChain) { + let (tx_info, _trace, receipt) = execute_tx(hash, chain, BlockNumber(block_number)); + let TransactionExecutionInfo { + call_info, + actual_fee, + .. + } = tx_info; + + assert!(call_info.is_none()); + + let actual_fee = actual_fee; + if receipt.actual_fee != actual_fee { + let diff = 100 * receipt.actual_fee.abs_diff(actual_fee) / receipt.actual_fee; + + if diff >= 5 { + assert_eq!( + actual_fee, receipt.actual_fee, + "actual_fee mismatch differs from the baseline by more than 5% ({diff}%)", + ); + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 22538125a..576e72758 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -870,7 +870,7 @@ mod test { nonce: 0.into(), hash_value: 0.into(), compiled_class_hash: TEST_FIB_COMPILED_CONTRACT_CLASS_HASH.clone(), - sierra_contract_class, + sierra_contract_class: Some(sierra_contract_class), sierra_class_hash, casm_class: Default::default(), skip_execute: false, diff --git a/src/state/cached_state.rs b/src/state/cached_state.rs index f47d5a60e..764a18384 100644 --- a/src/state/cached_state.rs +++ b/src/state/cached_state.rs @@ -266,7 +266,7 @@ impl State for CachedState { let compiled_class_hash = compiled_class_hash.to_be_bytes(); self.cache - .class_hash_to_compiled_class_hash + .compiled_class_hash_writes .insert(class_hash, compiled_class_hash); Ok(()) } diff --git a/src/state/mod.rs b/src/state/mod.rs index 06cba7613..c09d5a4e9 100644 --- a/src/state/mod.rs +++ b/src/state/mod.rs @@ -6,8 +6,9 @@ pub mod state_cache; use crate::{ core::errors::state_errors::StateError, - services::api::contract_classes::compiled_class::CompiledClass, - utils::{get_keys, to_cache_state_storage_mapping, to_state_diff_storage_mapping}, + utils::{ + get_keys, to_cache_state_storage_mapping, to_state_diff_storage_mapping, CompiledClassHash, + }, }; use cairo_vm::{felt::Felt252, vm::runners::cairo_runner::ExecutionResources}; use getset::Getters; @@ -106,7 +107,7 @@ impl ExecutionResourcesManager { pub struct StateDiff { pub(crate) address_to_class_hash: HashMap, pub(crate) address_to_nonce: HashMap, - pub(crate) class_hash_to_compiled_class: HashMap, + pub(crate) class_hash_to_compiled_class: HashMap, pub(crate) storage_updates: HashMap>, } @@ -114,7 +115,7 @@ impl StateDiff { pub const fn new( address_to_class_hash: HashMap, address_to_nonce: HashMap, - class_hash_to_compiled_class: HashMap, + class_hash_to_compiled_class: HashMap, storage_updates: HashMap>, ) -> Self { StateDiff { diff --git a/src/state/state_cache.rs b/src/state/state_cache.rs index 6238c258d..23a77400c 100644 --- a/src/state/state_cache.rs +++ b/src/state/state_cache.rs @@ -1,6 +1,5 @@ use crate::{ core::errors::state_errors::StateError, - services::api::contract_classes::compiled_class::CompiledClass, utils::{Address, ClassHash, CompiledClassHash}, }; use cairo_vm::felt::Felt252; @@ -18,7 +17,7 @@ pub struct StateCache { #[get_mut = "pub"] pub(crate) class_hash_initial_values: HashMap, #[get_mut = "pub"] - pub(crate) compiled_class_hash_initial_values: HashMap, + pub(crate) compiled_class_hash_initial_values: HashMap, #[getset(get = "pub", get_mut = "pub")] pub(crate) nonce_initial_values: HashMap, #[getset(get = "pub", get_mut = "pub")] @@ -28,7 +27,7 @@ pub struct StateCache { #[get_mut = "pub"] pub(crate) class_hash_writes: HashMap, #[get_mut = "pub"] - pub(crate) compiled_class_hash_writes: HashMap, + pub(crate) compiled_class_hash_writes: HashMap, #[get_mut = "pub"] pub(crate) nonce_writes: HashMap, #[getset(get = "pub", get_mut = "pub")] @@ -43,11 +42,11 @@ impl StateCache { /// Create a new StateCache with given initial and written values for testing pub const fn new( class_hash_initial_values: HashMap, - compiled_class_hash_initial_values: HashMap, + compiled_class_hash_initial_values: HashMap, nonce_initial_values: HashMap, storage_initial_values: HashMap, class_hash_writes: HashMap, - compiled_class_hash_writes: HashMap, + compiled_class_hash_writes: HashMap, nonce_writes: HashMap, storage_writes: HashMap, class_hash_to_compiled_class_hash: HashMap, @@ -84,11 +83,11 @@ impl StateCache { #[allow(clippy::too_many_arguments)] pub const fn new_for_testing( class_hash_initial_values: HashMap, - compiled_class_hash_initial_values: HashMap, + compiled_class_hash_initial_values: HashMap, nonce_initial_values: HashMap, storage_initial_values: HashMap, class_hash_writes: HashMap, - compiled_class_hash_writes: HashMap, + compiled_class_hash_writes: HashMap, nonce_writes: HashMap, storage_writes: HashMap<(Address, [u8; 32]), Felt252>, class_hash_to_compiled_class_hash: HashMap, @@ -116,7 +115,10 @@ impl StateCache { /// Get the compiled hash for a given class hash #[allow(dead_code)] - pub(crate) fn get_compiled_class_hash(&self, class_hash: &ClassHash) -> Option<&CompiledClass> { + pub(crate) fn get_compiled_class_hash( + &self, + class_hash: &ClassHash, + ) -> Option<&CompiledClassHash> { if self.compiled_class_hash_writes.contains_key(class_hash) { return self.compiled_class_hash_writes.get(class_hash); } @@ -143,7 +145,7 @@ impl StateCache { pub(crate) fn update_writes( &mut self, address_to_class_hash: &HashMap, - class_hash_to_compiled_class_hash: &HashMap, + class_hash_to_compiled_class_hash: &HashMap, address_to_nonce: &HashMap, storage_updates: &HashMap, ) { @@ -158,7 +160,7 @@ impl StateCache { pub fn set_initial_values( &mut self, address_to_class_hash: &HashMap, - class_hash_to_compiled_class: &HashMap, + class_hash_to_compiled_class: &HashMap, address_to_nonce: &HashMap, storage_updates: &HashMap, ) -> Result<(), StateError> { @@ -201,8 +203,7 @@ impl StateCache { } for (k, v) in self.compiled_class_hash_writes.iter() { - self.compiled_class_hash_initial_values - .insert(*k, v.clone()); + self.compiled_class_hash_initial_values.insert(*k, *v); } for (k, v) in self.storage_writes.iter() { @@ -219,9 +220,11 @@ impl StateCache { /// Unit tests for StateCache #[cfg(test)] mod tests { - use std::sync::Arc; - use crate::services::api::contract_classes::deprecated_contract_class::ContractClass; + use crate::{ + core::contract_address::compute_deprecated_class_hash, + services::api::contract_classes::deprecated_contract_class::ContractClass, + }; use super::*; @@ -232,7 +235,9 @@ mod tests { let contract_class = ContractClass::from_path("starknet_programs/raw_contract_classes/class_with_abi.json") .unwrap(); - let compiled_class = CompiledClass::Deprecated(Arc::new(contract_class)); + let compiled_class = compute_deprecated_class_hash(&contract_class) + .unwrap() + .to_be_bytes(); let class_hash_to_compiled_class_hash = HashMap::from([([8; 32], compiled_class)]); let address_to_nonce = HashMap::from([(Address(9.into()), 12.into())]); let storage_updates = HashMap::from([((Address(4.into()), [1; 32]), 18.into())]); diff --git a/src/transaction/declare.rs b/src/transaction/declare.rs index 762dfa5c9..ec1ea6dcf 100644 --- a/src/transaction/declare.rs +++ b/src/transaction/declare.rs @@ -145,6 +145,44 @@ impl Declare { Ok(internal_declare) } + #[allow(clippy::too_many_arguments)] + pub fn new_with_tx_and_class_hash( + contract_class: ContractClass, + sender_address: Address, + max_fee: u128, + version: Felt252, + signature: Vec, + nonce: Felt252, + hash_value: Felt252, + class_hash: ClassHash, + ) -> Result { + let validate_entry_point_selector = VALIDATE_DECLARE_ENTRY_POINT_SELECTOR.clone(); + + let internal_declare = Declare { + class_hash, + sender_address, + validate_entry_point_selector, + version, + max_fee, + signature, + nonce, + hash_value, + contract_class, + skip_execute: false, + skip_validate: false, + skip_fee_transfer: false, + }; + + verify_version( + &internal_declare.version, + internal_declare.max_fee, + &internal_declare.nonce, + &internal_declare.signature, + )?; + + Ok(internal_declare) + } + pub fn get_calldata(&self) -> Vec { let bytes = Felt252::from_bytes_be(&self.class_hash); Vec::from([bytes]) @@ -302,7 +340,7 @@ impl Declare { Ok(tx_exec_info) } - pub(crate) fn create_for_simulation( + pub fn create_for_simulation( &self, skip_validate: bool, skip_execute: bool, diff --git a/src/transaction/declare_v2.rs b/src/transaction/declare_v2.rs index 879f4efa5..f26cc5655 100644 --- a/src/transaction/declare_v2.rs +++ b/src/transaction/declare_v2.rs @@ -42,7 +42,7 @@ pub struct DeclareV2 { pub signature: Vec, pub nonce: Felt252, pub compiled_class_hash: Felt252, - pub sierra_contract_class: SierraContractClass, + pub sierra_contract_class: Option, pub sierra_class_hash: Felt252, pub hash_value: Felt252, pub casm_class: Option, @@ -89,7 +89,7 @@ impl DeclareV2 { )?; Self::new_with_sierra_class_hash_and_tx_hash( - sierra_contract_class, + Some(sierra_contract_class.clone()), sierra_class_hash, casm_contract_class, compiled_class_hash, @@ -118,7 +118,7 @@ impl DeclareV2 { /// may not hold. #[allow(clippy::too_many_arguments)] pub fn new_with_sierra_class_hash_and_tx_hash( - sierra_contract_class: &SierraContractClass, + sierra_contract_class: Option, sierra_class_hash: Felt252, casm_contract_class: Option, compiled_class_hash: Felt252, @@ -184,7 +184,7 @@ impl DeclareV2 { let sierra_class_hash = compute_sierra_class_hash(sierra_contract_class)?; Self::new_with_sierra_class_hash_and_tx_hash( - sierra_contract_class, + Some(sierra_contract_class.clone()), sierra_class_hash, casm_contract_class, compiled_class_hash, @@ -211,7 +211,7 @@ impl DeclareV2 { /// - nonce: The nonce of the contract. #[allow(clippy::too_many_arguments)] pub fn new_with_sierra_class_hash( - sierra_contract_class: &SierraContractClass, + sierra_contract_class: Option, sierra_class_hash: Felt252, casm_contract_class: Option, compiled_class_hash: Felt252, @@ -310,6 +310,7 @@ impl DeclareV2 { state: &mut CachedState, block_context: &BlockContext, ) -> Result { + self.handle_nonce(state)?; verify_version(&self.version, self.max_fee, &self.nonce, &self.signature)?; let initial_gas = INITIAL_GAS_COST; @@ -327,11 +328,13 @@ impl DeclareV2 { )?; (info, gas) }; + self.compile_and_store_casm_class(state)?; let storage_changes = state.count_actual_state_changes(Some(( &block_context.starknet_os_config.fee_token_address, &self.sender_address, )))?; + let actual_resources = calculate_tx_resources( resources_manager, &[execution_result.call_info.clone()], @@ -351,7 +354,6 @@ impl DeclareV2 { &mut tx_execution_context, self.skip_fee_transfer, )?; - self.compile_and_store_casm_class(state)?; let mut tx_exec_info = TransactionExecutionInfo::new_without_fee_info( execution_result.call_info, @@ -370,10 +372,13 @@ impl DeclareV2 { state: &mut S, ) -> Result<(), TransactionError> { let casm_class = match &self.casm_class { - None => { - CasmContractClass::from_contract_class(self.sierra_contract_class.clone(), true) - .map_err(|e| TransactionError::SierraCompileError(e.to_string()))? - } + None => CasmContractClass::from_contract_class( + self.sierra_contract_class + .clone() + .ok_or(TransactionError::DeclareV2NoSierraOrCasm)?, + true, + ) + .map_err(|e| TransactionError::SierraCompileError(e.to_string()))?, Some(casm_contract_class) => casm_contract_class.clone(), }; @@ -384,16 +389,15 @@ impl DeclareV2 { self.compiled_class_hash.to_string(), )); } - state.set_compiled_class_hash(&self.sierra_class_hash, &self.compiled_class_hash)?; + if let Some(ref class) = self.sierra_contract_class { + state.set_sierra_program(&self.sierra_class_hash, class.sierra_program.clone())?; + } + state.set_compiled_class_hash(&self.sierra_class_hash, &self.compiled_class_hash)?; state.set_contract_class( &self.compiled_class_hash.to_be_bytes(), &CompiledClass::Casm(Arc::new(casm_class)), )?; - state.set_sierra_program( - &self.sierra_class_hash, - self.sierra_contract_class.sierra_program.clone(), - )?; Ok(()) } @@ -446,7 +450,7 @@ impl DeclareV2 { // --------------- // Simulation // --------------- - pub(crate) fn create_for_simulation( + pub fn create_for_simulation( &self, skip_validate: bool, skip_execute: bool, @@ -540,7 +544,7 @@ mod tests { // test we can retreive the data let expected_casm_class = CasmContractClass::from_contract_class( - internal_declare.sierra_contract_class.clone(), + internal_declare.sierra_contract_class.unwrap().clone(), true, ) .unwrap(); @@ -609,7 +613,7 @@ mod tests { // test we can retreive the data let expected_casm_class = CasmContractClass::from_contract_class( - internal_declare.sierra_contract_class.clone(), + internal_declare.sierra_contract_class.unwrap(), true, ) .unwrap(); @@ -655,7 +659,7 @@ mod tests { // create internal declare v2 let internal_declare = DeclareV2::new_with_sierra_class_hash_and_tx_hash( - &sierra_contract_class, + Some(sierra_contract_class), sierra_class_hash, Some(casm_class), casm_class_hash, @@ -680,7 +684,7 @@ mod tests { // test we can retreive the data let expected_casm_class = CasmContractClass::from_contract_class( - internal_declare.sierra_contract_class.clone(), + internal_declare.sierra_contract_class.unwrap(), true, ) .unwrap(); @@ -749,7 +753,7 @@ mod tests { // test we can retreive the data let expected_casm_class = CasmContractClass::from_contract_class( - internal_declare.sierra_contract_class.clone(), + internal_declare.sierra_contract_class.unwrap().clone(), true, ) .unwrap(); diff --git a/src/transaction/error.rs b/src/transaction/error.rs index c254dd152..87a1f76a5 100644 --- a/src/transaction/error.rs +++ b/src/transaction/error.rs @@ -147,4 +147,6 @@ pub enum TransactionError { InvalidCompiledClassHash(String, String), #[error(transparent)] FromByteArrayError(#[from] FromByteArrayError), + #[error("DeclareV2 transaction has neither Sierra nor Casm contract class set")] + DeclareV2NoSierraOrCasm, } diff --git a/tests/deploy_account.rs b/tests/deploy_account.rs index 24ee3b162..1b7d26f3b 100644 --- a/tests/deploy_account.rs +++ b/tests/deploy_account.rs @@ -270,7 +270,7 @@ fn internal_deploy_account_cairo1() { ("n_steps", n_steps), ("pedersen_builtin", 23), ("range_check_builtin", 87), - ("l1_gas_usage", 4284) + ("l1_gas_usage", 5508) ] .into_iter() .map(|(k, v)| (k.to_string(), v)) diff --git a/tests/internals.rs b/tests/internals.rs index 9f0ff4a81..11d9b28f7 100644 --- a/tests/internals.rs +++ b/tests/internals.rs @@ -597,6 +597,20 @@ fn invoke_tx(calldata: Vec, max_fee: u128) -> InvokeFunction { .unwrap() } +fn invoke_tx_with_nonce(calldata: Vec, max_fee: u128, nonce: Felt252) -> InvokeFunction { + InvokeFunction::new( + TEST_ACCOUNT_CONTRACT_ADDRESS.clone(), + EXECUTE_ENTRY_POINT_SELECTOR.clone(), + max_fee, + TRANSACTION_VERSION.clone(), + calldata, + vec![], + StarknetChainId::TestNet.to_felt(), + Some(nonce), + ) + .unwrap() +} + fn expected_fee_transfer_info(fee: u128) -> CallInfo { CallInfo { failure_flag: false, @@ -695,13 +709,13 @@ fn expected_fib_fee_transfer_info(fee: u128) -> CallInfo { ], }], storage_read_values: vec![ - INITIAL_BALANCE.clone() - Felt252::from(1252), + INITIAL_BALANCE.clone() - Felt252::from(3700), Felt252::zero(), - INITIAL_BALANCE.clone() - Felt252::from(1252), + INITIAL_BALANCE.clone() - Felt252::from(3700), Felt252::zero(), - Felt252::from(1252), + Felt252::from(3700), Felt252::zero(), - Felt252::from(1252), + Felt252::from(3700), Felt252::zero(), ], accessed_storage_keys: HashSet::from([ @@ -762,7 +776,7 @@ fn declarev2_tx() -> DeclareV2 { nonce: 0.into(), hash_value: 0.into(), compiled_class_hash: casm_class_hash, - sierra_contract_class, + sierra_contract_class: Some(sierra_contract_class), sierra_class_hash, casm_class: casm_class.into(), skip_execute: false, @@ -1013,7 +1027,7 @@ fn test_declarev2_tx() { ("n_steps".to_string(), 2715), ("range_check_builtin".to_string(), 63), ("pedersen_builtin".to_string(), 15), - ("l1_gas_usage".to_string(), 1224), + ("l1_gas_usage".to_string(), 3672), ]); let fee = calculate_tx_fee(&resources, *GAS_PRICE, &block_context).unwrap(); @@ -1260,7 +1274,7 @@ fn expected_fib_transaction_execution_info( } let resources = HashMap::from([ ("n_steps".to_string(), n_steps), - ("l1_gas_usage".to_string(), 5508), + ("l1_gas_usage".to_string(), 6732), ("pedersen_builtin".to_string(), 16), ("range_check_builtin".to_string(), 104), ]); @@ -1475,7 +1489,7 @@ fn test_invoke_with_declarev2_tx() { Felt252::from(0), // b Felt252::from(0), // n ]; - let invoke_tx = invoke_tx(calldata, u128::MAX); + let invoke_tx = invoke_tx_with_nonce(calldata, u128::MAX, Felt252::one()); let expected_gas_consumed = 5551; let result = invoke_tx