Skip to main content

cairo_program_runner_lib/
tasks.rs

1use std::{
2    path::{Path, PathBuf},
3    str::FromStr,
4};
5
6use cairo_lang_executable::executable::EntryPointKind;
7use cairo_lang_executable::executable::Executable;
8use cairo_lang_execute_utils::{program_and_hints_from_executable, user_args_from_flags};
9use cairo_vm::types::errors::program_errors::ProgramError;
10use cairo_vm::types::program::Program;
11use cairo_vm::vm::runners::cairo_pie::CairoPie;
12use num_bigint::BigInt;
13use serde_json::Value;
14
15use crate::{types::Cairo1Executable, Cairo0Executable, Task};
16
17#[derive(thiserror::Error, Debug)]
18pub enum BootloaderTaskError {
19    #[error("Failed to read program: {0}")]
20    Program(#[from] ProgramError),
21
22    #[error("Failed to read PIE: {0}")]
23    Pie(#[from] std::io::Error),
24
25    #[error("Cairo1 error: {0}")]
26    Cairo1(String),
27}
28
29/// Creates a `TaskSpec` for a cairo0 program task by loading a program from a specified file path.
30///
31/// # Arguments
32/// - `program_path`: A reference to a `Path` where the program file is located.
33///
34/// # Returns
35/// - `Ok(Task)`: On success, returns a `Task` with the loaded program.
36/// - `Err(BootloaderTaskError)`: On failure, returns a `BootloaderTaskError::Program` if there's an
37///   issue with loading the program file.
38pub fn create_cairo0_program_task(
39    program_path: &Path,
40    program_input: Option<String>,
41) -> Result<Task, BootloaderTaskError> {
42    let program =
43        Program::from_file(program_path, Some("main")).map_err(BootloaderTaskError::Program)?;
44    Ok(Task::Cairo0Program(Cairo0Executable {
45        program,
46        program_input,
47    }))
48}
49
50/// Creates a `TaskSpec` for a Cairo PIE task by reading it from a zip file.
51///
52/// # Arguments
53/// - `pie_path`: A reference to a `Path` where the Cairo PIE file is located.
54///
55/// # Returns
56/// - `Ok(Task)`: On success, returns a `Task` with the loaded Cairo PIE.
57/// - `Err(BootloaderTaskError)`: On failure, returns a `BootloaderTaskError::Pie` if there's an
58///   issue with reading the Cairo PIE file.
59pub fn create_pie_task(pie_path: &Path) -> Result<Task, BootloaderTaskError> {
60    let pie = CairoPie::read_zip_file(pie_path).map_err(BootloaderTaskError::Pie)?;
61    Ok(Task::Pie(pie))
62}
63
64pub fn create_cairo1_program_task(
65    path: &PathBuf,
66    user_args_list: Option<Vec<Value>>,
67    user_args_file: Option<PathBuf>,
68) -> Result<Task, BootloaderTaskError> {
69    let file = std::fs::File::open(path)
70        .map_err(|e| BootloaderTaskError::Cairo1(format!("Failed to open file: {e:?}")))?;
71    let executable: Executable = serde_json::from_reader(file).map_err(|e| {
72        BootloaderTaskError::Cairo1(format!("Failed reading prebuilt executable: {e:?}"))
73    })?;
74    let user_args_list: Vec<BigInt> = user_args_list
75        .unwrap_or_default()
76        .iter()
77        .map(|n| BigInt::from_str(&n.to_string()).unwrap())
78        .collect();
79
80    let entrypoint = executable
81        .entrypoints
82        .iter()
83        .find(|e| matches!(e.kind, EntryPointKind::Bootloader))
84        .ok_or_else(|| {
85            BootloaderTaskError::Cairo1(format!(
86                "{:?} entrypoint not found",
87                EntryPointKind::Bootloader
88            ))
89        })?;
90    let (program, string_to_hint) = program_and_hints_from_executable(&executable, entrypoint)
91        .map_err(|e| BootloaderTaskError::Cairo1(format!("Failed to parse executable: {e:?}")))?;
92    let user_args = user_args_from_flags(user_args_file.as_ref(), &user_args_list)
93        .map_err(|e| BootloaderTaskError::Cairo1(format!("Failed to parse user args: {e:?}")))?;
94    Ok(Task::Cairo1Program(Cairo1Executable {
95        program,
96        user_args,
97        string_to_hint,
98    }))
99}