use crate::types::layout_name::LayoutName;
#[cfg(feature = "cairo-1-hints")]
use crate::vm::errors::cairo_run_errors::CairoRunError;
#[cfg(feature = "cairo-1-hints")]
use crate::vm::runners::cairo_runner::RunResources;
use crate::vm::trace::trace_entry::RelocatedTraceEntry;
#[cfg(feature = "cairo-1-hints")]
use crate::Felt252;
#[cfg(feature = "cairo-1-hints")]
use crate::{
hint_processor::cairo_1_hint_processor::hint_processor::Cairo1HintProcessor,
types::{builtin_name::BuiltinName, relocatable::MaybeRelocatable},
vm::runners::cairo_runner::{CairoArg, CairoRunner},
};
#[cfg(feature = "cairo-1-hints")]
use cairo_lang_starknet_classes::casm_contract_class::CasmContractClass;
use crate::stdlib::prelude::*;
use crate::{
cairo_run::{cairo_run, CairoRunConfig},
hint_processor::builtin_hint_processor::builtin_hint_processor_definition::BuiltinHintProcessor,
};
#[cfg(target_arch = "wasm32")]
use wasm_bindgen_test::*;
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
mod bitwise_test;
#[cfg(test)]
mod run_deprecated_contract_class_simplified;
#[cfg(feature = "cairo-1-hints")]
mod cairo_1_run_from_entrypoint_tests;
mod cairo_run_test;
mod pedersen_test;
mod struct_test;
mod cairo_pie_test;
#[cfg(feature = "test_utils")]
mod skip_instruction_test;
fn run_program_simple(data: &[u8]) {
run_program(data, false, None, None, None)
}
fn run_program_small(data: &[u8]) {
run_program(data, false, Some(LayoutName::small), None, None)
}
fn run_program_with_trace(data: &[u8], trace: &[(usize, usize, usize)]) {
run_program(data, false, None, Some(trace), None)
}
fn run_program_with_error(data: &[u8], error: &str) {
run_program(data, false, None, None, Some(error))
}
fn run_program(
data: &[u8],
proof_mode: bool,
layout: Option<LayoutName>,
trace: Option<&[(usize, usize, usize)]>,
error: Option<&str>,
) {
let mut hint_executor = BuiltinHintProcessor::new_empty();
let cairo_run_config = CairoRunConfig {
layout: layout.unwrap_or(LayoutName::all_cairo),
relocate_mem: true,
trace_enabled: true,
proof_mode,
..Default::default()
};
let res = cairo_run(data, &cairo_run_config, &mut hint_executor);
if let Some(error) = error {
assert!(res.is_err());
assert!(res.err().unwrap().to_string().contains(error));
return;
}
let runner = res.expect("Execution failed");
if let Some(trace) = trace {
let expected_trace: Vec<_> = trace
.iter()
.copied()
.map(|(pc, ap, fp)| RelocatedTraceEntry { pc, ap, fp })
.collect();
let trace = runner.relocated_trace.as_ref().unwrap();
assert_eq!(trace.len(), expected_trace.len());
for (entry, expected) in trace.iter().zip(expected_trace.iter()) {
assert_eq!(entry, expected);
}
}
}
#[cfg(feature = "cairo-1-hints")]
fn run_cairo_1_entrypoint(
program_content: &[u8],
entrypoint_offset: usize,
args: &[MaybeRelocatable],
expected_retdata: &[Felt252],
) {
let contract_class: CasmContractClass = serde_json::from_slice(program_content).unwrap();
let mut hint_processor =
Cairo1HintProcessor::new(&contract_class.hints, RunResources::default(), false);
let mut runner = CairoRunner::new(
&(contract_class.clone().try_into().unwrap()),
LayoutName::all_cairo,
None,
false,
false,
false,
)
.unwrap();
let program_builtins = get_casm_contract_builtins(&contract_class, entrypoint_offset);
runner
.initialize_function_runner_cairo_1(&program_builtins)
.unwrap();
let syscall_segment = MaybeRelocatable::from(runner.vm.add_memory_segment());
let builtins = runner.get_program_builtins();
let builtin_segment: Vec<MaybeRelocatable> = runner
.vm
.get_builtin_runners()
.iter()
.filter(|b| builtins.contains(&b.name()))
.flat_map(|b| b.initial_stack())
.collect();
let initial_gas = MaybeRelocatable::from(usize::MAX);
let mut implicit_args = builtin_segment;
implicit_args.extend([initial_gas]);
implicit_args.extend([syscall_segment]);
let builtin_costs: Vec<MaybeRelocatable> =
vec![0.into(), 0.into(), 0.into(), 0.into(), 0.into()];
let builtin_costs_ptr = runner.vm.add_memory_segment();
runner
.vm
.load_data(builtin_costs_ptr, &builtin_costs)
.unwrap();
let core_program_end_ptr =
(runner.program_base.unwrap() + runner.program.shared_program_data.data.len()).unwrap();
let program_extra_data: Vec<MaybeRelocatable> =
vec![0x208B7FFF7FFF7FFE.into(), builtin_costs_ptr.into()];
runner
.vm
.load_data(core_program_end_ptr, &program_extra_data)
.unwrap();
let calldata_start = runner.vm.add_memory_segment();
let calldata_end = runner.vm.load_data(calldata_start, args).unwrap();
let mut entrypoint_args: Vec<CairoArg> = implicit_args
.iter()
.map(|m| CairoArg::from(m.clone()))
.collect();
entrypoint_args.extend([
MaybeRelocatable::from(calldata_start).into(),
MaybeRelocatable::from(calldata_end).into(),
]);
let entrypoint_args: Vec<&CairoArg> = entrypoint_args.iter().collect();
runner
.run_from_entrypoint(
entrypoint_offset,
&entrypoint_args,
true,
Some(runner.program.shared_program_data.data.len() + program_extra_data.len()),
&mut hint_processor,
)
.unwrap();
let return_values = runner.vm.get_return_values(5).unwrap();
let retdata_start = return_values[3].get_relocatable().unwrap();
let retdata_end = return_values[4].get_relocatable().unwrap();
let retdata: Vec<Felt252> = runner
.vm
.get_integer_range(retdata_start, (retdata_end - retdata_start).unwrap())
.unwrap()
.iter()
.map(|c| c.clone().into_owned())
.collect();
assert_eq!(expected_retdata, &retdata);
}
#[cfg(feature = "cairo-1-hints")]
fn run_cairo_1_entrypoint_with_run_resources(
contract_class: CasmContractClass,
entrypoint_offset: usize,
hint_processor: &mut Cairo1HintProcessor,
args: &[MaybeRelocatable],
) -> Result<Vec<Felt252>, CairoRunError> {
let mut runner = CairoRunner::new(
&(contract_class.clone().try_into().unwrap()),
LayoutName::all_cairo,
None,
false,
false,
false,
)
.unwrap();
let program_builtins = get_casm_contract_builtins(&contract_class, entrypoint_offset);
runner
.initialize_function_runner_cairo_1(&program_builtins)
.unwrap();
let syscall_segment = MaybeRelocatable::from(runner.vm.add_memory_segment());
let builtins = runner.get_program_builtins();
let builtin_segment: Vec<MaybeRelocatable> = runner
.vm
.get_builtin_runners()
.iter()
.filter(|b| builtins.contains(&b.name()))
.flat_map(|b| b.initial_stack())
.collect();
let initial_gas = MaybeRelocatable::from(usize::MAX);
let mut implicit_args = builtin_segment;
implicit_args.extend([initial_gas]);
implicit_args.extend([syscall_segment]);
let builtin_costs: Vec<MaybeRelocatable> =
vec![0.into(), 0.into(), 0.into(), 0.into(), 0.into()];
let builtin_costs_ptr = runner.vm.add_memory_segment();
runner
.vm
.load_data(builtin_costs_ptr, &builtin_costs)
.unwrap();
let core_program_end_ptr =
(runner.program_base.unwrap() + runner.program.shared_program_data.data.len()).unwrap();
let program_extra_data: Vec<MaybeRelocatable> =
vec![0x208B7FFF7FFF7FFE.into(), builtin_costs_ptr.into()];
runner
.vm
.load_data(core_program_end_ptr, &program_extra_data)
.unwrap();
let calldata_start = runner.vm.add_memory_segment();
let calldata_end = runner.vm.load_data(calldata_start, args).unwrap();
let mut entrypoint_args: Vec<CairoArg> = implicit_args
.iter()
.map(|m| CairoArg::from(m.clone()))
.collect();
entrypoint_args.extend([
MaybeRelocatable::from(calldata_start).into(),
MaybeRelocatable::from(calldata_end).into(),
]);
let entrypoint_args: Vec<&CairoArg> = entrypoint_args.iter().collect();
runner.run_from_entrypoint(
entrypoint_offset,
&entrypoint_args,
true,
Some(runner.program.shared_program_data.data.len() + program_extra_data.len()),
hint_processor,
)?;
let return_values = runner.vm.get_return_values(5).unwrap();
let retdata_start = return_values[3].get_relocatable().unwrap();
let retdata_end = return_values[4].get_relocatable().unwrap();
let retdata: Vec<Felt252> = runner
.vm
.get_integer_range(retdata_start, (retdata_end - retdata_start).unwrap())
.unwrap()
.iter()
.map(|c| c.clone().into_owned())
.collect();
Ok(retdata)
}
#[cfg(feature = "cairo-1-hints")]
fn get_casm_contract_builtins(
contract_class: &CasmContractClass,
entrypoint_offset: usize,
) -> Vec<BuiltinName> {
contract_class
.entry_points_by_type
.external
.iter()
.find(|e| e.offset == entrypoint_offset)
.unwrap()
.builtins
.iter()
.map(|s| BuiltinName::from_str(s).expect("Invalid builtin name"))
.collect()
}