Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ Both branches support Stwo prover opcodes (Blake2s, QM31) since v2.0.0.
#### [3.2.0] - 2026-3-24

* adding codecov app.# added by sobhe.
* feat: Add `CairoFunctionRunner` for running Cairo entrypoints by name or PC, and broaden `CairoArg`/`MaybeRelocatable` conversions to support primitive signed/unsigned integers and big integers [#2352](https://github.com/lambdaclass/cairo-vm/pull/2352)
* chore: Add `CairoFunctionRunner` for running Cairo entrypoints by name or PC, and broaden `CairoArg`/`MaybeRelocatable` conversions to support primitive signed/unsigned integers and big integers [#2352](https://github.com/lambdaclass/cairo-vm/pull/2352)

* chore: Add unit tests for `CairoFunctionRunner`, `CairoArg` conversions/macros, and `MaybeRelocatable` conversion macro coverage [#2354](https://github.com/lambdaclass/cairo-vm/pull/2354)
* chore: Add function-runner methods to `CairoRunner` (`new_for_testing`, `run_default_cairo0`, `get_builtin_base`, `run_from_entrypoint`) under the `test_utils` feature [#2359](https://github.com/starkware-libs/cairo-vm/pull/2359)

#### [3.2.0] - 2026-3-3

Expand Down
13 changes: 0 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -246,19 +246,6 @@ When running a Cairo program directly using the Cairo-vm repository you would fi
cairo_runner.initialize_segments(None);
```

When using cairo-vm with the Starknet devnet there are additional parameters that are part of the OS context passed on to the `run_from_entrypoint` method that we do not have here when using it directly. These parameters are, for example, initial stacks of the builtins, which are the base of each of them and are needed as they are the implicit arguments of the function.

```rust
let _var = cairo_runner.run_from_entrypoint(
entrypoint,
vec![
&MaybeRelocatable::from(2).into(), //this is the entry point selector
&MaybeRelocatable::from((2,0)).into() //this would be the output_ptr for example if our cairo function uses it
],
false,
&mut hint_processor,
);
```
### Running cairo 1 programs

To run a cairo 1 program enter in the folder `cd cairo1-run` and follow the [`cairo1-run documentation`](cairo1-run/README.md)
Expand Down
37 changes: 20 additions & 17 deletions vm/src/tests/mod.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
use crate::types::layout_name::LayoutName;
#[cfg(feature = "cairo-1-hints")]
#[cfg(all(feature = "cairo-1-hints", feature = "test_utils"))]
use crate::vm::errors::cairo_run_errors::CairoRunError;
#[cfg(feature = "cairo-1-hints")]
#[cfg(all(feature = "cairo-1-hints", feature = "test_utils"))]
use crate::vm::runners::cairo_runner::RunResources;
use crate::vm::trace::trace_entry::RelocatedTraceEntry;
#[cfg(feature = "cairo-1-hints")]
#[cfg(all(feature = "cairo-1-hints", feature = "test_utils"))]
use crate::Felt252;
#[cfg(feature = "cairo-1-hints")]
#[cfg(all(feature = "cairo-1-hints", feature = "test_utils"))]
use crate::{
hint_processor::cairo_1_hint_processor::hint_processor::Cairo1HintProcessor,
types::{builtin_name::BuiltinName, relocatable::MaybeRelocatable},
vm::runners::cairo_runner::{CairoArg, CairoRunner},
vm::runners::function_runner::EntryPoint,
};
#[cfg(feature = "cairo-1-hints")]
#[cfg(all(feature = "cairo-1-hints", feature = "test_utils"))]
use cairo_lang_starknet_classes::casm_contract_class::CasmContractClass;

use crate::{
Expand All @@ -24,7 +25,7 @@ mod bitwise_test;
#[cfg(test)]
mod run_deprecated_contract_class_simplified;

#[cfg(feature = "cairo-1-hints")]
#[cfg(all(feature = "cairo-1-hints", feature = "test_utils"))]
mod cairo_1_run_from_entrypoint_tests;
mod cairo_run_test;
mod pedersen_test;
Expand Down Expand Up @@ -91,7 +92,7 @@ fn run_program(
}
}

#[cfg(feature = "cairo-1-hints")]
#[cfg(all(feature = "cairo-1-hints", feature = "test_utils"))]
// Runs a contract entrypoint with given arguments and checks its return values
// Doesn't use a syscall_handler
fn run_cairo_1_entrypoint(
Expand Down Expand Up @@ -153,7 +154,7 @@ fn run_cairo_1_entrypoint(
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()];
vec![0x208B7FFF7FFF7FFE_u64.into(), builtin_costs_ptr.into()];
runner
.vm
.load_data(core_program_end_ptr, &program_extra_data)
Expand All @@ -173,16 +174,17 @@ fn run_cairo_1_entrypoint(
MaybeRelocatable::from(calldata_start).into(),
MaybeRelocatable::from(calldata_end).into(),
]);
let entrypoint_args: Vec<&CairoArg> = entrypoint_args.iter().collect();

// Run contract entrypoint

let program_segment_size =
runner.program.shared_program_data.data.len() + program_extra_data.len();
runner
.run_from_entrypoint(
entrypoint_offset,
EntryPoint::Pc(entrypoint_offset),
&entrypoint_args,
true,
Some(runner.program.shared_program_data.data.len() + program_extra_data.len()),
Some(program_segment_size),
&mut hint_processor,
)
.unwrap();
Expand All @@ -201,7 +203,7 @@ fn run_cairo_1_entrypoint(
assert_eq!(expected_retdata, &retdata);
}

#[cfg(feature = "cairo-1-hints")]
#[cfg(all(feature = "cairo-1-hints", feature = "test_utils"))]
#[allow(clippy::result_large_err)]
/// Equals to fn run_cairo_1_entrypoint
/// But with run_resources as an input
Expand Down Expand Up @@ -260,7 +262,7 @@ fn run_cairo_1_entrypoint_with_run_resources(
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()];
vec![0x208B7FFF7FFF7FFE_u64.into(), builtin_costs_ptr.into()];
runner
.vm
.load_data(core_program_end_ptr, &program_extra_data)
Expand All @@ -280,15 +282,16 @@ fn run_cairo_1_entrypoint_with_run_resources(
MaybeRelocatable::from(calldata_start).into(),
MaybeRelocatable::from(calldata_end).into(),
]);
let entrypoint_args: Vec<&CairoArg> = entrypoint_args.iter().collect();

// Run contract entrypoint

let program_segment_size =
runner.program.shared_program_data.data.len() + program_extra_data.len();
runner.run_from_entrypoint(
entrypoint_offset,
EntryPoint::Pc(entrypoint_offset),
&entrypoint_args,
true,
Some(runner.program.shared_program_data.data.len() + program_extra_data.len()),
Some(program_segment_size),
hint_processor,
)?;

Expand All @@ -306,7 +309,7 @@ fn run_cairo_1_entrypoint_with_run_resources(
Ok(retdata)
}

#[cfg(feature = "cairo-1-hints")]
#[cfg(all(feature = "cairo-1-hints", feature = "test_utils"))]
fn get_casm_contract_builtins(
contract_class: &CasmContractClass,
entrypoint_offset: usize,
Expand Down
27 changes: 27 additions & 0 deletions vm/src/types/errors/program_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ pub enum ProgramError {
StrippedProgramNoMain,
#[error("Hint PC ({0}) is greater or equal to program length ({1})")]
InvalidHintPc(usize, usize),
#[error("Identifier \"{0}\" is type alias but has no destination")]
AliasMissingDestination(String),
#[error("invalid identifier type \"{1}\" for \"{0}\": expected \"alias\" or \"function\"")]
InvalidIdentifierTypeForPc(String, String),
}

#[cfg(test)]
Expand All @@ -31,4 +35,27 @@ mod tests {
let formatted_error = format!("{error}");
assert_eq!(formatted_error, "Entrypoint my_function not found");
}

#[test]
fn format_alias_missing_destination_error() {
let error = ProgramError::AliasMissingDestination(String::from("__main__.assert_nn"));
let formatted_error = format!("{error}");
assert_eq!(
formatted_error,
"Identifier \"__main__.assert_nn\" is type alias but has no destination"
);
}

#[test]
fn format_invalid_identifier_type_for_pc_error() {
let error = ProgramError::InvalidIdentifierTypeForPc(
String::from("__main__.my_struct"),
String::from("struct"),
);
let formatted_error = format!("{error}");
assert_eq!(
formatted_error,
"invalid identifier type \"struct\" for \"__main__.my_struct\": expected \"alias\" or \"function\""
);
}
}
63 changes: 57 additions & 6 deletions vm/src/types/relocatable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use crate::Felt252;
use crate::{
relocatable, types::errors::math_errors::MathError, vm::errors::memory_errors::MemoryError,
};
use num_bigint::{BigInt, BigUint};
use num_traits::ToPrimitive;
use serde::{Deserialize, Serialize};

Expand Down Expand Up @@ -58,12 +59,6 @@ impl From<(isize, usize)> for MaybeRelocatable {
}
}

impl From<usize> for MaybeRelocatable {
fn from(num: usize) -> Self {
MaybeRelocatable::Int(Felt252::from(num))
}
}

impl From<Felt252> for MaybeRelocatable {
fn from(num: Felt252) -> Self {
MaybeRelocatable::Int(num)
Expand Down Expand Up @@ -94,6 +89,22 @@ impl From<Relocatable> for MaybeRelocatable {
}
}

// Implement primitive and big-int (owned + reference) conversions by first converting to Felt252,
// then wrapping as MaybeRelocatable::Int.
macro_rules! impl_from_for_maybe_relocatable {
($($t:ty),* $(,)?) => {
$(
impl From<$t> for MaybeRelocatable {
fn from(num: $t) -> Self {
MaybeRelocatable::Int(Felt252::from(num))
}
}
)*
};
}

impl_from_for_maybe_relocatable!(u8, u32, u64, usize, i32, i64, BigUint, BigInt, &BigUint, &BigInt);

impl Display for MaybeRelocatable {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Expand Down Expand Up @@ -396,6 +407,7 @@ mod tests {
use super::*;
use crate::{felt_hex, felt_str};
use crate::{relocatable, utils::test_utils::mayberelocatable};
use num_bigint::{BigInt, BigUint};

use proptest::prelude::*;

Expand Down Expand Up @@ -429,6 +441,45 @@ mod tests {
}
}

#[test]
// Verifies primitive integers convert into `MaybeRelocatable::Int` via the macro-generated impls.
fn maybe_relocatable_from_primitive_via_macro() {
let value = MaybeRelocatable::from(42_u8);
assert_eq!(value, MaybeRelocatable::Int(Felt252::from(42_u8)));
}

#[test]
// Verifies owned `BigUint`/`BigInt` values convert into `MaybeRelocatable::Int`.
fn maybe_relocatable_from_owned_bigints_via_macro() {
let big_uint = BigUint::from(123_u32);
let big_int = BigInt::from(456_i32);

assert_eq!(
MaybeRelocatable::from(big_uint),
MaybeRelocatable::Int(Felt252::from(123_u32))
);
assert_eq!(
MaybeRelocatable::from(big_int),
MaybeRelocatable::Int(Felt252::from(456_i32))
);
}

#[test]
// Verifies referenced `&BigUint`/`&BigInt` values convert into `MaybeRelocatable::Int`.
fn maybe_relocatable_from_referenced_bigints_via_macro() {
let big_uint = BigUint::from(789_u32);
let big_int = BigInt::from(321_i32);

assert_eq!(
MaybeRelocatable::from(&big_uint),
MaybeRelocatable::Int(Felt252::from(789_u32))
);
assert_eq!(
MaybeRelocatable::from(&big_int),
MaybeRelocatable::Int(Felt252::from(321_i32))
);
}

#[test]
fn add_bigint_to_int() {
let addr = MaybeRelocatable::from(Felt252::from(7i32));
Expand Down
Loading
Loading