Skip to main content

light_client/
local_test_validator.rs

1use std::process::{Command, Stdio};
2
3use light_prover_client::helpers::get_project_root;
4
5#[derive(Debug)]
6pub struct LightValidatorConfig {
7    pub enable_indexer: bool,
8    pub enable_prover: bool,
9    pub wait_time: u64,
10    /// Non-upgradeable programs: (program_id, program_path)
11    pub sbf_programs: Vec<(String, String)>,
12    /// Upgradeable programs: (program_id, program_path, upgrade_authority)
13    /// Use this when the program needs a valid upgrade authority (e.g., for compression config)
14    pub upgradeable_programs: Vec<(String, String, String)>,
15    pub limit_ledger_size: Option<u64>,
16    /// Use surfpool instead of solana-test-validator
17    pub use_surfpool: bool,
18}
19
20impl Default for LightValidatorConfig {
21    fn default() -> Self {
22        Self {
23            enable_indexer: false,
24            enable_prover: false,
25            wait_time: 35,
26            sbf_programs: vec![],
27            upgradeable_programs: vec![],
28            limit_ledger_size: None,
29            use_surfpool: true,
30        }
31    }
32}
33
34pub async fn spawn_validator(config: LightValidatorConfig) {
35    if let Some(project_root) = get_project_root() {
36        let path = "cli/test_bin/run test-validator";
37        let mut path = format!("{}/{}", project_root.trim(), path);
38        if !config.enable_indexer {
39            path.push_str(" --skip-indexer");
40        }
41
42        if let Some(limit_ledger_size) = config.limit_ledger_size {
43            path.push_str(&format!(" --limit-ledger-size {}", limit_ledger_size));
44        }
45
46        for sbf_program in config.sbf_programs.iter() {
47            path.push_str(&format!(
48                " --sbf-program {} {}",
49                sbf_program.0, sbf_program.1
50            ));
51        }
52
53        for upgradeable_program in config.upgradeable_programs.iter() {
54            path.push_str(&format!(
55                " --upgradeable-program {} {} {}",
56                upgradeable_program.0, upgradeable_program.1, upgradeable_program.2
57            ));
58        }
59
60        if !config.enable_prover {
61            path.push_str(" --skip-prover");
62        }
63
64        if config.use_surfpool {
65            path.push_str(" --use-surfpool");
66        }
67
68        println!("Starting validator with command: {}", path);
69
70        if config.use_surfpool {
71            // The CLI starts surfpool, prover, and photon, then exits once all
72            // services are ready. Wait for it to finish so we know everything
73            // is up before the test proceeds.
74            let mut child = Command::new("sh")
75                .arg("-c")
76                .arg(path)
77                .stdin(Stdio::null())
78                .stdout(Stdio::inherit())
79                .stderr(Stdio::inherit())
80                .spawn()
81                .expect("Failed to start server process");
82            let status = child.wait().expect("Failed to wait for CLI process");
83            assert!(status.success(), "CLI exited with error: {}", status);
84        } else {
85            let child = Command::new("sh")
86                .arg("-c")
87                .arg(path)
88                .stdin(Stdio::null())
89                .stdout(Stdio::null())
90                .stderr(Stdio::null())
91                .spawn()
92                .expect("Failed to start server process");
93            std::mem::drop(child);
94            tokio::time::sleep(tokio::time::Duration::from_secs(config.wait_time)).await;
95        }
96    }
97}