light_prover_client/
prover.rs

1use std::{
2    fmt::{Display, Formatter},
3    process::Command,
4    sync::atomic::{AtomicBool, Ordering},
5    thread::sleep,
6    time::Duration,
7};
8
9use tracing::info;
10
11use crate::{
12    constants::{HEALTH_CHECK, SERVER_ADDRESS},
13    helpers::get_project_root,
14    proof_type::ProofType,
15};
16
17static IS_LOADING: AtomicBool = AtomicBool::new(false);
18#[derive(Debug, Clone, Copy, PartialEq)]
19pub enum ProverMode {
20    Rpc,
21    Forester,
22    ForesterTest,
23    Full,
24    FullTest,
25}
26
27impl Display for ProverMode {
28    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
29        write!(
30            f,
31            "{}",
32            match self {
33                ProverMode::Rpc => "rpc",
34                ProverMode::Forester => "forester",
35                ProverMode::ForesterTest => "forester-test",
36                ProverMode::Full => "full",
37                ProverMode::FullTest => "full-test",
38            }
39        )
40    }
41}
42
43#[derive(Debug, Clone)]
44pub struct ProverConfig {
45    pub run_mode: Option<ProverMode>,
46    pub circuits: Vec<ProofType>,
47}
48
49impl Default for ProverConfig {
50    #[cfg(feature = "devenv")]
51    fn default() -> Self {
52        Self {
53            run_mode: Some(ProverMode::ForesterTest),
54            circuits: vec![],
55        }
56    }
57    #[cfg(not(feature = "devenv"))]
58    fn default() -> Self {
59        Self {
60            run_mode: Some(ProverMode::Rpc),
61            circuits: vec![],
62        }
63    }
64}
65
66impl ProverConfig {
67    pub fn rpc_no_restart() -> Self {
68        Self {
69            run_mode: Some(ProverMode::Rpc),
70            circuits: vec![],
71        }
72    }
73}
74
75pub async fn spawn_prover(config: ProverConfig) {
76    if let Some(_project_root) = get_project_root() {
77        let prover_path: &str = {
78            #[cfg(feature = "devenv")]
79            {
80                &format!("{}/{}", _project_root.trim(), "cli/test_bin/run")
81            }
82            #[cfg(not(feature = "devenv"))]
83            {
84                println!("Running in production mode, using prover binary");
85                "light"
86            }
87        };
88
89        if !health_check(10, 1).await && !IS_LOADING.load(Ordering::Relaxed) {
90            IS_LOADING.store(true, Ordering::Relaxed);
91
92            let mut command = Command::new(prover_path);
93            command.arg("start-prover");
94
95            if let Some(ref mode) = config.run_mode {
96                command.arg("--run-mode").arg(mode.to_string());
97            }
98
99            for circuit in config.circuits.clone() {
100                command.arg("--circuit").arg(circuit.to_string());
101            }
102
103            println!("Starting prover with command: {:?}", command);
104
105            let _ = command
106                .spawn()
107                .expect("Failed to start prover process")
108                .wait();
109
110            let health_result = health_check(120, 1).await;
111            if health_result {
112                info!("Prover started successfully");
113            } else {
114                panic!("Failed to start prover, health check failed.");
115            }
116        }
117        #[cfg(not(feature = "devenv"))]
118        {
119            "light"
120        }
121    } else {
122        panic!("Failed to find project root.");
123    };
124}
125
126pub async fn health_check(retries: usize, timeout: usize) -> bool {
127    let client = reqwest::Client::new();
128    let mut result = false;
129    for _ in 0..retries {
130        match client
131            .get(format!("{}{}", SERVER_ADDRESS, HEALTH_CHECK))
132            .send()
133            .await
134        {
135            Ok(_) => {
136                result = true;
137                break;
138            }
139            Err(_) => {
140                sleep(Duration::from_secs(timeout as u64));
141            }
142        }
143    }
144    result
145}