Skip to content

Commit

Permalink
Remove sync api jsonrpsee (#699)
Browse files Browse the repository at this point in the history
* it's compiling

fix tests

update ci

cargo fmt

fix compile error

fix clippy

remove compile error and ensure jsonrpsee is only exported when not sync api

clean up dependencies

move keystore_tests.rs to sync examples

update .lock

remove unneeded deps

clean up sync example toml

clean up async example toml

remove sync part from async exmaple

speed up example

add box around dynamic error values

readd spacing

use async code smart

speed up example

make author_test actually async

add sleep

add some sleeps to avoid future error

remove obsolete async naming

update README

update README

update CI

* simplify author_test
  • Loading branch information
haerdib authored Feb 5, 2024
1 parent 724f7c3 commit 3098812
Show file tree
Hide file tree
Showing 45 changed files with 639 additions and 642 deletions.
16 changes: 8 additions & 8 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,19 +54,19 @@ jobs:
# Test for 32 bit and wasm32-unknown-unknown compatibility
cargo build --target wasm32-unknown-unknown --no-default-features --features sync-api,

# Test for async compilation
cargo build --no-default-features --features "std jsonrpsee-client",
# Compile async examples separately to enable async-mode
cargo build --release -p ac-examples --example get_blocks_async --no-default-features,
cargo build --release -p ac-examples --example runtime_update_async --no-default-features,
# Compile examples and integration test separately to ensure features are not cross-imported
cargo test --release -p ac-examples-async,
cargo test --release -p ac-examples-sync,
cargo test --release -p ac-testing-async,
cargo test --release -p ac-testing-sync,

# Clippy
cargo clippy -- -D warnings,
cargo clippy --no-default-features -- -D warnings,
cargo clippy --all-features --examples -- -D warnings,

# Run tests and build examples
cargo test --release --workspace --all-features --exclude test-no-std,
# Run unit tests
cargo test --release,

# Fmt
cargo fmt --all -- --check
Expand Down Expand Up @@ -148,7 +148,7 @@ jobs:
custom_nonce,
check_extrinsic_events,
get_account_identity,
get_blocks_async,
get_blocks,
get_storage,
print_metadata,
staking_batch_payout,
Expand Down
39 changes: 27 additions & 12 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 8 additions & 6 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@ members = [
".",
"client-keystore",
"compose-macros",
"examples",
"examples/async",
"examples/sync",
"node-api",
"test-no-std",
"testing",
"testing/async",
"testing/sync",
]

[dependencies]
Expand All @@ -40,7 +42,6 @@ serde_json = { version = "1.0.79", default-features = false }
url = { version = "2.0.0", optional = true }

# websocket dependent features
futures = { version = "0.3", optional = true }
jsonrpsee = { version = "0.16", optional = true, features = ["async-client", "client-ws-transport", "jsonrpsee-types"] }
tungstenite = { version = "0.21", optional = true, features = ["native-tls"] }
ws = { version = "0.9.2", optional = true, features = ["ssl"] }
Expand All @@ -66,9 +67,10 @@ ac-node-api = { path = "node-api", features = ["mocks"] }
kitchensink-runtime = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "master" }
scale-info = { version = "2.1.1", features = ["derive"] }
test-case = "3.1.0"
futures = "0.3.28"

[features]
default = ["std", "jsonrpsee-client", "sync-api"]
default = ["std", "jsonrpsee-client"]
# To support `no_std` builds in non-32 bit environments.
disable_target_static_assertions = [
"sp-runtime-interface/disable_target_static_assertions",
Expand All @@ -77,10 +79,10 @@ disable_target_static_assertions = [
# If this is active all the code compiles in synchronous mode. If not selected, code will compile to async mode.
sync-api = ["ac-compose-macros/sync-api", "maybe-async/is_sync"]

# Use the `jsonrpsee` crate for websocket communication. Does provide sync and async support but needs a tokio runtime.
# Use the `jsonrpsee` crate for websocket communication. Does only provide async support and needs a tokio runtime.
# Provides convenience functions such as subscription callbacks.
# Most examples use the `jsonrpsee` feature and can be used for reference.
jsonrpsee-client = ["std", "jsonrpsee", "futures"]
jsonrpsee-client = ["std", "jsonrpsee"]

# Use the `tungstenite` crate for websocket communication. No async support but has some reconnection capabilities.
# See the example `transfer_with_tungstenite_client` on how to use it.
Expand Down
59 changes: 32 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ The substrate-api-client connects to the substrate's RPC interface via WebSocket
* Support `no_std` builds. Only the rpc-client is std only. For `no_std` builds, a custom rpc client needs to be implemented.
* Watch events and execute code upon events.
* Parse and print the node metadata.
* Support async and sync implementations.
* Support three different websocket crates (`jsonrpsee`, `tungstenite` and `ws`). See `Cargo.toml` for more information and limitations.

## Prerequisites
Expand All @@ -30,14 +31,18 @@ docker run -p 9944:9944 -p 9933:9933 -p 30333:30333 parity/substrate:latest --de
For more information, please refer to the [substrate](https://github.com/paritytech/substrate) repository.

## Examples

The api-client provides several examples which show how to fetch node states or submit extrinsic. Examples are differentiated between `sync` and `async` implementations. Don't forget to check the feature import of the associated `Cargo.toml`. It shows how to import the api-client as an `async` or `sync` library.
To run an example, clone the `substrate-api-client` repository and run the desired example directly with the cargo command:

```bash
git clone https://github.com/scs/substrate-api-client.git
cd substrate-api-client
cargo run -p ac-examples --example get_storage
# Run an async example:
cargo run -p ac-examples-async --example get_storage
# Run a sync example:
cargo run -p ac-examples-sync --example runtime_update_sync
```

or download the already built binaries from [GitHub Actions](https://github.com/scs/substrate-api-client/actions) and run them without any previous building:

```bash
Expand All @@ -50,24 +55,26 @@ chmod +x <example>

Set the output verbosity by prepending `RUST_LOG=info` or `RUST_LOG=debug`.

The following examples can be found in the [examples](/examples/examples) folder:

* [benchmark_bulk_xt](/examples/examples/benchmark_bulk_xt.rs): Float the node with a series of transactions.
* [check_extrinsic_events](/examples/examples/check_extrinsic_events.rs): Check and react according to events associated to an extrinsic.
* [compose_extrinsic](/examples/examples/compose_extrinsic.rs): Compose an extrinsic without interacting with the node or in no_std mode.
* [contract_instantiate_with_code](/examples/examples/contract_instantiate_with_code.rs): Instantiate a contract on the chain.
* [custom_nonce](/examples/examples/custom_nonce.rs): Compose an with a custom nonce.
* [get_account_identity](/examples/examples/get_account_identity.rs): Create an custom Unchecked Extrinsic to set an account identity and retrieve it afterwards with a getter.
* [get_block_async](/examples/examples/get_block_async.rs): Read header, block and signed block from storage.
* [get_storage](/examples/examples/get_storage.rs): Read storage values.
* [print_metadata](/examples/examples/print_metadata.rs): Print the metadata of the node in a readable way.
* [runtime_update_async](/src/examples/examples/runtime_update_async.rs): How to do an runtime upgrade asynchronously.
* [runtime_update_sync](/src/examples/examples/runtime_update_sync.rs): How to do an runtime upgrade synchronously.
* [staking_batch_payout](/src/examples/examples/staking_batch_payout.rs): Batch reward payout for validator.
* [subscribe_events](/examples/examples/subscribe_events.rs): Subscribe and react on events.
* [sudo](/examples/examples/sudo.rs): Create and send a sudo wrapped call.
* [transfer_with_tungstenite_client](/examples/examples/transfer_with_tungstenite_client.rs): Transfer tokens by using a wrapper of compose_extrinsic with an account generated with a seed.
* [transfer_with_ws_client](/examples/examples/transfer_with_ws_client.rs): Transfer tokens by using a wrapper of compose_extrinsic with an account generated with a seed.
The following async examples can be found in the [async examples](/examples/async/examples) folder:
* [benchmark_bulk_xt](/examples/async/examples/benchmark_bulk_xt.rs): Float the node with a series of transactions.
* [check_extrinsic_events](/examples/async/examples/check_extrinsic_events.rs): Check and react according to events associated to an extrinsic.
* [compose_extrinsic](/examples/async/examples/compose_extrinsic.rs): Compose an extrinsic without interacting with the node or in no_std mode.
* [contract_instantiate_with_code](/examples/async/examples/contract_instantiate_with_code.rs): Instantiate a contract on the chain.
* [custom_nonce](/examples/async/examples/custom_nonce.rs): Compose an with a custom nonce.
* [get_account_identity](/examples/async/examples/get_account_identity.rs): Create an custom Unchecked Extrinsic to set an account identity and retrieve it afterwards with a getter.
* [get_blocks](/examples/async/examples/get_blocks.rs): Read header, block and signed block from storage.
* [get_storage](/examples/async/examples/get_storage.rs): Read storage values.
* [print_metadata](/examples/async/examples/print_metadata.rs): Print the metadata of the node in a readable way.
* [runtime_update_async](/examples/async/examples/runtime_update_async.rs): How to do an runtime upgrade asynchronously.
* [staking_batch_payout](/examples/async/examples/staking_batch_payout.rs): Batch reward payout for validator.
* [subscribe_events](/examples/async/examples/subscribe_events.rs): Subscribe and react on events.
* [sudo](/examples/async/examples/sudo.rs): Create and send a sudo wrapped call.

The following sync examples can be found in the [sync examples](/examples/sync/examples) folder:
* [runtime_update_sync](/examples/sync/examples/runtime_update_sync.rs): How to do an runtime upgrade synchronously.
* [transfer_with_tungstenite_client](/examples/sync/examples/transfer_with_tungstenite_client.rs): Transfer tokens by using a wrapper of compose_extrinsic with an account generated with a seed.
* [transfer_with_ws_client](/examples/sync/examples/transfer_with_ws_client.rs): Transfer tokens by using a wrapper of compose_extrinsic with an account generated with a seed.


## `no_std` build
Almost everything in the api-client, except for the [rpc-clients](https://github.com/scs/substrate-api-client/tree/master/src/rpc) and a few additional features, is `no_std` compatible.
Expand All @@ -78,19 +85,17 @@ To import the api-client in `no_std` make sure the default features are turned o
```toml
# In the Cargo.toml import the api-client as following:
substrate-api-client = { git = "https://github.com/scs/substrate-api-client.git", default-features = false, features = ["disable_target_static_assertions"] }

```
### RPC Client
Depending on the usage, there are two traits that the RPC Client needs to implement.
Depending on the usage, there are two traits that the RPC Client needs to implement. You can choose between the sync and async implementation. If you decide to use the async implementation, you need to use the library `async-trait` for now (until it is integrated into the rust toolchain).

#### Request

For simple requests (send one request and receive one answer) the trait [`Request`](https://github.com/scs/substrate-api-client/blob/d0a875e70f688c8ae2ce641935189c6374bc0ced/src/rpc/mod.rs#L44-L48) is required:
```rust
/// Trait to be implemented by the ws-client for sending rpc requests and extrinsic.
pub trait Request {
/// Sends a RPC request to the substrate node and returns the answer as string.
fn request<R: DeserializeOwned>(&self, method: &str, params: RpcParams) -> Result<R>;
(async) fn request<R: DeserializeOwned>(&self, method: &str, params: RpcParams) -> Result<R>;
}
```
By implementing this trait with a custom RPC client, most basic functionalities of the `Api` can already be used.
Expand All @@ -107,7 +112,7 @@ pub trait Subscribe {
where
Notification: DeserializeOwned;

fn subscribe<Notification: DeserializeOwned>(
(async) fn subscribe<Notification: DeserializeOwned>(
&self,
sub: &str,
params: RpcParams,
Expand All @@ -123,10 +128,10 @@ pub trait HandleSubscription<Notification: DeserializeOwned> {
/// Returns the next notification from the stream.
/// This may return `None` if the subscription has been terminated,
/// which may happen if the channel becomes full or is dropped.
fn next(&mut self) -> Option<Result<Notification>>;
(async) fn next(&mut self) -> Option<Result<Notification>>;

/// Unsubscribe and consume the subscription.
fn unsubscribe(self) -> Result<()>;
(async) fn unsubscribe(self) -> Result<()>;
}
```
Refering to the `std` example of the tungstenite, the `HandleSubscription` impl can be looked up [here](https://github.com/scs/substrate-api-client/blob/d0a875e70f688c8ae2ce641935189c6374bc0ced/src/rpc/tungstenite_client/subscription.rs#L23-L54). It implements a simple channel receiver, waiting for the sender of the websocket client to send something.
Expand Down
42 changes: 0 additions & 42 deletions examples/Cargo.toml

This file was deleted.

37 changes: 12 additions & 25 deletions testing/Cargo.toml → examples/async/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,42 +1,29 @@
[package]
name = "ac-testing"
version = "0.3.2"
authors = ["Supercomputing Systems AG <info@scs.ch>"]
name = "ac-examples-async"
version = "0.4.2"
license = "Apache-2.0"
edition = "2021"

[dev-dependencies]
codec = { package = "parity-scale-codec", version = "3.6.1", features = [
'derive',
] }
serde_json = { version = "1.0.79" }
codec = { package = "parity-scale-codec", version = "3.6.1", features = ['derive'] }
env_logger = "0.10.0"
log = "0.4.14"
serde_json = "1.0.79"
tokio = { version = "1.24", features = ["rt-multi-thread", "macros", "time"] }
tokio-util = "0.7.8"
wabt = "0.10.0"

# Substrate dependencies
frame-support = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "master" }
frame-system = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "master" }
kitchensink-runtime = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "master" }
sp-application-crypto = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "master" }
sp-core = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "master" }
sp-keyring = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "master" }
sp-runtime = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "master" }
sp-staking = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "master" }
sp-version = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "master" }
pallet-balances = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "master" }
pallet-identity = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "master" }
pallet-staking = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "master" }
sp-core = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "master" }
sp-keyring = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "master" }
sp-runtime = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "master" }
sp-weights = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "master" }

# local deps
substrate-api-client = { path = "..", features = [
"tungstenite-client",
"ws-client",
"staking-xt",
"contracts-xt",
] }
substrate-client-keystore = { path = "../client-keystore" }


[features]
default = ["ws-client"]
ws-client = []
substrate-api-client = { path = "../..", features = ["staking-xt", "contracts-xt"] }
Loading

0 comments on commit 3098812

Please sign in to comment.