diff --git a/Cargo.lock b/Cargo.lock index 7aa1e70ee..1591bd083 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -671,11 +671,11 @@ dependencies = [ "ark-ff", "ark-secp256k1", "cached", - "cairo-felt", + "cairo-felt 0.8.7", "cairo-lang-casm", "cairo-lang-runner", "cairo-lang-starknet", - "cairo-vm", + "cairo-vm 0.8.7", "ctor", "derive_more", "indexmap 1.9.3", @@ -799,6 +799,19 @@ dependencies = [ "serde", ] +[[package]] +name = "cairo-felt" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "074959652bb6ba212393f21353fe1d09d31d5b3f7436d4d6fe41c4abe2a8d954" +dependencies = [ + "lazy_static", + "num-bigint", + "num-integer", + "num-traits 0.2.16", + "serde", +] + [[package]] name = "cairo-lang-casm" version = "2.2.0" @@ -1011,7 +1024,7 @@ dependencies = [ "ark-secp256k1", "ark-secp256r1", "ark-std", - "cairo-felt", + "cairo-felt 0.8.7", "cairo-lang-casm", "cairo-lang-compiler", "cairo-lang-defs", @@ -1027,7 +1040,7 @@ dependencies = [ "cairo-lang-sierra-type-size", "cairo-lang-starknet", "cairo-lang-utils", - "cairo-vm", + "cairo-vm 0.8.7", "itertools 0.11.0", "keccak", "num-bigint", @@ -1147,7 +1160,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa1c799de62972dfd7112d563000695be94305b6f7d9bedd29f347799bf03e1c" dependencies = [ "assert_matches", - "cairo-felt", + "cairo-felt 0.8.7", "cairo-lang-casm", "cairo-lang-sierra", "cairo-lang-sierra-ap-change", @@ -1179,7 +1192,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75df624e71e33a31a924e799dd2a9a8284204b41d8db9c51803317bd9edff81f" dependencies = [ "anyhow", - "cairo-felt", + "cairo-felt 0.8.7", "cairo-lang-casm", "cairo-lang-compiler", "cairo-lang-defs", @@ -1261,13 +1274,43 @@ name = "cairo-vm" version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00d9bf139b0fe845627cf09d11af43eec9575dba702033bf6b08050c776b8553" +dependencies = [ + "anyhow", + "bincode", + "bitvec", + "cairo-felt 0.8.7", + "generic-array", + "hashbrown 0.14.0", + "hex", + "keccak", + "lazy_static", + "mimalloc", + "nom", + "num-bigint", + "num-integer", + "num-prime", + "num-traits 0.2.16", + "rand", + "serde", + "serde_json", + "sha2", + "sha3", + "starknet-crypto 0.5.1", + "thiserror-no-std", +] + +[[package]] +name = "cairo-vm" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d907e35a2551c6683a5cccabb7e8328484019985c84a1cf08c744323afbea3f2" dependencies = [ "anyhow", "ark-ff", "ark-std", "bincode", "bitvec", - "cairo-felt", + "cairo-felt 0.9.0", "cairo-lang-casm", "cairo-lang-starknet", "generic-array", @@ -1901,7 +1944,7 @@ dependencies = [ name = "fuzzer" version = "0.4.0" dependencies = [ - "cairo-vm", + "cairo-vm 0.9.0", "honggfuzz", "num-traits 0.2.16", "serde_json", @@ -3204,7 +3247,8 @@ dependencies = [ "blockifier", "cairo-lang-starknet", "cairo-lang-utils", - "cairo-vm", + "cairo-vm 0.8.7", + "cairo-vm 0.9.0", "dotenv", "flate2", "pretty_assertions_sorted", @@ -3858,7 +3902,7 @@ dependencies = [ "actix-web", "assert_matches", "awc", - "cairo-vm", + "cairo-vm 0.9.0", "clap", "coverage-helper", "mimalloc", @@ -3913,7 +3957,7 @@ dependencies = [ "cairo-lang-sierra", "cairo-lang-starknet", "cairo-lang-utils", - "cairo-vm", + "cairo-vm 0.9.0", "coverage-helper", "flate2", "getset", diff --git a/Cargo.toml b/Cargo.toml index a4eef6dd1..781643eb9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,7 @@ cairo-lang-runner = "2.1.0-rc4" cairo-lang-sierra = "2.1.0-rc4" cairo-lang-starknet = "2.1.0-rc4" cairo-lang-utils = "2.1.0-rc4" -cairo-vm = { version = "0.8.5", features = ["cairo-1-hints"] } +cairo-vm = { version = "0.9.0", features = ["cairo-1-hints"] } num-traits = "0.2.15" starknet = "0.5.0" starknet_api = "0.4.1" diff --git a/rpc_state_reader/Cargo.toml b/rpc_state_reader/Cargo.toml index 370ee93d4..d598bc2f5 100644 --- a/rpc_state_reader/Cargo.toml +++ b/rpc_state_reader/Cargo.toml @@ -20,7 +20,9 @@ thiserror = { workspace = true } flate2 = "1.0.25" serde_with = "3.0.0" dotenv = "0.15.0" -cairo-vm = "0.8.5" +cairo-vm.workspace = true +# To create the `Program` in Blockifier's tests +cairo-vm-blockifier = { package = "cairo-vm", version = "0.8.7" } blockifier = "0.2.0-rc0" starknet_in_rust = { path = "../", version = "0.4.0" } diff --git a/rpc_state_reader/tests/blockifier_tests.rs b/rpc_state_reader/tests/blockifier_tests.rs index a32139934..741f0edb6 100644 --- a/rpc_state_reader/tests/blockifier_tests.rs +++ b/rpc_state_reader/tests/blockifier_tests.rs @@ -19,7 +19,7 @@ use blockifier::{ use cairo_lang_starknet::{ casm_contract_class::CasmContractClass, contract_class::ContractClass as SierraContractClass, }; -use cairo_vm::types::program::Program; +use cairo_vm_blockifier::types::program::Program; use pretty_assertions_sorted::{assert_eq, assert_eq_sorted}; use rpc_state_reader::rpc_state::*; use rpc_state_reader::utils; @@ -217,14 +217,24 @@ fn blockifier_test_recent_tx() { .. } = execute_call_info.unwrap(); + let trace_resources = &trace + .function_invocation + .as_ref() + .unwrap() + .execution_resources; assert_eq!(actual_fee.0, receipt.actual_fee); - assert_eq!( - vm_resources, - trace - .function_invocation - .as_ref() - .unwrap() - .execution_resources + // NOTE: had to check field by field due to version mismatch causing type errors + assert_eq_sorted!( + ( + vm_resources.n_steps, + vm_resources.n_memory_holes, + &vm_resources.builtin_instance_counter + ), + ( + trace_resources.n_steps, + trace_resources.n_memory_holes, + &trace_resources.builtin_instance_counter + ), ); assert_eq!( inner_calls.len(), @@ -313,13 +323,23 @@ fn blockifier_test_case_tx(hash: &str, block_number: u64, chain: RpcChain) { } } + let trace_resources = &trace + .function_invocation + .as_ref() + .unwrap() + .execution_resources; + // NOTE: had to check field by field due to version mismatch causing type errors assert_eq_sorted!( - vm_resources, - trace - .function_invocation - .as_ref() - .unwrap() - .execution_resources + ( + vm_resources.n_steps, + vm_resources.n_memory_holes, + &vm_resources.builtin_instance_counter + ), + ( + trace_resources.n_steps, + trace_resources.n_memory_holes, + &trace_resources.builtin_instance_counter + ), ); assert_eq!( inner_calls.len(), diff --git a/src/serde_structs/mod.rs b/src/serde_structs/mod.rs index db4adb862..89a3b656a 100644 --- a/src/serde_structs/mod.rs +++ b/src/serde_structs/mod.rs @@ -12,15 +12,16 @@ struct Signature { #[serde(default, rename = "stateMutability")] state_mutability: Option, #[serde(rename = "type")] - type_name: String, + type_name: EntryPointType, } -// We should should consider reading all the information from the abi in the future. Right now we are not considering: -// - type: "event" -// - type: "struct" +// We should should consider reading all the information from the abi in the future. Right now we +// are not considering: +// // - type: "event" +// // - type: "struct" pub fn read_abi(abi_name: &PathBuf) -> HashMap { let abi: Vec = serde_json::from_reader(&File::open(abi_name).unwrap()).unwrap(); - let mut func_type_counter: HashMap = HashMap::new(); + let mut func_type_counter: HashMap = HashMap::new(); let mut result_hash_map: HashMap = HashMap::new(); for function in abi { @@ -29,14 +30,8 @@ pub fn read_abi(abi_name: &PathBuf) -> HashMap None => 0, }; - let entry_point_type = match &function.type_name { - type_name if type_name == "function" => EntryPointType::External, - type_name if type_name == "constructor" => EntryPointType::Constructor, - _ => EntryPointType::L1Handler, - }; - func_type_counter.insert(function.type_name, function_address); - result_hash_map.insert(function.name, (function_address, entry_point_type)); + result_hash_map.insert(function.name, (function_address, function.type_name)); } result_hash_map diff --git a/src/services/api/contract_classes/deprecated_contract_class.rs b/src/services/api/contract_classes/deprecated_contract_class.rs index f2ede7801..837581c16 100644 --- a/src/services/api/contract_classes/deprecated_contract_class.rs +++ b/src/services/api/contract_classes/deprecated_contract_class.rs @@ -1,16 +1,15 @@ use crate::core::contract_address::compute_hinted_class_hash; use crate::services::api::contract_class_errors::ContractClassError; -use cairo_vm::felt::{Felt252, PRIME_STR}; -use cairo_vm::serde::deserialize_program::{ - deserialize_array_of_bigint_hex, Attribute, BuiltinName, HintParams, Identifier, - ReferenceManager, -}; +use cairo_vm::felt::Felt252; +use cairo_vm::serde::deserialize_program::deserialize_felt_hex; use cairo_vm::types::relocatable::MaybeRelocatable; use cairo_vm::types::{errors::program_errors::ProgramError, program::Program}; use core::str::FromStr; use getset::{CopyGetters, Getters}; +use serde; +use serde::{Deserialize, Serialize}; use serde_json::Value; -use starknet_api::deprecated_contract_class::{ContractClassAbiEntry, EntryPoint}; +use starknet_api::deprecated_contract_class::{number_or_string, ContractClassAbiEntry}; use std::collections::HashMap; use std::path::Path; @@ -20,17 +19,28 @@ pub type AbiType = Vec; // Entry Point types // ------------------------------- -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Deserialize, Serialize)] +#[serde(deny_unknown_fields)] pub enum EntryPointType { + #[serde( + rename = "function", + alias = "FUNCTION", + alias = "external", + alias = "EXTERNAL" + )] External, + #[serde(rename = "l1_handler", alias = "L1_HANDLER")] L1Handler, + #[serde(rename = "constructor", alias = "CONSTRUCTOR")] Constructor, } -#[derive(Clone, CopyGetters, Debug, Default, Eq, Getters, Hash, PartialEq)] +#[derive(Clone, CopyGetters, Debug, Default, Eq, Getters, Hash, PartialEq, Deserialize)] pub struct ContractEntryPoint { + #[serde(deserialize_with = "deserialize_felt_hex")] #[getset(get = "pub")] selector: Felt252, + #[serde(deserialize_with = "number_or_string")] #[getset(get_copy = "pub")] offset: usize, } @@ -71,11 +81,13 @@ impl From for EntryPoin // Contract Class // ------------------------------- -#[derive(Clone, Debug, Eq, Getters, PartialEq)] +#[derive(Clone, Debug, Eq, Getters, PartialEq, Deserialize)] pub struct ContractClass { #[getset(get = "pub")] + #[serde(deserialize_with = "deserialize_program")] pub(crate) program: Program, #[getset(get = "pub")] + #[serde(skip)] pub(crate) hinted_class_hash: Felt252, #[getset(get = "pub")] pub(crate) entry_points_by_type: HashMap>, @@ -144,18 +156,10 @@ impl ContractClass { pub fn from_program_json_and_class_hash( program_json: &str, hinted_class_hash: Felt252, - ) -> Result { - let contract_class: starknet_api::deprecated_contract_class::ContractClass = - serde_json::from_str(program_json).map_err(|_| ContractClassError::ParseError)?; - let program = to_cairo_runner_program(contract_class.program) - .map_err(|e| ContractClassError::ProgramError(e.to_string()))?; - let entry_points_by_type = convert_entry_points(contract_class.entry_points_by_type); - Ok(ContractClass { - hinted_class_hash, - program, - entry_points_by_type, - abi: contract_class.abi, - }) + ) -> Result { + let mut contract_class: ContractClass = serde_json::from_str(program_json)?; + contract_class.hinted_class_hash = hinted_class_hash; + Ok(contract_class) } /// Parses a [`ContractClass`] from a compiled Cairo 0 program's JSON @@ -188,18 +192,9 @@ impl FromStr for ContractClass { /// Parses a [`ContractClass`] from a compiled Cairo 0 program's JSON. fn from_str(program_json: &str) -> Result { - let contract_class: starknet_api::deprecated_contract_class::ContractClass = - serde_json::from_str(program_json)?; - let program = to_cairo_runner_program(contract_class.program)?; - let entry_points_by_type = convert_entry_points(contract_class.entry_points_by_type); let hinted_class_hash = compute_hinted_class_hash(&serde_json::from_str(program_json)?).unwrap(); - Ok(ContractClass { - hinted_class_hash, - program, - entry_points_by_type, - abi: contract_class.abi, - }) + Self::from_program_json_and_class_hash(program_json, hinted_class_hash) } } @@ -207,53 +202,10 @@ impl FromStr for ContractClass { // Helper Functions // ------------------- -pub(crate) fn convert_entry_points( - entry_points: HashMap>, -) -> HashMap> { - let mut converted_entries: HashMap> = HashMap::new(); - for (entry_type, entry_points) in entry_points { - let en_type = entry_type.into(); - - let contracts_entry_points = entry_points - .into_iter() - .map(|e| { - let selector = Felt252::from_bytes_be(e.selector.0.bytes()); - let offset = e.offset.0; - ContractEntryPoint::new(selector, offset) - }) - .collect::>(); - - converted_entries.insert(en_type, contracts_entry_points); - } - - converted_entries -} - -pub(crate) fn to_cairo_runner_program( - program: starknet_api::deprecated_contract_class::Program, -) -> Result { - let identifiers = serde_json::from_value::>(program.identifiers)?; - - if program.prime != *PRIME_STR { - return Err(ProgramError::PrimeDiffers(program.prime.to_string())); - }; - - let mut error_message_attributes = - serde_json::from_value::>(program.attributes).unwrap_or_default(); - error_message_attributes.retain(|attr| attr.name == "error_message"); - - let program = Program::new( - serde_json::from_value::>(program.builtins)?, - deserialize_array_of_bigint_hex(program.data)?, - None, - serde_json::from_value::>>(program.hints)?, - serde_json::from_value::(program.reference_manager)?, - identifiers, - error_message_attributes, - None, - )?; - - Ok(program) +fn deserialize_program<'de, D: serde::Deserializer<'de>>(d: D) -> Result { + use cairo_vm::serde::deserialize_program::{parse_program_json, ProgramJson}; + let json = ProgramJson::deserialize(d)?; + Ok(parse_program_json(json, None).unwrap()) } #[cfg(test)]