cairo_program_runner_lib/utils.rs
1use std::{
2 io,
3 path::{Path, PathBuf},
4};
5
6use cairo_vm::{
7 cairo_run::CairoRunConfig,
8 types::{
9 errors::program_errors::ProgramError, layout::CairoLayoutParams, layout_name::LayoutName,
10 program::Program,
11 },
12 vm::runners::cairo_runner::CairoRunner,
13 Felt252,
14};
15
16use crate::types::RunMode;
17
18/// Loads a Cairo program from a file.
19///
20/// This function reads a Cairo program from the specified file path, expecting
21/// an entry point named `"main"`. It returns a `Program` instance on success or a
22/// `ProgramError` if the file cannot be read or parsed as a valid Cairo program.
23///
24/// # Arguments
25///
26/// * `program` - A reference to the file path containing the Cairo program.
27///
28/// # Errors
29///
30/// Returns a `ProgramError` if the program file cannot be read or is invalid.
31pub fn get_program(program: &Path) -> Result<Program, ProgramError> {
32 Program::from_file(program, Some("main"))
33}
34
35/// Reads the input for a Cairo program from a file.
36///
37/// This function checks if an input file is provided. If so, it reads the entire
38/// content of the file into a `String` and returns it wrapped in `Some`.
39/// If no input file is provided, it returns `Ok(None)`.
40///
41/// # Arguments
42///
43/// * `program_input` - An optional file path to the input file.
44///
45/// # Errors
46///
47/// Returns an `io::Error` if there is an issue reading the input file.
48pub fn get_program_input(program_input: &Option<PathBuf>) -> io::Result<Option<String>> {
49 let Some(ref input_path) = program_input else {
50 return Ok(None);
51 };
52 Ok(Some(std::fs::read_to_string(input_path)?))
53}
54
55/// Creates a Cairo run configuration based on the provided parameters.
56///
57/// Depending on the `proof_mode` flag, this function creates a run configuration
58/// for either proof or validation. If a dynamic parameters file is provided,
59/// the layout must be `LayoutName::dynamic`, and the dynamic layout parameters are read
60/// from the file.
61///
62/// # Arguments
63///
64/// * `dynamic_params_file` - An optional file path containing dynamic layout parameters.
65/// * `layout` - The layout name to use for the run configuration.
66/// * `proof_mode` - A boolean flag indicating whether to generate a proof (true) or run in
67/// validation mode (false).
68/// * `disable_trace_padding` - A boolean flag to disable trace padding (used in proof mode).
69/// * `allow_missing_builtins` - A boolean flag to allow missing built-ins (used in validation
70/// mode).
71/// * `relocate_mem` - A boolean flag indicating whether to relocate memory in the VM (used in proof
72/// mode).
73///
74/// # Returns
75///
76/// Returns a `CairoRunConfig` instance configured according to the provided parameters.
77///
78/// # Errors
79///
80/// Returns an `io::Error` if there is an issue reading the dynamic layout parameters file.
81///
82/// # Panics
83///
84/// Panics if `dynamic_params_file` is provided but `layout` is not `LayoutName::dynamic`.
85pub fn get_cairo_run_config(
86 dynamic_params_file: &Option<PathBuf>,
87 layout: LayoutName,
88 proof_mode: bool,
89 disable_trace_padding: bool,
90 allow_missing_builtins: bool,
91 relocate_mem: bool,
92) -> std::io::Result<CairoRunConfig<'static>> {
93 let dynamic_layout_params = match dynamic_params_file {
94 Some(file) => {
95 assert!(
96 layout == LayoutName::dynamic,
97 "dynamic_params_file should not be provided for layout {layout}."
98 );
99 Some(CairoLayoutParams::from_file(file)?)
100 }
101 None => None,
102 };
103
104 Ok(if proof_mode {
105 RunMode::Proof {
106 layout,
107 dynamic_layout_params,
108 disable_trace_padding,
109 relocate_mem,
110 }
111 .create_config()
112 } else {
113 RunMode::Validation {
114 layout,
115 allow_missing_builtins,
116 }
117 .create_config()
118 })
119}
120
121/// Write the program output to the specified output path as Felt252 values.
122pub fn write_output_to_file(runner: &mut CairoRunner, output_path: PathBuf) -> anyhow::Result<()> {
123 let mut output_buffer = String::new();
124 runner.vm.write_output(&mut output_buffer)?;
125 let output_lines = output_buffer
126 .lines()
127 .map(|line| {
128 Felt252::from_dec_str(line)
129 .map_err(|_| anyhow::anyhow!("Failed to parse output line as Felt decimal: {line}"))
130 })
131 .collect::<Result<Vec<Felt252>, anyhow::Error>>()?;
132 std::fs::write(&output_path, sonic_rs::to_string_pretty(&output_lines)?)?;
133 Ok(())
134}