Skip to content

Commit

Permalink
CairoRunner.run_until_pc_with_steps_limit (#1181)
Browse files Browse the repository at this point in the history
* Add CairoRunner.run_until_pc_with_steps_limit

* Add unit test

* Add integration test

* Minor API change

* Update CHANGELOG.md

* Add doc

* change error msg
  • Loading branch information
pefontana authored May 29, 2023
1 parent 90ecedd commit 45bf5c8
Show file tree
Hide file tree
Showing 3 changed files with 151 additions and 0 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

#### Upcoming Changes

* Add `CairoRunner::run_until_pc_with_steps_limit method` [#1181](https://github.com/lambdaclass/cairo-rs/pull/1181)

* fix: felt_from_number not properly returning parse errors [#1012](https://github.com/lambdaclass/cairo-rs/pull/1012)

* fix: Fix felt sqrt and Signed impl [#1150](https://github.com/lambdaclass/cairo-rs/pull/1150)
Expand Down
2 changes: 2 additions & 0 deletions src/vm/errors/vm_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ pub enum VirtualMachineError {
NoImm,
#[error("Execution reached the end of the program. Requested remaining steps: {0}.")]
EndOfProgram(usize),
#[error("Could not reach the end of the program. Executed steps: {0}.")]
StepsLimit(u64),
#[error(transparent)]
TracerError(#[from] TraceError),
#[error(transparent)]
Expand Down
147 changes: 147 additions & 0 deletions src/vm/runners/cairo_runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -534,6 +534,40 @@ impl CairoRunner {
Ok(())
}

/// Runs the self.program until it completes execution or reaches the steps_limit.
/// If the execution reaches the steps_limit without completing the execution
/// returns an error
pub fn run_until_pc_with_steps_limit(
&mut self,
address: Relocatable,
steps_limit: u64,
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)?;

if vm.run_context.pc == address {
return Ok(());
}

for _ in 0..steps_limit {
vm.step(
hint_processor,
&mut self.exec_scopes,
&hint_data_dictionary,
&self.program.constants,
)?;

if vm.run_context.pc == address {
return Ok(());
}
}
Err(VirtualMachineError::StepsLimit(steps_limit))
}

/// Execute an exact number of steps on the program from the actual position.
pub fn run_for_steps(
&mut self,
Expand Down Expand Up @@ -4853,4 +4887,117 @@ mod tests {

assert_eq!(runner.get_program().data_len(), 2)
}

#[test]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
fn test_run_until_pc_with_steps_limit() {
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_with_steps_limit(end, 20, &mut vm, &mut BuiltinHintProcessor::new_empty()),
Err(VirtualMachineError::StepsLimit(x)) if x == 20
);
assert_matches!(
runner
.run_until_pc_with_steps_limit(end, 20, &mut vm, &mut BuiltinHintProcessor::new_empty()),
Err(VirtualMachineError::StepsLimit(x)) if x == 20
);
assert_matches!(
runner
.run_until_pc_with_steps_limit(end, 20, &mut vm, &mut BuiltinHintProcessor::new_empty()),
Err(VirtualMachineError::StepsLimit(x)) if x == 20
);
assert_matches!(
runner.run_until_pc_with_steps_limit(
end,
20,
&mut vm,
&mut BuiltinHintProcessor::new_empty(),
),
Ok(())
);

assert_matches!(
runner.run_until_pc_with_steps_limit(
end,
0,
&mut vm,
&mut BuiltinHintProcessor::new_empty(),
),
Ok(())
);
}

#[test]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
fn test_steps_limit_fibonacci_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();

// program takes 80 steps
assert_matches!(
runner
.run_until_pc_with_steps_limit(end, 0, &mut vm, &mut BuiltinHintProcessor::new_empty()),
Err(VirtualMachineError::StepsLimit(x)) if x == 0
)
}

#[test]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
fn test_steps_limit_fibonacci_error_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();

// program takes 80 steps
assert_matches!(
runner
.run_until_pc_with_steps_limit(end, 79, &mut vm, &mut BuiltinHintProcessor::new_empty()),
Err(VirtualMachineError::StepsLimit(x)) if x == 79
)
}

#[test]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
fn test_steps_limit_fibonacci_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();

// program takes 80 steps
assert_matches!(
runner.run_until_pc_with_steps_limit(
end,
80,
&mut vm,
&mut BuiltinHintProcessor::new_empty(),
),
Ok(())
)
}
}

0 comments on commit 45bf5c8

Please sign in to comment.