diff --git a/CHANGELOG.md b/CHANGELOG.md index 30eab4396c..a7d012637b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,9 +12,12 @@ * fix: Handle the deserialization of serde_json::Number with scientific notation (e.g.: Number(1e27)) in felt_from_number function [#1188](https://github.com/lambdaclass/cairo-rs/pull/1188) +* feat: Add RunResources Struct [#1175](https://github.com/lambdaclass/cairo-rs/pull/1175) + * BREAKING: Modify `CairoRunner::run_until_pc` arity. Add `run_resources: &mut Option` input + * BREAKING: Modify `CairoRunner::run_from_entrypoint` arity. Add `run_resources: &mut Option` input + * fix: Fix 'as_int' conversion usage in hints `ASSERT_250_BIT` & `SIGNED_DIV_REM` [#1191](https://github.com/lambdaclass/cairo-rs/pull/1191) -* fix: Fix hint `BIGINT_PACK_DIV_MOD` [#1189](https://github.com/lambdaclass/cairo-rs/pull/1189) * bugfix: Use cairo constants in `ASSERT_250_BIT` hint [#1187](https://github.com/lambdaclass/cairo-rs/pull/1187) diff --git a/src/cairo_run.rs b/src/cairo_run.rs index 9edfa4dc74..4976c829d6 100644 --- a/src/cairo_run.rs +++ b/src/cairo_run.rs @@ -55,11 +55,14 @@ pub fn cairo_run( cairo_run_config.layout, cairo_run_config.proof_mode, )?; + let mut vm = VirtualMachine::new(cairo_run_config.trace_enabled); let end = cairo_runner.initialize(&mut vm)?; + // check step calculation + let mut run_resources = None; cairo_runner - .run_until_pc(end, &mut vm, hint_executor) + .run_until_pc(end, &mut run_resources, &mut vm, hint_executor) .map_err(|err| VmException::from_vm_error(&cairo_runner, &vm, err))?; cairo_runner.end_run(false, false, &mut vm, hint_executor)?; @@ -153,7 +156,7 @@ mod tests { .map_err(CairoRunError::Runner)?; assert!(cairo_runner - .run_until_pc(end, &mut vm, hint_processor) + .run_until_pc(end, &mut None, &mut vm, hint_processor) .is_ok()); Ok((cairo_runner, vm)) @@ -173,7 +176,7 @@ mod tests { let end = cairo_runner.initialize(&mut vm).unwrap(); assert!(cairo_runner - .run_until_pc(end, &mut vm, &mut hint_processor) + .run_until_pc(end, &mut None, &mut vm, &mut hint_processor) .is_ok()); assert!(cairo_runner.relocate(&mut vm, true).is_ok()); // `main` returns without doing nothing, but `not_main` sets `[ap]` to `1` @@ -293,7 +296,7 @@ mod tests { let mut vm = vm!(); let end = cairo_runner.initialize(&mut vm).unwrap(); assert!(cairo_runner - .run_until_pc(end, &mut vm, &mut hint_processor) + .run_until_pc(end, &mut None, &mut vm, &mut hint_processor) .is_ok()); assert!(cairo_runner.relocate(&mut vm, false).is_ok()); assert!(vm.get_relocated_trace().is_err()); diff --git a/src/tests/cairo_1_run_from_entrypoint_tests.rs b/src/tests/cairo_1_run_from_entrypoint_tests.rs index ec159e9635..5234f966f4 100644 --- a/src/tests/cairo_1_run_from_entrypoint_tests.rs +++ b/src/tests/cairo_1_run_from_entrypoint_tests.rs @@ -1,4 +1,5 @@ use crate::tests::*; +use assert_matches::assert_matches; #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] @@ -558,3 +559,60 @@ fn uint512_div_mod_test() { &[], ); } + +// ================ +// Tests run cairo 1 entrypoint with RunResources +// ================ + +#[test] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] +fn fibonacci_with_run_resources_ok() { + let program_data = include_bytes!("../../cairo_programs/cairo-1-contracts/fib.casm"); + let mut resources = Some(RunResources::new(621)); + // Program takes 621 steps + assert_matches!( + run_cairo_1_entrypoint_with_run_resources( + program_data.as_slice(), + 0, + &mut resources, + &[1_usize.into(), 1_usize.into(), 20_usize.into()], + ), + Ok(x) if x == [10946_usize.into()] + ); + + assert_eq!(resources, Some(RunResources::new(0))); +} + +#[test] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] +fn fibonacci_with_run_resources_2_ok() { + let program_data = include_bytes!("../../cairo_programs/cairo-1-contracts/fib.casm"); + let mut resources = Some(RunResources::new(1000)); + // Program takes 621 steps + assert_matches!( + run_cairo_1_entrypoint_with_run_resources( + program_data.as_slice(), + 0, + &mut resources, + &[1_usize.into(), 1_usize.into(), 20_usize.into()], + ), + Ok(x) if x == [10946_usize.into()] + ); + assert_eq!(resources, Some(RunResources::new(1000 - 621))); +} + +#[test] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] +fn fibonacci_with_run_resources_error() { + let program_data = include_bytes!("../../cairo_programs/cairo-1-contracts/fib.casm"); + let mut resources = Some(RunResources::new(100)); + // Program takes 621 steps + assert!(run_cairo_1_entrypoint_with_run_resources( + program_data.as_slice(), + 0, + &mut resources, + &[1_usize.into(), 1_usize.into(), 20_usize.into()], + ) + .is_err()); + assert_eq!(resources, Some(RunResources::new(0))); +} diff --git a/src/tests/mod.rs b/src/tests/mod.rs index c1c718819c..af220315cd 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -1,4 +1,8 @@ #[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; +#[cfg(feature = "cairo-1-hints")] use crate::{ hint_processor::cairo_1_hint_processor::hint_processor::Cairo1HintProcessor, serde::deserialize_program::BuiltinName, @@ -186,6 +190,7 @@ pub(self) fn run_cairo_1_entrypoint( .run_from_entrypoint( entrypoint_offset, &entrypoint_args, + &mut None, true, Some(runner.program.shared_program_data.data.len() + program_extra_data.len()), &mut vm, @@ -206,6 +211,110 @@ pub(self) fn run_cairo_1_entrypoint( assert_eq!(expected_retdata, &retdata); } +#[cfg(feature = "cairo-1-hints")] +/// Equals to fn run_cairo_1_entrypoint +/// But with run_resources as an input +pub(self) fn run_cairo_1_entrypoint_with_run_resources( + program_content: &[u8], + entrypoint_offset: usize, + run_resources: &mut Option, + args: &[MaybeRelocatable], +) -> Result, CairoRunError> { + let contract_class: CasmContractClass = serde_json::from_slice(program_content).unwrap(); + let mut hint_processor = Cairo1HintProcessor::new(&contract_class.hints); + + let mut runner = CairoRunner::new( + &(contract_class.clone().try_into().unwrap()), + "all_cairo", + false, + ) + .unwrap(); + let mut vm = VirtualMachine::new(false); + + let program_builtins = get_casm_contract_builtins(&contract_class, entrypoint_offset); + runner + .initialize_function_runner_cairo_1(&mut vm, &program_builtins) + .unwrap(); + + // Implicit Args + let syscall_segment = MaybeRelocatable::from(vm.add_memory_segment()); + + let builtins: Vec<&'static str> = runner + .get_program_builtins() + .iter() + .map(|b| b.name()) + .collect(); + + let builtin_segment: Vec = 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]); + + // Other args + + // Load builtin costs + let builtin_costs: Vec = + vec![0.into(), 0.into(), 0.into(), 0.into(), 0.into()]; + let builtin_costs_ptr = vm.add_memory_segment(); + vm.load_data(builtin_costs_ptr, &builtin_costs).unwrap(); + + // Load extra data + let core_program_end_ptr = + (runner.program_base.unwrap() + runner.program.shared_program_data.data.len()).unwrap(); + let program_extra_data: Vec = + vec![0x208B7FFF7FFF7FFE.into(), builtin_costs_ptr.into()]; + vm.load_data(core_program_end_ptr, &program_extra_data) + .unwrap(); + + // Load calldata + let calldata_start = vm.add_memory_segment(); + let calldata_end = vm.load_data(calldata_start, &args.to_vec()).unwrap(); + + // Create entrypoint_args + + let mut entrypoint_args: Vec = 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(); + + // Run contract entrypoint + + runner.run_from_entrypoint( + entrypoint_offset, + &entrypoint_args, + run_resources, + true, + Some(runner.program.shared_program_data.data.len() + program_extra_data.len()), + &mut vm, + &mut hint_processor, + )?; + + // Check return values + let return_values = 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 = 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, diff --git a/src/vm/errors/vm_errors.rs b/src/vm/errors/vm_errors.rs index 330ec3c703..5db2338e7d 100644 --- a/src/vm/errors/vm_errors.rs +++ b/src/vm/errors/vm_errors.rs @@ -106,6 +106,8 @@ pub enum VirtualMachineError { EndOfProgram(usize), #[error("Could not reach the end of the program. Executed steps: {0}.")] StepsLimit(u64), + #[error("Could not reach the end of the program. RunResources has no remaining steps.")] + UnfinishedExecution, #[error("Current run is not finished")] RunNotFinished, #[error("Invalid argument count, expected {} but got {}", (*.0).0, (*.0).1)] diff --git a/src/vm/errors/vm_exception.rs b/src/vm/errors/vm_exception.rs index 83414e96ec..933f4223ca 100644 --- a/src/vm/errors/vm_exception.rs +++ b/src/vm/errors/vm_exception.rs @@ -643,7 +643,7 @@ mod test { let end = cairo_runner.initialize(&mut vm).unwrap(); assert!(cairo_runner - .run_until_pc(end, &mut vm, &mut hint_processor) + .run_until_pc(end, &mut None, &mut vm, &mut hint_processor) .is_err()); #[cfg(all(feature = "std"))] @@ -657,7 +657,7 @@ mod test { let end = cairo_runner.initialize(&mut vm).unwrap(); assert!(cairo_runner - .run_until_pc(end, &mut vm, &mut hint_processor) + .run_until_pc(end, &mut None, &mut vm, &mut hint_processor) .is_err()); assert_eq!(get_traceback(&vm, &cairo_runner), Some(expected_traceback)); } @@ -695,7 +695,7 @@ cairo_programs/bad_programs/bad_usort.cairo:64:5: (pc=0:60) let end = cairo_runner.initialize(&mut vm).unwrap(); assert!(cairo_runner - .run_until_pc(end, &mut vm, &mut hint_processor) + .run_until_pc(end, &mut None, &mut vm, &mut hint_processor) .is_err()); assert_eq!( get_traceback(&vm, &cairo_runner), @@ -854,7 +854,7 @@ cairo_programs/bad_programs/bad_range_check.cairo:11:5: (pc=0:6) let end = cairo_runner.initialize(&mut vm).unwrap(); let error = cairo_runner - .run_until_pc(end, &mut vm, &mut hint_processor) + .run_until_pc(end, &mut None, &mut vm, &mut hint_processor) .unwrap_err(); let vm_excepction = VmException::from_vm_error(&cairo_runner, &vm, error); assert_eq!(vm_excepction.to_string(), expected_error_string); @@ -899,7 +899,7 @@ cairo_programs/bad_programs/bad_usort.cairo:64:5: (pc=0:60) let end = cairo_runner.initialize(&mut vm).unwrap(); let error = cairo_runner - .run_until_pc(end, &mut vm, &mut hint_processor) + .run_until_pc(end, &mut None, &mut vm, &mut hint_processor) .unwrap_err(); let vm_excepction = VmException::from_vm_error(&cairo_runner, &vm, error); assert_eq!(vm_excepction.to_string(), expected_error_string); diff --git a/src/vm/hooks.rs b/src/vm/hooks.rs index 05b1dea773..02b177452a 100644 --- a/src/vm/hooks.rs +++ b/src/vm/hooks.rs @@ -146,7 +146,7 @@ mod tests { let end = cairo_runner.initialize(&mut vm).unwrap(); assert!(cairo_runner - .run_until_pc(end, &mut vm, &mut hint_processor) + .run_until_pc(end, &mut None, &mut vm, &mut hint_processor) .is_ok()); } @@ -194,7 +194,7 @@ mod tests { let end = cairo_runner.initialize(&mut vm).unwrap(); assert!(cairo_runner - .run_until_pc(end, &mut vm, &mut hint_processor) + .run_until_pc(end, &mut None, &mut vm, &mut hint_processor) .is_err()); // Pre step fail @@ -205,7 +205,7 @@ mod tests { let end = cairo_runner.initialize(&mut vm).unwrap(); assert!(cairo_runner - .run_until_pc(end, &mut vm, &mut hint_processor) + .run_until_pc(end, &mut None, &mut vm, &mut hint_processor) .is_err()); // Post step fail @@ -216,7 +216,7 @@ mod tests { let end = cairo_runner.initialize(&mut vm).unwrap(); assert!(cairo_runner - .run_until_pc(end, &mut vm, &mut hint_processor) + .run_until_pc(end, &mut None, &mut vm, &mut hint_processor) .is_err()); } @@ -267,7 +267,7 @@ mod tests { let end = cairo_runner.initialize(&mut vm).unwrap(); assert!(cairo_runner - .run_until_pc(end, &mut vm, &mut hint_processor) + .run_until_pc(end, &mut None, &mut vm, &mut hint_processor) .is_ok()); } } diff --git a/src/vm/runners/builtin_runner/bitwise.rs b/src/vm/runners/builtin_runner/bitwise.rs index d09347bac2..b93ebbdedc 100644 --- a/src/vm/runners/builtin_runner/bitwise.rs +++ b/src/vm/runners/builtin_runner/bitwise.rs @@ -359,7 +359,7 @@ mod tests { let address = cairo_runner.initialize(&mut vm).unwrap(); cairo_runner - .run_until_pc(address, &mut vm, &mut hint_processor) + .run_until_pc(address, &mut None, &mut vm, &mut hint_processor) .unwrap(); assert_eq!(builtin.get_used_cells_and_allocated_size(&vm), Ok((0, 5))); @@ -404,7 +404,7 @@ mod tests { let address = cairo_runner.initialize(&mut vm).unwrap(); cairo_runner - .run_until_pc(address, &mut vm, &mut hint_processor) + .run_until_pc(address, &mut None, &mut vm, &mut hint_processor) .unwrap(); assert_eq!(builtin.get_allocated_memory_units(&vm), Ok(5)); diff --git a/src/vm/runners/builtin_runner/ec_op.rs b/src/vm/runners/builtin_runner/ec_op.rs index 8d5b21e1f0..083f437f76 100644 --- a/src/vm/runners/builtin_runner/ec_op.rs +++ b/src/vm/runners/builtin_runner/ec_op.rs @@ -445,7 +445,7 @@ mod tests { let address = cairo_runner.initialize(&mut vm).unwrap(); cairo_runner - .run_until_pc(address, &mut vm, &mut hint_processor) + .run_until_pc(address, &mut None, &mut vm, &mut hint_processor) .unwrap(); assert_eq!(builtin.get_used_cells_and_allocated_size(&vm), Ok((0, 7))); @@ -490,7 +490,7 @@ mod tests { let address = cairo_runner.initialize(&mut vm).unwrap(); cairo_runner - .run_until_pc(address, &mut vm, &mut hint_processor) + .run_until_pc(address, &mut None, &mut vm, &mut hint_processor) .unwrap(); assert_eq!(builtin.get_allocated_memory_units(&vm), Ok(7)); diff --git a/src/vm/runners/builtin_runner/hash.rs b/src/vm/runners/builtin_runner/hash.rs index 0ebd19f9ff..6f97d068f3 100644 --- a/src/vm/runners/builtin_runner/hash.rs +++ b/src/vm/runners/builtin_runner/hash.rs @@ -350,7 +350,7 @@ mod tests { let address = cairo_runner.initialize(&mut vm).unwrap(); cairo_runner - .run_until_pc(address, &mut vm, &mut hint_processor) + .run_until_pc(address, &mut None, &mut vm, &mut hint_processor) .unwrap(); assert_eq!(builtin.get_used_cells_and_allocated_size(&vm), Ok((0, 3))); @@ -394,7 +394,7 @@ mod tests { let address = cairo_runner.initialize(&mut vm).unwrap(); cairo_runner - .run_until_pc(address, &mut vm, &mut hint_processor) + .run_until_pc(address, &mut None, &mut vm, &mut hint_processor) .unwrap(); assert_eq!(builtin.get_allocated_memory_units(&vm), Ok(3)); diff --git a/src/vm/runners/builtin_runner/keccak.rs b/src/vm/runners/builtin_runner/keccak.rs index 285a45a18b..579c4df1aa 100644 --- a/src/vm/runners/builtin_runner/keccak.rs +++ b/src/vm/runners/builtin_runner/keccak.rs @@ -387,7 +387,7 @@ mod tests { let address = cairo_runner.initialize(&mut vm).unwrap(); cairo_runner - .run_until_pc(address, &mut vm, &mut hint_processor) + .run_until_pc(address, &mut None, &mut vm, &mut hint_processor) .unwrap(); assert_eq!( diff --git a/src/vm/runners/builtin_runner/mod.rs b/src/vm/runners/builtin_runner/mod.rs index 7f5297b060..f5223322b0 100644 --- a/src/vm/runners/builtin_runner/mod.rs +++ b/src/vm/runners/builtin_runner/mod.rs @@ -803,7 +803,7 @@ mod tests { let address = cairo_runner.initialize(&mut vm).unwrap(); cairo_runner - .run_until_pc(address, &mut vm, &mut hint_processor) + .run_until_pc(address, &mut None, &mut vm, &mut hint_processor) .unwrap(); assert_eq!(builtin.get_allocated_memory_units(&vm), Ok(5)); @@ -850,7 +850,7 @@ mod tests { let address = cairo_runner.initialize(&mut vm).unwrap(); cairo_runner - .run_until_pc(address, &mut vm, &mut hint_processor) + .run_until_pc(address, &mut None, &mut vm, &mut hint_processor) .unwrap(); assert_eq!(builtin.get_allocated_memory_units(&vm), Ok(7)); @@ -894,7 +894,7 @@ mod tests { let address = cairo_runner.initialize(&mut vm).unwrap(); cairo_runner - .run_until_pc(address, &mut vm, &mut hint_processor) + .run_until_pc(address, &mut None, &mut vm, &mut hint_processor) .unwrap(); assert_eq!(builtin.get_allocated_memory_units(&vm), Ok(3)); @@ -938,7 +938,7 @@ mod tests { let address = cairo_runner.initialize(&mut vm).unwrap(); cairo_runner - .run_until_pc(address, &mut vm, &mut hint_processor) + .run_until_pc(address, &mut None, &mut vm, &mut hint_processor) .unwrap(); assert_eq!(builtin.get_allocated_memory_units(&vm), Ok(1)); diff --git a/src/vm/runners/builtin_runner/poseidon.rs b/src/vm/runners/builtin_runner/poseidon.rs index bd0a7a060f..5b0d0e9cb0 100644 --- a/src/vm/runners/builtin_runner/poseidon.rs +++ b/src/vm/runners/builtin_runner/poseidon.rs @@ -340,7 +340,7 @@ mod tests { let address = cairo_runner.initialize(&mut vm).unwrap(); cairo_runner - .run_until_pc(address, &mut vm, &mut hint_processor) + .run_until_pc(address, &mut None, &mut vm, &mut hint_processor) .unwrap(); assert_eq!(builtin.get_used_cells_and_allocated_size(&vm), Ok((0, 6))); @@ -384,7 +384,7 @@ mod tests { let address = cairo_runner.initialize(&mut vm).unwrap(); cairo_runner - .run_until_pc(address, &mut vm, &mut hint_processor) + .run_until_pc(address, &mut None, &mut vm, &mut hint_processor) .unwrap(); assert_eq!(builtin.get_allocated_memory_units(&vm), Ok(6)); diff --git a/src/vm/runners/builtin_runner/range_check.rs b/src/vm/runners/builtin_runner/range_check.rs index c82d85cca6..34b4963436 100644 --- a/src/vm/runners/builtin_runner/range_check.rs +++ b/src/vm/runners/builtin_runner/range_check.rs @@ -363,7 +363,7 @@ mod tests { let address = cairo_runner.initialize(&mut vm).unwrap(); cairo_runner - .run_until_pc(address, &mut vm, &mut hint_processor) + .run_until_pc(address, &mut None, &mut vm, &mut hint_processor) .unwrap(); assert_eq!(builtin.get_used_cells_and_allocated_size(&vm), Ok((0, 1))); @@ -407,7 +407,7 @@ mod tests { let address = cairo_runner.initialize(&mut vm).unwrap(); cairo_runner - .run_until_pc(address, &mut vm, &mut hint_processor) + .run_until_pc(address, &mut None, &mut vm, &mut hint_processor) .unwrap(); assert_eq!(builtin.get_allocated_memory_units(&vm), Ok(1)); diff --git a/src/vm/runners/cairo_runner.rs b/src/vm/runners/cairo_runner.rs index 1e56e0e4a6..35151c5441 100644 --- a/src/vm/runners/cairo_runner.rs +++ b/src/vm/runners/cairo_runner.rs @@ -72,6 +72,30 @@ impl From> for CairoArg { } } +// ================ +// RunResources +// ================ + +/// Maintains the resources of a cairo run. Can be used across multiple runners. +#[derive(Clone, Default, Debug, PartialEq)] +pub struct RunResources { + n_steps: usize, +} + +impl RunResources { + pub fn new(n_steps: usize) -> Self { + RunResources { n_steps } + } + + pub fn consumed(&self) -> bool { + self.n_steps == 0 + } + + pub fn consume_steps(&mut self) { + self.n_steps -= 1; + } +} + #[derive(Debug)] pub struct CairoRunner { pub(crate) program: Program, @@ -519,24 +543,43 @@ impl CairoRunner { &self.program.builtins } + fn consumed(&self, run_resources: &mut Option) -> bool { + if let Some(r) = run_resources.as_ref() { + r.consumed() + } else { + false + } + } + pub fn run_until_pc( &mut self, address: Relocatable, + run_resources: &mut Option, vm: &mut VirtualMachine, hint_processor: &mut dyn HintProcessor, ) -> Result<(), VirtualMachineError> { let references = self.get_reference_list(); let hint_data_dictionary = self.get_hint_data_dictionary(&references, hint_processor)?; + #[cfg(feature = "hooks")] vm.execute_before_first_step(self, &hint_data_dictionary)?; - while vm.run_context.pc != address { + + while vm.run_context.pc != address && !self.consumed(run_resources) { vm.step( hint_processor, &mut self.exec_scopes, &hint_data_dictionary, &self.program.constants, )?; + if let Some(r) = run_resources.as_mut() { + r.consume_steps() + }; + } + + if vm.run_context.pc != address { + return Err(VirtualMachineError::UnfinishedExecution); } + Ok(()) } @@ -919,10 +962,12 @@ impl CairoRunner { /// Runs a cairo program from a give entrypoint, indicated by its pc offset, with the given arguments. /// If `verify_secure` is set to true, [verify_secure_runner] will be called to run extra verifications. /// `program_segment_size` is only used by the [verify_secure_runner] function and will be ignored if `verify_secure` is set to false. + #[allow(clippy::too_many_arguments)] pub fn run_from_entrypoint( &mut self, entrypoint: usize, args: &[&CairoArg], + run_resources: &mut Option, verify_secure: bool, program_segment_size: Option, vm: &mut VirtualMachine, @@ -937,7 +982,7 @@ impl CairoRunner { self.initialize_vm(vm)?; - self.run_until_pc(end, vm, hint_processor) + self.run_until_pc(end, run_resources, vm, hint_processor) .map_err(|err| VmException::from_vm_error(self, vm, err))?; self.end_run(true, false, vm, hint_processor)?; @@ -1932,7 +1977,7 @@ mod tests { cairo_runner.initialize_vm(&mut vm).unwrap(); //Execution Phase assert_matches!( - cairo_runner.run_until_pc(end, &mut vm, &mut hint_processor), + cairo_runner.run_until_pc(end, &mut None, &mut vm, &mut hint_processor), Ok(()) ); //Check final values against Python VM @@ -2008,7 +2053,7 @@ mod tests { cairo_runner.initialize_vm(&mut vm).unwrap(); //Execution Phase assert_matches!( - cairo_runner.run_until_pc(end, &mut vm, &mut hint_processor), + cairo_runner.run_until_pc(end, &mut None, &mut vm, &mut hint_processor), Ok(()) ); //Check final values against Python VM @@ -2123,7 +2168,7 @@ mod tests { cairo_runner.initialize_vm(&mut vm).unwrap(); //Execution Phase assert_matches!( - cairo_runner.run_until_pc(end, &mut vm, &mut hint_processor), + cairo_runner.run_until_pc(end, &mut None, &mut vm, &mut hint_processor), Ok(()) ); //Check final values against Python VM @@ -2262,7 +2307,7 @@ mod tests { cairo_runner.initialize_vm(&mut vm).unwrap(); //Execution Phase assert_matches!( - cairo_runner.run_until_pc(end, &mut vm, &mut hint_processor), + cairo_runner.run_until_pc(end, &mut None, &mut vm, &mut hint_processor), Ok(()) ); //Check final values against Python VM @@ -2499,7 +2544,7 @@ mod tests { let end = cairo_runner.initialize_main_entrypoint(&mut vm).unwrap(); cairo_runner.initialize_vm(&mut vm).unwrap(); assert_matches!( - cairo_runner.run_until_pc(end, &mut vm, &mut hint_processor), + cairo_runner.run_until_pc(end, &mut None, &mut vm, &mut hint_processor), Ok(()) ); vm.segments.compute_effective_sizes(); @@ -2638,7 +2683,7 @@ mod tests { let end = cairo_runner.initialize_main_entrypoint(&mut vm).unwrap(); cairo_runner.initialize_vm(&mut vm).unwrap(); assert_matches!( - cairo_runner.run_until_pc(end, &mut vm, &mut hint_processor), + cairo_runner.run_until_pc(end, &mut None, &mut vm, &mut hint_processor), Ok(()) ); vm.segments.compute_effective_sizes(); @@ -2815,7 +2860,7 @@ mod tests { //Execution Phase let mut hint_processor = BuiltinHintProcessor::new_empty(); assert_matches!( - cairo_runner.run_until_pc(end, &mut vm, &mut hint_processor), + cairo_runner.run_until_pc(end, &mut None, &mut vm, &mut hint_processor), Ok(()) ); @@ -2856,7 +2901,7 @@ mod tests { //Execution Phase let mut hint_processor = BuiltinHintProcessor::new_empty(); assert_matches!( - cairo_runner.run_until_pc(end, &mut vm, &mut hint_processor), + cairo_runner.run_until_pc(end, &mut None, &mut vm, &mut hint_processor), Ok(()) ); @@ -2942,7 +2987,7 @@ mod tests { let mut hint_processor = BuiltinHintProcessor::new_empty(); assert_matches!( - cairo_runner.run_until_pc(end, &mut vm, &mut hint_processor), + cairo_runner.run_until_pc(end, &mut None, &mut vm, &mut hint_processor), Ok(()) ); @@ -3435,7 +3480,7 @@ mod tests { let end = cairo_runner.initialize(&mut vm).unwrap(); cairo_runner - .run_until_pc(end, &mut vm, &mut hint_processor) + .run_until_pc(end, &mut None, &mut vm, &mut hint_processor) .expect("Call to `CairoRunner::run_until_pc()` failed."); assert_matches!( cairo_runner.end_run(false, false, &mut vm, &mut hint_processor), @@ -4536,6 +4581,7 @@ mod tests { &mayberelocatable!(2).into(), &MaybeRelocatable::from((2, 0)).into() ], //range_check_ptr + &mut None, true, None, &mut vm, @@ -4566,6 +4612,7 @@ mod tests { &mayberelocatable!(2).into(), &MaybeRelocatable::from((2, 0)).into() ], + &mut None, true, None, &mut new_vm, @@ -4604,6 +4651,7 @@ mod tests { &[ &MaybeRelocatable::from((2, 0)).into() //bitwise_ptr ], + &mut None, true, None, &mut vm, @@ -4721,6 +4769,7 @@ mod tests { let result = cairo_runner.run_from_entrypoint( main_entrypoint, &[], + &mut None, true, None, &mut vm, @@ -4750,7 +4799,12 @@ mod tests { let mut vm = vm!(); let end = runner.initialize(&mut vm).unwrap(); runner - .run_until_pc(end, &mut vm, &mut BuiltinHintProcessor::new_empty()) + .run_until_pc( + end, + &mut None, + &mut vm, + &mut BuiltinHintProcessor::new_empty(), + ) .unwrap(); vm.segments.compute_effective_sizes(); let initial_pointer = vm.get_ap(); @@ -4773,7 +4827,12 @@ mod tests { let mut vm = vm!(); let end = runner.initialize(&mut vm).unwrap(); runner - .run_until_pc(end, &mut vm, &mut BuiltinHintProcessor::new_empty()) + .run_until_pc( + end, + &mut None, + &mut vm, + &mut BuiltinHintProcessor::new_empty(), + ) .unwrap(); vm.segments.compute_effective_sizes(); let initial_pointer = vm.get_ap(); @@ -4796,7 +4855,12 @@ mod tests { let mut vm = vm!(); let end = runner.initialize(&mut vm).unwrap(); runner - .run_until_pc(end, &mut vm, &mut BuiltinHintProcessor::new_empty()) + .run_until_pc( + end, + &mut None, + &mut vm, + &mut BuiltinHintProcessor::new_empty(), + ) .unwrap(); vm.segments.compute_effective_sizes(); let initial_pointer = vm.get_ap(); @@ -4820,7 +4884,12 @@ mod tests { let mut vm = vm!(); let end = runner.initialize(&mut vm).unwrap(); runner - .run_until_pc(end, &mut vm, &mut BuiltinHintProcessor::new_empty()) + .run_until_pc( + end, + &mut None, + &mut vm, + &mut BuiltinHintProcessor::new_empty(), + ) .unwrap(); vm.segments.compute_effective_sizes(); let mut exec = runner.get_execution_resources(&vm).unwrap(); @@ -5008,4 +5077,105 @@ mod tests { Ok(()) ) } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + fn test_run_resources_none() { + let program = Program::from_bytes( + include_bytes!("../../../cairo_programs/fibonacci.json"), + Some("main"), + ) + .unwrap(); + let mut runner = cairo_runner!(program); + let mut vm = vm!(); + let end = runner.initialize(&mut vm).unwrap(); + + // program takes 80 steps + assert_matches!( + runner.run_until_pc( + end, + &mut None, + &mut vm, + &mut BuiltinHintProcessor::new_empty(), + ), + Ok(()) + ) + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + fn test_run_resources_ok() { + let program = Program::from_bytes( + include_bytes!("../../../cairo_programs/fibonacci.json"), + Some("main"), + ) + .unwrap(); + let mut runner = cairo_runner!(program); + let mut vm = vm!(); + let end = runner.initialize(&mut vm).unwrap(); + let mut run_resources = Some(RunResources::new(81)); + // program takes 80 steps + assert_matches!( + runner.run_until_pc( + end, + &mut run_resources, + &mut vm, + &mut BuiltinHintProcessor::new_empty(), + ), + Ok(()) + ); + + assert_eq!(run_resources, Some(RunResources::new(1))); + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + fn test_run_resources_ok_2() { + let program = Program::from_bytes( + include_bytes!("../../../cairo_programs/fibonacci.json"), + Some("main"), + ) + .unwrap(); + let mut runner = cairo_runner!(program); + let mut vm = vm!(); + let end = runner.initialize(&mut vm).unwrap(); + let mut run_resources = Some(RunResources::new(80)); + // program takes 80 steps + assert_matches!( + runner.run_until_pc( + end, + &mut run_resources, + &mut vm, + &mut BuiltinHintProcessor::new_empty(), + ), + Ok(()) + ); + + assert_eq!(run_resources, Some(RunResources::new(0))); + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + fn test_run_resources_error() { + let program = Program::from_bytes( + include_bytes!("../../../cairo_programs/fibonacci.json"), + Some("main"), + ) + .unwrap(); + let mut runner = cairo_runner!(program); + let mut vm = vm!(); + let end = runner.initialize(&mut vm).unwrap(); + let mut run_resources = Some(RunResources::new(9)); + // program takes 80 steps + assert_matches!( + runner.run_until_pc( + end, + &mut run_resources, + &mut vm, + &mut BuiltinHintProcessor::new_empty(), + ), + Err(VirtualMachineError::UnfinishedExecution) + ); + assert_eq!(run_resources, Some(RunResources::new(0))); + } } diff --git a/src/vm/vm_core.rs b/src/vm/vm_core.rs index 58b58020a9..707f860b2e 100644 --- a/src/vm/vm_core.rs +++ b/src/vm/vm_core.rs @@ -4129,7 +4129,7 @@ mod tests { let end = cairo_runner.initialize(&mut vm).unwrap(); assert!(cairo_runner - .run_until_pc(end, &mut vm, &mut hint_processor) + .run_until_pc(end, &mut None, &mut vm, &mut hint_processor) .is_err()); let expected_traceback = vec![ (Relocatable::from((1, 3)), Relocatable::from((0, 97))), @@ -4154,7 +4154,7 @@ mod tests { let end = cairo_runner.initialize(&mut vm).unwrap(); assert!(cairo_runner - .run_until_pc(end, &mut vm, &mut hint_processor) + .run_until_pc(end, &mut None, &mut vm, &mut hint_processor) .is_err()); let expected_traceback = vec![(Relocatable::from((1, 2)), Relocatable::from((0, 34)))]; assert_eq!(vm.get_traceback_entries(), expected_traceback); @@ -4243,7 +4243,12 @@ mod tests { .unwrap(); assert!(cairo_runner - .run_until_pc(end, &mut virtual_machine_from_builder, &mut hint_processor) + .run_until_pc( + end, + &mut None, + &mut virtual_machine_from_builder, + &mut hint_processor + ) .is_err()); } }