Skip to content

Commit 761c5f6

Browse files
avi-starkwareclaude
andcommitted
add ContractExecutor dispatch enum (Aot + Emu)
Adds a public dispatch enum so a single call site can pick between the AOT executor and the sierra-emu interpreter at runtime, without forcing every caller to maintain its own match. - ContractExecutor { Aot(AotContractExecutor), Emu(EmuContractInfo) }, with Emu gated on the new sierra-emu cargo feature. - EmuContractInfo carries Arc<Program> so the program is shared across invocations rather than cloned per call. - ContractExecutor::run dispatches: Aot delegates to AotContractExecutor::run; Emu constructs a sierra_emu::VirtualMachine and runs it with the caller's syscall handler directly. No adapter is needed: the trait is shared via the cairo-native-syscalls crate. - Cargo: new `sierra-emu` feature (= ["dep:sierra-emu"]). The existing `with-trace-dump` feature now activates `sierra-emu` instead of the optional dep directly. Companion to the bridge-free design: with cairo-native and sierra-emu sharing one trait, the SierraEmuSyscallBridge that PR #1597 / #1607 introduced is no longer necessary. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 0ae0d06 commit 761c5f6

3 files changed

Lines changed: 131 additions & 2 deletions

File tree

Cargo.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,10 @@ with-debug-utils = []
124124
with-mem-tracing = []
125125
with-libfunc-profiling = []
126126
with-segfault-catcher = []
127-
with-trace-dump = ["dep:sierra-emu"]
127+
with-trace-dump = ["sierra-emu"]
128+
# Enables the `ContractExecutor::Emu` variant for dispatching contract execution
129+
# through the sierra-emu interpreter.
130+
sierra-emu = ["dep:sierra-emu"]
128131
testing = ["dep:cairo-lang-compiler", "dep:cairo-lang-filesystem"]
129132

130133
[dependencies]

src/executor.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,12 @@
33
//! This module provides methods to execute the programs, either via JIT or compiled ahead
44
//! of time. It also provides a cache to avoid recompiling previously compiled programs.
55
6-
pub use self::{aot::AotNativeExecutor, contract::AotContractExecutor, jit::JitNativeExecutor};
6+
pub use self::{
7+
aot::AotNativeExecutor, contract::AotContractExecutor, contract_executor::ContractExecutor,
8+
jit::JitNativeExecutor,
9+
};
10+
#[cfg(feature = "sierra-emu")]
11+
pub use self::contract_executor::EmuContractInfo;
712
use crate::{
813
arch::{AbiArgument, ValueWithInfoWrapper},
914
error::{panic::ToNativeAssertError, Error},
@@ -39,6 +44,7 @@ use std::{alloc::Layout, arch::global_asm, ptr::NonNull};
3944

4045
mod aot;
4146
mod contract;
47+
mod contract_executor;
4248
mod jit;
4349

4450
#[cfg(target_arch = "aarch64")]

src/executor/contract_executor.rs

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
//! Dispatch enum that lets a single call site choose between AOT-compiled execution and
2+
//! sierra-emu interpretation, without changing call-site code.
3+
//!
4+
//! The `Emu` variant is gated on the `sierra-emu` feature. Both variants share the same
5+
//! `H: StarknetSyscallHandler` — sierra-emu and cairo-native re-export the trait from
6+
//! `cairo-native-syscalls`, so no adapter is needed.
7+
8+
#[cfg(feature = "sierra-emu")]
9+
use cairo_lang_sierra::program::Program;
10+
#[cfg(feature = "sierra-emu")]
11+
use cairo_lang_starknet_classes::compiler_version::VersionId;
12+
#[cfg(feature = "sierra-emu")]
13+
use cairo_lang_starknet_classes::contract_class::ContractEntryPoints;
14+
use starknet_types_core::felt::Felt;
15+
#[cfg(feature = "sierra-emu")]
16+
use std::sync::Arc;
17+
18+
use crate::error::Result;
19+
use crate::execution_result::ContractExecutionResult;
20+
use crate::executor::AotContractExecutor;
21+
use crate::starknet::StarknetSyscallHandler;
22+
use crate::utils::BuiltinCosts;
23+
24+
/// Runtime selection between cairo-native's AOT executor and the sierra-emu interpreter.
25+
///
26+
/// `Emu` is constructed from the program + entry points + sierra version triple that
27+
/// `sierra_emu::VirtualMachine::new_starknet` requires; the `Arc<Program>` is shared across
28+
/// invocations rather than cloned per call.
29+
#[derive(Debug)]
30+
pub enum ContractExecutor {
31+
Aot(AotContractExecutor),
32+
#[cfg(feature = "sierra-emu")]
33+
Emu(EmuContractInfo),
34+
}
35+
36+
/// Inputs required to construct a `sierra_emu::VirtualMachine` for the `Emu` variant.
37+
#[cfg(feature = "sierra-emu")]
38+
#[derive(Debug, Clone)]
39+
pub struct EmuContractInfo {
40+
pub program: Arc<Program>,
41+
pub entry_points: ContractEntryPoints,
42+
pub sierra_version: VersionId,
43+
}
44+
45+
impl From<AotContractExecutor> for ContractExecutor {
46+
fn from(value: AotContractExecutor) -> Self {
47+
Self::Aot(value)
48+
}
49+
}
50+
51+
#[cfg(feature = "sierra-emu")]
52+
impl From<EmuContractInfo> for ContractExecutor {
53+
fn from(value: EmuContractInfo) -> Self {
54+
Self::Emu(value)
55+
}
56+
}
57+
58+
impl ContractExecutor {
59+
/// Run the contract entry point identified by `selector`.
60+
///
61+
/// Dispatches to [`AotContractExecutor::run`] for the `Aot` variant and to a
62+
/// [`sierra_emu::VirtualMachine`] for the `Emu` variant. The same `syscall_handler`
63+
/// flows through both paths unchanged — its trait is shared across the two crates.
64+
pub fn run<H: StarknetSyscallHandler>(
65+
&self,
66+
selector: Felt,
67+
args: &[Felt],
68+
gas: u64,
69+
builtin_costs: Option<BuiltinCosts>,
70+
#[cfg_attr(not(feature = "sierra-emu"), allow(unused_mut))] mut syscall_handler: H,
71+
) -> Result<ContractExecutionResult> {
72+
match self {
73+
ContractExecutor::Aot(aot) => {
74+
aot.run(selector, args, gas, builtin_costs, syscall_handler)
75+
}
76+
#[cfg(feature = "sierra-emu")]
77+
ContractExecutor::Emu(EmuContractInfo {
78+
program,
79+
entry_points,
80+
sierra_version,
81+
}) => {
82+
let mut virtual_machine = sierra_emu::VirtualMachine::new_starknet(
83+
Arc::clone(program),
84+
entry_points,
85+
*sierra_version,
86+
);
87+
88+
let emu_builtin_costs = builtin_costs.map(convert_builtin_costs);
89+
90+
virtual_machine.call_contract(selector, gas, args.to_vec(), emu_builtin_costs);
91+
92+
let result = virtual_machine
93+
.run(&mut syscall_handler)
94+
.expect("sierra-emu VM run failed");
95+
96+
Ok(ContractExecutionResult {
97+
remaining_gas: result.remaining_gas,
98+
failure_flag: result.failure_flag,
99+
return_values: result.return_values,
100+
error_msg: result.error_msg,
101+
builtin_stats: Default::default(),
102+
})
103+
}
104+
}
105+
}
106+
}
107+
108+
#[cfg(feature = "sierra-emu")]
109+
fn convert_builtin_costs(builtin_costs: BuiltinCosts) -> sierra_emu::BuiltinCosts {
110+
sierra_emu::BuiltinCosts {
111+
r#const: builtin_costs.r#const,
112+
pedersen: builtin_costs.pedersen,
113+
bitwise: builtin_costs.bitwise,
114+
ecop: builtin_costs.ecop,
115+
poseidon: builtin_costs.poseidon,
116+
add_mod: builtin_costs.add_mod,
117+
mul_mod: builtin_costs.mul_mod,
118+
blake: builtin_costs.blake,
119+
}
120+
}

0 commit comments

Comments
 (0)