bolt_cli/
ephemeral_validator.rs

1use anyhow::Result;
2use std::process::Stdio;
3
4pub struct EphemeralValidator;
5
6impl EphemeralValidator {
7    pub fn is_available() -> bool {
8        which::which("ephemeral-validator").is_ok()
9    }
10
11    async fn wait_for_basenet() -> Result<()> {
12        let balance = tokio::spawn(async move {
13            loop {
14                let status = std::process::Command::new("solana")
15                    .arg("balance")
16                    .args(["-u", "localhost"])
17                    .stdout(Stdio::null())
18                    .stderr(Stdio::null())
19                    .status()
20                    .expect("Failed to check solana balance");
21                if status.success() {
22                    break;
23                }
24                std::thread::sleep(std::time::Duration::from_secs(1));
25            }
26        });
27        balance.await.expect("Failed to check solana balance");
28        Ok(())
29    }
30
31    pub async fn start() -> Result<Self> {
32        if !Self::is_available() {
33            return Err(anyhow::anyhow!("ephemeral-validator not available"));
34        }
35        Self::wait_for_basenet().await?;
36        Self::cleanup()?;
37        let temp_file = std::env::temp_dir().join("ephemeral-validator.toml");
38        std::fs::write(
39            &temp_file,
40            include_str!("templates/ephemeral-validator.toml"),
41        )
42        .expect("Failed to write ephemeral validator config");
43        tokio::process::Command::new("ephemeral-validator")
44            .arg(temp_file)
45            .spawn()
46            .expect("Failed to start ephemeral validator");
47        println!("Ephemeral validator started");
48
49        Ok(Self)
50    }
51
52    pub fn cleanup() -> Result<()> {
53        let mut system = sysinfo::System::new_all();
54        system.refresh_processes(sysinfo::ProcessesToUpdate::All, true);
55        let processes = system.processes();
56        for process in processes.values() {
57            if let Some(name) = process
58                .exe()
59                .and_then(|path| path.file_name())
60                .and_then(|name| name.to_str())
61            {
62                if name == "ephemeral-validator" {
63                    process
64                        .kill_with(sysinfo::Signal::Term)
65                        .expect("Failed to kill ephemeral validator");
66                }
67            }
68        }
69        Ok(())
70    }
71}
72
73impl Drop for EphemeralValidator {
74    fn drop(&mut self) {
75        if EphemeralValidator::is_available() {
76            EphemeralValidator::cleanup().expect("Failed to cleanup ephemeral validator");
77        }
78    }
79}