Skip to content

Commit

Permalink
use contract executor
Browse files Browse the repository at this point in the history
  • Loading branch information
enitrat committed Sep 24, 2024
1 parent 595f442 commit e6b4eeb
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 107 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ tmp*
# Ignore the generated tests
/crates/ef-testing/tests/*

/crates/ef-testing/native_cache/*

# Ignore the launch file
launch.json

Expand Down
78 changes: 73 additions & 5 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,12 @@ cairo-lang-starknet-classes = "2.8.0"
cairo-lang-sierra = "2.8.0"
cairo-native = {path = "/Users/msaug/deps/cairo_native"}
cairo-vm = "1.0.1"
blockifier = { package = "blockifier", path = "../../deps/sequencer/crates/blockifier", default-features = false, features = [
blockifier = { package = "blockifier", git = "https://github.com/kkrt-labs/sequencer.git", branch = "kkrt-native-2.8", default-features = false, features = [
"testing",
] }
starknet = "0.12"
starknet-crypto = "0.7"
starknet_api = { package = "starknet_api", path = "../../deps/sequencer/crates/starknet_api" }
starknet_api = { package = "starknet_api", git = "https://github.com/kkrt-labs/sequencer.git", branch = "kkrt-native-2.8" }

# Other
async-trait = "0.1"
Expand Down
8 changes: 4 additions & 4 deletions crates/ef-testing/src/evm_sequencer/sequencer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,17 +236,17 @@ lazy_static! {
{
#[cfg(feature = "native")]
{
let account_json = CLASS_HASH_TO_JSON_CLASS.get(&ACCOUNT_CONTRACT_CLASS_HASH).unwrap();
let kakarot_json = CLASS_HASH_TO_JSON_CLASS.get(&KAKAROT_CLASS_HASH).unwrap();
let account_json = CLASS_HASH_TO_JSON_CLASS.get(&ACCOUNT_CONTRACT_CLASS_HASH).unwrap();
let uninitialized_json = CLASS_HASH_TO_JSON_CLASS.get(&UNINITIALIZED_ACCOUNT_CLASS_HASH).unwrap();
println!("Got account's json of length {}", account_json.len());
println!("Got kakarot's json of length {}", kakarot_json.len());
println!("Got account's json of length {}", account_json.len());
println!("Got uninitialized's json of length {}", uninitialized_json.len());
let account_class= class_from_json_str(account_json, *ACCOUNT_CONTRACT_CLASS_HASH).unwrap();
let kakarot_class= class_from_json_str(kakarot_json, *KAKAROT_CLASS_HASH).unwrap();
let account_class= class_from_json_str(account_json, *ACCOUNT_CONTRACT_CLASS_HASH).unwrap();
let uninitialized_class= class_from_json_str(uninitialized_json, *UNINITIALIZED_ACCOUNT_CLASS_HASH).unwrap();
println!("Got class");
(account_class, kakarot_class, uninitialized_class)
(kakarot_class, account_class, uninitialized_class)
}
#[cfg(not(feature = "native"))]
{
Expand Down
113 changes: 17 additions & 96 deletions crates/sequencer/src/native.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,17 @@ use blockifier::{
ClassInfo as BlockifierClassInfo},
};
use cairo_lang_starknet_classes::abi::Contract;
use cairo_native::OptLevel;
use cairo_native::{
context::NativeContext, error::Error as NativeError, executor::AotNativeExecutor,
context::NativeContext, error::Error as NativeError, executor::AotContractExecutor,
metadata::gas::GasMetadata, module::NativeModule,
};
use cairo_lang_starknet_classes::contract_class::ContractClass as SierraContractClass;
use libloading::Library;
use starknet_api::core::ClassHash;
use serde::{Deserialize, Serialize};

use std::sync::Arc;
use std::{
ffi::{c_char, c_uchar, c_void, CStr},
fs,
Expand All @@ -41,36 +43,6 @@ fn generate_library_path(class_hash: ClassHash) -> PathBuf {
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<AotNativeExecutor, Box<dyn std::error::Error>> {
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,
))
}

fn setup_native_cache_dir() -> PathBuf {
let mut path: PathBuf = match std::env::var("NATIVE_CACHE_DIR") {
Ok(path) => path.into(),
Expand All @@ -84,42 +56,6 @@ fn setup_native_cache_dir() -> PathBuf {
path
}


/// 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<Result<AotNativeExecutor, Box<dyn std::error::Error>>> {
fn load(
sierra_program: &Program,
library_output_path: &PathBuf,
) -> Result<AotNativeExecutor, Box<dyn std::error::Error>> {
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))
}

/// Compiled Native contracts

/// Load a compiled native contract into memory
///
/// Tries to load the compiled contract class from library_output_path if it
Expand All @@ -129,40 +65,25 @@ fn native_try_from_json_string(
raw_contract_class: &str,
library_output_path: &PathBuf,
) -> Result<NativeContractClassV1, Box<dyn std::error::Error>> {
fn compile_and_load(
sierra_program: Program,
library_output_path: &PathBuf,
) -> Result<AotNativeExecutor, Box<dyn std::error::Error>> {
println!("Compiling native contract");
let native_context = NativeContext::new();
// Ignore the debug names, that might cause conflicts when retrieving entrypoints upon execution of blockifier.
let native_module = native_context.compile(&sierra_program, false)?;

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
serde_json::from_str(raw_contract_class)?;

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) => {
println!("Loaded cached compiled contract from {:?}", library_output_path);
executor.or_else(|_err| compile_and_load(sierra_program, library_output_path))
}
None => {
compile_and_load(sierra_program, library_output_path)
},
}?;
let maybe_cached_executor = AotContractExecutor::load(library_output_path);
if let Ok(executor) = maybe_cached_executor {
println!("Loaded cached executor");
let native_class = NativeContractClassV1::new(Arc::new(executor), sierra_contract_class)?;
return Ok(native_class);
}

println!("Creating new executor");
let mut executor = AotContractExecutor::new(&sierra_program, OptLevel::Default)?;
executor.save(library_output_path)?;
println!("Saved executor to {:?}", library_output_path);

Ok(NativeContractClassV1::new(executor, sierra_contract_class)?)
let native_class = NativeContractClassV1::new(Arc::new(executor), sierra_contract_class)?;
Ok(native_class)
}


Expand Down

0 comments on commit e6b4eeb

Please sign in to comment.