cargo_tangle/command/run/
eigenlayer.rs

1use blueprint_core::info;
2use blueprint_manager::sources::{BlueprintArgs, BlueprintEnvVars};
3use blueprint_runner::config::{BlueprintEnvironment, Protocol, SupportedChains};
4use blueprint_std::fs;
5use blueprint_std::path::PathBuf;
6use color_eyre::eyre::{Result, eyre};
7use tokio::io::AsyncBufReadExt;
8use tokio::io::BufReader;
9use tokio::process::{Child, Command};
10use toml::Value;
11
12fn get_binary_name() -> Result<String> {
13    let cargo_toml = fs::read_to_string("Cargo.toml")?;
14    let cargo_data: Value = toml::from_str(&cargo_toml)?;
15
16    // First check for [[bin]] section
17    if let Some(Value::Array(bins)) = cargo_data.get("bin") {
18        if let Some(first_bin) = bins.first() {
19            if let Some(name) = first_bin.get("name").and_then(|n| n.as_str()) {
20                return Ok(name.to_string());
21            }
22        }
23    }
24
25    // If no [[bin]] section, try package name
26    if let Some(package) = cargo_data.get("package") {
27        if let Some(name) = package.get("name").and_then(|n| n.as_str()) {
28            return Ok(name.to_string());
29        }
30    }
31
32    Err(eyre!("Could not find binary name in Cargo.toml"))
33}
34
35/// Run a compiled Eigenlayer AVS binary with the provided options
36///
37/// # Errors
38///
39/// * Failed to build the binary (if needed)
40/// * The binary fails to run, for any reason
41#[allow(clippy::missing_panics_doc)]
42pub async fn run_eigenlayer_avs(
43    config: BlueprintEnvironment,
44    chain: SupportedChains,
45    binary_path: Option<PathBuf>,
46) -> Result<Child> {
47    let binary_path = if let Some(path) = binary_path {
48        path
49    } else {
50        let target_dir = PathBuf::from("./target/release");
51        let binary_name = get_binary_name()?;
52        target_dir.join(&binary_name)
53    };
54
55    println!(
56        "Attempting to run Eigenlayer AVS binary at: {}",
57        binary_path.display()
58    );
59
60    // Build only if binary doesn't exist or no path was provided
61    if !binary_path.exists() {
62        info!("Binary not found at {}, building...", binary_path.display());
63        let status = Command::new("cargo")
64            .arg("build")
65            .arg("--release")
66            .status()
67            .await?;
68
69        if !status.success() {
70            return Err(eyre!("Failed to build AVS binary"));
71        }
72    }
73
74    // Get contract addresses
75    let contract_addresses = config
76        .protocol_settings
77        .eigenlayer()
78        .map_err(|_| eyre!("Missing Eigenlayer contract addresses"))?;
79
80    // Run the AVS binary with the provided options
81    println!("Starting AVS...");
82    let mut command = Command::new(&binary_path);
83
84    let env = BlueprintEnvVars {
85        http_rpc_endpoint: config.http_rpc_endpoint,
86        ws_rpc_endpoint: config.ws_rpc_endpoint,
87        keystore_uri: config.keystore_uri,
88        data_dir: config.data_dir,
89        blueprint_id: 0,
90        service_id: 0,
91        protocol: Protocol::Eigenlayer,
92        chain: Some(chain),
93        bootnodes: String::new(),
94        registration_mode: false,
95        bridge_socket_path: None,
96    };
97
98    command.envs(env.encode());
99
100    let args = BlueprintArgs {
101        test_mode: false,
102        pretty: false,
103        verbose: 0,
104    };
105
106    command.args(args.encode());
107
108    // Optional arguments
109    // TODO: Implement Keystore Password
110    // if let Some(password) = &config.keystore_password {
111    //     command.arg("--keystore-password").arg(password);
112    // }
113
114    // Contract addresses
115    command
116        .arg("--registry-coordinator")
117        .arg(contract_addresses.registry_coordinator_address.to_string())
118        .arg("--operator-state-retriever")
119        .arg(
120            contract_addresses
121                .operator_state_retriever_address
122                .to_string(),
123        )
124        .arg("--delegation-manager")
125        .arg(contract_addresses.delegation_manager_address.to_string())
126        .arg("--strategy-manager")
127        .arg(contract_addresses.strategy_manager_address.to_string())
128        .arg("--service-manager")
129        .arg(contract_addresses.service_manager_address.to_string())
130        .arg("--stake-registry")
131        .arg(contract_addresses.stake_registry_address.to_string())
132        .arg("--avs-directory")
133        .arg(contract_addresses.avs_directory_address.to_string())
134        .arg("--rewards-coordinator")
135        .arg(contract_addresses.rewards_coordinator_address.to_string())
136        .arg("--allocation-manager")
137        .arg(contract_addresses.allocation_manager_address.to_string())
138        .arg("--permission-controller")
139        .arg(contract_addresses.permission_controller_address.to_string())
140        .arg("--strategy")
141        .arg(contract_addresses.strategy_address.to_string());
142
143    assert!(binary_path.exists(), "Binary path does not exist");
144
145    let mut child = command
146        .stdout(std::process::Stdio::piped())
147        .stderr(std::process::Stdio::piped())
148        .spawn()?;
149
150    // Handle stdout
151    let stdout = child.stdout.take().expect("Failed to capture stdout");
152    let mut stdout_reader = BufReader::new(stdout).lines();
153
154    // Handle stderr
155    let stderr = child.stderr.take().expect("Failed to capture stderr");
156    let mut stderr_reader = BufReader::new(stderr).lines();
157
158    // Spawn tasks to handle stdout and stderr
159    let stdout_task = tokio::spawn(async move {
160        while let Some(line) = stdout_reader
161            .next_line()
162            .await
163            .expect("Failed to read stdout")
164        {
165            println!("{}", line);
166        }
167    });
168
169    let stderr_task = tokio::spawn(async move {
170        while let Some(line) = stderr_reader
171            .next_line()
172            .await
173            .expect("Failed to read stderr")
174        {
175            eprintln!("{}", line);
176        }
177    });
178
179    // Wait for both tasks to complete
180    let _ = tokio::join!(stdout_task, stderr_task);
181
182    println!(
183        "AVS is running with PID: {}",
184        child.id().unwrap_or_default()
185    );
186    Ok(child)
187}