Skip to content

Commit f62b57a

Browse files
avi-starkwareclaude
andcommitted
add EmuContractExecutor: a sierra-emu-backed contract executor
Mirrors AotContractExecutor::run so the two are interchangeable at call sites. sierra_emu::VirtualMachine::run_contract owns the new_starknet + call_contract + run sequence; this crate only converts BuiltinCosts and the result type at the seam. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent aa56499 commit f62b57a

4 files changed

Lines changed: 116 additions & 1 deletion

File tree

Cargo.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,10 @@ with-debug-utils = []
130130
with-mem-tracing = []
131131
with-libfunc-profiling = []
132132
with-segfault-catcher = []
133-
with-trace-dump = ["dep:sierra-emu"]
133+
with-trace-dump = ["sierra-emu"]
134+
# Enables the `ContractExecutor::Emu` variant for dispatching contract execution
135+
# through the sierra-emu interpreter.
136+
sierra-emu = ["dep:sierra-emu"]
134137
testing = ["dep:cairo-lang-compiler", "dep:cairo-lang-filesystem"]
135138

136139
[dependencies]

debug_utils/sierra-emu/src/vm.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,32 @@ impl VirtualMachine {
449449

450450
ContractExecutionResult::from_state(&last?)
451451
}
452+
453+
/// One-shot convenience over [`VirtualMachine::new_starknet`],
454+
/// [`VirtualMachine::call_contract`] and [`VirtualMachine::run`]: build a
455+
/// Starknet VM for `program`, call the entry point identified by `selector`
456+
/// and run it to completion.
457+
///
458+
/// Returns `None` when execution never produced a final state.
459+
#[allow(clippy::too_many_arguments)]
460+
pub fn run_contract<I>(
461+
program: Arc<Program>,
462+
entry_points: &ContractEntryPoints,
463+
sierra_version: VersionId,
464+
selector: Felt,
465+
initial_gas: u64,
466+
calldata: I,
467+
builtin_costs: Option<BuiltinCosts>,
468+
syscall_handler: &mut impl StarknetSyscallHandler,
469+
) -> Option<ContractExecutionResult>
470+
where
471+
I: IntoIterator<Item = Felt>,
472+
I::IntoIter: ExactSizeIterator,
473+
{
474+
let mut vm = Self::new_starknet(program, entry_points, sierra_version);
475+
vm.call_contract(selector, initial_gas, calldata, builtin_costs);
476+
vm.run(syscall_handler)
477+
}
452478
}
453479

454480
#[derive(Clone, Debug)]

src/executor.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
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+
#[cfg(feature = "sierra-emu")]
7+
pub use self::emu_contract_executor::EmuContractExecutor;
68
pub use self::{aot::AotNativeExecutor, contract::AotContractExecutor, jit::JitNativeExecutor};
79
use crate::{
810
arch::{AbiArgument, ValueWithInfoWrapper},
@@ -39,6 +41,8 @@ use std::{alloc::Layout, arch::global_asm, ptr::NonNull};
3941

4042
mod aot;
4143
mod contract;
44+
#[cfg(feature = "sierra-emu")]
45+
mod emu_contract_executor;
4246
mod jit;
4347

4448
#[cfg(target_arch = "aarch64")]
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
//! A sierra-emu-backed contract executor exposing the same `run` shape as
2+
//! [`AotContractExecutor::run`](crate::executor::AotContractExecutor::run), so a caller
3+
//! can swap the two behind a feature flag without changing call-site code.
4+
//!
5+
//! Both executors share the same `H: StarknetSyscallHandler` -- sierra-emu and
6+
//! cairo-native re-export the trait from `cairo-native-syscalls`, so no adapter is
7+
//! needed.
8+
9+
use cairo_lang_sierra::program::Program;
10+
use cairo_lang_starknet_classes::compiler_version::VersionId;
11+
use cairo_lang_starknet_classes::contract_class::ContractEntryPoints;
12+
use starknet_types_core::felt::Felt;
13+
use std::sync::Arc;
14+
15+
use crate::error::{Error, Result};
16+
use crate::execution_result::ContractExecutionResult;
17+
use crate::starknet::StarknetSyscallHandler;
18+
use crate::utils::BuiltinCosts;
19+
20+
/// Runs contract entry points through the sierra-emu interpreter.
21+
///
22+
/// Holds the program + entry points + sierra version triple that
23+
/// `sierra_emu::VirtualMachine::run_contract` requires; the `Arc<Program>` is shared
24+
/// across invocations rather than cloned per call.
25+
#[derive(Debug, Clone)]
26+
pub struct EmuContractExecutor {
27+
pub program: Arc<Program>,
28+
pub entry_points: ContractEntryPoints,
29+
pub sierra_version: VersionId,
30+
}
31+
32+
impl EmuContractExecutor {
33+
/// Run the contract entry point identified by `selector`.
34+
///
35+
/// Mirrors [`AotContractExecutor::run`](crate::executor::AotContractExecutor::run) so
36+
/// the two executor types are interchangeable at the call site.
37+
pub fn run(
38+
&self,
39+
selector: Felt,
40+
args: &[Felt],
41+
gas: u64,
42+
builtin_costs: Option<BuiltinCosts>,
43+
mut syscall_handler: impl StarknetSyscallHandler,
44+
) -> Result<ContractExecutionResult> {
45+
// `run_contract` returns `None` when the VM never produced a final state --
46+
// propagate as an error rather than aborting the host.
47+
let result = sierra_emu::VirtualMachine::run_contract(
48+
Arc::clone(&self.program),
49+
&self.entry_points,
50+
self.sierra_version,
51+
selector,
52+
gas,
53+
args.to_vec(),
54+
builtin_costs.map(convert_builtin_costs),
55+
&mut syscall_handler,
56+
)
57+
.ok_or_else(|| {
58+
Error::UnexpectedValue("sierra-emu VM produced no final state".to_string())
59+
})?;
60+
61+
Ok(ContractExecutionResult {
62+
remaining_gas: result.remaining_gas,
63+
failure_flag: result.failure_flag,
64+
return_values: result.return_values,
65+
error_msg: result.error_msg,
66+
builtin_stats: Default::default(),
67+
})
68+
}
69+
}
70+
71+
fn convert_builtin_costs(builtin_costs: BuiltinCosts) -> sierra_emu::BuiltinCosts {
72+
sierra_emu::BuiltinCosts {
73+
r#const: builtin_costs.r#const,
74+
pedersen: builtin_costs.pedersen,
75+
bitwise: builtin_costs.bitwise,
76+
ecop: builtin_costs.ecop,
77+
poseidon: builtin_costs.poseidon,
78+
add_mod: builtin_costs.add_mod,
79+
mul_mod: builtin_costs.mul_mod,
80+
blake: builtin_costs.blake,
81+
}
82+
}

0 commit comments

Comments
 (0)