Skip to content

Commit 52cfdf6

Browse files
avi-starkwareclaude
andcommitted
blockifier,apollo_compile_to_native: adopt cairo_native::ContractExecutor + libfunc profiling
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 441098f commit 52cfdf6

11 files changed

Lines changed: 312 additions & 12 deletions

File tree

Cargo.lock

Lines changed: 105 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,11 @@ cairo-lang-sierra = "2.17.0-rc.4"
259259
cairo-lang-sierra-to-casm = "2.17.0-rc.4"
260260
cairo-lang-starknet-classes = "2.17.0-rc.4"
261261
cairo-lang-utils = "2.17.0-rc.4"
262-
cairo-native = "0.9.0-rc.6"
262+
# TEMP: git dep pinned to the tip of the unreleased PR stack
263+
# (starkware-libs/cairo_native#1610 → #1611 → #1612 → #1613) containing
264+
# `ContractExecutor`, `EmuContractInfo`, `AotWithProgram`, and `run_with_profile`.
265+
# Switch back to a crates.io version once those land in a published cairo-native release.
266+
cairo-native = { git = "https://github.com/starkware-libs/cairo_native.git", rev = "74aab36c21aa3a87f918d910420efe4c0dbd9d02" }
263267
cairo-program-runner-lib = "1.1.0"
264268
cairo-vm = "3.2.0"
265269
camelpaste = "0.1.0"

crates/apollo_compile_to_native/Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@ description = "A utility crate for compiling Sierra code into Cairo native."
99
[lints]
1010
workspace = true
1111

12+
[features]
13+
# Enables `SierraToNativeCompiler::compile_with_program`, which returns the
14+
# AOT executor paired with the Sierra program required by cairo-native's
15+
# libfunc profiler.
16+
with-libfunc-profiling = ["cairo-native/with-libfunc-profiling"]
17+
1218
[dependencies]
1319
apollo_compilation_utils.workspace = true
1420
apollo_compile_to_native_types.workspace = true

crates/apollo_compile_to_native/src/compiler.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
use std::path::{Path, PathBuf};
2+
#[cfg(feature = "with-libfunc-profiling")]
3+
use std::sync::Arc;
24

35
use apollo_compilation_utils::compiler_utils::compile_with_args;
46
use apollo_compilation_utils::errors::CompilationUtilError;
@@ -7,6 +9,8 @@ use apollo_compilation_utils::resource_limits::ResourceLimits;
79
use apollo_compile_to_native_types::SierraCompilationConfig;
810
use cairo_lang_starknet_classes::contract_class::ContractClass;
911
use cairo_native::executor::AotContractExecutor;
12+
#[cfg(feature = "with-libfunc-profiling")]
13+
use cairo_native::executor::AotWithProgram;
1014
use tempfile::NamedTempFile;
1115

1216
use crate::constants::CAIRO_NATIVE_BINARY_NAME;
@@ -54,6 +58,27 @@ impl SierraToNativeCompiler {
5458
.map_err(|e| CompilationUtilError::CompilationError(e.to_string()))?
5559
.unwrap())
5660
}
61+
62+
/// Like [`Self::compile`], but also returns the Sierra program so cairo-native's
63+
/// libfunc profiler can resolve runtime libfunc IDs back to declarations. The
64+
/// program is extracted from `contract_class` before compilation so the two are
65+
/// guaranteed to correspond.
66+
#[cfg(feature = "with-libfunc-profiling")]
67+
pub fn compile_with_program(
68+
&self,
69+
contract_class: ContractClass,
70+
) -> Result<AotWithProgram, CompilationUtilError> {
71+
let program = contract_class
72+
.extract_sierra_program(false)
73+
.map(|extracted| Arc::new(extracted.program))
74+
.map_err(|err| {
75+
CompilationUtilError::UnexpectedError(format!(
76+
"Failed to extract Sierra program for profiling: {err}"
77+
))
78+
})?;
79+
let executor = self.compile(contract_class)?;
80+
Ok(AotWithProgram { executor, program })
81+
}
5782
}
5883

5984
// Returns the OUT_DIR. This function is only operable at run time.

crates/blockifier/Cargo.toml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,21 @@ native_blockifier = []
2222
node_api = []
2323
only-native = ["cairo_native"]
2424
reexecution = ["transaction_serde"]
25+
# Enables the sierra-emu execution path of `cairo_native::ContractExecutor`. Pulls in
26+
# cairo-native's `sierra-emu` feature which compiles `SierraEmuSyscallBridge`.
27+
sierra-emu = ["cairo-native/sierra-emu", "cairo_native"]
2528
testing = ["blockifier_test_utils", "rand", "rstest", "rstest_reuse", "starknet_api/testing"]
2629
tracing = []
2730
transaction_serde = []
31+
# Enables libfunc-level profiling for native execution. Pulls in cairo-native's
32+
# `with-libfunc-profiling` so `ContractExecutor::run_with_profile` is available,
33+
# and apollo_compile_to_native's matching feature so `SierraToNativeCompiler` can
34+
# pair the compiled executor with its Sierra program in one call.
35+
with-libfunc-profiling = [
36+
"apollo_compile_to_native/with-libfunc-profiling",
37+
"cairo-native/with-libfunc-profiling",
38+
"cairo_native",
39+
]
2840

2941
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
3042

crates/blockifier/src/execution/native.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
pub mod contract_class;
22
pub mod entry_point_execution;
3+
#[cfg(feature = "with-libfunc-profiling")]
4+
pub mod profiling;
5+
mod run_dispatch;
36
pub mod syscall_handler;
47
pub mod utils;
58

crates/blockifier/src/execution/native/contract_class.rs

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@ use std::borrow::Cow;
22
use std::ops::Deref;
33
use std::sync::Arc;
44

5-
use cairo_native::executor::AotContractExecutor;
5+
#[cfg(feature = "with-libfunc-profiling")]
6+
use cairo_native::executor::AotWithProgram;
7+
#[cfg(feature = "sierra-emu")]
8+
use cairo_native::executor::EmuContractInfo;
9+
use cairo_native::executor::{AotContractExecutor, ContractExecutor};
610
use starknet_api::contract_class::compiled_class_hash::HashableCompiledClass;
711
use starknet_api::core::EntryPointSelector;
812
use starknet_types_core::felt::Felt;
@@ -30,7 +34,28 @@ impl NativeCompiledClassV1 {
3034
/// executor must be derived from sierra_program which in turn must be derived from
3135
/// sierra_contract_class.
3236
pub fn new(executor: AotContractExecutor, casm: CompiledClassV1) -> NativeCompiledClassV1 {
33-
let contract = NativeCompiledClassV1Inner::new(executor, casm);
37+
let contract = NativeCompiledClassV1Inner::new(executor.into(), casm);
38+
39+
Self(Arc::new(contract))
40+
}
41+
42+
/// Initialize a compiled class backed by the sierra-emu interpreter instead of the AOT
43+
/// executor. Used by benchmarking / replay tooling that wants to execute through the emu
44+
/// VM while reusing the rest of the blockifier pipeline.
45+
#[cfg(feature = "sierra-emu")]
46+
pub fn new_from_emu(info: EmuContractInfo, casm: CompiledClassV1) -> NativeCompiledClassV1 {
47+
let contract = NativeCompiledClassV1Inner::new(info.into(), casm);
48+
49+
Self(Arc::new(contract))
50+
}
51+
52+
/// Like [`Self::new`], but also stores the Sierra `Program` (via the cairo-native
53+
/// [`AotWithProgram`] pairing) so [`cairo_native::ContractExecutor::run_with_profile`]
54+
/// can resolve libfunc samples. Only callable when the `with-libfunc-profiling`
55+
/// feature is enabled.
56+
#[cfg(feature = "with-libfunc-profiling")]
57+
pub fn new_with_program(info: AotWithProgram, casm: CompiledClassV1) -> NativeCompiledClassV1 {
58+
let contract = NativeCompiledClassV1Inner::new(info.into(), casm);
3459

3560
Self(Arc::new(contract))
3661
}
@@ -71,12 +96,12 @@ impl HashableCompiledClass<EntryPointV1, NestedFeltCounts> for NativeCompiledCla
7196

7297
#[derive(Debug)]
7398
pub struct NativeCompiledClassV1Inner {
74-
pub executor: AotContractExecutor,
99+
pub executor: ContractExecutor,
75100
casm: CompiledClassV1,
76101
}
77102

78103
impl NativeCompiledClassV1Inner {
79-
fn new(executor: AotContractExecutor, casm: CompiledClassV1) -> Self {
104+
fn new(executor: ContractExecutor, casm: CompiledClassV1) -> Self {
80105
NativeCompiledClassV1Inner { executor, casm }
81106
}
82107
}

crates/blockifier/src/execution/native/entry_point_execution.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use crate::execution::entry_point::{
1818
};
1919
use crate::execution::errors::{EntryPointExecutionError, PostExecutionError, PreExecutionError};
2020
use crate::execution::native::contract_class::NativeCompiledClassV1;
21+
use crate::execution::native::run_dispatch::run_native_executor;
2122
use crate::execution::native::syscall_handler::NativeSyscallHandler;
2223
use crate::state::state_api::State;
2324
use crate::transaction::objects::ExecutionResourcesTraits;
@@ -59,11 +60,12 @@ pub fn execute_entry_point_call(
5960
.checked_sub(initial_budget)
6061
.ok_or(PreExecutionError::InsufficientEntryPointGas)?;
6162

62-
let execution_result = compiled_class.executor.run(
63+
let execution_result = run_native_executor(
64+
&compiled_class.executor,
6365
entry_point.selector.0,
6466
&syscall_handler.base.call.calldata.0.clone(),
6567
call_initial_gas,
66-
Some(builtin_costs),
68+
builtin_costs,
6769
&mut syscall_handler,
6870
);
6971

0 commit comments

Comments
 (0)