diff --git a/Cargo.lock b/Cargo.lock index e44bda2..c14f1d5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1831,8 +1831,14 @@ dependencies = [ name = "quartz-enclave" version = "0.1.0" dependencies = [ + "clap", + "color-eyre", "prost", "quartz-proto", + "serde", + "serde_json", + "tendermint", + "tendermint-light-client", "tokio", "tonic", ] diff --git a/enclaves/quartz/Cargo.toml b/enclaves/quartz/Cargo.toml index bfdcdf3..815fecd 100644 --- a/enclaves/quartz/Cargo.toml +++ b/enclaves/quartz/Cargo.toml @@ -4,7 +4,13 @@ version = "0.1.0" edition = "2021" [dependencies] +clap = { version = "4.1.8", features = ["derive"] } +color-eyre = "0.6.2" prost = "0.12" +tendermint = "0.34.0" +tendermint-light-client = "0.34.0" +serde = { version = "1.0.189", features = ["derive"] } +serde_json = "1.0.94" tonic = "0.11" tokio = { version = "1.0", features = ["macros", "rt-multi-thread"] } diff --git a/enclaves/quartz/src/cli.rs b/enclaves/quartz/src/cli.rs new file mode 100644 index 0000000..bb618ac --- /dev/null +++ b/enclaves/quartz/src/cli.rs @@ -0,0 +1,56 @@ +use std::net::SocketAddr; + +use clap::Parser; +use color_eyre::eyre::{eyre, Result}; +use tendermint::Hash; +use tendermint_light_client::types::{Height, TrustThreshold}; + +fn parse_trust_threshold(s: &str) -> Result { + if let Some((l, r)) = s.split_once('/') { + TrustThreshold::new(l.parse()?, r.parse()?).map_err(Into::into) + } else { + Err(eyre!( + "invalid trust threshold: {s}, format must be X/Y where X and Y are integers" + )) + } +} + +#[derive(Debug, Parser)] +#[command(author, version, about, long_about = None)] +pub struct Cli { + /// RPC server address + #[clap(long, default_value = "127.0.0.1:11090")] + pub rpc_addr: SocketAddr, + + /// Identifier of the chain + #[clap(long)] + pub chain_id: String, + + /// Height of the header to verify + #[clap(long)] + pub target_height: Height, + + /// Height of the trusted header (AKA root-of-trust) + #[clap(long)] + pub trusted_height: Height, + + /// Hash of the trusted header (AKA root-of-trust) + #[clap(long)] + pub trusted_hash: Hash, + + /// Trust threshold + #[clap(long, value_parser = parse_trust_threshold, default_value_t = TrustThreshold::TWO_THIRDS)] + pub trust_threshold: TrustThreshold, + + /// Trusting period, in seconds (default: two weeks) + #[clap(long, default_value = "1209600")] + pub trusting_period: u64, + + /// Maximum clock drift, in seconds + #[clap(long, default_value = "5")] + pub max_clock_drift: u64, + + /// Maximum block lag, in seconds + #[clap(long, default_value = "5")] + pub max_block_lag: u64, +} diff --git a/enclaves/quartz/src/main.rs b/enclaves/quartz/src/main.rs index 8f8bfe0..64b04b8 100644 --- a/enclaves/quartz/src/main.rs +++ b/enclaves/quartz/src/main.rs @@ -14,21 +14,39 @@ unused_qualifications )] +mod cli; mod server; +use std::time::Duration; + +use clap::Parser; use quartz_proto::quartz::core_server::CoreServer; use tonic::transport::Server; -use crate::server::CoreService; +use crate::{ + cli::Cli, + server::{Config, CoreService, LightClientOpts}, +}; #[tokio::main(flavor = "current_thread")] async fn main() -> Result<(), Box> { - let addr = "127.0.0.1:11090".parse()?; - let core_service = CoreService::default(); + let args = Cli::parse(); + + let light_client_opts = LightClientOpts::new( + args.chain_id, + args.target_height, + args.trusted_height, + args.trusted_hash, + args.trust_threshold, + args.trusting_period, + args.max_clock_drift, + args.max_block_lag, + ); + let config = Config::new(Duration::from_secs(30 * 24 * 60), light_client_opts); Server::builder() - .add_service(CoreServer::new(core_service)) - .serve(addr) + .add_service(CoreServer::new(CoreService(config))) + .serve(args.rpc_addr) .await?; Ok(()) diff --git a/enclaves/quartz/src/server.rs b/enclaves/quartz/src/server.rs index 14934f0..57e05b7 100644 --- a/enclaves/quartz/src/server.rs +++ b/enclaves/quartz/src/server.rs @@ -1,11 +1,16 @@ +use std::time::Duration; + use quartz_proto::quartz::{ core_server::Core, InstantiateRequest, InstantiateResponse, SessionCreateRequest, SessionCreateResponse, }; +use serde::{Deserialize, Serialize}; +use tendermint::Hash; +use tendermint_light_client::types::{Height, TrustThreshold}; use tonic::{Request, Response, Status}; -#[derive(Debug, Default)] -pub struct CoreService; +#[derive(Clone, Debug)] +pub struct CoreService(pub Config); #[tonic::async_trait] impl Core for CoreService { @@ -34,3 +39,55 @@ impl Core for CoreService { Ok(Response::new(reply)) } } + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Config { + epoch_duration: Duration, + light_client_opts: LightClientOpts, +} + +impl Config { + pub fn new(epoch_duration: Duration, light_client_opts: LightClientOpts) -> Self { + Self { + epoch_duration, + light_client_opts, + } + } +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct LightClientOpts { + chain_id: String, + target_height: Height, + trusted_height: Height, + trusted_hash: Hash, + trust_threshold: TrustThreshold, + trusting_period: u64, + max_clock_drift: u64, + max_block_lag: u64, +} + +impl LightClientOpts { + #[allow(clippy::too_many_arguments)] + pub fn new( + chain_id: String, + target_height: Height, + trusted_height: Height, + trusted_hash: Hash, + trust_threshold: TrustThreshold, + trusting_period: u64, + max_clock_drift: u64, + max_block_lag: u64, + ) -> Self { + Self { + chain_id, + target_height, + trusted_height, + trusted_hash, + trust_threshold, + trusting_period, + max_clock_drift, + max_block_lag, + } + } +}