mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-14 05:11:09 +00:00
rpc: stabilize chainhead backend (#1802)
* rpc: stabilize ChainHeadBackend * remove noise from example * add missing features * make tests compile * make tests compile v2 * revert stop event * feature-gate runtime * Update subxt/Cargo.toml * add docsrs feature stuff * Update subxt/src/backend/chain_head/mod.rs * Update subxt/src/backend/chain_head/mod.rs * Update subxt/src/backend/chain_head/mod.rs
This commit is contained in:
@@ -301,7 +301,7 @@ jobs:
|
||||
uses: "andymckay/cancel-action@a955d435292c0d409d104b57d8e78435a93a6ef1" # v0.5
|
||||
|
||||
unstable_backend_tests:
|
||||
name: "Test (Unstable Backend)"
|
||||
name: "Test chainhead backend"
|
||||
runs-on: ubuntu-latest-16-cores
|
||||
needs: [clippy, wasm_clippy, check, wasm_check, docs]
|
||||
timeout-minutes: 30
|
||||
@@ -329,7 +329,7 @@ jobs:
|
||||
uses: actions-rs/cargo@v1.0.3
|
||||
with:
|
||||
command: nextest
|
||||
args: run --workspace --features unstable-backend-client
|
||||
args: run --workspace --features chainhead-backend
|
||||
|
||||
- if: "failure()"
|
||||
uses: "andymckay/cancel-action@a955d435292c0d409d104b57d8e78435a93a6ef1" # v0.5
|
||||
|
||||
+10
-1
@@ -47,12 +47,21 @@ web = [
|
||||
"finito?/wasm-bindgen",
|
||||
]
|
||||
|
||||
# Feature flag to enable the default future executor.
|
||||
# Technically it's a hack enable to both but simplifies the conditional compilation
|
||||
# and subxt is selecting executor based on the used platform.
|
||||
#
|
||||
# For instance `wasm-bindgen-futures` panics if the platform isn't wasm32 and
|
||||
# similar for tokio that requires a tokio runtime to be initialized.
|
||||
runtime = ["tokio/rt", "wasm-bindgen-futures"]
|
||||
|
||||
# Enable this to use the reconnecting rpc client
|
||||
unstable-reconnecting-rpc-client = ["dep:finito", "dep:tokio", "jsonrpsee", "wasm-bindgen-futures"]
|
||||
unstable-reconnecting-rpc-client = ["dep:finito", "jsonrpsee"]
|
||||
|
||||
# Enable this to use jsonrpsee (allowing for example `OnlineClient::from_url`).
|
||||
jsonrpsee = [
|
||||
"dep:jsonrpsee",
|
||||
"runtime",
|
||||
]
|
||||
|
||||
# Enable this to pull in extra Substrate dependencies which make it possible to
|
||||
|
||||
@@ -34,20 +34,13 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
.build("ws://localhost:9944".to_string())
|
||||
.await?;
|
||||
|
||||
// If you want to use the unstable backend with the reconnecting RPC client, you can do so like this:
|
||||
// If you want to use the chainhead backend with the reconnecting RPC client, you can do so like this:
|
||||
//
|
||||
// ```
|
||||
// use subxt::backend::unstable::UnstableBackend;
|
||||
// use subxt::backend::chain_head:ChainHeadBackend;
|
||||
// use subxt::OnlineClient;
|
||||
//
|
||||
// let (backend, mut driver) = UnstableBackend::builder().build(RpcClient::new(rpc.clone()));
|
||||
// tokio::spawn(async move {
|
||||
// while let Some(val) = driver.next().await {
|
||||
// if let Err(e) = val {
|
||||
// eprintln!("Error driving unstable backend: {e}; terminating client");
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
// let backend = ChainHeadBackend::builder().build_with_background_task(RpcClient::new(rpc.clone()));
|
||||
// let api: OnlineClient<PolkadotConfig> = OnlineClient::from_backend(Arc::new(backend)).await?;
|
||||
// ```
|
||||
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
//! Example to utilize the ChainHeadBackend rpc backend to subscribe to finalized blocks.
|
||||
|
||||
#![allow(missing_docs)]
|
||||
|
||||
use futures::StreamExt;
|
||||
use subxt::backend::chain_head::{ChainHeadBackend, ChainHeadBackendBuilder};
|
||||
use subxt::backend::rpc::RpcClient;
|
||||
use subxt::{OnlineClient, PolkadotConfig};
|
||||
|
||||
// Generate an interface that we can use from the node's metadata.
|
||||
#[subxt::subxt(runtime_metadata_path = "../artifacts/polkadot_metadata_small.scale")]
|
||||
pub mod polkadot {}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
tracing_subscriber::fmt::init();
|
||||
|
||||
let rpc = RpcClient::from_url("ws://localhost:9944".to_string()).await?;
|
||||
let backend: ChainHeadBackend<PolkadotConfig> =
|
||||
ChainHeadBackendBuilder::default().build_with_background_driver(rpc.clone());
|
||||
let api = OnlineClient::from_backend(std::sync::Arc::new(backend)).await?;
|
||||
|
||||
let mut blocks_sub = api.blocks().subscribe_finalized().await?.take(100);
|
||||
|
||||
while let Some(block) = blocks_sub.next().await {
|
||||
let block = block?;
|
||||
|
||||
let block_number = block.number();
|
||||
let block_hash = block.hash();
|
||||
|
||||
println!("Block #{block_number} ({block_hash})");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
+3
-3
@@ -2,7 +2,7 @@
|
||||
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
||||
// see LICENSE for license details.
|
||||
|
||||
use super::rpc_methods::{FollowEvent, UnstableRpcMethods};
|
||||
use super::rpc_methods::{ChainHeadRpcMethods, FollowEvent};
|
||||
use crate::config::Config;
|
||||
use crate::error::Error;
|
||||
use futures::{FutureExt, Stream, StreamExt};
|
||||
@@ -99,7 +99,7 @@ impl<Hash> FollowStream<Hash> {
|
||||
}
|
||||
|
||||
/// Create a new [`FollowStream`] given the RPC methods.
|
||||
pub fn from_methods<T: Config>(methods: UnstableRpcMethods<T>) -> FollowStream<T::Hash> {
|
||||
pub fn from_methods<T: Config>(methods: ChainHeadRpcMethods<T>) -> FollowStream<T::Hash> {
|
||||
FollowStream {
|
||||
stream_getter: Box::new(move || {
|
||||
let methods = methods.clone();
|
||||
@@ -215,7 +215,7 @@ impl<Hash> Stream for FollowStream<Hash> {
|
||||
#[cfg(test)]
|
||||
pub(super) mod test_utils {
|
||||
use super::*;
|
||||
use crate::backend::unstable::rpc_methods::{
|
||||
use crate::backend::chain_head::rpc_methods::{
|
||||
BestBlockChanged, Finalized, Initialized, NewBlock,
|
||||
};
|
||||
use crate::config::substrate::H256;
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
// see LICENSE for license details.
|
||||
|
||||
use super::follow_stream_unpin::{BlockRef, FollowStreamMsg, FollowStreamUnpin};
|
||||
use crate::backend::unstable::rpc_methods::{FollowEvent, Initialized, RuntimeEvent};
|
||||
use crate::backend::chain_head::rpc_methods::{FollowEvent, Initialized, RuntimeEvent};
|
||||
use crate::config::BlockHash;
|
||||
use crate::error::{Error, RpcError};
|
||||
use futures::stream::{Stream, StreamExt};
|
||||
+3
-3
@@ -3,8 +3,8 @@
|
||||
// see LICENSE for license details.
|
||||
|
||||
use super::follow_stream::FollowStream;
|
||||
use super::UnstableRpcMethods;
|
||||
use crate::backend::unstable::rpc_methods::{
|
||||
use super::ChainHeadRpcMethods;
|
||||
use crate::backend::chain_head::rpc_methods::{
|
||||
BestBlockChanged, Finalized, FollowEvent, Initialized, NewBlock,
|
||||
};
|
||||
use crate::config::{BlockHash, Config};
|
||||
@@ -275,7 +275,7 @@ impl<Hash: BlockHash> FollowStreamUnpin<Hash> {
|
||||
/// Create a new [`FollowStreamUnpin`] given the RPC methods.
|
||||
pub fn from_methods<T: Config>(
|
||||
follow_stream: FollowStream<T::Hash>,
|
||||
methods: UnstableRpcMethods<T>,
|
||||
methods: ChainHeadRpcMethods<T>,
|
||||
max_block_life: usize,
|
||||
) -> FollowStreamUnpin<T::Hash> {
|
||||
let unpin_method = Box::new(move |hash: T::Hash, sub_id: Arc<str>| {
|
||||
@@ -38,22 +38,22 @@ use std::task::Poll;
|
||||
use storage_items::StorageItems;
|
||||
|
||||
// Expose the RPC methods.
|
||||
pub use rpc_methods::UnstableRpcMethods;
|
||||
pub use rpc_methods::ChainHeadRpcMethods;
|
||||
|
||||
/// Configure and build an [`UnstableBackend`].
|
||||
pub struct UnstableBackendBuilder<T> {
|
||||
/// Configure and build an [`ChainHeadBackend`].
|
||||
pub struct ChainHeadBackendBuilder<T> {
|
||||
max_block_life: usize,
|
||||
_marker: std::marker::PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T: Config> Default for UnstableBackendBuilder<T> {
|
||||
impl<T: Config> Default for ChainHeadBackendBuilder<T> {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Config> UnstableBackendBuilder<T> {
|
||||
/// Create a new [`UnstableBackendBuilder`].
|
||||
impl<T: Config> ChainHeadBackendBuilder<T> {
|
||||
/// Create a new [`ChainHeadBackendBuilder`].
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
max_block_life: usize::MAX,
|
||||
@@ -73,15 +73,20 @@ impl<T: Config> UnstableBackendBuilder<T> {
|
||||
self
|
||||
}
|
||||
|
||||
/// Given an [`RpcClient`] to use to make requests, this returns a tuple of an [`UnstableBackend`],
|
||||
/// which implements the [`Backend`] trait, and an [`UnstableBackendDriver`] which must be polled in
|
||||
/// order for the backend to make progress.
|
||||
/// A low-level API to build the backend and driver which requires polling the driver for the backend
|
||||
/// to make progress.
|
||||
///
|
||||
/// This is useful if you want to manage the driver yourself, for example if you want to run it in on
|
||||
/// a specific runtime.
|
||||
///
|
||||
/// If you just want to run the driver in the background until completion in on the default runtime,
|
||||
/// use [`ChainHeadBackendBuilder::build_with_background_driver`] instead.
|
||||
pub fn build(
|
||||
self,
|
||||
client: impl Into<RpcClient>,
|
||||
) -> (UnstableBackend<T>, UnstableBackendDriver<T>) {
|
||||
) -> (ChainHeadBackend<T>, ChainHeadBackendDriver<T>) {
|
||||
// Construct the underlying follow_stream layers:
|
||||
let rpc_methods = UnstableRpcMethods::new(client.into());
|
||||
let rpc_methods = ChainHeadRpcMethods::new(client.into());
|
||||
let follow_stream =
|
||||
follow_stream::FollowStream::<T::Hash>::from_methods(rpc_methods.clone());
|
||||
let follow_stream_unpin = follow_stream_unpin::FollowStreamUnpin::<T::Hash>::from_methods(
|
||||
@@ -92,26 +97,61 @@ impl<T: Config> UnstableBackendBuilder<T> {
|
||||
let follow_stream_driver = FollowStreamDriver::new(follow_stream_unpin);
|
||||
|
||||
// Wrap these into the backend and driver that we'll expose.
|
||||
let backend = UnstableBackend {
|
||||
let backend = ChainHeadBackend {
|
||||
methods: rpc_methods,
|
||||
follow_handle: follow_stream_driver.handle(),
|
||||
};
|
||||
let driver = UnstableBackendDriver {
|
||||
let driver = ChainHeadBackendDriver {
|
||||
driver: follow_stream_driver,
|
||||
};
|
||||
|
||||
(backend, driver)
|
||||
}
|
||||
|
||||
/// An API to build the backend and driver which will run in the background until completion
|
||||
/// on the default runtime.
|
||||
///
|
||||
/// - On non-wasm targets, this will spawn the driver on `tokio`.
|
||||
/// - On wasm targets, this will spawn the driver on `wasm-bindgen-futures`.
|
||||
#[cfg(feature = "runtime")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "runtime")))]
|
||||
pub fn build_with_background_driver(self, client: impl Into<RpcClient>) -> ChainHeadBackend<T> {
|
||||
fn spawn<F: std::future::Future + Send + 'static>(future: F) {
|
||||
#[cfg(not(target_family = "wasm"))]
|
||||
tokio::spawn(async move {
|
||||
future.await;
|
||||
});
|
||||
#[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
|
||||
wasm_bindgen_futures::spawn_local(async move {
|
||||
future.await;
|
||||
});
|
||||
}
|
||||
|
||||
let (backend, mut driver) = self.build(client);
|
||||
|
||||
spawn(async move {
|
||||
while let Some(res) = driver.next().await {
|
||||
if let Err(e) = res {
|
||||
if !e.is_disconnected_will_reconnect() {
|
||||
tracing::debug!(target: "subxt", "chainHead driver was closed: {e}");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
backend
|
||||
}
|
||||
}
|
||||
|
||||
/// Driver for the [`UnstableBackend`]. This must be polled in order for the
|
||||
/// Driver for the [`ChainHeadBackend`]. This must be polled in order for the
|
||||
/// backend to make progress.
|
||||
#[derive(Debug)]
|
||||
pub struct UnstableBackendDriver<T: Config> {
|
||||
pub struct ChainHeadBackendDriver<T: Config> {
|
||||
driver: FollowStreamDriver<T::Hash>,
|
||||
}
|
||||
|
||||
impl<T: Config> Stream for UnstableBackendDriver<T> {
|
||||
impl<T: Config> Stream for ChainHeadBackendDriver<T> {
|
||||
type Item = <FollowStreamDriver<T::Hash> as Stream>::Item;
|
||||
fn poll_next(
|
||||
mut self: std::pin::Pin<&mut Self>,
|
||||
@@ -121,19 +161,19 @@ impl<T: Config> Stream for UnstableBackendDriver<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// The unstable backend.
|
||||
/// The chainHead backend.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct UnstableBackend<T: Config> {
|
||||
pub struct ChainHeadBackend<T: Config> {
|
||||
// RPC methods we'll want to call:
|
||||
methods: UnstableRpcMethods<T>,
|
||||
methods: ChainHeadRpcMethods<T>,
|
||||
// A handle to the chainHead_follow subscription:
|
||||
follow_handle: FollowStreamDriverHandle<T::Hash>,
|
||||
}
|
||||
|
||||
impl<T: Config> UnstableBackend<T> {
|
||||
/// Configure and construct an [`UnstableBackend`] and the associated [`UnstableBackendDriver`].
|
||||
pub fn builder() -> UnstableBackendBuilder<T> {
|
||||
UnstableBackendBuilder::new()
|
||||
impl<T: Config> ChainHeadBackend<T> {
|
||||
/// Configure and construct an [`ChainHeadBackend`] and the associated [`ChainHeadBackendDriver`].
|
||||
pub fn builder() -> ChainHeadBackendBuilder<T> {
|
||||
ChainHeadBackendBuilder::new()
|
||||
}
|
||||
|
||||
/// Stream block headers based on the provided filter fn
|
||||
@@ -193,10 +233,10 @@ impl<Hash: BlockHash + 'static> From<follow_stream_unpin::BlockRef<Hash>> for Bl
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Config> super::sealed::Sealed for UnstableBackend<T> {}
|
||||
impl<T: Config> super::sealed::Sealed for ChainHeadBackend<T> {}
|
||||
|
||||
#[async_trait]
|
||||
impl<T: Config + Send + Sync + 'static> Backend<T> for UnstableBackend<T> {
|
||||
impl<T: Config + Send + Sync + 'static> Backend<T> for ChainHeadBackend<T> {
|
||||
async fn storage_fetch_values(
|
||||
&self,
|
||||
keys: Vec<Vec<u8>>,
|
||||
+13
-13
@@ -19,15 +19,15 @@ use std::task::Poll;
|
||||
/// some `T: Config` trait which determines some of the types that the RPC methods will
|
||||
/// take or hand back.
|
||||
#[derive_where(Clone, Debug)]
|
||||
pub struct UnstableRpcMethods<T> {
|
||||
pub struct ChainHeadRpcMethods<T> {
|
||||
client: RpcClient,
|
||||
_marker: std::marker::PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T: Config> UnstableRpcMethods<T> {
|
||||
impl<T: Config> ChainHeadRpcMethods<T> {
|
||||
/// Instantiate the legacy RPC method interface.
|
||||
pub fn new(client: RpcClient) -> Self {
|
||||
UnstableRpcMethods {
|
||||
ChainHeadRpcMethods {
|
||||
client,
|
||||
_marker: std::marker::PhantomData,
|
||||
}
|
||||
@@ -36,15 +36,15 @@ impl<T: Config> UnstableRpcMethods<T> {
|
||||
/// Subscribe to `chainHead_v1_follow` to obtain all reported blocks by the chain.
|
||||
///
|
||||
/// The subscription ID can be used to make queries for the
|
||||
/// block's body ([`chainHead_v1_body`](UnstableRpcMethods::chainhead_v1_follow)),
|
||||
/// block's header ([`chainHead_v1_header`](UnstableRpcMethods::chainhead_v1_header)),
|
||||
/// block's storage ([`chainHead_v1_storage`](UnstableRpcMethods::chainhead_v1_storage)) and submitting
|
||||
/// runtime API calls at this block ([`chainHead_v1_call`](UnstableRpcMethods::chainhead_v1_call)).
|
||||
/// block's body ([`chainHead_v1_body`](ChainHeadRpcMethods::chainhead_v1_follow)),
|
||||
/// block's header ([`chainHead_v1_header`](ChainHeadRpcMethods::chainhead_v1_header)),
|
||||
/// block's storage ([`chainHead_v1_storage`](ChainHeadRpcMethods::chainhead_v1_storage)) and submitting
|
||||
/// runtime API calls at this block ([`chainHead_v1_call`](ChainHeadRpcMethods::chainhead_v1_call)).
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// When the user is no longer interested in a block, the user is responsible
|
||||
/// for calling the [`chainHead_v1_unpin`](UnstableRpcMethods::chainhead_v1_unpin) method.
|
||||
/// for calling the [`chainHead_v1_unpin`](ChainHeadRpcMethods::chainhead_v1_unpin) method.
|
||||
/// Failure to do so will result in the subscription being stopped by generating the `Stop` event.
|
||||
pub async fn chainhead_v1_follow(
|
||||
&self,
|
||||
@@ -106,7 +106,7 @@ impl<T: Config> UnstableRpcMethods<T> {
|
||||
/// # Note
|
||||
///
|
||||
/// The subscription ID is obtained from an open subscription created by
|
||||
/// [`chainHead_v1_follow`](UnstableRpcMethods::chainhead_v1_follow).
|
||||
/// [`chainHead_v1_follow`](ChainHeadRpcMethods::chainhead_v1_follow).
|
||||
pub async fn chainhead_v1_body(
|
||||
&self,
|
||||
subscription_id: &str,
|
||||
@@ -125,7 +125,7 @@ impl<T: Config> UnstableRpcMethods<T> {
|
||||
/// # Note
|
||||
///
|
||||
/// The subscription ID is obtained from an open subscription created by
|
||||
/// [`chainHead_v1_follow`](UnstableRpcMethods::chainhead_v1_follow).
|
||||
/// [`chainHead_v1_follow`](ChainHeadRpcMethods::chainhead_v1_follow).
|
||||
pub async fn chainhead_v1_header(
|
||||
&self,
|
||||
subscription_id: &str,
|
||||
@@ -151,7 +151,7 @@ impl<T: Config> UnstableRpcMethods<T> {
|
||||
/// # Note
|
||||
///
|
||||
/// The subscription ID is obtained from an open subscription created by
|
||||
/// [`chainHead_v1_follow`](UnstableRpcMethods::chainhead_v1_follow).
|
||||
/// [`chainHead_v1_follow`](ChainHeadRpcMethods::chainhead_v1_follow).
|
||||
pub async fn chainhead_v1_storage(
|
||||
&self,
|
||||
subscription_id: &str,
|
||||
@@ -186,7 +186,7 @@ impl<T: Config> UnstableRpcMethods<T> {
|
||||
/// # Note
|
||||
///
|
||||
/// The subscription ID is obtained from an open subscription created by
|
||||
/// [`chainHead_v1_follow`](UnstableRpcMethods::chainhead_v1_follow).
|
||||
/// [`chainHead_v1_follow`](ChainHeadRpcMethods::chainhead_v1_follow).
|
||||
pub async fn chainhead_v1_call(
|
||||
&self,
|
||||
subscription_id: &str,
|
||||
@@ -210,7 +210,7 @@ impl<T: Config> UnstableRpcMethods<T> {
|
||||
/// # Note
|
||||
///
|
||||
/// The subscription ID is obtained from an open subscription created by
|
||||
/// [`chainHead_v1_follow`](UnstableRpcMethods::chainhead_v1_follow).
|
||||
/// [`chainHead_v1_follow`](ChainHeadRpcMethods::chainhead_v1_follow).
|
||||
pub async fn chainhead_v1_unpin(
|
||||
&self,
|
||||
subscription_id: &str,
|
||||
+2
-2
@@ -5,7 +5,7 @@
|
||||
use super::follow_stream_driver::FollowStreamDriverHandle;
|
||||
use super::follow_stream_unpin::BlockRef;
|
||||
use super::rpc_methods::{
|
||||
FollowEvent, MethodResponse, StorageQuery, StorageResult, UnstableRpcMethods,
|
||||
ChainHeadRpcMethods, FollowEvent, MethodResponse, StorageQuery, StorageResult,
|
||||
};
|
||||
use crate::config::Config;
|
||||
use crate::error::{Error, RpcError};
|
||||
@@ -35,7 +35,7 @@ impl<T: Config> StorageItems<T> {
|
||||
queries: impl Iterator<Item = StorageQuery<&[u8]>>,
|
||||
at: T::Hash,
|
||||
follow_handle: &FollowStreamDriverHandle<T::Hash>,
|
||||
methods: UnstableRpcMethods<T>,
|
||||
methods: ChainHeadRpcMethods<T>,
|
||||
) -> Result<Self, Error> {
|
||||
let sub_id = super::get_subscription_id(follow_handle).await?;
|
||||
|
||||
+14
-11
@@ -6,9 +6,9 @@
|
||||
//! the necessary information (probably from a JSON-RPC API, but that's up to the
|
||||
//! implementation).
|
||||
|
||||
pub mod chain_head;
|
||||
pub mod legacy;
|
||||
pub mod rpc;
|
||||
pub mod unstable;
|
||||
pub mod utils;
|
||||
|
||||
use subxt_core::client::RuntimeVersion;
|
||||
@@ -881,18 +881,18 @@ mod test {
|
||||
OperationStorageItems, RuntimeSpec, RuntimeVersionEvent,
|
||||
};
|
||||
|
||||
use super::unstable::*;
|
||||
use super::chain_head::*;
|
||||
use super::*;
|
||||
|
||||
fn build_backend(
|
||||
rpc_client: impl RpcClientT,
|
||||
) -> (UnstableBackend<Conf>, UnstableBackendDriver<Conf>) {
|
||||
let (backend, driver): (UnstableBackend<Conf>, _) =
|
||||
UnstableBackend::builder().build(rpc_client);
|
||||
) -> (ChainHeadBackend<Conf>, ChainHeadBackendDriver<Conf>) {
|
||||
let (backend, driver): (ChainHeadBackend<Conf>, _) =
|
||||
ChainHeadBackend::builder().build(rpc_client);
|
||||
(backend, driver)
|
||||
}
|
||||
|
||||
fn build_backend_spawn_background(rpc_client: impl RpcClientT) -> UnstableBackend<Conf> {
|
||||
fn build_backend_spawn_background(rpc_client: impl RpcClientT) -> ChainHeadBackend<Conf> {
|
||||
let (backend, mut driver) = build_backend(rpc_client);
|
||||
tokio::spawn(async move {
|
||||
while let Some(val) = driver.next().await {
|
||||
@@ -931,7 +931,7 @@ mod test {
|
||||
serde_json::from_value(spec).unwrap()
|
||||
}
|
||||
|
||||
type FollowEvent = unstable::rpc_methods::FollowEvent<<Conf as Config>::Hash>;
|
||||
type FollowEvent = chain_head::rpc_methods::FollowEvent<<Conf as Config>::Hash>;
|
||||
|
||||
fn setup_mock_rpc_client(cycle_ids: bool) -> MockRpcBuilder {
|
||||
let hash = random_hash();
|
||||
@@ -993,13 +993,16 @@ mod test {
|
||||
operation_id: id.to_owned(),
|
||||
})
|
||||
}
|
||||
fn storage_result(key: &str, value: &str) -> unstable::rpc_methods::StorageResult {
|
||||
unstable::rpc_methods::StorageResult {
|
||||
fn storage_result(key: &str, value: &str) -> chain_head::rpc_methods::StorageResult {
|
||||
chain_head::rpc_methods::StorageResult {
|
||||
key: Bytes(key.to_owned().into()),
|
||||
result: rpc_methods::StorageResultType::Value(Bytes(value.to_owned().into())),
|
||||
}
|
||||
}
|
||||
fn storage_items(id: &str, items: &[unstable::rpc_methods::StorageResult]) -> FollowEvent {
|
||||
fn storage_items(
|
||||
id: &str,
|
||||
items: &[chain_head::rpc_methods::StorageResult],
|
||||
) -> FollowEvent {
|
||||
FollowEvent::OperationStorageItems(OperationStorageItems {
|
||||
operation_id: id.to_owned(),
|
||||
items: VecDeque::from(items.to_owned()),
|
||||
@@ -1400,7 +1403,7 @@ mod test {
|
||||
.add_mock_data(mock_data)
|
||||
.add_mock_data(response_data)
|
||||
.build();
|
||||
let (backend, mut driver): (UnstableBackend<Conf>, _) = build_backend(rpc_client);
|
||||
let (backend, mut driver): (ChainHeadBackend<Conf>, _) = build_backend(rpc_client);
|
||||
|
||||
let _ = driver.next().await.unwrap();
|
||||
let _ = driver.next().await.unwrap();
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
//! # RPC calls
|
||||
//!
|
||||
//! Subxt exposes low level interfaces that can be used to make RPC requests; [`crate::backend::legacy::rpc_methods`]
|
||||
//! and [`crate::backend::unstable::rpc_methods`].
|
||||
//! and [`crate::backend::chain_head::rpc_methods`].
|
||||
//!
|
||||
//! These interfaces cannot be accessed directly through an [`crate::OnlineClient`]; this is so that the high level
|
||||
//! Subxt APIs can target either the "legacy" or the more modern "unstable" sets of RPC methods by selecting an appropriate
|
||||
|
||||
@@ -21,9 +21,9 @@ unstable-light-client = ["subxt/unstable-light-client"]
|
||||
# Enable to run the full-client tests with Light Client support.
|
||||
unstable-light-client-long-running = ["subxt/unstable-light-client"]
|
||||
|
||||
# Enable this to use the unstable backend in tests _instead of_
|
||||
# Enable this to use the chainhead backend in tests _instead of_
|
||||
# the default one which relies on the "old" RPC methods.
|
||||
unstable-backend-client = []
|
||||
chainhead-backend = []
|
||||
|
||||
[dev-dependencies]
|
||||
assert_matches = { workspace = true }
|
||||
|
||||
@@ -5,5 +5,7 @@ fn main() {
|
||||
cfg_aliases! {
|
||||
lightclient: { any(feature = "unstable-light-client", feature = "unstable-light-client-long-running") },
|
||||
fullclient: { all(not(feature = "unstable-light-client"), not(feature = "unstable-light-client-long-running")) },
|
||||
legacy_backend: { not(feature = "chainhead-backend") },
|
||||
chainhead_backend: { feature = "chainhead-backend" },
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,8 +77,8 @@ async fn storage_iter() {
|
||||
async fn storage_child_values_same_across_backends() {
|
||||
let ctx = test_context().await;
|
||||
|
||||
let unstable_client = ctx.unstable_client().await;
|
||||
let legacy_client = ctx.legacy_client().await;
|
||||
let chainhead_client = ctx.chainhead_backend().await;
|
||||
let legacy_client = ctx.legacy_backend().await;
|
||||
|
||||
let addr = node_runtime::storage().system().account_iter();
|
||||
let block_ref = legacy_client
|
||||
@@ -88,7 +88,7 @@ async fn storage_child_values_same_across_backends() {
|
||||
.unwrap()
|
||||
.reference();
|
||||
|
||||
let a: Vec<_> = unstable_client
|
||||
let a: Vec<_> = chainhead_client
|
||||
.storage()
|
||||
.at(block_ref.clone())
|
||||
.iter(addr.clone())
|
||||
@@ -215,9 +215,9 @@ async fn external_signing() {
|
||||
}
|
||||
|
||||
#[cfg(fullclient)]
|
||||
// TODO: Investigate and fix this test failure when using the UnstableBackend.
|
||||
// TODO: Investigate and fix this test failure when using the ChainHeadBackend.
|
||||
// (https://github.com/paritytech/subxt/issues/1308)
|
||||
#[cfg(not(feature = "unstable-backend-client"))]
|
||||
#[cfg(legacy_backend)]
|
||||
#[subxt_test]
|
||||
async fn submit_large_extrinsic() {
|
||||
let ctx = test_context().await;
|
||||
@@ -415,8 +415,8 @@ async fn partial_fee_estimate_correct() {
|
||||
#[subxt_test]
|
||||
async fn legacy_and_unstable_block_subscription_reconnect() {
|
||||
let ctx = test_context_reconnecting_rpc_client().await;
|
||||
let api = ctx.unstable_client().await;
|
||||
let unstable_client_blocks = move |num: usize| {
|
||||
let api = ctx.chainhead_backend().await;
|
||||
let chainhead_client_blocks = move |num: usize| {
|
||||
let api = api.clone();
|
||||
async move {
|
||||
let mut missed_blocks = false;
|
||||
@@ -445,17 +445,17 @@ async fn legacy_and_unstable_block_subscription_reconnect() {
|
||||
}
|
||||
};
|
||||
|
||||
let (blocks, _) = unstable_client_blocks(3).await;
|
||||
let (blocks, _) = chainhead_client_blocks(3).await;
|
||||
let blocks: HashSet<String> = HashSet::from_iter(blocks.into_iter());
|
||||
|
||||
assert!(blocks.len() == 3);
|
||||
|
||||
let ctx = ctx.restart().await;
|
||||
|
||||
// Make client aware that connection was dropped and force them to reconnect
|
||||
let _ = ctx.unstable_client().await.backend().genesis_hash().await;
|
||||
// Make client aware that connection was dropped and force them to reconnect
|
||||
let _ = ctx.chainhead_backend().await.backend().genesis_hash().await;
|
||||
|
||||
let (unstable_blocks, blocks_missed) = unstable_client_blocks(6).await;
|
||||
let (unstable_blocks, blocks_missed) = chainhead_client_blocks(6).await;
|
||||
|
||||
if !blocks_missed {
|
||||
let unstable_blocks: HashSet<String> = HashSet::from_iter(unstable_blocks.into_iter());
|
||||
|
||||
@@ -13,7 +13,7 @@ use assert_matches::assert_matches;
|
||||
use codec::Encode;
|
||||
use futures::Stream;
|
||||
use subxt::{
|
||||
backend::unstable::rpc_methods::{
|
||||
backend::chain_head::rpc_methods::{
|
||||
FollowEvent, Initialized, MethodResponse, RuntimeEvent, RuntimeVersionEvent, StorageQuery,
|
||||
StorageQueryType,
|
||||
},
|
||||
@@ -27,7 +27,7 @@ use subxt_signer::sr25519::dev;
|
||||
#[subxt_test]
|
||||
async fn chainhead_v1_follow() {
|
||||
let ctx = test_context().await;
|
||||
let rpc = ctx.unstable_rpc_methods().await;
|
||||
let rpc = ctx.chainhead_rpc_methods().await;
|
||||
let legacy_rpc = ctx.legacy_rpc_methods().await;
|
||||
|
||||
// Check subscription with runtime updates set on false.
|
||||
@@ -67,7 +67,7 @@ async fn chainhead_v1_follow() {
|
||||
#[subxt_test]
|
||||
async fn chainhead_v1_body() {
|
||||
let ctx = test_context().await;
|
||||
let rpc = ctx.unstable_rpc_methods().await;
|
||||
let rpc = ctx.chainhead_rpc_methods().await;
|
||||
|
||||
let mut blocks = rpc.chainhead_v1_follow(false).await.unwrap();
|
||||
let event = blocks.next().await.unwrap().unwrap();
|
||||
@@ -95,7 +95,7 @@ async fn chainhead_v1_body() {
|
||||
#[subxt_test]
|
||||
async fn chainhead_v1_header() {
|
||||
let ctx = test_context().await;
|
||||
let rpc = ctx.unstable_rpc_methods().await;
|
||||
let rpc = ctx.chainhead_rpc_methods().await;
|
||||
let legacy_rpc = ctx.legacy_rpc_methods().await;
|
||||
|
||||
let mut blocks = rpc.chainhead_v1_follow(false).await.unwrap();
|
||||
@@ -124,7 +124,7 @@ async fn chainhead_v1_header() {
|
||||
async fn chainhead_v1_storage() {
|
||||
let ctx = test_context().await;
|
||||
let api = ctx.client();
|
||||
let rpc = ctx.unstable_rpc_methods().await;
|
||||
let rpc = ctx.chainhead_rpc_methods().await;
|
||||
|
||||
let mut blocks = rpc.chainhead_v1_follow(false).await.unwrap();
|
||||
let event = blocks.next().await.unwrap().unwrap();
|
||||
@@ -169,7 +169,7 @@ async fn chainhead_v1_storage() {
|
||||
#[subxt_test]
|
||||
async fn chainhead_v1_call() {
|
||||
let ctx = test_context().await;
|
||||
let rpc = ctx.unstable_rpc_methods().await;
|
||||
let rpc = ctx.chainhead_rpc_methods().await;
|
||||
|
||||
let mut blocks = rpc.chainhead_v1_follow(true).await.unwrap();
|
||||
let event = blocks.next().await.unwrap().unwrap();
|
||||
@@ -206,7 +206,7 @@ async fn chainhead_v1_call() {
|
||||
#[subxt_test]
|
||||
async fn chainhead_v1_unpin() {
|
||||
let ctx = test_context().await;
|
||||
let rpc = ctx.unstable_rpc_methods().await;
|
||||
let rpc = ctx.chainhead_rpc_methods().await;
|
||||
|
||||
let mut blocks = rpc.chainhead_v1_follow(true).await.unwrap();
|
||||
let event = blocks.next().await.unwrap().unwrap();
|
||||
@@ -226,7 +226,7 @@ async fn chainhead_v1_unpin() {
|
||||
async fn chainspec_v1_genesishash() {
|
||||
let ctx = test_context().await;
|
||||
let old_rpc = ctx.legacy_rpc_methods().await;
|
||||
let rpc = ctx.unstable_rpc_methods().await;
|
||||
let rpc = ctx.chainhead_rpc_methods().await;
|
||||
|
||||
let a = old_rpc.genesis_hash().await.unwrap();
|
||||
let b = rpc.chainspec_v1_genesis_hash().await.unwrap();
|
||||
@@ -239,7 +239,7 @@ async fn chainspec_v1_genesishash() {
|
||||
async fn chainspec_v1_chainname() {
|
||||
let ctx = test_context().await;
|
||||
let old_rpc = ctx.legacy_rpc_methods().await;
|
||||
let rpc = ctx.unstable_rpc_methods().await;
|
||||
let rpc = ctx.chainhead_rpc_methods().await;
|
||||
|
||||
let a = old_rpc.system_chain().await.unwrap();
|
||||
let b = rpc.chainspec_v1_chain_name().await.unwrap();
|
||||
@@ -252,7 +252,7 @@ async fn chainspec_v1_chainname() {
|
||||
async fn chainspec_v1_properties() {
|
||||
let ctx = test_context().await;
|
||||
let old_rpc = ctx.legacy_rpc_methods().await;
|
||||
let rpc = ctx.unstable_rpc_methods().await;
|
||||
let rpc = ctx.chainhead_rpc_methods().await;
|
||||
|
||||
let a = old_rpc.system_properties().await.unwrap();
|
||||
let b = rpc.chainspec_v1_properties().await.unwrap();
|
||||
@@ -264,7 +264,7 @@ async fn chainspec_v1_properties() {
|
||||
#[subxt_test]
|
||||
async fn transactionwatch_v1_submit_and_watch() {
|
||||
let ctx = test_context().await;
|
||||
let rpc = ctx.unstable_rpc_methods().await;
|
||||
let rpc = ctx.chainhead_rpc_methods().await;
|
||||
|
||||
// Build and sign some random tx, just to get some appropriate bytes:
|
||||
let payload = node_runtime::tx().system().remark(b"hello".to_vec());
|
||||
@@ -327,7 +327,7 @@ async fn transaction_v1_broadcast() {
|
||||
|
||||
let ctx = test_context().await;
|
||||
let api = ctx.client();
|
||||
let rpc = ctx.unstable_rpc_methods().await;
|
||||
let rpc = ctx.chainhead_rpc_methods().await;
|
||||
|
||||
let tx_payload = node_runtime::tx()
|
||||
.balances()
|
||||
@@ -391,7 +391,7 @@ async fn transaction_v1_stop() {
|
||||
let bob_address: MultiAddress<AccountId32, u32> = bob.public_key().into();
|
||||
|
||||
let ctx = test_context().await;
|
||||
let rpc = ctx.unstable_rpc_methods().await;
|
||||
let rpc = ctx.chainhead_rpc_methods().await;
|
||||
|
||||
// Cannot stop an operation that was not started.
|
||||
let _err = rpc
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
||||
// see LICENSE for license details.
|
||||
|
||||
#[cfg(all(feature = "unstable-light-client", feature = "unstable-backend-client"))]
|
||||
#[cfg(all(feature = "unstable-light-client", feature = "chainhead-backend"))]
|
||||
compile_error!(
|
||||
"The features 'unstable-light-client' and 'unstable-backend-client' cannot be used together"
|
||||
"The features 'unstable-light-client' and 'chainhead-backend' cannot be used together"
|
||||
);
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -31,8 +31,8 @@ use crate::utils::node_runtime;
|
||||
use codec::Compact;
|
||||
use futures::StreamExt;
|
||||
use std::sync::Arc;
|
||||
use subxt::backend::chain_head::ChainHeadBackend;
|
||||
use subxt::backend::rpc::RpcClient;
|
||||
use subxt::backend::unstable::UnstableBackend;
|
||||
use subxt::{client::OnlineClient, config::PolkadotConfig, lightclient::LightClient};
|
||||
use subxt_metadata::Metadata;
|
||||
|
||||
@@ -184,7 +184,7 @@ async fn run_test(backend: BackendType) -> Result<(), subxt::Error> {
|
||||
|
||||
let api = match backend {
|
||||
BackendType::Unstable => {
|
||||
let (backend, mut driver) = UnstableBackend::builder().build(RpcClient::new(rpc));
|
||||
let (backend, mut driver) = ChainHeadBackend::builder().build(RpcClient::new(rpc));
|
||||
tokio::spawn(async move {
|
||||
while let Some(val) = driver.next().await {
|
||||
if let Err(e) = val {
|
||||
|
||||
@@ -9,7 +9,7 @@ use std::time::Duration;
|
||||
use substrate_runner::SubstrateNode;
|
||||
use subxt::backend::rpc::reconnecting_rpc_client::{ExponentialBackoff, RpcClientBuilder};
|
||||
use subxt::{
|
||||
backend::{legacy, rpc, unstable},
|
||||
backend::{chain_head, legacy, rpc},
|
||||
Config, OnlineClient,
|
||||
};
|
||||
|
||||
@@ -41,8 +41,8 @@ pub struct TestNodeProcess<R: Config> {
|
||||
proc: Option<SubstrateNode>,
|
||||
|
||||
// Lazily construct these when asked for.
|
||||
unstable_client: RefCell<Option<OnlineClient<R>>>,
|
||||
legacy_client: RefCell<Option<OnlineClient<R>>>,
|
||||
chainhead_backend: RefCell<Option<OnlineClient<R>>>,
|
||||
legacy_backend: RefCell<Option<OnlineClient<R>>>,
|
||||
|
||||
rpc_client: rpc::RpcClient,
|
||||
client: OnlineClient<R>,
|
||||
@@ -78,38 +78,38 @@ where
|
||||
}
|
||||
|
||||
/// Hand back an RPC client connected to the test node which exposes the unstable RPC methods.
|
||||
pub async fn unstable_rpc_methods(&self) -> unstable::UnstableRpcMethods<R> {
|
||||
pub async fn chainhead_rpc_methods(&self) -> chain_head::ChainHeadRpcMethods<R> {
|
||||
let rpc_client = self.rpc_client.clone();
|
||||
unstable::UnstableRpcMethods::new(rpc_client)
|
||||
chain_head::ChainHeadRpcMethods::new(rpc_client)
|
||||
}
|
||||
|
||||
/// Always return a client using the unstable backend.
|
||||
/// Always return a client using the chainhead backend.
|
||||
/// Only use for comparing backends; use [`TestNodeProcess::client()`] normally,
|
||||
/// which enables us to run each test against both backends.
|
||||
pub async fn unstable_client(&self) -> OnlineClient<R> {
|
||||
if self.unstable_client.borrow().is_none() {
|
||||
let c = build_unstable_client(self.rpc_client.clone())
|
||||
pub async fn chainhead_backend(&self) -> OnlineClient<R> {
|
||||
if self.chainhead_backend.borrow().is_none() {
|
||||
let c = build_chainhead_backend(self.rpc_client.clone())
|
||||
.await
|
||||
.unwrap();
|
||||
self.unstable_client.replace(Some(c));
|
||||
self.chainhead_backend.replace(Some(c));
|
||||
}
|
||||
self.unstable_client.borrow().as_ref().unwrap().clone()
|
||||
self.chainhead_backend.borrow().as_ref().unwrap().clone()
|
||||
}
|
||||
|
||||
/// Always return a client using the legacy backend.
|
||||
/// Only use for comparing backends; use [`TestNodeProcess::client()`] normally,
|
||||
/// which enables us to run each test against both backends.
|
||||
pub async fn legacy_client(&self) -> OnlineClient<R> {
|
||||
if self.legacy_client.borrow().is_none() {
|
||||
let c = build_legacy_client(self.rpc_client.clone()).await.unwrap();
|
||||
self.legacy_client.replace(Some(c));
|
||||
pub async fn legacy_backend(&self) -> OnlineClient<R> {
|
||||
if self.legacy_backend.borrow().is_none() {
|
||||
let c = build_legacy_backend(self.rpc_client.clone()).await.unwrap();
|
||||
self.legacy_backend.replace(Some(c));
|
||||
}
|
||||
self.legacy_client.borrow().as_ref().unwrap().clone()
|
||||
self.legacy_backend.borrow().as_ref().unwrap().clone()
|
||||
}
|
||||
|
||||
/// Returns the subxt client connected to the running node. This client
|
||||
/// will use the legacy backend by default or the unstable backend if the
|
||||
/// "unstable-backend-client" feature is enabled, so that we can run each
|
||||
/// will use the legacy backend by default or the chainhead backend if the
|
||||
/// "chainhead-backend" feature is enabled, so that we can run each
|
||||
/// test against both.
|
||||
pub fn client(&self) -> OnlineClient<R> {
|
||||
self.client.clone()
|
||||
@@ -187,38 +187,38 @@ impl TestNodeProcessBuilder {
|
||||
let ws_url = get_url(proc.as_ref().map(|p| p.ws_port()));
|
||||
let rpc_client = match self.rpc_client {
|
||||
RpcClientKind::Legacy => build_rpc_client(&ws_url).await,
|
||||
RpcClientKind::UnstableReconnecting => build_unstable_rpc_client(&ws_url).await,
|
||||
RpcClientKind::UnstableReconnecting => build_reconnecting_rpc_client(&ws_url).await,
|
||||
}
|
||||
.map_err(|e| format!("Failed to connect to node at {ws_url}: {e}"))?;
|
||||
|
||||
// Cache whatever client we build, and None for the other.
|
||||
#[allow(unused_assignments, unused_mut)]
|
||||
let mut unstable_client = None;
|
||||
let mut chainhead_backend = None;
|
||||
#[allow(unused_assignments, unused_mut)]
|
||||
let mut legacy_client = None;
|
||||
let mut legacy_backend = None;
|
||||
|
||||
#[cfg(lightclient)]
|
||||
let client = build_light_client(&proc).await?;
|
||||
|
||||
#[cfg(feature = "unstable-backend-client")]
|
||||
#[cfg(chainhead_backend)]
|
||||
let client = {
|
||||
let client = build_unstable_client(rpc_client.clone()).await?;
|
||||
unstable_client = Some(client.clone());
|
||||
let client = build_chainhead_backend(rpc_client.clone()).await?;
|
||||
chainhead_backend = Some(client.clone());
|
||||
client
|
||||
};
|
||||
|
||||
#[cfg(all(not(lightclient), not(feature = "unstable-backend-client")))]
|
||||
#[cfg(all(not(lightclient), legacy_backend))]
|
||||
let client = {
|
||||
let client = build_legacy_client(rpc_client.clone()).await?;
|
||||
legacy_client = Some(client.clone());
|
||||
let client = build_legacy_backend(rpc_client.clone()).await?;
|
||||
legacy_backend = Some(client.clone());
|
||||
client
|
||||
};
|
||||
|
||||
Ok(TestNodeProcess {
|
||||
proc,
|
||||
client,
|
||||
legacy_client: RefCell::new(legacy_client),
|
||||
unstable_client: RefCell::new(unstable_client),
|
||||
legacy_backend: RefCell::new(legacy_backend),
|
||||
chainhead_backend: RefCell::new(chainhead_backend),
|
||||
rpc_client,
|
||||
})
|
||||
}
|
||||
@@ -232,7 +232,7 @@ async fn build_rpc_client(ws_url: &str) -> Result<rpc::RpcClient, String> {
|
||||
Ok(rpc_client)
|
||||
}
|
||||
|
||||
async fn build_unstable_rpc_client(ws_url: &str) -> Result<rpc::RpcClient, String> {
|
||||
async fn build_reconnecting_rpc_client(ws_url: &str) -> Result<rpc::RpcClient, String> {
|
||||
let client = RpcClientBuilder::new()
|
||||
.retry_policy(ExponentialBackoff::from_millis(100).max_delay(Duration::from_secs(10)))
|
||||
.build(ws_url.to_string())
|
||||
@@ -242,7 +242,7 @@ async fn build_unstable_rpc_client(ws_url: &str) -> Result<rpc::RpcClient, Strin
|
||||
Ok(rpc::RpcClient::new(client))
|
||||
}
|
||||
|
||||
async fn build_legacy_client<T: Config>(
|
||||
async fn build_legacy_backend<T: Config>(
|
||||
rpc_client: rpc::RpcClient,
|
||||
) -> Result<OnlineClient<T>, String> {
|
||||
let backend = legacy::LegacyBackend::builder().build(rpc_client);
|
||||
@@ -253,23 +253,10 @@ async fn build_legacy_client<T: Config>(
|
||||
Ok(client)
|
||||
}
|
||||
|
||||
async fn build_unstable_client<T: Config>(
|
||||
async fn build_chainhead_backend<T: Config>(
|
||||
rpc_client: rpc::RpcClient,
|
||||
) -> Result<OnlineClient<T>, String> {
|
||||
let (backend, mut driver) = unstable::UnstableBackend::builder().build(rpc_client);
|
||||
|
||||
// The unstable backend needs driving:
|
||||
tokio::spawn(async move {
|
||||
use futures::StreamExt;
|
||||
while let Some(val) = driver.next().await {
|
||||
if let Err(e) = val {
|
||||
// This is a test; bail if something does wrong and try to
|
||||
// ensure that the message makes it to some logs.
|
||||
eprintln!("Error driving unstable backend in tests (will panic): {e}");
|
||||
panic!("Error driving unstable backend in tests: {e}");
|
||||
}
|
||||
}
|
||||
});
|
||||
let backend = chain_head::ChainHeadBackend::builder().build_with_background_driver(rpc_client);
|
||||
|
||||
let client = OnlineClient::from_backend(Arc::new(backend))
|
||||
.await
|
||||
@@ -323,5 +310,5 @@ async fn build_light_client<T: Config>(
|
||||
.map_err(|e| format!("Light client: cannot add relay chain: {e}"))?;
|
||||
|
||||
// Instantiate subxt client from this.
|
||||
build_unstable_client(rpc.into()).await
|
||||
build_chainhead_backend(rpc.into()).await
|
||||
}
|
||||
|
||||
Generated
+73
-34
@@ -97,7 +97,7 @@ checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.75",
|
||||
"syn 2.0.79",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -445,7 +445,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.75",
|
||||
"syn 2.0.79",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -493,7 +493,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"strsim 0.11.1",
|
||||
"syn 2.0.75",
|
||||
"syn 2.0.79",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -515,7 +515,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806"
|
||||
dependencies = [
|
||||
"darling_core 0.20.10",
|
||||
"quote",
|
||||
"syn 2.0.75",
|
||||
"syn 2.0.79",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -526,7 +526,7 @@ checksum = "62d671cc41a825ebabc75757b62d3d168c577f9149b2d49ece1dad1f72119d25"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.75",
|
||||
"syn 2.0.79",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -539,7 +539,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustc_version",
|
||||
"syn 2.0.75",
|
||||
"syn 2.0.79",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -667,6 +667,21 @@ dependencies = [
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "frame-decode"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed90459016b06a2855321469cb01fbc74208c80c06b085d1ed13162cf8bd7e1b"
|
||||
dependencies = [
|
||||
"frame-metadata 16.0.0",
|
||||
"hex",
|
||||
"parity-scale-codec",
|
||||
"scale-decode",
|
||||
"scale-info",
|
||||
"scale-type-resolver",
|
||||
"sp-crypto-hashing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "frame-metadata"
|
||||
version = "15.1.0"
|
||||
@@ -750,7 +765,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.75",
|
||||
"syn 2.0.79",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1301,11 +1316,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "keccak-hash"
|
||||
version = "0.10.0"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4b286e6b663fb926e1eeb68528e69cb70ed46c6d65871a21b2215ae8154c6d3c"
|
||||
checksum = "3e1b8590eb6148af2ea2d75f38e7d29f5ca970d5a4df456b3ef19b8b415d0264"
|
||||
dependencies = [
|
||||
"primitive-types",
|
||||
"primitive-types 0.13.1",
|
||||
"tiny-keccak",
|
||||
]
|
||||
|
||||
@@ -1485,7 +1500,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.75",
|
||||
"syn 2.0.79",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1608,7 +1623,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.75",
|
||||
"syn 2.0.79",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1653,7 +1668,17 @@ dependencies = [
|
||||
"impl-codec",
|
||||
"impl-serde",
|
||||
"scale-info",
|
||||
"uint",
|
||||
"uint 0.9.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "primitive-types"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d15600a7d856470b7d278b3fe0e311fe28c2526348549f8ef2ff7db3299c87f5"
|
||||
dependencies = [
|
||||
"fixed-hash",
|
||||
"uint 0.10.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1694,7 +1719,7 @@ dependencies = [
|
||||
"proc-macro-error-attr2",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.75",
|
||||
"syn 2.0.79",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1920,7 +1945,7 @@ checksum = "e98f3262c250d90e700bb802eb704e1f841e03331c2eb815e46516c4edbf5b27"
|
||||
dependencies = [
|
||||
"derive_more",
|
||||
"parity-scale-codec",
|
||||
"primitive-types",
|
||||
"primitive-types 0.12.2",
|
||||
"scale-bits",
|
||||
"scale-decode-derive",
|
||||
"scale-type-resolver",
|
||||
@@ -1947,7 +1972,7 @@ checksum = "4ba0b9c48dc0eb20c60b083c29447c0c4617cb7c4a4c9fef72aa5c5bc539e15e"
|
||||
dependencies = [
|
||||
"derive_more",
|
||||
"parity-scale-codec",
|
||||
"primitive-types",
|
||||
"primitive-types 0.12.2",
|
||||
"scale-bits",
|
||||
"scale-encode-derive",
|
||||
"scale-type-resolver",
|
||||
@@ -2012,15 +2037,15 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"scale-info",
|
||||
"syn 2.0.75",
|
||||
"syn 2.0.79",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scale-value"
|
||||
version = "0.16.2"
|
||||
version = "0.16.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba4d772cfb7569e03868400344a1695d16560bf62b86b918604773607d39ec84"
|
||||
checksum = "8cd6ab090d823e75cfdb258aad5fe92e13f2af7d04b43a55d607d25fcc38c811"
|
||||
dependencies = [
|
||||
"base58",
|
||||
"blake2",
|
||||
@@ -2139,7 +2164,7 @@ checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.75",
|
||||
"syn 2.0.79",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2423,7 +2448,7 @@ dependencies = [
|
||||
"instant",
|
||||
"jsonrpsee",
|
||||
"parity-scale-codec",
|
||||
"primitive-types",
|
||||
"primitive-types 0.12.2",
|
||||
"scale-bits",
|
||||
"scale-decode",
|
||||
"scale-encode",
|
||||
@@ -2458,7 +2483,7 @@ dependencies = [
|
||||
"scale-info",
|
||||
"scale-typegen",
|
||||
"subxt-metadata",
|
||||
"syn 2.0.75",
|
||||
"syn 2.0.79",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
]
|
||||
@@ -2470,13 +2495,14 @@ dependencies = [
|
||||
"base58",
|
||||
"blake2",
|
||||
"derive-where",
|
||||
"frame-decode",
|
||||
"frame-metadata 16.0.0",
|
||||
"hashbrown",
|
||||
"hex",
|
||||
"impl-serde",
|
||||
"keccak-hash",
|
||||
"parity-scale-codec",
|
||||
"primitive-types",
|
||||
"primitive-types 0.12.2",
|
||||
"scale-bits",
|
||||
"scale-decode",
|
||||
"scale-encode",
|
||||
@@ -2524,13 +2550,14 @@ dependencies = [
|
||||
"quote",
|
||||
"scale-typegen",
|
||||
"subxt-codegen",
|
||||
"syn 2.0.75",
|
||||
"syn 2.0.79",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "subxt-metadata"
|
||||
version = "0.37.0"
|
||||
dependencies = [
|
||||
"frame-decode",
|
||||
"frame-metadata 16.0.0",
|
||||
"hashbrown",
|
||||
"parity-scale-codec",
|
||||
@@ -2551,9 +2578,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.75"
|
||||
version = "2.0.79"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6af063034fc1935ede7be0122941bafa9bacb949334d090b77ca98b5817c7d9"
|
||||
checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -2583,7 +2610,7 @@ checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.75",
|
||||
"syn 2.0.79",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2644,7 +2671,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.75",
|
||||
"syn 2.0.79",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2759,7 +2786,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.75",
|
||||
"syn 2.0.79",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2828,6 +2855,18 @@ dependencies = [
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uint"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "909988d098b2f738727b161a106cfc7cab00c539c2687a8836f8e565976fb53e"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"crunchy",
|
||||
"hex",
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi"
|
||||
version = "0.3.15"
|
||||
@@ -2929,7 +2968,7 @@ dependencies = [
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.75",
|
||||
"syn 2.0.79",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
@@ -2963,7 +3002,7 @@ checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.75",
|
||||
"syn 2.0.79",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
@@ -2997,7 +3036,7 @@ checksum = "4b8220be1fa9e4c889b30fd207d4906657e7e90b12e0e6b0c8b8d8709f5de021"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.75",
|
||||
"syn 2.0.79",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3248,7 +3287,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.75",
|
||||
"syn 2.0.79",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3268,5 +3307,5 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.75",
|
||||
"syn 2.0.79",
|
||||
]
|
||||
|
||||
@@ -15,4 +15,4 @@ futures-util = "0.3.30"
|
||||
# This crate is not a part of the workspace, because it
|
||||
# requires the "jsonrpsee web" features to be enabled, which we don't
|
||||
# want enabled for workspace builds in general.
|
||||
subxt = { path = "../../subxt", default-features = false, features = ["web", "jsonrpsee", "unstable-reconnecting-rpc-client"] }
|
||||
subxt = { path = "../../subxt", default-features = false, features = ["web", "jsonrpsee", "unstable-reconnecting-rpc-client", "runtime"] }
|
||||
@@ -36,6 +36,16 @@ async fn wasm_ws_transport_works() {
|
||||
assert!(stream.next().await.is_some());
|
||||
}
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
async fn wasm_ws_chainhead_works() {
|
||||
let rpc = subxt::backend::rpc::RpcClient::from_url("ws://127.0.0.1:9944").await.unwrap();
|
||||
let backend = subxt::backend::chain_head::ChainHeadBackendBuilder::new().build_with_background_driver(rpc);
|
||||
let client = subxt::client::OnlineClient::<SubstrateConfig>::from_backend(std::sync::Arc::new(backend)).await.unwrap();
|
||||
|
||||
let mut stream = client.backend().stream_best_block_headers().await.unwrap();
|
||||
assert!(stream.next().await.is_some());
|
||||
}
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
async fn reconnecting_rpc_client_ws_transport_works() {
|
||||
let rpc = ReconnectingRpcClient::builder().build("ws://127.0.0.1:9944".to_string()).await.unwrap();
|
||||
|
||||
Reference in New Issue
Block a user