Skip to content

Commit 8111d7c

Browse files
committed
node: Add clementine node.
1 parent 6bf6bf4 commit 8111d7c

File tree

3 files changed

+151
-0
lines changed

3 files changed

+151
-0
lines changed

src/clementine/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pub mod node;

src/clementine/node.rs

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
//! # Clementine Node
2+
use std::{fs::File, process::Stdio, time::Duration};
3+
4+
use anyhow::Context;
5+
use async_trait::async_trait;
6+
use tokio::{process::Command, time::Instant};
7+
use tracing::info;
8+
9+
use crate::{
10+
client::Client,
11+
config::config_to_file,
12+
log_provider::LogPathProvider,
13+
node::Config,
14+
traits::{NodeT, Restart, SpawnOutput},
15+
utils::get_clementine_path,
16+
Result,
17+
};
18+
19+
pub struct ClementineNode<C: Config + LogPathProvider> {
20+
spawn_output: SpawnOutput,
21+
config: C,
22+
pub client: Client,
23+
}
24+
25+
impl<C: Config + LogPathProvider> ClementineNode<C> {
26+
pub async fn new(config: &C) -> Result<Self> {
27+
let spawn_output = Self::spawn(config)?;
28+
29+
let client = Client::new(config.rpc_bind_host(), config.rpc_bind_port())?;
30+
Ok(Self {
31+
spawn_output,
32+
config: config.clone(),
33+
client,
34+
})
35+
}
36+
37+
fn spawn(config: &C) -> Result<SpawnOutput> {
38+
let clementine = get_clementine_path()?;
39+
let dir = config.dir();
40+
41+
let kind = C::node_kind();
42+
43+
let stdout_path = config.log_path();
44+
let stdout_file = File::create(&stdout_path).context("Failed to create stdout file")?;
45+
info!(
46+
"{} stdout logs available at : {}",
47+
kind,
48+
stdout_path.display()
49+
);
50+
51+
let stderr_path = config.stderr_path();
52+
let stderr_file = File::create(stderr_path).context("Failed to create stderr file")?;
53+
54+
let server_arg = match kind {
55+
crate::node::NodeKind::Verifier => "--verifier-server",
56+
_ => panic!("Wrong kind {}", kind),
57+
};
58+
59+
let config_path = dir.join(format!("{kind}_config.toml"));
60+
config_to_file(&config.clementine_config(), &config_path)?;
61+
62+
Command::new(clementine)
63+
.arg(server_arg)
64+
.envs(config.env())
65+
.stdout(Stdio::from(stdout_file))
66+
.stderr(Stdio::from(stderr_file))
67+
.kill_on_drop(true)
68+
.spawn()
69+
.context(format!("Failed to spawn {kind} process"))
70+
.map(SpawnOutput::Child)
71+
}
72+
}
73+
74+
#[async_trait]
75+
impl<C> NodeT for ClementineNode<C>
76+
where
77+
C: Config + LogPathProvider + Send + Sync,
78+
{
79+
type Config = C;
80+
type Client = Client;
81+
82+
fn spawn(config: &Self::Config) -> Result<SpawnOutput> {
83+
Self::spawn(config)
84+
}
85+
86+
fn spawn_output(&mut self) -> &mut SpawnOutput {
87+
&mut self.spawn_output
88+
}
89+
90+
async fn wait_for_ready(&self, timeout: Option<Duration>) -> Result<()> {
91+
let start = Instant::now();
92+
let timeout = timeout.unwrap_or(Duration::from_secs(30));
93+
while start.elapsed() < timeout {
94+
// if self
95+
// .client
96+
// .ledger_get_head_soft_confirmation()
97+
// .await
98+
// .is_ok()
99+
// {
100+
return Ok(());
101+
// }
102+
// sleep(Duration::from_millis(500)).await;
103+
}
104+
anyhow::bail!(
105+
"{} failed to become ready within the specified timeout",
106+
C::node_kind()
107+
)
108+
}
109+
110+
fn client(&self) -> &Self::Client {
111+
&self.client
112+
}
113+
114+
fn env(&self) -> Vec<(&'static str, &'static str)> {
115+
self.config.env()
116+
}
117+
118+
fn config_mut(&mut self) -> &mut Self::Config {
119+
&mut self.config
120+
}
121+
122+
fn config(&self) -> &Self::Config {
123+
&self.config
124+
}
125+
}
126+
127+
#[async_trait]
128+
impl<C> Restart for ClementineNode<C>
129+
where
130+
C: Config + LogPathProvider + Send + Sync,
131+
{
132+
async fn wait_until_stopped(&mut self) -> Result<()> {
133+
self.stop().await?;
134+
match &mut self.spawn_output {
135+
SpawnOutput::Child(pid) => pid.wait().await?,
136+
SpawnOutput::Container(_) => unimplemented!("L2 nodes don't run in docker yet"),
137+
};
138+
Ok(())
139+
}
140+
141+
async fn start(&mut self, new_config: Option<Self::Config>) -> Result<()> {
142+
let config = self.config_mut();
143+
if let Some(new_config) = new_config {
144+
*config = new_config;
145+
}
146+
*self.spawn_output() = Self::spawn(config)?;
147+
self.wait_for_ready(None).await
148+
}
149+
}

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
pub mod batch_prover;
22
pub mod bitcoin;
33
mod citrea_config;
4+
pub mod clementine;
45
mod client;
56
pub mod config;
67
mod docker;

0 commit comments

Comments
 (0)