diff --git a/crates/blockifier/src/fee/eth_gas_constants.rs b/crates/blockifier/src/fee/eth_gas_constants.rs index 6c337ea245..e01eb73132 100644 --- a/crates/blockifier/src/fee/eth_gas_constants.rs +++ b/crates/blockifier/src/fee/eth_gas_constants.rs @@ -1,6 +1,7 @@ // Calldata. pub const GAS_PER_MEMORY_ZERO_BYTE: usize = 4; pub const GAS_PER_MEMORY_BYTE: usize = 16; +// TODO(AvivG): use starknet_api::core::WORD_WIDTH instead. pub const WORD_WIDTH: usize = 32; pub const GAS_PER_MEMORY_WORD: usize = GAS_PER_MEMORY_BYTE * WORD_WIDTH; diff --git a/crates/starknet_api/src/contract_class.rs b/crates/starknet_api/src/contract_class.rs index e633e3e4ae..72f4bde161 100644 --- a/crates/starknet_api/src/contract_class.rs +++ b/crates/starknet_api/src/contract_class.rs @@ -1,8 +1,9 @@ use cairo_lang_starknet_classes::casm_contract_class::CasmContractClass; use serde::{Deserialize, Serialize}; -use crate::core::CompiledClassHash; +use crate::core::{CompiledClassHash, WORD_WIDTH}; use crate::deprecated_contract_class::ContractClass as DeprecatedContractClass; +use crate::StarknetApiError; #[derive( Debug, Default, Clone, Copy, Eq, PartialEq, Hash, Deserialize, Serialize, PartialOrd, Ord, @@ -41,9 +42,58 @@ impl ContractClass { /// All relevant information about a declared contract class, including the compiled contract class /// and other parameters derived from the original declare transaction required for billing. #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] +// TODO(Ayelet,10/02/2024): Change to bytes. pub struct ClassInfo { // TODO(Noa): Consider using Arc. pub contract_class: ContractClass, pub sierra_program_length: usize, pub abi_length: usize, } + +impl ClassInfo { + pub fn bytecode_length(&self) -> usize { + match &self.contract_class { + ContractClass::V0(contract_class) => contract_class.bytecode_length(), + ContractClass::V1(contract_class) => contract_class.bytecode.len(), + } + } + + pub fn contract_class(&self) -> ContractClass { + self.contract_class.clone() + } + + pub fn sierra_program_length(&self) -> usize { + self.sierra_program_length + } + + pub fn abi_length(&self) -> usize { + self.abi_length + } + + pub fn code_size(&self) -> usize { + (self.bytecode_length() + self.sierra_program_length()) + // We assume each felt is a word. + * WORD_WIDTH + + self.abi_length() + } + + pub fn new( + contract_class: &ContractClass, + sierra_program_length: usize, + abi_length: usize, + ) -> Result { + let (contract_class_version, condition) = match contract_class { + ContractClass::V0(_) => (0, sierra_program_length == 0), + ContractClass::V1(_) => (1, sierra_program_length > 0), + }; + + if condition { + Ok(Self { contract_class: contract_class.clone(), sierra_program_length, abi_length }) + } else { + Err(StarknetApiError::ContractClassVersionSierraProgramLengthMismatch { + contract_class_version, + sierra_program_length, + }) + } + } +} diff --git a/crates/starknet_api/src/core.rs b/crates/starknet_api/src/core.rs index ec2ac3ed8e..4f7f6d395b 100644 --- a/crates/starknet_api/src/core.rs +++ b/crates/starknet_api/src/core.rs @@ -16,6 +16,10 @@ use crate::serde_utils::{BytesAsHex, PrefixedBytesAsHex}; use crate::transaction::fields::{Calldata, ContractAddressSalt}; use crate::{impl_from_through_intermediate, StarknetApiError}; +// Ethereum constant. +/// One Felt fits into 32 bytes. +pub const WORD_WIDTH: usize = 32; + /// Felt. pub fn ascii_as_felt(ascii_str: &str) -> Result { Felt::from_hex(hex::encode(ascii_str).as_str()) diff --git a/crates/starknet_api/src/lib.rs b/crates/starknet_api/src/lib.rs index 98f9f42eda..4ba0366232 100644 --- a/crates/starknet_api/src/lib.rs +++ b/crates/starknet_api/src/lib.rs @@ -49,6 +49,14 @@ pub enum StarknetApiError { InvalidStarknetVersion(Vec), #[error("NonzeroGasPrice cannot be zero.")] ZeroGasPrice, + #[error( + "Sierra program length must be > 0 for Cairo1, and == 0 for Cairo0. Got: \ + {sierra_program_length:?} for contract class version {contract_class_version:?}" + )] + ContractClassVersionSierraProgramLengthMismatch { + contract_class_version: u8, + sierra_program_length: usize, + }, } pub type StarknetApiResult = Result;