From d3ec78d109b29d3a03fd0278efd96f3300d7befa Mon Sep 17 00:00:00 2001 From: Ryan Date: Wed, 31 Jan 2024 22:19:42 +0100 Subject: [PATCH] feat: wasm client --- Cargo.lock | 2 ++ rpc/Cargo.toml | 4 ++++ rpc/src/client.rs | 30 ++++++++++++++++++++---------- rpc/src/lib.rs | 1 - rpc/tests/wasm.rs | 25 +++++++++++++++++++++++++ 5 files changed, 51 insertions(+), 11 deletions(-) create mode 100644 rpc/tests/wasm.rs diff --git a/Cargo.lock b/Cargo.lock index 7c6f5da6a..dac8b901f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -708,6 +708,7 @@ dependencies = [ "celestia-types", "dotenvy", "futures", + "getrandom", "http", "jsonrpsee", "libp2p", @@ -717,6 +718,7 @@ dependencies = [ "thiserror", "tokio", "tracing", + "wasm-bindgen-test", ] [[package]] diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index 600045783..9f8930047 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -33,6 +33,10 @@ jsonrpsee = { version = "0.20", features = ["http-client", "ws-client"] } [target.'cfg(target_arch = "wasm32")'.dependencies] jsonrpsee = { version = "0.20", features = ["wasm-client"] } +[target.'cfg(target_arch = "wasm32")'.dev-dependencies] +getrandom = { version = "0.2", features = ["js"] } +wasm-bindgen-test = "0.3.0" + [dev-dependencies] libp2p = { workspace = true, features = [ "tokio", diff --git a/rpc/src/client.rs b/rpc/src/client.rs index d2ce89133..199f36e5c 100644 --- a/rpc/src/client.rs +++ b/rpc/src/client.rs @@ -7,6 +7,9 @@ #[cfg(not(target_arch = "wasm32"))] pub use self::native::Client; +#[cfg(target_arch = "wasm32")] +pub use self::wasm::Client; + #[cfg(not(target_arch = "wasm32"))] mod native { use std::fmt; @@ -155,28 +158,35 @@ mod wasm { use std::fmt; use std::result::Result as StdResult; - use crate::Result; + use crate::{Error, Result}; use async_trait::async_trait; use jsonrpsee::core::client::{BatchResponse, ClientT, Subscription, SubscriptionClientT}; use jsonrpsee::core::params::BatchRequestBuilder; use jsonrpsee::core::traits::ToRpcParams; use jsonrpsee::core::Error as JrpcError; - use jsonrpsee::wasm_client::{Client, WasmClientBuilder}; + use jsonrpsee::wasm_client::{Client as WasmClient, WasmClientBuilder}; use serde::de::DeserializeOwned; - pub struct WasmClient { - client: Client, + pub struct Client { + client: WasmClient, } - impl WasmClient { - pub async fn new(_conn_str: &str) -> Result { - let client = WasmClientBuilder::default().build(_conn_str).await?; - Ok(WasmClient { client }) + impl Client { + pub async fn new(conn_str: &str) -> Result { + // Since headers are not supported in the current version of `jsonrpsee-wasm-client`, + // celestia-node requires disabling authentication (--rpc.skip-auth) to use wasm. + let protocol = conn_str.split_once(':').map(|(proto, _)| proto); + let client = match protocol { + Some("ws") | Some("wss") => WasmClientBuilder::default().build(conn_str).await?, + _ => return Err(Error::ProtocolNotSupported(conn_str.into())), + }; + + Ok(Client { client }) } } #[async_trait] - impl ClientT for WasmClient { + impl ClientT for Client { async fn notification( &self, method: &str, @@ -208,7 +218,7 @@ mod wasm { } #[async_trait] - impl SubscriptionClientT for WasmClient { + impl SubscriptionClientT for Client { async fn subscribe<'a, N, Params>( &self, subscribe_method: &'a str, diff --git a/rpc/src/lib.rs b/rpc/src/lib.rs index 2cf6a0d18..8e47e2289 100644 --- a/rpc/src/lib.rs +++ b/rpc/src/lib.rs @@ -11,7 +11,6 @@ mod share; mod state; pub use crate::blob::BlobClient; -#[cfg(not(target_arch = "wasm32"))] pub use crate::client::Client; pub use crate::error::{Error, Result}; pub use crate::header::HeaderClient; diff --git a/rpc/tests/wasm.rs b/rpc/tests/wasm.rs new file mode 100644 index 000000000..f5b44bb33 --- /dev/null +++ b/rpc/tests/wasm.rs @@ -0,0 +1,25 @@ +#![cfg(target_arch = "wasm32")] + +use celestia_rpc::client::Client; +use celestia_rpc::prelude::*; +use wasm_bindgen_test::*; + +const CELESTIA_RPC_URL: &str = "ws://localhost:26658"; + +wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); + +#[wasm_bindgen_test] +async fn network_head() { + let client = Client::new(CELESTIA_RPC_URL).await.unwrap(); + let network_head = client.header_network_head().await.unwrap(); + + let genesis_header = client.header_get_by_height(1).await.unwrap(); + let adjacent_header = client + .header_get_by_height(network_head.height().value() - 1) + .await + .unwrap(); + + network_head.validate().unwrap(); + genesis_header.verify(&network_head).unwrap(); + adjacent_header.verify(&network_head).unwrap(); +}