Skip to content

Commit

Permalink
tmp clementine verifier
Browse files Browse the repository at this point in the history
  • Loading branch information
ceyhunsen committed Oct 10, 2024
1 parent a96abcf commit f52f2a6
Show file tree
Hide file tree
Showing 6 changed files with 329 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/clementine/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod verifier;
204 changes: 204 additions & 0 deletions src/clementine/verifier.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
use std::path::PathBuf;
use std::sync::Arc;
use std::time::{Duration, Instant};

use anyhow::{bail, Context};
use async_trait::async_trait;
use futures::TryStreamExt;
use tokio::process::Command;
use tokio::time::sleep;

use crate::Result;
use crate::client::Client;
use crate::config::ClementineConfig;
use crate::docker::DockerEnv;
use crate::node::NodeKind;
use crate::traits::{ContainerSpawnOutput, LogProvider, NodeT, Restart, SpawnOutput};

pub struct VerifierNode {
spawn_output: SpawnOutput,
pub config: ClementineConfig,
docker_env: Arc<Option<DockerEnv>>,
client: Client,
}

impl VerifierNode {
pub async fn new(config: &ClementineConfig, docker: Arc<Option<DockerEnv>>) -> Result<Self> {
let spawn_output = Self::spawn(config, &docker).await?;

Ok(Self {
spawn_output,
config: config.clone(),
docker_env: docker,
client: Client::new(&config.client.host, config.client.port.try_into().unwrap())?,
})
}

async fn spawn(
config: &ClementineConfig,
docker: &Arc<Option<DockerEnv>>,
) -> Result<SpawnOutput> {
match docker.as_ref() {
Some(docker) => docker.spawn(config.into()).await,
None => <Self as NodeT>::spawn(config),
}
}

async fn wait_for_shutdown(&self) -> Result<()> {
let timeout_duration = Duration::from_secs(30);
let start = std::time::Instant::now();

while start.elapsed() < timeout_duration {
if !self.is_process_running().await? {
println!("Bridge backend has stopped successfully");
return Ok(());
}
sleep(Duration::from_millis(200)).await;
}

bail!("Timeout waiting for bridge backend to stop")
}

async fn is_process_running(&self) -> Result<bool> {
// let data_dir = &self.config.data_dir;
// let output = Command::new("pgrep")
// .args(["-f", &format!("bitcoind.*{}", data_dir.display())])
// .output()
// .await?;

// Ok(output.status.success())
todo!()
}
}

#[async_trait]
impl NodeT for VerifierNode {
type Config = ClementineConfig;
type Client = Client;

fn spawn(config: &Self::Config) -> Result<SpawnOutput> {
let env = config.get_env();
println!("Running bridge backend with environment variables: {env:?}");

Command::new("npm run server:dev")
.kill_on_drop(true)
.env_clear()
.envs(env.clone())
.spawn()
.context("Failed to spawn bridge backend server process")
.map(SpawnOutput::Child)?;

Command::new("npm run worker:dev")
.kill_on_drop(true)
.env_clear()
.envs(env)
.spawn()
.context("Failed to spawn bridge backend worker process")
.map(SpawnOutput::Child)
}

fn spawn_output(&mut self) -> &mut SpawnOutput {
&mut self.spawn_output
}

async fn wait_for_ready(&self, timeout: Option<Duration>) -> Result<()> {
println!("Waiting for ready");
let start = Instant::now();
let timeout = timeout.unwrap_or(Duration::from_secs(30));
while start.elapsed() < timeout {
if true
// TODO: Do this check.
{
return Ok(());
}
tokio::time::sleep(Duration::from_millis(500)).await;
}
anyhow::bail!("Node failed to become ready within the specified timeout")
}

fn config_mut(&mut self) -> &mut Self::Config {
&mut self.config
}

async fn stop(&mut self) -> Result<()> {
match self.spawn_output() {
SpawnOutput::Child(process) => {
process
.kill()
.await
.context("Failed to kill child process")?;
Ok(())
}
SpawnOutput::Container(ContainerSpawnOutput { id, .. }) => {
std::println!("Stopping container {id}");
let docker = bollard::Docker::connect_with_local_defaults()
.context("Failed to connect to Docker")?;
docker
.stop_container(id, Some(bollard::container::StopContainerOptions { t: 10 }))
.await
.context("Failed to stop Docker container")?;
Ok(())
}
}
}

fn client(&self) -> &Self::Client {
&self.client
}

fn env(&self) -> Vec<(&'static str, &'static str)> {
// self.config.get_env()
todo!()
}

fn config(&self) -> &<Self as NodeT>::Config {
&self.config
}
}

#[async_trait]
impl Restart for VerifierNode {
async fn wait_until_stopped(&mut self) -> Result<()> {
// self.client.stop().await?;
self.stop().await?;

match &self.spawn_output {
SpawnOutput::Child(_) => self.wait_for_shutdown().await,
SpawnOutput::Container(output) => {
let Some(env) = self.docker_env.as_ref() else {
bail!("Missing docker environment")
};
env.docker.stop_container(&output.id, None).await?;

env.docker
.wait_container::<String>(&output.id, None)
.try_collect::<Vec<_>>()
.await?;
env.docker.remove_container(&output.id, None).await?;
println!("Docker container {} succesfully removed", output.id);
Ok(())
}
}
}

async fn start(&mut self, config: Option<Self::Config>) -> Result<()> {
if let Some(config) = config {
self.config = config
}
self.spawn_output = Self::spawn(&self.config, &self.docker_env).await?;

self.wait_for_ready(None).await?;

Ok(())
}
}

impl LogProvider for VerifierNode {
fn kind(&self) -> NodeKind {
NodeKind::Verifier
}

fn log_path(&self) -> PathBuf {
todo!()
}
}
119 changes: 119 additions & 0 deletions src/config/clementine.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
//! # Clementine Configuration Options
use std::path::PathBuf;

use bitcoin::{address::NetworkUnchecked, secp256k1, Amount, Network};
use serde::{Deserialize, Serialize};

/// Clementine's configuration options.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ClementineClient {
/// Host of the operator or the verifier
pub host: String,
/// Port of the operator or the verifier
pub port: u16,
/// Bitcoin network to work on.
pub network: Network,
/// Secret key for the operator or the verifier.
pub secret_key: secp256k1::SecretKey,
/// Verifiers public keys.
pub verifiers_public_keys: Vec<secp256k1::PublicKey>,
/// Number of verifiers.
pub num_verifiers: usize,
/// Operators x-only public keys.
pub operators_xonly_pks: Vec<secp256k1::XOnlyPublicKey>,
/// Operators wallet addresses.
pub operator_wallet_addresses: Vec<bitcoin::Address<NetworkUnchecked>>,
/// Number of operators.
pub num_operators: usize,
/// Operator's fee for withdrawal, in satoshis.
pub operator_withdrawal_fee_sats: Option<Amount>,
/// Number of blocks after which user can take deposit back if deposit request fails.
pub user_takes_after: u32,
/// Number of blocks after which operator can take reimburse the bridge fund if they are honest.
pub operator_takes_after: u32,
/// Bridge amount in satoshis.
pub bridge_amount_sats: Amount,
/// Operator: number of kickoff UTXOs per funding transaction.
pub operator_num_kickoff_utxos_per_tx: usize,
/// Threshold for confirmation.
pub confirmation_threshold: u32,
/// Bitcoin remote procedure call URL.
pub bitcoin_rpc_url: String,
/// Bitcoin RPC user.
pub bitcoin_rpc_user: String,
/// Bitcoin RPC user password.
pub bitcoin_rpc_password: String,
/// All Secret keys. Just for testing purposes.
pub all_verifiers_secret_keys: Option<Vec<secp256k1::SecretKey>>,
/// All Secret keys. Just for testing purposes.
pub all_operators_secret_keys: Option<Vec<secp256k1::SecretKey>>,
/// Verifier endpoints.
pub verifier_endpoints: Option<Vec<String>>,
/// PostgreSQL database host address.
pub db_host: String,
/// PostgreSQL database port.
pub db_port: usize,
/// PostgreSQL database user name.
pub db_user: String,
/// PostgreSQL database user password.
pub db_password: String,
/// PostgreSQL database name.
pub db_name: String,
/// Citrea RPC URL.
pub citrea_rpc_url: String,
/// Bridge contract address.
pub bridge_contract_address: String,
}

impl Default for ClementineClient {
fn default() -> Self {
Self {
host: "127.0.0.1".to_string(),
port: 3030,
secret_key: secp256k1::SecretKey::new(&mut secp256k1::rand::thread_rng()),
verifiers_public_keys: vec![],
num_verifiers: 7,
operators_xonly_pks: vec![],
operator_wallet_addresses: vec![],
num_operators: 3,
operator_withdrawal_fee_sats: None,
user_takes_after: 5,
operator_takes_after: 5,
bridge_amount_sats: Amount::from_sat(100_000_000),
operator_num_kickoff_utxos_per_tx: 10,
confirmation_threshold: 1,
network: Network::Regtest,
bitcoin_rpc_url: "http://127.0.0.1:18443".to_string(),
bitcoin_rpc_user: "admin".to_string(),
bitcoin_rpc_password: "admin".to_string(),
all_verifiers_secret_keys: None,
all_operators_secret_keys: None,
verifier_endpoints: None,
db_host: "127.0.0.1".to_string(),
db_port: 5432,
db_user: "postgres".to_string(),
db_password: "postgres".to_string(),
db_name: "postgres".to_string(),
citrea_rpc_url: "http://127.0.0.1:12345".to_string(),
bridge_contract_address: "3100000000000000000000000000000000000002".to_string(),
}
}
}

#[derive(Debug, Clone)]
pub struct ClementineConfig {
pub client: ClementineClient,
pub docker_image: Option<String>,
pub data_dir: PathBuf,
}

impl Default for ClementineConfig {
fn default() -> Self {
Self {
client: ClementineClient::default(),
docker_image: None,
data_dir: PathBuf::from("bridge_backend"),
}
}
}
2 changes: 2 additions & 0 deletions src/config/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
mod bitcoin;
mod clementine;
mod docker;
mod rollup;
mod test;
Expand All @@ -7,6 +8,7 @@ mod utils;

use std::path::PathBuf;

pub use clementine::{ClementineClient, ClementineConfig};
pub use bitcoin::BitcoinConfig;
pub use docker::DockerConfig;
pub use rollup::{default_rollup_config, RollupConfig};
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@ pub mod sequencer;
pub mod test_case;
pub mod traits;
mod utils;
pub mod clementine;

pub type Result<T> = anyhow::Result<T>;
2 changes: 2 additions & 0 deletions src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ pub enum NodeKind {
LightClientProver,
Sequencer,
FullNode,
Verifier,
}

impl fmt::Display for NodeKind {
Expand All @@ -40,6 +41,7 @@ impl fmt::Display for NodeKind {
NodeKind::LightClientProver => write!(f, "light-client-prover"),
NodeKind::Sequencer => write!(f, "sequencer"),
NodeKind::FullNode => write!(f, "full-node"),
NodeKind::Verifier => write!(f, "verifier"),
}
}
}
Expand Down

0 comments on commit f52f2a6

Please sign in to comment.