Files
pezkuwi-subxt/subxt/src/client/light_client/mod.rs
T
Alexandru Vasile 34ff3da37d lightclient: Add support for multi-chain usecase (#1238)
* lightclient: Make `smoldot::chainID` part of the RPC requests

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* lightclient: Make `BackgroundTask` generic over `PlatformRef` and chain

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* lightclient: Construct from raw smoldot and target different chains

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* testing: Update cargo lock for wasm tests

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* lightclient: Reuse `new_from_client` method and removed unused imports

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* lightclient: Reexport smoldot client and RPC objects used in pub
interface

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* lightclient: Adjust `new_from_client` interface

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* lightclient: Extend background to poll over multiple RPC objects

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* subxt: Build light client from raw and target different chains

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* artifacts: Add demo chain specs

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* artifacts: Move artifacts to dedicated folder

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* lightclient: Use SelectAll to drive all streams

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* lightclient: Fetch initial data from the target chain

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* lightclient: Reexport other smoldot objects

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* subxt: Target chain with potentially different config

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* subxt/rpc: Log chainID for debugging

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* subxt/examples: Add smoldot client with parachain example

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* lightclient: Propagate chain ID together with rpc responses object

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* lightclient: Multiplex responses by request ID and chain ID

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* subxt: Add raw light client builder

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* subxt: Add cargo feature flag for parachains example

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* lightclient: Derive default for internal structure

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* lightclient: Guard reexports by std feature flag

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* Update subxt/src/client/light_client/mod.rs

Co-authored-by: James Wilson <james@jsdw.me>

* lightclient: Update the builder pattern and chain targetting

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* lightclient: Fix documentation

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* Provide more insightful docs wrt native/wasm panics

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* examples: Adjust comment location

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* lightclient: Refactor UniqueChainId into the background task

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* Update lightclient/src/background.rs

Co-authored-by: Niklas Adolfsson <niklasadolfsson1@gmail.com>

* Update subxt/src/client/light_client/builder.rs

Co-authored-by: James Wilson <james@jsdw.me>

* lightclient: Update docs wrt panics

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* subxt: Update docs wrt to smoldot instance -> client

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* lightclient: Use IntoIter instead of Iterator

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* subxt: Adjsut docs wrt [`Self::new_from_client`]

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* subxt: Remove RawRpc from LightClient in favor of chainID

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* lightclient: Reexport everything under smoldot module

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* artifacts: Use stateRootHash instead of genesis.raw

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

---------

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
Co-authored-by: James Wilson <james@jsdw.me>
Co-authored-by: Niklas Adolfsson <niklasadolfsson1@gmail.com>
2023-11-16 18:29:00 +02:00

195 lines
6.0 KiB
Rust

// Copyright 2019-2023 Parity Technologies (UK) Ltd.
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
// see LICENSE for license details.
//! This module provides support for light clients.
mod builder;
mod rpc;
use crate::{
backend::rpc::RpcClient,
blocks::BlocksClient,
client::{OfflineClientT, OnlineClientT},
config::Config,
constants::ConstantsClient,
custom_values::CustomValuesClient,
events::EventsClient,
runtime_api::RuntimeApiClient,
storage::StorageClient,
tx::TxClient,
OnlineClient,
};
pub use builder::{LightClientBuilder, RawLightClientBuilder};
use derivative::Derivative;
use subxt_lightclient::LightClientRpcError;
// Re-export smoldot related objects.
pub use subxt_lightclient::smoldot;
/// Light client error.
#[derive(Debug, thiserror::Error)]
pub enum LightClientError {
/// Error originated from the low-level RPC layer.
#[error("Rpc error: {0}")]
Rpc(LightClientRpcError),
/// The background task is closed.
#[error("Failed to communicate with the background task.")]
BackgroundClosed,
/// Invalid RPC parameters cannot be serialized as JSON string.
#[error("RPC parameters cannot be serialized as JSON string.")]
InvalidParams,
/// The provided URL scheme is invalid.
///
/// Supported versions: WS, WSS.
#[error("The provided URL scheme is invalid.")]
InvalidScheme,
/// The provided URL is invalid.
#[error("The provided URL scheme is invalid.")]
InvalidUrl,
/// The provided chain spec is invalid.
#[error("The provided chain spec is not a valid JSON object.")]
InvalidChainSpec,
/// Handshake error while connecting to a node.
#[error("WS handshake failed.")]
Handshake,
}
/// The raw light-client RPC implementation that is used to connect with the chain.
#[derive(Clone)]
pub struct RawLightClient {
raw_rpc: rpc::RawLightClientRpc,
}
impl RawLightClient {
/// Construct a [`RawLightClient`] using its builder interface.
///
/// The raw builder is utilized for constructing light-clients from a low
/// level smoldot client.
///
/// This is especially useful when you want to gain access to the smoldot client.
/// For example, you may want to connect to multiple chains and/or parachains while reusing the
/// same smoldot client under the hood. Or you may want to configure different values for
/// smoldot internal buffers, number of subscriptions and relay chains.
///
/// # Note
///
/// If you are unsure, please use [`LightClient::builder`] instead.
pub fn builder() -> RawLightClientBuilder {
RawLightClientBuilder::default()
}
/// Target a different chain identified by the provided chain ID for requests.
///
/// The provided chain ID is provided by the `smoldot_light::Client::add_chain` and it must
/// match one of the `smoldot_light::JsonRpcResponses` provided in [`RawLightClientBuilder::add_chain`].
///
/// # Note
///
/// This uses the same underlying instance spawned by the builder.
pub async fn for_chain<TChainConfig: Config>(
&self,
chain_id: smoldot::ChainId,
) -> Result<LightClient<TChainConfig>, crate::Error> {
let raw_rpc = self.raw_rpc.for_chain(chain_id);
let rpc_client = RpcClient::new(raw_rpc.clone());
let client = OnlineClient::<TChainConfig>::from_rpc_client(rpc_client).await?;
Ok(LightClient { client, chain_id })
}
}
/// The light-client RPC implementation that is used to connect with the chain.
#[derive(Derivative)]
#[derivative(Clone(bound = ""))]
pub struct LightClient<T: Config> {
client: OnlineClient<T>,
chain_id: smoldot::ChainId,
}
impl<T: Config> LightClient<T> {
/// Construct a [`LightClient`] using its builder interface.
pub fn builder() -> LightClientBuilder<T> {
LightClientBuilder::new()
}
// We add the below impls so that we don't need to
// think about importing the OnlineClientT/OfflineClientT
// traits to use these things:
/// Return the [`crate::Metadata`] used in this client.
fn metadata(&self) -> crate::Metadata {
self.client.metadata()
}
/// Return the genesis hash.
fn genesis_hash(&self) -> <T as Config>::Hash {
self.client.genesis_hash()
}
/// Return the runtime version.
fn runtime_version(&self) -> crate::backend::RuntimeVersion {
self.client.runtime_version()
}
/// Work with transactions.
pub fn tx(&self) -> TxClient<T, Self> {
<Self as OfflineClientT<T>>::tx(self)
}
/// Work with events.
pub fn events(&self) -> EventsClient<T, Self> {
<Self as OfflineClientT<T>>::events(self)
}
/// Work with storage.
pub fn storage(&self) -> StorageClient<T, Self> {
<Self as OfflineClientT<T>>::storage(self)
}
/// Access constants.
pub fn constants(&self) -> ConstantsClient<T, Self> {
<Self as OfflineClientT<T>>::constants(self)
}
/// Access custom types.
pub fn custom_values(&self) -> CustomValuesClient<T, Self> {
<Self as OfflineClientT<T>>::custom_values(self)
}
/// Work with blocks.
pub fn blocks(&self) -> BlocksClient<T, Self> {
<Self as OfflineClientT<T>>::blocks(self)
}
/// Work with runtime API.
pub fn runtime_api(&self) -> RuntimeApiClient<T, Self> {
<Self as OfflineClientT<T>>::runtime_api(self)
}
/// Returns the chain ID of the current light-client.
pub fn chain_id(&self) -> smoldot::ChainId {
self.chain_id
}
}
impl<T: Config> OnlineClientT<T> for LightClient<T> {
fn backend(&self) -> &dyn crate::backend::Backend<T> {
self.client.backend()
}
}
impl<T: Config> OfflineClientT<T> for LightClient<T> {
fn metadata(&self) -> crate::Metadata {
self.metadata()
}
fn genesis_hash(&self) -> <T as Config>::Hash {
self.genesis_hash()
}
fn runtime_version(&self) -> crate::backend::RuntimeVersion {
self.runtime_version()
}
}