From 21de5fb34162f92992ed45f9dd9e6e9be2122def Mon Sep 17 00:00:00 2001 From: Heemank Verma Date: Sat, 20 Jul 2024 12:03:16 +0530 Subject: [PATCH] update: build_da_client impl with basic builder --- crates/da-clients/celestia/src/config.rs | 27 ++++---- crates/da-clients/celestia/src/lib.rs | 61 +++++++++---------- .../da-clients/da-client-interface/src/lib.rs | 4 +- crates/da-clients/ethereum/src/config.rs | 7 ++- crates/orchestrator/src/config.rs | 16 +++-- crates/utils/src/env_utils.rs | 26 +++++++- 6 files changed, 86 insertions(+), 55 deletions(-) diff --git a/crates/da-clients/celestia/src/config.rs b/crates/da-clients/celestia/src/config.rs index 2afc5369..a1dec798 100644 --- a/crates/da-clients/celestia/src/config.rs +++ b/crates/da-clients/celestia/src/config.rs @@ -1,9 +1,10 @@ use da_client_interface::DaConfig; -use std::fs::File; -use std::path::PathBuf; -use utils::env_utils::get_env_var_or_panic; +use async_trait::async_trait; use serde::Deserialize; use dotenv::dotenv; +use celestia_rpc::Client; +use utils::env_utils::{get_env_car_optional_or_panic, get_env_var_or_panic}; + #[derive(Clone, PartialEq, Deserialize, Debug)] pub struct CelestiaDaConfig { pub http_provider: String, @@ -11,22 +12,20 @@ pub struct CelestiaDaConfig { pub nid: String, } -impl TryFrom<&PathBuf> for CelestiaDaConfig { - type Error = String; - fn try_from(path: &PathBuf) -> Result { - let file = File::open(path).map_err(|e| format!("error opening da config: {e}"))?; - serde_json::from_reader(file).map_err(|e| format!("error parsing da config: {e}")) - } -} - -impl DaConfig for CelestiaDaConfig { +#[async_trait] +impl DaConfig for CelestiaDaConfig { + // TODO: Possibility to merge these two ? fn new_from_env() -> Self { dotenv().ok(); Self { http_provider: get_env_var_or_panic("CELESTIA_DA_RPC_URL"), - auth_token: Some(get_env_var_or_panic("CELESTIA_DA_AUTH_TOKEN")), + auth_token: get_env_car_optional_or_panic("CELESTIA_DA_AUTH_TOKEN"), nid: get_env_var_or_panic("CELESTIA_DA_NID"), + } } -} \ No newline at end of file + async fn build_da_client(&self) -> Client{ + Client::new(&self.http_provider, self.auth_token.as_deref()).await.expect("Failed to create Client: ") + } +} \ No newline at end of file diff --git a/crates/da-clients/celestia/src/lib.rs b/crates/da-clients/celestia/src/lib.rs index 8cedd1b1..35a27d86 100644 --- a/crates/da-clients/celestia/src/lib.rs +++ b/crates/da-clients/celestia/src/lib.rs @@ -3,22 +3,25 @@ pub mod error; use async_trait::async_trait; use color_eyre::Result; +use config::CelestiaDaConfig; use error::CelestiaDaError; -use jsonrpsee::http_client::{HeaderMap, HeaderValue, HttpClient, HttpClientBuilder}; -use reqwest::header; -use celestia_rpc::BlobClient; +use celestia_rpc::{BlobClient, Client}; use celestia_types::blob::GasPrice; use celestia_types::{nmt::Namespace, Blob}; use da_client_interface::{DaClient, DaVerificationStatus}; -#[derive(Clone, Debug)] pub struct CelestiaDaClient { - celestia_client: HttpClient, + client: Client, nid: Namespace, } +pub struct CelestiaDaConfigAndClient { + pub config : CelestiaDaConfig, + pub client : Client +} + #[async_trait] impl DaClient for CelestiaDaClient { async fn publish_state_diff(&self, state_diff: Vec>, to: &[u8; 32]) -> Result { @@ -28,10 +31,11 @@ impl DaClient for CelestiaDaClient { // Submit the blobs to celestia let height = self - .celestia_client + .client .blob_submit(blobs?.as_slice(), GasPrice::default()) .await?; + println!("{}",height); // // Return back the height of the block that will contain the blob. Ok(height.to_string()) } @@ -58,35 +62,21 @@ impl DaClient for CelestiaDaClient { } } -impl TryFrom for CelestiaDaClient { - type Error = anyhow::Error; - fn try_from(conf: config::CelestiaDaConfig) -> Result { - // Borrowed the below code from https://github.com/eigerco/lumina/blob/ccc5b9bfeac632cccd32d35ecb7b7d51d71fbb87/rpc/src/client.rs#L41. - // Directly calling the function wasn't possible as the function is async. Since - // we only need to initiate the http provider and not the ws provider, we don't need async - - let mut headers = HeaderMap::new(); - // checking if Auth is available - if let Some(auth_token) = conf.auth_token { - let val = HeaderValue::from_str(&format!("Bearer {}", auth_token))?; - headers.insert(header::AUTHORIZATION, val); - } - let http_client = HttpClientBuilder::default() - .set_headers(headers) - .build(conf.http_provider.as_str()) - .map_err(|e| CelestiaDaError::Client(format!("could not init http client: {e}")))?; - - // Convert the input string to bytes - let bytes = conf.nid.as_bytes(); +impl TryFrom for CelestiaDaClient { + type Error = anyhow::Error; + fn try_from(config_and_client: CelestiaDaConfigAndClient) -> Result { + let bytes = config_and_client.config.nid.as_bytes(); - // Create a new Namespace from these bytes let nid = Namespace::new_v0(bytes) - .map_err(|e| CelestiaDaError::Generic(format!("could not init namespace: {e}"))) - .unwrap(); + .map_err(|e| CelestiaDaError::Generic(format!("could not init namespace: {e}"))) + .unwrap(); - Ok(Self { celestia_client: http_client, nid }) + Ok(Self { + client : config_and_client.client, + nid + }) } } @@ -117,10 +107,17 @@ mod tests { use super::*; #[tokio::test] - #[ignore = "Can't run without manual intervention, setup celestia-node and fund address."] + // #[ignore = "Can't run without manual intervention, setup celestia-node and fund address."] async fn test_celestia_publish_state_diff_and_verify_inclusion() { let config: CelestiaDaConfig = CelestiaDaConfig::new_from_env(); - let celestia_da_client = CelestiaDaClient::try_from(config).unwrap(); + let client = config.build_da_client().await; + + let conf_client = CelestiaDaConfigAndClient{ + config, + client + }; + + let celestia_da_client = CelestiaDaClient::try_from(conf_client).unwrap(); let s = "Hello World!"; let bytes: Vec = s.bytes().collect(); diff --git a/crates/da-clients/da-client-interface/src/lib.rs b/crates/da-clients/da-client-interface/src/lib.rs index 33e9de8b..bca97748 100644 --- a/crates/da-clients/da-client-interface/src/lib.rs +++ b/crates/da-clients/da-client-interface/src/lib.rs @@ -29,7 +29,9 @@ pub trait DaClient: Send + Sync { } /// Trait for every new DaConfig to implement -pub trait DaConfig { +#[async_trait] +pub trait DaConfig { /// Should create a new instance of the DaConfig from the environment variables fn new_from_env() -> Self; + async fn build_da_client(&self) -> T; } diff --git a/crates/da-clients/ethereum/src/config.rs b/crates/da-clients/ethereum/src/config.rs index cb0ec9b9..8d9e5406 100644 --- a/crates/da-clients/ethereum/src/config.rs +++ b/crates/da-clients/ethereum/src/config.rs @@ -1,5 +1,6 @@ use da_client_interface::DaConfig; use utils::env_utils::get_env_var_or_panic; +use async_trait::async_trait; #[derive(Clone, Debug)] pub struct EthereumDaConfig { @@ -8,12 +9,16 @@ pub struct EthereumDaConfig { pub private_key: String, } -impl DaConfig for EthereumDaConfig { +#[async_trait] +impl DaConfig for EthereumDaConfig { fn new_from_env() -> Self { Self { rpc_url: get_env_var_or_panic("ETHEREUM_RPC_URL"), memory_pages_contract: get_env_var_or_panic("MEMORY_PAGES_CONTRACT_ADDRESS"), private_key: get_env_var_or_panic("PRIVATE_KEY"), } + } + async fn build_da_client(&self) -> String{ + "Create Ethereum Client here".to_string() } } diff --git a/crates/orchestrator/src/config.rs b/crates/orchestrator/src/config.rs index 8cf28f03..a5a3ff31 100644 --- a/crates/orchestrator/src/config.rs +++ b/crates/orchestrator/src/config.rs @@ -6,7 +6,7 @@ use dotenvy::dotenv; use ethereum_da_client::config::EthereumDaConfig; use ethereum_da_client::EthereumDaClient; use celestia_da_client::config::CelestiaDaConfig; -use celestia_da_client::CelestiaDaClient; +use celestia_da_client::{CelestiaDaClient, CelestiaDaConfigAndClient}; use ethereum_settlement_client::EthereumSettlementClient; use prover_client_interface::ProverClient; use settlement_client_interface::SettlementClient; @@ -56,7 +56,7 @@ pub async fn init_config() -> Config { // init the queue let queue = Box::new(SqsQueue {}); - let da_client = build_da_client(); + let da_client = build_da_client().await; let settings_provider = DefaultSettingsProvider {}; let settlement_client = build_settlement_client(&settings_provider).await; @@ -137,7 +137,7 @@ pub async fn config_force_init(config: Config) { } /// Builds the DA client based on the environment variable DA_LAYER -fn build_da_client() -> Box { +async fn build_da_client() -> Box { match get_env_var_or_panic("DA_LAYER").as_str() { "ethereum" => { let config = EthereumDaConfig::new_from_env(); @@ -145,7 +145,15 @@ fn build_da_client() -> Box { } "celestia" => { let config: CelestiaDaConfig = CelestiaDaConfig::new_from_env(); - Box::new(CelestiaDaClient::try_from(config).unwrap()) + let client = config.build_da_client().await; + + let conf_client = CelestiaDaConfigAndClient{ + config, + client + }; + + // TODO: might want to move away from unwrap ? + Box::new(CelestiaDaClient::try_from(conf_client).unwrap()) } _ => panic!("Unsupported DA layer"), } diff --git a/crates/utils/src/env_utils.rs b/crates/utils/src/env_utils.rs index 78e11609..1a573f3a 100644 --- a/crates/utils/src/env_utils.rs +++ b/crates/utils/src/env_utils.rs @@ -1,7 +1,27 @@ -use color_eyre::Result; +use std::env::VarError; + + +pub fn get_env_var(key: &str) -> Result { + std::env::var(key) +} + +pub fn get_env_var_optional(key: &str) -> Result,VarError> { + match get_env_var(key){ + Ok(s) => { + Ok(Some(s)) + } + Err(VarError::NotPresent) => { + Ok(None) + } + Err(e) => { + Err(e) + } + } +} + +pub fn get_env_car_optional_or_panic(key: &str) -> Option { + get_env_var_optional(key).unwrap_or_else(|e| panic!("Failed to get env var {}: {}", key, e)) -pub fn get_env_var(key: &str) -> Result { - std::env::var(key).map_err(|e| e.into()) } pub fn get_env_var_or_panic(key: &str) -> String {