Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Cargo.lock

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

6 changes: 3 additions & 3 deletions crates/blockifier_reexecution/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ blockifier_regression_https_testing = []
cairo_native = ["blockifier/cairo_native"]

[dependencies]
apollo_compile_to_casm.workspace = true
apollo_compile_to_casm_types.workspace = true
apollo_compilation_utils.workspace = true
apollo_config.workspace = true
apollo_rpc_execution.workspace = true
apollo_sierra_compilation_config.workspace = true
assert_matches.workspace = true
blockifier = { workspace = true, features = ["reexecution"] }
cairo-lang-starknet-classes.workspace = true
clap = { workspace = true, features = ["cargo", "derive"] }
flate2.workspace = true
google-cloud-storage.workspace = true
Expand All @@ -37,7 +37,7 @@ tracing-subscriber = { workspace = true, features = ["env-filter"] }
validator.workspace = true

[dev-dependencies]
cairo-lang-starknet-classes.workspace = true
mempool_test_utils.workspace = true
mockito.workspace = true
rstest.workspace = true
starknet_api = { workspace = true, features = ["testing"] }
Expand Down
64 changes: 39 additions & 25 deletions crates/blockifier_reexecution/src/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,13 @@

use std::collections::HashMap;
use std::io::{self, Read};
use std::sync::LazyLock;

use apollo_compile_to_casm::{create_sierra_compiler, SierraCompiler};
use apollo_compile_to_casm_types::RawClass;
use apollo_sierra_compilation_config::config::{
SierraCompilationConfig,
DEFAULT_MAX_BYTECODE_SIZE,
};
use apollo_compilation_utils::class_utils::into_contract_class_for_compilation;
use apollo_sierra_compilation_config::config::DEFAULT_MAX_BYTECODE_SIZE;
use blockifier::state::errors::StateError;
use blockifier::state::state_api::StateResult;
use cairo_lang_starknet_classes::allowed_libfuncs::ListSelector;
use cairo_lang_starknet_classes::casm_contract_class::CasmContractClass;
use flate2::bufread;
use starknet_api::contract_class::{ContractClass, EntryPointType, SierraVersion};
use starknet_api::core::EntryPointSelector;
Expand All @@ -30,13 +28,9 @@ use starknet_core::types::{
LegacyEntryPointsByType,
};

static SIERRA_COMPILER: LazyLock<SierraCompiler> = LazyLock::new(|| {
create_sierra_compiler(SierraCompilationConfig {
max_bytecode_size: 10 * DEFAULT_MAX_BYTECODE_SIZE,
audited_libfuncs_only: false,
..Default::default()
})
});
#[cfg(test)]
#[path = "compile_test.rs"]
pub mod test;

/// Maps `LegacyEntryPointsByType` to a `HashMap` where each `EntryPointType`
/// is associated with a vector of `EntryPoint`. Converts selectors and offsets
Expand Down Expand Up @@ -76,22 +70,42 @@ pub fn decode_reader(bytes: Vec<u8>) -> io::Result<String> {
Ok(s)
}

/// Compile a SierraContractClass to a versioned ContractClass V1 (casm) using
/// apollo_compile_to_casm.
/// Compile a SierraContractClass to a versioned ContractClass V1 (casm) in-process, using the
/// Sierra→Casm compiler as a library. The classes compiled here are fetched from the chain, so
/// unlike the sequencer gateway (which compiles user-submitted classes in a resource-limited
/// subprocess), no process isolation is needed.
pub fn sierra_to_versioned_contract_class_v1(
sierra_contract: SierraContractClass,
) -> StateResult<(ContractClass, SierraVersion)> {
let sierra_version = SierraVersion::extract_from_program(&sierra_contract.sierra_program)
.unwrap_or_else(|err| panic!("Failed to extract Sierra version: {err}"));
let raw_class = RawClass::try_from(sierra_contract)
.unwrap_or_else(|err| panic!("Failed to convert SierraContractClass into RawClass: {err}"));
let (raw_executable_class, _) = SIERRA_COMPILER
.compile(raw_class)
.unwrap_or_else(|err| panic!("Failed to compile Sierra to Casm: {err}"));
let contract_class: ContractClass = serde_json::from_value(raw_executable_class.into_value())
.unwrap_or_else(|err| panic!("Failed to deserialize ContractClass: {err}"));
.map_err(|err| {
StateError::StateReadError(format!("Failed to extract Sierra version: {err}"))
})?;
let contract_class_for_compilation = into_contract_class_for_compilation(&sierra_contract);
let extracted_sierra_program =
contract_class_for_compilation.extract_sierra_program(false).map_err(|err| {
StateError::StateReadError(format!("Failed to extract the Sierra program: {err}"))
})?;
// Re-execution must accept any class the network accepted; do not restrict to the audited
// libfuncs list.
extracted_sierra_program
.validate_version_compatible(ListSelector::ListName("all".to_string()))
.map_err(|err| {
StateError::StateReadError(format!("Sierra program version validation failed: {err}"))
})?;
let casm_contract_class = CasmContractClass::from_contract_class(
contract_class_for_compilation,
extracted_sierra_program,
// Add pythonic hints, as the sequencer does when compiling declared classes.
true,
// Generous bound; declared classes already passed the network's bytecode-size limit.
10 * DEFAULT_MAX_BYTECODE_SIZE,
)
.map_err(|err| {
StateError::StateReadError(format!("Failed to compile Sierra to Casm: {err}"))
})?;

Ok((contract_class, sierra_version))
Ok((ContractClass::V1((casm_contract_class, sierra_version.clone())), sierra_version))
}

/// Compile a CompressedLegacyContractClass to a ContractClass V0 using cairo_lang_starknet_classes.
Expand Down
14 changes: 14 additions & 0 deletions crates/blockifier_reexecution/src/compile_test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
use mempool_test_utils::starknet_api_test_utils::{contract_class, COMPILED_CLASS_HASH};

use crate::compile::sierra_to_versioned_contract_class_v1;

/// Pins the in-process compilation output to the fixture's known compiled class hash — the same
/// hash the gateway's compilation flow produces for this class — guarding against output
/// divergence from the compiler used elsewhere in the system.
#[test]
fn compiled_fixture_class_matches_expected_compiled_class_hash() {
let (contract_class, _sierra_version) =
sierra_to_versioned_contract_class_v1(contract_class()).unwrap();

assert_eq!(contract_class.compiled_class_hash(), *COMPILED_CLASS_HASH);
}
Loading