Skip to main content

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}