Skip to content

Commit f52f2a6

Browse files
committed
tmp clementine verifier
1 parent a96abcf commit f52f2a6

File tree

6 files changed

+329
-0
lines changed

6 files changed

+329
-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 verifier;

src/clementine/verifier.rs

Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
use std::path::PathBuf;
2+
use std::sync::Arc;
3+
use std::time::{Duration, Instant};
4+
5+
use anyhow::{bail, Context};
6+
use async_trait::async_trait;
7+
use futures::TryStreamExt;
8+
use tokio::process::Command;
9+
use tokio::time::sleep;
10+
11+
use crate::Result;
12+
use crate::client::Client;
13+
use crate::config::ClementineConfig;
14+
use crate::docker::DockerEnv;
15+
use crate::node::NodeKind;
16+
use crate::traits::{ContainerSpawnOutput, LogProvider, NodeT, Restart, SpawnOutput};
17+
18+
pub struct VerifierNode {
19+
spawn_output: SpawnOutput,
20+
pub config: ClementineConfig,
21+
docker_env: Arc<Option<DockerEnv>>,
22+
client: Client,
23+
}
24+
25+
impl VerifierNode {
26+
pub async fn new(config: &ClementineConfig, docker: Arc<Option<DockerEnv>>) -> Result<Self> {
27+
let spawn_output = Self::spawn(config, &docker).await?;
28+
29+
Ok(Self {
30+
spawn_output,
31+
config: config.clone(),
32+
docker_env: docker,
33+
client: Client::new(&config.client.host, config.client.port.try_into().unwrap())?,
34+
})
35+
}
36+
37+
async fn spawn(
38+
config: &ClementineConfig,
39+
docker: &Arc<Option<DockerEnv>>,
40+
) -> Result<SpawnOutput> {
41+
match docker.as_ref() {
42+
Some(docker) => docker.spawn(config.into()).await,
43+
None => <Self as NodeT>::spawn(config),
44+
}
45+
}
46+
47+
async fn wait_for_shutdown(&self) -> Result<()> {
48+
let timeout_duration = Duration::from_secs(30);
49+
let start = std::time::Instant::now();
50+
51+
while start.elapsed() < timeout_duration {
52+
if !self.is_process_running().await? {
53+
println!("Bridge backend has stopped successfully");
54+
return Ok(());
55+
}
56+
sleep(Duration::from_millis(200)).await;
57+
}
58+
59+
bail!("Timeout waiting for bridge backend to stop")
60+
}
61+
62+
async fn is_process_running(&self) -> Result<bool> {
63+
// let data_dir = &self.config.data_dir;
64+
// let output = Command::new("pgrep")
65+
// .args(["-f", &format!("bitcoind.*{}", data_dir.display())])
66+
// .output()
67+
// .await?;
68+
69+
// Ok(output.status.success())
70+
todo!()
71+
}
72+
}
73+
74+
#[async_trait]
75+
impl NodeT for VerifierNode {
76+
type Config = ClementineConfig;
77+
type Client = Client;
78+
79+
fn spawn(config: &Self::Config) -> Result<SpawnOutput> {
80+
let env = config.get_env();
81+
println!("Running bridge backend with environment variables: {env:?}");
82+
83+
Command::new("npm run server:dev")
84+
.kill_on_drop(true)
85+
.env_clear()
86+
.envs(env.clone())
87+
.spawn()
88+
.context("Failed to spawn bridge backend server process")
89+
.map(SpawnOutput::Child)?;
90+
91+
Command::new("npm run worker:dev")
92+
.kill_on_drop(true)
93+
.env_clear()
94+
.envs(env)
95+
.spawn()
96+
.context("Failed to spawn bridge backend worker process")
97+
.map(SpawnOutput::Child)
98+
}
99+
100+
fn spawn_output(&mut self) -> &mut SpawnOutput {
101+
&mut self.spawn_output
102+
}
103+
104+
async fn wait_for_ready(&self, timeout: Option<Duration>) -> Result<()> {
105+
println!("Waiting for ready");
106+
let start = Instant::now();
107+
let timeout = timeout.unwrap_or(Duration::from_secs(30));
108+
while start.elapsed() < timeout {
109+
if true
110+
// TODO: Do this check.
111+
{
112+
return Ok(());
113+
}
114+
tokio::time::sleep(Duration::from_millis(500)).await;
115+
}
116+
anyhow::bail!("Node failed to become ready within the specified timeout")
117+
}
118+
119+
fn config_mut(&mut self) -> &mut Self::Config {
120+
&mut self.config
121+
}
122+
123+
async fn stop(&mut self) -> Result<()> {
124+
match self.spawn_output() {
125+
SpawnOutput::Child(process) => {
126+
process
127+
.kill()
128+
.await
129+
.context("Failed to kill child process")?;
130+
Ok(())
131+
}
132+
SpawnOutput::Container(ContainerSpawnOutput { id, .. }) => {
133+
std::println!("Stopping container {id}");
134+
let docker = bollard::Docker::connect_with_local_defaults()
135+
.context("Failed to connect to Docker")?;
136+
docker
137+
.stop_container(id, Some(bollard::container::StopContainerOptions { t: 10 }))
138+
.await
139+
.context("Failed to stop Docker container")?;
140+
Ok(())
141+
}
142+
}
143+
}
144+
145+
fn client(&self) -> &Self::Client {
146+
&self.client
147+
}
148+
149+
fn env(&self) -> Vec<(&'static str, &'static str)> {
150+
// self.config.get_env()
151+
todo!()
152+
}
153+
154+
fn config(&self) -> &<Self as NodeT>::Config {
155+
&self.config
156+
}
157+
}
158+
159+
#[async_trait]
160+
impl Restart for VerifierNode {
161+
async fn wait_until_stopped(&mut self) -> Result<()> {
162+
// self.client.stop().await?;
163+
self.stop().await?;
164+
165+
match &self.spawn_output {
166+
SpawnOutput::Child(_) => self.wait_for_shutdown().await,
167+
SpawnOutput::Container(output) => {
168+
let Some(env) = self.docker_env.as_ref() else {
169+
bail!("Missing docker environment")
170+
};
171+
env.docker.stop_container(&output.id, None).await?;
172+
173+
env.docker
174+
.wait_container::<String>(&output.id, None)
175+
.try_collect::<Vec<_>>()
176+
.await?;
177+
env.docker.remove_container(&output.id, None).await?;
178+
println!("Docker container {} succesfully removed", output.id);
179+
Ok(())
180+
}
181+
}
182+
}
183+
184+
async fn start(&mut self, config: Option<Self::Config>) -> Result<()> {
185+
if let Some(config) = config {
186+
self.config = config
187+
}
188+
self.spawn_output = Self::spawn(&self.config, &self.docker_env).await?;
189+
190+
self.wait_for_ready(None).await?;
191+
192+
Ok(())
193+
}
194+
}
195+
196+
impl LogProvider for VerifierNode {
197+
fn kind(&self) -> NodeKind {
198+
NodeKind::Verifier
199+
}
200+
201+
fn log_path(&self) -> PathBuf {
202+
todo!()
203+
}
204+
}

src/config/clementine.rs

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
//! # Clementine Configuration Options
2+
3+
use std::path::PathBuf;
4+
5+
use bitcoin::{address::NetworkUnchecked, secp256k1, Amount, Network};
6+
use serde::{Deserialize, Serialize};
7+
8+
/// Clementine's configuration options.
9+
#[derive(Debug, Clone, Serialize, Deserialize)]
10+
pub struct ClementineClient {
11+
/// Host of the operator or the verifier
12+
pub host: String,
13+
/// Port of the operator or the verifier
14+
pub port: u16,
15+
/// Bitcoin network to work on.
16+
pub network: Network,
17+
/// Secret key for the operator or the verifier.
18+
pub secret_key: secp256k1::SecretKey,
19+
/// Verifiers public keys.
20+
pub verifiers_public_keys: Vec<secp256k1::PublicKey>,
21+
/// Number of verifiers.
22+
pub num_verifiers: usize,
23+
/// Operators x-only public keys.
24+
pub operators_xonly_pks: Vec<secp256k1::XOnlyPublicKey>,
25+
/// Operators wallet addresses.
26+
pub operator_wallet_addresses: Vec<bitcoin::Address<NetworkUnchecked>>,
27+
/// Number of operators.
28+
pub num_operators: usize,
29+
/// Operator's fee for withdrawal, in satoshis.
30+
pub operator_withdrawal_fee_sats: Option<Amount>,
31+
/// Number of blocks after which user can take deposit back if deposit request fails.
32+
pub user_takes_after: u32,
33+
/// Number of blocks after which operator can take reimburse the bridge fund if they are honest.
34+
pub operator_takes_after: u32,
35+
/// Bridge amount in satoshis.
36+
pub bridge_amount_sats: Amount,
37+
/// Operator: number of kickoff UTXOs per funding transaction.
38+
pub operator_num_kickoff_utxos_per_tx: usize,
39+
/// Threshold for confirmation.
40+
pub confirmation_threshold: u32,
41+
/// Bitcoin remote procedure call URL.
42+
pub bitcoin_rpc_url: String,
43+
/// Bitcoin RPC user.
44+
pub bitcoin_rpc_user: String,
45+
/// Bitcoin RPC user password.
46+
pub bitcoin_rpc_password: String,
47+
/// All Secret keys. Just for testing purposes.
48+
pub all_verifiers_secret_keys: Option<Vec<secp256k1::SecretKey>>,
49+
/// All Secret keys. Just for testing purposes.
50+
pub all_operators_secret_keys: Option<Vec<secp256k1::SecretKey>>,
51+
/// Verifier endpoints.
52+
pub verifier_endpoints: Option<Vec<String>>,
53+
/// PostgreSQL database host address.
54+
pub db_host: String,
55+
/// PostgreSQL database port.
56+
pub db_port: usize,
57+
/// PostgreSQL database user name.
58+
pub db_user: String,
59+
/// PostgreSQL database user password.
60+
pub db_password: String,
61+
/// PostgreSQL database name.
62+
pub db_name: String,
63+
/// Citrea RPC URL.
64+
pub citrea_rpc_url: String,
65+
/// Bridge contract address.
66+
pub bridge_contract_address: String,
67+
}
68+
69+
impl Default for ClementineClient {
70+
fn default() -> Self {
71+
Self {
72+
host: "127.0.0.1".to_string(),
73+
port: 3030,
74+
secret_key: secp256k1::SecretKey::new(&mut secp256k1::rand::thread_rng()),
75+
verifiers_public_keys: vec![],
76+
num_verifiers: 7,
77+
operators_xonly_pks: vec![],
78+
operator_wallet_addresses: vec![],
79+
num_operators: 3,
80+
operator_withdrawal_fee_sats: None,
81+
user_takes_after: 5,
82+
operator_takes_after: 5,
83+
bridge_amount_sats: Amount::from_sat(100_000_000),
84+
operator_num_kickoff_utxos_per_tx: 10,
85+
confirmation_threshold: 1,
86+
network: Network::Regtest,
87+
bitcoin_rpc_url: "http://127.0.0.1:18443".to_string(),
88+
bitcoin_rpc_user: "admin".to_string(),
89+
bitcoin_rpc_password: "admin".to_string(),
90+
all_verifiers_secret_keys: None,
91+
all_operators_secret_keys: None,
92+
verifier_endpoints: None,
93+
db_host: "127.0.0.1".to_string(),
94+
db_port: 5432,
95+
db_user: "postgres".to_string(),
96+
db_password: "postgres".to_string(),
97+
db_name: "postgres".to_string(),
98+
citrea_rpc_url: "http://127.0.0.1:12345".to_string(),
99+
bridge_contract_address: "3100000000000000000000000000000000000002".to_string(),
100+
}
101+
}
102+
}
103+
104+
#[derive(Debug, Clone)]
105+
pub struct ClementineConfig {
106+
pub client: ClementineClient,
107+
pub docker_image: Option<String>,
108+
pub data_dir: PathBuf,
109+
}
110+
111+
impl Default for ClementineConfig {
112+
fn default() -> Self {
113+
Self {
114+
client: ClementineClient::default(),
115+
docker_image: None,
116+
data_dir: PathBuf::from("bridge_backend"),
117+
}
118+
}
119+
}

src/config/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
mod bitcoin;
2+
mod clementine;
23
mod docker;
34
mod rollup;
45
mod test;
@@ -7,6 +8,7 @@ mod utils;
78

89
use std::path::PathBuf;
910

11+
pub use clementine::{ClementineClient, ClementineConfig};
1012
pub use bitcoin::BitcoinConfig;
1113
pub use docker::DockerConfig;
1214
pub use rollup::{default_rollup_config, RollupConfig};

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,6 @@ pub mod sequencer;
1212
pub mod test_case;
1313
pub mod traits;
1414
mod utils;
15+
pub mod clementine;
1516

1617
pub type Result<T> = anyhow::Result<T>;

src/node.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ pub enum NodeKind {
3030
LightClientProver,
3131
Sequencer,
3232
FullNode,
33+
Verifier,
3334
}
3435

3536
impl fmt::Display for NodeKind {
@@ -40,6 +41,7 @@ impl fmt::Display for NodeKind {
4041
NodeKind::LightClientProver => write!(f, "light-client-prover"),
4142
NodeKind::Sequencer => write!(f, "sequencer"),
4243
NodeKind::FullNode => write!(f, "full-node"),
44+
NodeKind::Verifier => write!(f, "verifier"),
4345
}
4446
}
4547
}

0 commit comments

Comments
 (0)