From f5e1828198a5595138c7319a0aca7819a3eb3ae5 Mon Sep 17 00:00:00 2001 From: Pearson White Date: Mon, 16 Sep 2024 14:31:40 -0400 Subject: [PATCH] Use the new ContractExecutor API from cairo native Corresponding sequencer PR: NethermindEth/sequencer#19 PR: #2156 --- vm/rust/Cargo.lock | 13 ++-- vm/rust/Cargo.toml | 8 +-- vm/rust/src/juno_state_reader.rs | 106 ++++--------------------------- vm/rust/src/lib.rs | 4 +- 4 files changed, 25 insertions(+), 106 deletions(-) diff --git a/vm/rust/Cargo.lock b/vm/rust/Cargo.lock index 6bc0208f8c..9ec63a408e 100644 --- a/vm/rust/Cargo.lock +++ b/vm/rust/Cargo.lock @@ -450,7 +450,7 @@ dependencies = [ [[package]] name = "blockifier" version = "0.0.0" -source = "git+https://github.com/NethermindEth/sequencer?branch=native2.8.x#398a608a1d2a6be03d7cf7f34a60d4824ab72b9b" +source = "git+https://github.com/NethermindEth/sequencer?rev=68cd327a71062ea4ad03f930b11d1f6a0b019c17#68cd327a71062ea4ad03f930b11d1f6a0b019c17" dependencies = [ "anyhow", "ark-ec", @@ -469,6 +469,7 @@ dependencies = [ "indexmap 2.4.0", "itertools 0.10.5", "keccak", + "lazy_static", "log", "num-bigint", "num-integer", @@ -1129,7 +1130,7 @@ dependencies = [ [[package]] name = "cairo-native" version = "0.2.0" -source = "git+https://github.com/lambdaclass/cairo_native?rev=4355357697e9ab57ab88ae3a4282aac61455619e#4355357697e9ab57ab88ae3a4282aac61455619e" +source = "git+https://github.com/lambdaclass/cairo_native?rev=a478e89b749bf0b596a7e63afd14e834c08a84e3#a478e89b749bf0b596a7e63afd14e834c08a84e3" dependencies = [ "anyhow", "aquamarine", @@ -1166,6 +1167,8 @@ dependencies = [ "num-traits 0.2.19", "p256", "sec1", + "serde", + "serde_json", "sha2", "starknet-types-core", "stats_alloc", @@ -1178,7 +1181,7 @@ dependencies = [ [[package]] name = "cairo-native-runtime" version = "0.2.0" -source = "git+https://github.com/lambdaclass/cairo_native?rev=4355357697e9ab57ab88ae3a4282aac61455619e#4355357697e9ab57ab88ae3a4282aac61455619e" +source = "git+https://github.com/lambdaclass/cairo_native?rev=a478e89b749bf0b596a7e63afd14e834c08a84e3#a478e89b749bf0b596a7e63afd14e834c08a84e3" dependencies = [ "cairo-lang-sierra-gas", "lazy_static", @@ -3123,7 +3126,7 @@ dependencies = [ [[package]] name = "papyrus_config" version = "0.0.0" -source = "git+https://github.com/NethermindEth/sequencer?branch=native2.8.x#398a608a1d2a6be03d7cf7f34a60d4824ab72b9b" +source = "git+https://github.com/NethermindEth/sequencer?rev=68cd327a71062ea4ad03f930b11d1f6a0b019c17#68cd327a71062ea4ad03f930b11d1f6a0b019c17" dependencies = [ "clap", "itertools 0.10.5", @@ -4348,7 +4351,7 @@ dependencies = [ [[package]] name = "starknet_api" version = "0.0.0" -source = "git+https://github.com/NethermindEth/sequencer?branch=native2.8.x#398a608a1d2a6be03d7cf7f34a60d4824ab72b9b" +source = "git+https://github.com/NethermindEth/sequencer?rev=68cd327a71062ea4ad03f930b11d1f6a0b019c17#68cd327a71062ea4ad03f930b11d1f6a0b019c17" dependencies = [ "bitvec", "cairo-lang-starknet-classes", diff --git a/vm/rust/Cargo.toml b/vm/rust/Cargo.toml index 8f35283049..01cccd20f3 100644 --- a/vm/rust/Cargo.toml +++ b/vm/rust/Cargo.toml @@ -8,8 +8,8 @@ edition = "2021" [dependencies] serde = "1.0.171" serde_json = { version = "1.0.96", features = ["raw_value"] } -blockifier = { git = "https://github.com/NethermindEth/sequencer", branch = "native2.8.x" } -starknet_api = { git = "https://github.com/NethermindEth/sequencer", branch = "native2.8.x" } +blockifier = { git = "https://github.com/NethermindEth/sequencer", rev = "68cd327a71062ea4ad03f930b11d1f6a0b019c17" } +starknet_api = { git = "https://github.com/NethermindEth/sequencer", rev = "68cd327a71062ea4ad03f930b11d1f6a0b019c17" } cairo-lang-sierra = "2.8.0" cairo-lang-starknet = "2.8.0" cairo-lang-starknet-classes = "2.8.0" @@ -18,7 +18,7 @@ starknet-types-core = { version = "0.1.5", features = [ "prime-bigint", "serde", ] } -cairo-native = { git = "https://github.com/lambdaclass/cairo_native", rev = "4355357697e9ab57ab88ae3a4282aac61455619e" } +cairo-native = { git = "https://github.com/lambdaclass/cairo_native", rev = "a478e89b749bf0b596a7e63afd14e834c08a84e3" } cairo-vm = "1.0.0" indexmap = "2.1.0" cached = "0.46.1" @@ -30,7 +30,7 @@ libloading = "0.8.5" thiserror = "1.0.63" ciborium = "0.2.2" -# Trace block dependencies +# Trace block dependencies starknet-core = "0.11.1" starknet-providers = "0.11.0" tokio = { version = "1.38.1", features = ["rt", "macros"] } diff --git a/vm/rust/src/juno_state_reader.rs b/vm/rust/src/juno_state_reader.rs index 83ce8226e6..bdf5619bbf 100644 --- a/vm/rust/src/juno_state_reader.rs +++ b/vm/rust/src/juno_state_reader.rs @@ -7,18 +7,15 @@ use blockifier::{ state::state_api::{StateReader, StateResult}, }; use cached::{Cached, SizedCache}; -use cairo_lang_sierra::{program::Program, program_registry::ProgramRegistry}; -use cairo_native::{ - context::NativeContext, error::Error as NativeError, executor::AotNativeExecutor, - metadata::gas::GasMetadata, module::NativeModule, -}; -use libloading::Library; +use cairo_native::executor::contract::ContractExecutor; +use cairo_native::OptLevel; use once_cell::sync::Lazy; use serde::Deserialize; use starknet_api::core::{ClassHash, CompiledClassHash, ContractAddress, Nonce}; use starknet_api::state::StorageKey; use starknet_types_core::felt::Felt; use std::cell::RefCell; +use std::sync::Arc; use std::{ ffi::{c_char, c_uchar, c_void, CStr}, fs, @@ -185,6 +182,7 @@ impl StateReader for JunoStateReader { /// Returns the contract class of the given class hash. fn get_compiled_contract_class(&self, class_hash: ClassHash) -> StateResult { println!("Juno State Reader(Rust): calling `get_compiled_contract_class` with class hash: {class_hash}"); + if let Some(cached_class) = CLASS_CACHE.lock().unwrap().cache_get(&class_hash) { // skip the cache if it comes from a height higher than ours. Class might be undefined on the height // that we are reading from right now. @@ -311,68 +309,16 @@ fn native_try_from_json_string( raw_contract_class: &str, library_output_path: &PathBuf, ) -> Result> { - fn compile_and_load( - sierra_program: Program, - library_output_path: &PathBuf, - ) -> Result> { - let native_context = NativeContext::new(); - let native_module = native_context.compile(&sierra_program)?; - - persist_from_native_module(native_module, &sierra_program, library_output_path) - } - let sierra_contract_class: cairo_lang_starknet_classes::contract_class::ContractClass = serde_json::from_str(raw_contract_class)?; - - // todo(rodro): we are having two instances of a sierra program, one it's object form - // and another in its felt encoded form. This can be avoided by either: - // 1. Having access to the encoding/decoding functions - // 2. Refactoring the code on the Cairo mono-repo - let sierra_program = sierra_contract_class.extract_sierra_program()?; - - // todo(xrvdg) lift this match out of the function once we do not need sierra_program anymore - let executor = match load_compiled_contract(&sierra_program, library_output_path) { - Some(executor) => { - executor.or_else(|_err| compile_and_load(sierra_program, library_output_path)) - } - None => compile_and_load(sierra_program, library_output_path), - }?; - - Ok(NativeContractClassV1::new(executor, sierra_contract_class)?) -} - -/// Load a contract that is already compiled. -/// -/// Returns None if the contract does not exist at the output_path. -/// -/// To compile and load a contract use [persist_from_native_module] instead. -fn load_compiled_contract( - sierra_program: &Program, - library_output_path: &PathBuf, -) -> Option>> { - fn load( - sierra_program: &Program, - library_output_path: &PathBuf, - ) -> Result> { - let has_gas_builtin = sierra_program - .type_declarations - .iter() - .any(|decl| decl.long_id.generic_id.0.as_str() == "GasBuiltin"); - let config = has_gas_builtin.then_some(Default::default()); - let gas_metadata = GasMetadata::new(sierra_program, config)?; - let program_registry = ProgramRegistry::new(sierra_program)?; - let library = unsafe { Library::new(library_output_path)? }; - Ok(AotNativeExecutor::new( - library, - program_registry, - gas_metadata, - )) - } - - library_output_path - .is_file() - .then_some(load(sierra_program, library_output_path)) + let executor = ContractExecutor::load(library_output_path).or_else(|_| { + let executor = ContractExecutor::new(&sierra_program, OptLevel::Default)?; + executor.save(library_output_path)?; + Ok::>(executor) + })?; + let contract_executor = NativeContractClassV1::new(Arc::new(executor), sierra_contract_class)?; + Ok(contract_executor) } // todo(xrvdg) once [class_info_from_json_str] is part of JunoStateReader @@ -403,33 +349,3 @@ fn generate_library_path(class_hash: ClassHash) -> PathBuf { path.push(class_hash.to_string().trim_start_matches("0x")); path } - -/// Compiles and load contract -/// -/// Modelled after [AotNativeExecutor::from_native_module]. -/// Needs a sierra_program to workaround limitations of NativeModule -fn persist_from_native_module( - mut native_module: NativeModule, - sierra_program: &Program, - library_output_path: &PathBuf, -) -> Result> { - let object_data = cairo_native::module_to_object(native_module.module(), Default::default()) - .map_err(|err| NativeError::LLVMCompileError(err.to_string()))?; // cairo native didn't include a from instance - - cairo_native::object_to_shared_lib(&object_data, library_output_path)?; - - let gas_metadata = native_module - .remove_metadata() - .expect("native_module should have set gas_metadata"); - - // Recreate the program registry as it can't be moved out of native module. - let program_registry = ProgramRegistry::new(sierra_program)?; - - let library = unsafe { Library::new(library_output_path)? }; - - Ok(AotNativeExecutor::new( - library, - program_registry, - gas_metadata, - )) -} diff --git a/vm/rust/src/lib.rs b/vm/rust/src/lib.rs index a075b07576..a840e123b6 100644 --- a/vm/rust/src/lib.rs +++ b/vm/rust/src/lib.rs @@ -339,7 +339,7 @@ fn cairo_vm_execute( }; if let Some(path) = JUNO_RECORD_DIR.clone() { - let mut args_path: PathBuf = path.into(); + let mut args_path: PathBuf = path; args_path.push(format!("{}.args.cbor", block_info.block_number)); let file_args = std::fs::File::create(args_path).unwrap(); @@ -401,7 +401,7 @@ fn cairo_vm_execute( } if let Some(path) = JUNO_RECORD_DIR.clone() { - let mut state_path: PathBuf = path.into(); + let mut state_path: PathBuf = path; state_path.push(format!("{}.state.cbor", block_info.block_number)); let state_file = File::create(state_path).unwrap();