From 9235d5041ce27a3761649948ec08d7a6c259ff9f Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Fri, 11 Nov 2022 12:03:23 +0100 Subject: [PATCH 1/3] fix clippy (#715) * fix clippy * remove used id in codegen * fix clippy again --- codegen/src/types/mod.rs | 6 ++---- examples/examples/fetch_staking_details.rs | 2 +- examples/examples/storage_iterating.rs | 6 +++--- subxt/src/dynamic.rs | 2 +- subxt/src/events/events_client.rs | 2 +- subxt/src/storage/utils.rs | 4 ++-- subxt/src/tx/tx_payload.rs | 2 +- testing/integration-tests/src/frame/balances.rs | 10 +++++----- testing/integration-tests/src/frame/staking.rs | 2 +- testing/integration-tests/src/storage/mod.rs | 2 +- 10 files changed, 18 insertions(+), 20 deletions(-) diff --git a/codegen/src/types/mod.rs b/codegen/src/types/mod.rs index bd3896bb92..5a9c2c7f23 100644 --- a/codegen/src/types/mod.rs +++ b/codegen/src/types/mod.rs @@ -92,14 +92,13 @@ impl<'a> TypeGenerator<'a> { let mut root_mod = Module::new(self.types_mod_ident.clone(), self.types_mod_ident.clone()); - for (id, ty) in self.type_registry.types().iter().enumerate() { + for ty in self.type_registry.types().iter() { if ty.ty().path().namespace().is_empty() { // prelude types e.g. Option/Result have no namespace, so we don't generate them continue } self.insert_type( ty.ty().clone(), - id as u32, ty.ty().path().namespace().to_vec(), &self.types_mod_ident, &mut root_mod, @@ -112,7 +111,6 @@ impl<'a> TypeGenerator<'a> { fn insert_type( &'a self, ty: Type, - id: u32, path: Vec, root_mod_ident: &Ident, module: &mut Module, @@ -136,7 +134,7 @@ impl<'a> TypeGenerator<'a> { TypeDefGen::from_type(ty, self, &self.crate_path), ); } else { - self.insert_type(ty, id, path[1..].to_vec(), root_mod_ident, child_mod) + self.insert_type(ty, path[1..].to_vec(), root_mod_ident, child_mod) } } diff --git a/examples/examples/fetch_staking_details.rs b/examples/examples/fetch_staking_details.rs index 7ade78005d..cd7986bbf2 100644 --- a/examples/examples/fetch_staking_details.rs +++ b/examples/examples/fetch_staking_details.rs @@ -59,7 +59,7 @@ async fn main() -> Result<(), Box> { .unwrap(); println!(" account controlled by: {:?}", controller_acc); - let era_reward_addr = polkadot::storage().staking().eras_reward_points(&era.index); + let era_reward_addr = polkadot::storage().staking().eras_reward_points(era.index); let era_result = api.storage().fetch(&era_reward_addr, None).await?; println!("Era reward points: {:?}", era_result); diff --git a/examples/examples/storage_iterating.rs b/examples/examples/storage_iterating.rs index 6403d1446a..c9bed2c645 100644 --- a/examples/examples/storage_iterating.rs +++ b/examples/examples/storage_iterating.rs @@ -57,7 +57,7 @@ async fn main() -> Result<(), Box> { println!("Example 2. Obtained keys:"); for key in keys.iter() { - println!("Key: 0x{}", hex::encode(&key)); + println!("Key: 0x{}", hex::encode(key)); if let Some(storage_data) = api.storage().fetch_raw(&key.0, None).await? { // We know the return value to be `QueryId` (`u64`) from inspecting either: @@ -80,7 +80,7 @@ async fn main() -> Result<(), Box> { // We know that the first key is a u32 (the `XcmVersion`) and is hashed by twox64_concat. // We can build a `StorageMapKey` that replicates that, and append those bytes to the above. - StorageMapKey::new(&2u32, StorageHasher::Twox64Concat).to_bytes(&mut query_key); + StorageMapKey::new(2u32, StorageHasher::Twox64Concat).to_bytes(&mut query_key); // The final query key is essentially the result of: // `twox_128("XcmPallet") ++ twox_128("VersionNotifiers") ++ twox_64(2u32) ++ 2u32` @@ -90,7 +90,7 @@ async fn main() -> Result<(), Box> { println!("Obtained keys:"); for key in keys.iter() { - println!("Key: 0x{}", hex::encode(&key)); + println!("Key: 0x{}", hex::encode(key)); if let Some(storage_data) = api.storage().fetch_raw(&key.0, None).await? { // We know the return value to be `QueryId` (`u64`) from inspecting either: diff --git a/subxt/src/dynamic.rs b/subxt/src/dynamic.rs index d9650805bc..a4d86f7c66 100644 --- a/subxt/src/dynamic.rs +++ b/subxt/src/dynamic.rs @@ -51,7 +51,7 @@ impl DecodeWithMetadata for DecodedValueThunk { metadata: &Metadata, ) -> Result { let mut v = Vec::with_capacity(bytes.len()); - v.extend_from_slice(*bytes); + v.extend_from_slice(bytes); *bytes = &[]; Ok(DecodedValueThunk { type_id, diff --git a/subxt/src/events/events_client.rs b/subxt/src/events/events_client.rs index d774ff1fa7..e91bf15c50 100644 --- a/subxt/src/events/events_client.rs +++ b/subxt/src/events/events_client.rs @@ -68,7 +68,7 @@ where let event_bytes = client .rpc() - .storage(&*system_events_key().0, Some(block_hash)) + .storage(&system_events_key().0, Some(block_hash)) .await? .map(|e| e.0) .unwrap_or_else(Vec::new); diff --git a/subxt/src/storage/utils.rs b/subxt/src/storage/utils.rs index ecf6c3a134..811743586d 100644 --- a/subxt/src/storage/utils.rs +++ b/subxt/src/storage/utils.rs @@ -18,8 +18,8 @@ pub fn write_storage_address_root_bytes( addr: &Address, out: &mut Vec, ) { - out.extend(&sp_core::twox_128(addr.pallet_name().as_bytes())); - out.extend(&sp_core::twox_128(addr.entry_name().as_bytes())); + out.extend(sp_core::twox_128(addr.pallet_name().as_bytes())); + out.extend(sp_core::twox_128(addr.entry_name().as_bytes())); } /// Outputs the [`storage_address_root_bytes`] as well as any additional bytes that represent diff --git a/subxt/src/tx/tx_payload.rs b/subxt/src/tx/tx_payload.rs index 70b25be864..285e537566 100644 --- a/subxt/src/tx/tx_payload.rs +++ b/subxt/src/tx/tx_payload.rs @@ -138,7 +138,7 @@ impl<'a> TxPayload for DynamicTxPayload<'a> { let pallet = metadata.pallet(&self.pallet_name)?; let call_id = pallet.call_ty_id().ok_or(MetadataError::CallNotFound)?; let call_value = - Value::unnamed_variant(self.call_name.to_owned(), self.fields.clone()); + Value::unnamed_variant(self.call_name.clone(), self.fields.clone()); pallet.index().encode_to(out); scale_value::scale::encode_as_type(&call_value, call_id, metadata.types(), out)?; diff --git a/testing/integration-tests/src/frame/balances.rs b/testing/integration-tests/src/frame/balances.rs index 40b20ac3c9..d787bdbc5f 100644 --- a/testing/integration-tests/src/frame/balances.rs +++ b/testing/integration-tests/src/frame/balances.rs @@ -101,12 +101,12 @@ async fn tx_dynamic_transfer() -> Result<(), subxt::Error> { let alice_account_addr = subxt::dynamic::storage( "System", "Account", - vec![Value::from_bytes(&alice.account_id())], + vec![Value::from_bytes(alice.account_id())], ); let bob_account_addr = subxt::dynamic::storage( "System", "Account", - vec![Value::from_bytes(&bob.account_id())], + vec![Value::from_bytes(bob.account_id())], ); let alice_pre = api @@ -122,7 +122,7 @@ async fn tx_dynamic_transfer() -> Result<(), subxt::Error> { "Balances", "transfer", vec![ - Value::unnamed_variant("Id", vec![Value::from_bytes(&bob.account_id())]), + Value::unnamed_variant("Id", vec![Value::from_bytes(bob.account_id())]), Value::u128(10_000u128), ], ); @@ -145,11 +145,11 @@ async fn tx_dynamic_transfer() -> Result<(), subxt::Error> { let expected_fields = Composite::Named(vec![ ( "from".into(), - Value::unnamed_composite(vec![Value::from_bytes(&alice.account_id())]), + Value::unnamed_composite(vec![Value::from_bytes(alice.account_id())]), ), ( "to".into(), - Value::unnamed_composite(vec![Value::from_bytes(&bob.account_id())]), + Value::unnamed_composite(vec![Value::from_bytes(bob.account_id())]), ), ("amount".into(), Value::u128(10_000)), ]); diff --git a/testing/integration-tests/src/frame/staking.rs b/testing/integration-tests/src/frame/staking.rs index 29a6200667..16337d2285 100644 --- a/testing/integration-tests/src/frame/staking.rs +++ b/testing/integration-tests/src/frame/staking.rs @@ -242,7 +242,7 @@ async fn storage_current_era() -> Result<(), Error> { async fn storage_era_reward_points() -> Result<(), Error> { let ctx = test_context().await; let api = ctx.client(); - let reward_points_addr = node_runtime::storage().staking().eras_reward_points(&0); + let reward_points_addr = node_runtime::storage().staking().eras_reward_points(0); let current_era_result = api.storage().fetch(&reward_points_addr, None).await; assert!(current_era_result.is_ok()); diff --git a/testing/integration-tests/src/storage/mod.rs b/testing/integration-tests/src/storage/mod.rs index f56ad8885a..3cae0ef37f 100644 --- a/testing/integration-tests/src/storage/mod.rs +++ b/testing/integration-tests/src/storage/mod.rs @@ -72,7 +72,7 @@ async fn storage_n_mapish_key_is_properly_created() -> Result<(), subxt::Error> bytes.extend(&sp_core::twox_128("KeyOwner".as_bytes())[..]); // twox64_concat a *tuple* of the args expected: let suffix = (KeyTypeId([1, 2, 3, 4]), vec![5u8, 6, 7, 8]).encode(); - bytes.extend(&sp_core::twox_64(&suffix)); + bytes.extend(sp_core::twox_64(&suffix)); bytes.extend(&suffix); bytes }; From 71e58b2c164a3285aa9cea09e4374fa10ba40246 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 11 Nov 2022 14:44:27 +0100 Subject: [PATCH 2/3] Bump Swatinem/rust-cache from 2.0.1 to 2.2.0 (#710) Bumps [Swatinem/rust-cache](https://github.com/Swatinem/rust-cache) from 2.0.1 to 2.2.0. - [Release notes](https://github.com/Swatinem/rust-cache/releases) - [Changelog](https://github.com/Swatinem/rust-cache/blob/master/CHANGELOG.md) - [Commits](https://github.com/Swatinem/rust-cache/compare/22c9328bcba27aa81a32b1bef27c7e3c78052531...359a70e43a0bb8a13953b04a90f76428b4959bb6) --- updated-dependencies: - dependency-name: Swatinem/rust-cache dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/nightly.yml | 2 +- .github/workflows/rust.yml | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 2d09afc547..0a1a16c88c 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -34,7 +34,7 @@ jobs: override: true - name: Rust Cache - uses: Swatinem/rust-cache@22c9328bcba27aa81a32b1bef27c7e3c78052531 # v2.0.1 + uses: Swatinem/rust-cache@359a70e43a0bb8a13953b04a90f76428b4959bb6 # v2.2.0 - name: Cargo test uses: actions-rs/cargo@v1.0.3 diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index cf5ea8d34d..f311d15390 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -40,7 +40,7 @@ jobs: override: true - name: Rust Cache - uses: Swatinem/rust-cache@22c9328bcba27aa81a32b1bef27c7e3c78052531 # v2.0.1 + uses: Swatinem/rust-cache@359a70e43a0bb8a13953b04a90f76428b4959bb6 # v2.2.0 - name: Build uses: actions-rs/cargo@v1.0.3 @@ -64,7 +64,7 @@ jobs: components: rustfmt - name: Rust Cache - uses: Swatinem/rust-cache@22c9328bcba27aa81a32b1bef27c7e3c78052531 # v2.0.1 + uses: Swatinem/rust-cache@359a70e43a0bb8a13953b04a90f76428b4959bb6 # v2.2.0 - name: Cargo fmt uses: actions-rs/cargo@v1.0.3 @@ -94,7 +94,7 @@ jobs: override: true - name: Rust Cache - uses: Swatinem/rust-cache@22c9328bcba27aa81a32b1bef27c7e3c78052531 # v2.0.1 + uses: Swatinem/rust-cache@359a70e43a0bb8a13953b04a90f76428b4959bb6 # v2.2.0 - name: Check internal documentation links run: RUSTDOCFLAGS="--deny rustdoc::broken_intra_doc_links" cargo doc -vv --workspace --no-deps --document-private-items @@ -127,7 +127,7 @@ jobs: override: true - name: Rust Cache - uses: Swatinem/rust-cache@22c9328bcba27aa81a32b1bef27c7e3c78052531 # v2.0.1 + uses: Swatinem/rust-cache@359a70e43a0bb8a13953b04a90f76428b4959bb6 # v2.2.0 - name: Cargo test uses: actions-rs/cargo@v1.0.3 @@ -158,7 +158,7 @@ jobs: override: true - name: Rust Cache - uses: Swatinem/rust-cache@22c9328bcba27aa81a32b1bef27c7e3c78052531 # v2.0.1 + uses: Swatinem/rust-cache@359a70e43a0bb8a13953b04a90f76428b4959bb6 # v2.2.0 - name: Run clippy uses: actions-rs/cargo@v1 From 14e8e6f6b6595e050f64dabb96b96ec93254624d Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Mon, 14 Nov 2022 12:45:21 +0100 Subject: [PATCH 3/3] add wasm support (#700) * get started * make it work again * make it compile again * Use async-wasm-feature of jsonrpsee from the master branch * Ensure we enable JS feature of getrandom for the wasm target * Update subxt/src/lib.rs * update jsonrpsee * fix CI * cargo fmt * fix wasm test * fix grumbles * exclude wasm-tests from workspace To avoid leaking `jsonrpsee-web` feature into the workspace Co-authored-by: Igor Matuszewski --- .github/workflows/rust.yml | 36 +++++++++++++++++++--- Cargo.toml | 5 +++- cli/Cargo.toml | 2 +- codegen/Cargo.toml | 2 +- codegen/src/utils/fetch_metadata.rs | 2 +- subxt/Cargo.toml | 14 +++++---- subxt/src/client/online_client.rs | 34 ++++++++++++++++++--- subxt/src/lib.rs | 7 +++++ subxt/src/rpc/jsonrpsee_impl.rs | 46 ++++++++++------------------- testing/test-runtime/Cargo.toml | 2 +- testing/test-runtime/build.rs | 7 +++-- testing/wasm-tests/Cargo.toml | 11 +++++++ testing/wasm-tests/tests/wasm.rs | 26 ++++++++++++++++ 13 files changed, 144 insertions(+), 50 deletions(-) create mode 100644 testing/wasm-tests/Cargo.toml create mode 100644 testing/wasm-tests/tests/wasm.rs diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index f311d15390..8ea01482b7 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -42,11 +42,14 @@ jobs: - name: Rust Cache uses: Swatinem/rust-cache@359a70e43a0bb8a13953b04a90f76428b4959bb6 # v2.2.0 - - name: Build - uses: actions-rs/cargo@v1.0.3 + - name: Install cargo-hack + uses: baptiste0928/cargo-install@v1 with: - command: check - args: --all-targets --all-features --workspace + crate: cargo-hack + version: 0.5 + + - name: Cargo check + run: cargo hack --exclude-all-features --each-feature check --all-targets --workspace fmt: name: Cargo fmt @@ -165,3 +168,28 @@ jobs: with: command: clippy args: --all-targets -- -D warnings + + wasm_tests: + name: Test wasm + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3.1.0 + + - name: Install + run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh + + - name: Download Substrate + run: | + curl $SUBSTRATE_URL --output substrate --location + chmod +x substrate + mkdir -p ~/.local/bin + mv substrate ~/.local/bin + + - name: Run WASM tests + run: | + substrate --dev --tmp > /dev/null 2>&1 & + wasm-pack test --headless --firefox + wasm-pack test --headless --chrome + pkill substrate + working-directory: testing/wasm-tests diff --git a/Cargo.toml b/Cargo.toml index f69ba5d891..f2d12b9bc3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,5 +9,8 @@ members = [ "testing/ui-tests", "macro", "metadata", - "subxt", + "subxt" ] +exclude = ["testing/wasm-tests"] + +resolver = "2" diff --git a/cli/Cargo.toml b/cli/Cargo.toml index f0409edd14..068f0e4e09 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -36,6 +36,6 @@ scale = { package = "parity-scale-codec", version = "3.0.0", default-features = # generate the item mod for codegen syn = "1.0.80" # communicate with the substrate nodes -jsonrpsee = { version = "0.15.1", features = ["async-client", "client-ws-transport", "http-client"] } +jsonrpsee = { version = "0.16.0", features = ["async-client", "client-ws-transport", "http-client"] } # async runtime tokio = { version = "1.8", features = ["rt-multi-thread", "macros", "time"] } diff --git a/codegen/Cargo.toml b/codegen/Cargo.toml index 1996ce36da..79b247585f 100644 --- a/codegen/Cargo.toml +++ b/codegen/Cargo.toml @@ -21,7 +21,7 @@ quote = "1.0.8" syn = "1.0.58" scale-info = { version = "2.0.0", features = ["bit-vec"] } subxt-metadata = { version = "0.24.0", path = "../metadata" } -jsonrpsee = { version = "0.15.1", features = ["async-client", "client-ws-transport", "http-client"] } +jsonrpsee = { version = "0.16.0", features = ["async-client", "client-ws-transport", "http-client"] } hex = "0.4.3" tokio = { version = "1.8", features = ["macros", "rt-multi-thread"] } diff --git a/codegen/src/utils/fetch_metadata.rs b/codegen/src/utils/fetch_metadata.rs index d205b3bc5f..9c63f495c0 100644 --- a/codegen/src/utils/fetch_metadata.rs +++ b/codegen/src/utils/fetch_metadata.rs @@ -71,7 +71,7 @@ async fn fetch_metadata_http(url: &Uri) -> Result { .request_timeout(Duration::from_secs(180)) .build(url.to_string())?; - Ok(client.request::("state_getMetadata", None).await?) + Ok(client.request("state_getMetadata", rpc_params![]).await?) } #[derive(Debug)] diff --git a/subxt/Cargo.toml b/subxt/Cargo.toml index 67dc9eaae1..1202e41b35 100644 --- a/subxt/Cargo.toml +++ b/subxt/Cargo.toml @@ -13,7 +13,7 @@ description = "Submit extrinsics (transactions) to a substrate node via RPC" keywords = ["parity", "substrate", "blockchain"] [features] -default = ["jsonrpsee"] +default = ["jsonrpsee-ws"] # Activate this to expose functionality only used for integration testing. # The exposed functionality is subject to breaking changes at any point, @@ -22,7 +22,8 @@ integration-tests = [] # Jsonrpsee if the default RPC provider used in Subxt. However, it can be # swapped out for an alternative implementation, and so is optional. -jsonrpsee = ["dep:jsonrpsee"] +jsonrpsee-ws = ["jsonrpsee/async-client", "jsonrpsee/client-ws-transport"] +jsonrpsee-web = ["jsonrpsee/async-wasm-client", "jsonrpsee/client-web-transport"] [dependencies] bitvec = { version = "1.0.0", default-features = false, features = ["alloc"] } @@ -30,11 +31,11 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = scale-info = { version = "2.0.0", features = ["bit-vec"] } scale-value = "0.6.0" scale-decode = "0.4.0" -futures = "0.3.13" +futures = { version = "0.3.13", default-features = false } hex = "0.4.3" -jsonrpsee = { version = "0.15.1", features = ["async-client", "client-ws-transport", "jsonrpsee-types"], optional = true } +jsonrpsee = { version = "0.16", optional = true, features = ["jsonrpsee-types"] } serde = { version = "1.0.124", features = ["derive"] } -serde_json = "1.0.64" +serde_json = { version = "1.0.64", features = ["raw_value"] } thiserror = "1.0.24" tracing = "0.1.34" parking_lot = "0.12.0" @@ -48,5 +49,8 @@ sp-runtime = "6.0.0" frame-metadata = "15.0.0" derivative = "2.2.0" +[target.wasm32-unknown-unknown.dependencies] +getrandom = { version = "0.2", features = ["js"] } + [dev-dependencies] tokio = { version = "1.8", features = ["macros", "time", "rt-multi-thread"] } diff --git a/subxt/src/client/online_client.rs b/subxt/src/client/online_client.rs index b70d103db1..fc85fad5fd 100644 --- a/subxt/src/client/online_client.rs +++ b/subxt/src/client/online_client.rs @@ -61,7 +61,10 @@ impl std::fmt::Debug for OnlineClient { } // The default constructors assume Jsonrpsee. -#[cfg(feature = "jsonrpsee")] +#[cfg(any( + feature = "jsonrpsee-ws", + all(feature = "jsonrpsee-web", target_arch = "wasm32") +))] impl OnlineClient { /// Construct a new [`OnlineClient`] using default settings which /// point to a locally running node on `ws://127.0.0.1:9944`. @@ -72,7 +75,7 @@ impl OnlineClient { /// Construct a new [`OnlineClient`], providing a URL to connect to. pub async fn from_url(url: impl AsRef) -> Result, Error> { - let client = jsonrpsee_helpers::ws_client(url.as_ref()) + let client = jsonrpsee_helpers::client(url.as_ref()) .await .map_err(|e| crate::error::RpcError::ClientError(Box::new(e)))?; OnlineClient::from_rpc_client(Arc::new(client)).await @@ -346,7 +349,7 @@ impl Update { } // helpers for a jsonrpsee specific OnlineClient. -#[cfg(feature = "jsonrpsee")] +#[cfg(feature = "jsonrpsee-ws")] mod jsonrpsee_helpers { pub use jsonrpsee::{ client_transport::ws::{ @@ -366,7 +369,7 @@ mod jsonrpsee_helpers { }; /// Build WS RPC client from URL - pub async fn ws_client(url: &str) -> Result { + pub async fn client(url: &str) -> Result { let (sender, receiver) = ws_transport(url).await?; Ok(ClientBuilder::default() .max_notifs_per_subscription(4096) @@ -383,3 +386,26 @@ mod jsonrpsee_helpers { .map_err(|e| Error::Transport(e.into())) } } + +// helpers for a jsonrpsee specific OnlineClient. +#[cfg(all(feature = "jsonrpsee-web", target_arch = "wasm32"))] +mod jsonrpsee_helpers { + pub use jsonrpsee::{ + client_transport::web, + core::{ + client::{ + Client, + ClientBuilder, + }, + Error, + }, + }; + + /// Build web RPC client from URL + pub async fn client(url: &str) -> Result { + let (sender, receiver) = web::connect(url).await.unwrap(); + Ok(ClientBuilder::default() + .max_notifs_per_subscription(4096) + .build_with_wasm(sender, receiver)) + } +} diff --git a/subxt/src/lib.rs b/subxt/src/lib.rs index 86a4db7496..18e705015a 100644 --- a/subxt/src/lib.rs +++ b/subxt/src/lib.rs @@ -140,6 +140,13 @@ use tokio as _; pub use subxt_macro::subxt; +// Used to enable the js feature for wasm. +#[cfg(target_arch = "wasm32")] +pub use getrandom as _; + +#[cfg(all(feature = "jsonrpsee-ws", feature = "jsonrpsee-web"))] +std::compile_error!("Both the features `jsonrpsee-ws` and `jsonrpsee-web` are enabled which are mutually exclusive"); + pub mod blocks; pub mod client; pub mod config; diff --git a/subxt/src/rpc/jsonrpsee_impl.rs b/subxt/src/rpc/jsonrpsee_impl.rs index 52b9a3e61e..09dbfe663b 100644 --- a/subxt/src/rpc/jsonrpsee_impl.rs +++ b/subxt/src/rpc/jsonrpsee_impl.rs @@ -12,18 +12,24 @@ use futures::stream::{ StreamExt, TryStreamExt, }; -use jsonrpsee::{ - core::client::{ +use jsonrpsee::core::{ + client::{ Client, ClientT, SubscriptionClientT, }, - types::ParamsSer, -}; -use serde_json::value::{ - RawValue, - Value, + traits::ToRpcParams, + Error as JsonRpseeError, }; +use serde_json::value::RawValue; + +struct Params(Option>); + +impl ToRpcParams for Params { + fn to_rpc_params(self) -> Result>, JsonRpseeError> { + Ok(self.0) + } +} impl RpcClientT for Client { fn request_raw<'a>( @@ -32,8 +38,7 @@ impl RpcClientT for Client { params: Option>, ) -> RpcFuture<'a, Box> { Box::pin(async move { - let params = prep_params_for_jsonrpsee(params); - let res = ClientT::request(self, method, Some(params)) + let res = ClientT::request(self, method, Params(params)) .await .map_err(|e| RpcError::ClientError(Box::new(e)))?; Ok(res) @@ -47,11 +52,10 @@ impl RpcClientT for Client { unsub: &'a str, ) -> RpcFuture<'a, RpcSubscription> { Box::pin(async move { - let params = prep_params_for_jsonrpsee(params); - let sub = SubscriptionClientT::subscribe::>( + let sub = SubscriptionClientT::subscribe::, _>( self, sub, - Some(params), + Params(params), unsub, ) .await @@ -62,21 +66,3 @@ impl RpcClientT for Client { }) } } - -// This is ugly; we have to encode to Value's to be compat with the jsonrpc interface. -// Remove and simplify this once something like https://github.com/paritytech/jsonrpsee/issues/862 is in: -fn prep_params_for_jsonrpsee(params: Option>) -> ParamsSer<'static> { - let params = match params { - Some(params) => params, - // No params? avoid any work and bail early. - None => return ParamsSer::Array(Vec::new()), - }; - let val = serde_json::to_value(¶ms).expect("RawValue guarantees valid JSON"); - let arr = match val { - Value::Array(arr) => arr, - _ => { - panic!("RPC Params are expected to be an array but got {params}"); - } - }; - ParamsSer::Array(arr) -} diff --git a/testing/test-runtime/Cargo.toml b/testing/test-runtime/Cargo.toml index ba7314e55c..51956f2452 100644 --- a/testing/test-runtime/Cargo.toml +++ b/testing/test-runtime/Cargo.toml @@ -13,4 +13,4 @@ subxt = { path = "../../subxt" } sp-core = "6.0.0" tokio = { version = "1.8", features = ["macros", "rt-multi-thread"] } which = "4.2.2" -jsonrpsee = { version = "0.15.1", features = ["async-client", "client-ws-transport"] } +jsonrpsee = { version = "0.16.0", features = ["async-client", "client-ws-transport"] } diff --git a/testing/test-runtime/build.rs b/testing/test-runtime/build.rs index 607433fa59..783d602753 100644 --- a/testing/test-runtime/build.rs +++ b/testing/test-runtime/build.rs @@ -60,7 +60,7 @@ async fn run() { // Thus, the connection might get rejected a few times. use client::ClientT; let res = match client::build(&format!("ws://localhost:{}", port)).await { - Ok(c) => c.request("state_getMetadata", None).await, + Ok(c) => c.request("state_getMetadata", client::rpc_params![]).await, Err(e) => Err(e), }; @@ -174,7 +174,10 @@ mod client { }, }; - pub use jsonrpsee::core::client::ClientT; + pub use jsonrpsee::core::{ + client::ClientT, + rpc_params, + }; /// Build WS RPC client from URL pub async fn build(url: &str) -> Result { diff --git a/testing/wasm-tests/Cargo.toml b/testing/wasm-tests/Cargo.toml new file mode 100644 index 0000000000..d539bebb87 --- /dev/null +++ b/testing/wasm-tests/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "wasm-test" +version = "0.1.0" +edition = "2021" + +[dev-dependencies] +wasm-bindgen-test = "0.3.24" +tracing-wasm = "0.2.1" +console_error_panic_hook = "0.1.7" +serde_json = "1.0.57" +subxt = { path = "../../subxt", default-features = false, features = ["jsonrpsee-web"] } diff --git a/testing/wasm-tests/tests/wasm.rs b/testing/wasm-tests/tests/wasm.rs new file mode 100644 index 0000000000..310d6da311 --- /dev/null +++ b/testing/wasm-tests/tests/wasm.rs @@ -0,0 +1,26 @@ +#![cfg(target_arch = "wasm32")] + +use subxt::config::PolkadotConfig; +use wasm_bindgen_test::*; + +wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); + +/// Run the tests by `$ wasm-pack test --firefox --headless` + +fn init_tracing() { + console_error_panic_hook::set_once(); + tracing_wasm::set_as_global_default(); +} + +#[wasm_bindgen_test] +async fn wasm_ws_transport_works() { + init_tracing(); + + let client = + subxt::client::OnlineClient::::from_url("ws://127.0.0.1:9944") + .await + .unwrap(); + + let chain = client.rpc().system_chain().await.unwrap(); + assert_eq!(&chain, "Development"); +}