From 8111d7c9999523f1516c1adab50b3ed9ea61f1d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ceyhun=20=C5=9Een?= Date: Fri, 11 Oct 2024 11:19:35 +0300 Subject: [PATCH] node: Add clementine node. --- src/clementine/mod.rs | 1 + src/clementine/node.rs | 149 +++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 1 + 3 files changed, 151 insertions(+) create mode 100644 src/clementine/mod.rs create mode 100644 src/clementine/node.rs diff --git a/src/clementine/mod.rs b/src/clementine/mod.rs new file mode 100644 index 0000000..492bc84 --- /dev/null +++ b/src/clementine/mod.rs @@ -0,0 +1 @@ +pub mod node; diff --git a/src/clementine/node.rs b/src/clementine/node.rs new file mode 100644 index 0000000..fa31b9f --- /dev/null +++ b/src/clementine/node.rs @@ -0,0 +1,149 @@ +//! # Clementine Node +use std::{fs::File, process::Stdio, time::Duration}; + +use anyhow::Context; +use async_trait::async_trait; +use tokio::{process::Command, time::Instant}; +use tracing::info; + +use crate::{ + client::Client, + config::config_to_file, + log_provider::LogPathProvider, + node::Config, + traits::{NodeT, Restart, SpawnOutput}, + utils::get_clementine_path, + Result, +}; + +pub struct ClementineNode { + spawn_output: SpawnOutput, + config: C, + pub client: Client, +} + +impl ClementineNode { + pub async fn new(config: &C) -> Result { + let spawn_output = Self::spawn(config)?; + + let client = Client::new(config.rpc_bind_host(), config.rpc_bind_port())?; + Ok(Self { + spawn_output, + config: config.clone(), + client, + }) + } + + fn spawn(config: &C) -> Result { + let clementine = get_clementine_path()?; + let dir = config.dir(); + + let kind = C::node_kind(); + + let stdout_path = config.log_path(); + let stdout_file = File::create(&stdout_path).context("Failed to create stdout file")?; + info!( + "{} stdout logs available at : {}", + kind, + stdout_path.display() + ); + + let stderr_path = config.stderr_path(); + let stderr_file = File::create(stderr_path).context("Failed to create stderr file")?; + + let server_arg = match kind { + crate::node::NodeKind::Verifier => "--verifier-server", + _ => panic!("Wrong kind {}", kind), + }; + + let config_path = dir.join(format!("{kind}_config.toml")); + config_to_file(&config.clementine_config(), &config_path)?; + + Command::new(clementine) + .arg(server_arg) + .envs(config.env()) + .stdout(Stdio::from(stdout_file)) + .stderr(Stdio::from(stderr_file)) + .kill_on_drop(true) + .spawn() + .context(format!("Failed to spawn {kind} process")) + .map(SpawnOutput::Child) + } +} + +#[async_trait] +impl NodeT for ClementineNode +where + C: Config + LogPathProvider + Send + Sync, +{ + type Config = C; + type Client = Client; + + fn spawn(config: &Self::Config) -> Result { + Self::spawn(config) + } + + fn spawn_output(&mut self) -> &mut SpawnOutput { + &mut self.spawn_output + } + + async fn wait_for_ready(&self, timeout: Option) -> Result<()> { + let start = Instant::now(); + let timeout = timeout.unwrap_or(Duration::from_secs(30)); + while start.elapsed() < timeout { + // if self + // .client + // .ledger_get_head_soft_confirmation() + // .await + // .is_ok() + // { + return Ok(()); + // } + // sleep(Duration::from_millis(500)).await; + } + anyhow::bail!( + "{} failed to become ready within the specified timeout", + C::node_kind() + ) + } + + fn client(&self) -> &Self::Client { + &self.client + } + + fn env(&self) -> Vec<(&'static str, &'static str)> { + self.config.env() + } + + fn config_mut(&mut self) -> &mut Self::Config { + &mut self.config + } + + fn config(&self) -> &Self::Config { + &self.config + } +} + +#[async_trait] +impl Restart for ClementineNode +where + C: Config + LogPathProvider + Send + Sync, +{ + async fn wait_until_stopped(&mut self) -> Result<()> { + self.stop().await?; + match &mut self.spawn_output { + SpawnOutput::Child(pid) => pid.wait().await?, + SpawnOutput::Container(_) => unimplemented!("L2 nodes don't run in docker yet"), + }; + Ok(()) + } + + async fn start(&mut self, new_config: Option) -> Result<()> { + let config = self.config_mut(); + if let Some(new_config) = new_config { + *config = new_config; + } + *self.spawn_output() = Self::spawn(config)?; + self.wait_for_ready(None).await + } +} diff --git a/src/lib.rs b/src/lib.rs index ffe9d63..8321ddc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,7 @@ pub mod batch_prover; pub mod bitcoin; mod citrea_config; +pub mod clementine; mod client; pub mod config; mod docker;