mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-12 12:21:32 +00:00
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>
This commit is contained in:
@@ -4,9 +4,10 @@
|
||||
|
||||
use super::{rpc::LightClientRpc, LightClient, LightClientError};
|
||||
use crate::backend::rpc::RpcClient;
|
||||
use crate::client::RawLightClient;
|
||||
use crate::{config::Config, error::Error, OnlineClient};
|
||||
use std::num::NonZeroU32;
|
||||
use subxt_lightclient::{AddChainConfig, AddChainConfigJsonRpc, ChainId};
|
||||
use subxt_lightclient::{smoldot, AddedChain};
|
||||
|
||||
/// Builder for [`LightClient`].
|
||||
#[derive(Clone, Debug)]
|
||||
@@ -14,7 +15,7 @@ pub struct LightClientBuilder<T: Config> {
|
||||
max_pending_requests: NonZeroU32,
|
||||
max_subscriptions: u32,
|
||||
bootnodes: Option<Vec<serde_json::Value>>,
|
||||
potential_relay_chains: Option<Vec<ChainId>>,
|
||||
potential_relay_chains: Option<Vec<smoldot::ChainId>>,
|
||||
_marker: std::marker::PhantomData<T>,
|
||||
}
|
||||
|
||||
@@ -77,7 +78,7 @@ impl<T: Config> LightClientBuilder<T> {
|
||||
/// be wrong to connect to the "Kusama" created by user A.
|
||||
pub fn potential_relay_chains(
|
||||
mut self,
|
||||
potential_relay_chains: impl IntoIterator<Item = ChainId>,
|
||||
potential_relay_chains: impl IntoIterator<Item = smoldot::ChainId>,
|
||||
) -> Self {
|
||||
self.potential_relay_chains = Some(potential_relay_chains.into_iter().collect());
|
||||
self
|
||||
@@ -88,7 +89,16 @@ impl<T: Config> LightClientBuilder<T> {
|
||||
///
|
||||
/// ## Panics
|
||||
///
|
||||
/// Panics if being called outside of `tokio` runtime context.
|
||||
/// The panic behaviour depends on the feature flag being used:
|
||||
///
|
||||
/// ### Native
|
||||
///
|
||||
/// Panics when called outside of a `tokio` runtime context.
|
||||
///
|
||||
/// ### Web
|
||||
///
|
||||
/// If smoldot panics, then the promise created will be leaked. For more details, see
|
||||
/// https://docs.rs/wasm-bindgen-futures/latest/wasm_bindgen_futures/fn.future_to_promise.html.
|
||||
#[cfg(feature = "jsonrpsee")]
|
||||
pub async fn build_from_url<Url: AsRef<str>>(self, url: Url) -> Result<LightClient<T>, Error> {
|
||||
let chain_spec = fetch_url(url.as_ref()).await?;
|
||||
@@ -104,7 +114,7 @@ impl<T: Config> LightClientBuilder<T> {
|
||||
///
|
||||
/// The chain spec must be obtained from a trusted entity.
|
||||
///
|
||||
/// It can be fetched from a trused node with the following command:
|
||||
/// It can be fetched from a trusted node with the following command:
|
||||
/// ```bash
|
||||
/// curl -H "Content-Type: application/json" -d '{"id":1, "jsonrpc":"2.0", "method": "sync_state_genSyncSpec", "params":[true]}' http://localhost:9944/ | jq .result > res.spec
|
||||
/// ```
|
||||
@@ -116,7 +126,16 @@ impl<T: Config> LightClientBuilder<T> {
|
||||
///
|
||||
/// ## Panics
|
||||
///
|
||||
/// Panics if being called outside of `tokio` runtime context.
|
||||
/// The panic behaviour depends on the feature flag being used:
|
||||
///
|
||||
/// ### Native
|
||||
///
|
||||
/// Panics when called outside of a `tokio` runtime context.
|
||||
///
|
||||
/// ### Web
|
||||
///
|
||||
/// If smoldot panics, then the promise created will be leaked. For more details, see
|
||||
/// https://docs.rs/wasm-bindgen-futures/latest/wasm_bindgen_futures/fn.future_to_promise.html.
|
||||
pub async fn build(self, chain_spec: &str) -> Result<LightClient<T>, Error> {
|
||||
let chain_spec = serde_json::from_str(chain_spec)
|
||||
.map_err(|_| Error::LightClient(LightClientError::InvalidChainSpec))?;
|
||||
@@ -136,9 +155,9 @@ impl<T: Config> LightClientBuilder<T> {
|
||||
}
|
||||
}
|
||||
|
||||
let config = AddChainConfig {
|
||||
let config = smoldot::AddChainConfig {
|
||||
specification: &chain_spec.to_string(),
|
||||
json_rpc: AddChainConfigJsonRpc::Enabled {
|
||||
json_rpc: smoldot::AddChainConfigJsonRpc::Enabled {
|
||||
max_pending_requests: self.max_pending_requests,
|
||||
max_subscriptions: self.max_subscriptions,
|
||||
},
|
||||
@@ -147,12 +166,71 @@ impl<T: Config> LightClientBuilder<T> {
|
||||
user_data: (),
|
||||
};
|
||||
|
||||
let rpc_client = RpcClient::new(LightClientRpc::new(config)?);
|
||||
let online_client = OnlineClient::<T>::from_rpc_client(rpc_client).await?;
|
||||
Ok(LightClient(online_client))
|
||||
let raw_rpc = LightClientRpc::new(config)?;
|
||||
build_client_from_rpc(raw_rpc).await
|
||||
}
|
||||
}
|
||||
|
||||
/// Raw builder for [`RawLightClient`].
|
||||
pub struct RawLightClientBuilder {
|
||||
chains: Vec<AddedChain>,
|
||||
}
|
||||
|
||||
impl Default for RawLightClientBuilder {
|
||||
fn default() -> Self {
|
||||
Self { chains: Vec::new() }
|
||||
}
|
||||
}
|
||||
|
||||
impl RawLightClientBuilder {
|
||||
/// Create a new [`RawLightClientBuilder`].
|
||||
pub fn new() -> RawLightClientBuilder {
|
||||
RawLightClientBuilder::default()
|
||||
}
|
||||
|
||||
/// Adds a new chain to the list of chains synchronized by the light client.
|
||||
pub fn add_chain(
|
||||
mut self,
|
||||
chain_id: smoldot::ChainId,
|
||||
rpc_responses: smoldot::JsonRpcResponses,
|
||||
) -> Self {
|
||||
self.chains.push(AddedChain {
|
||||
chain_id,
|
||||
rpc_responses,
|
||||
});
|
||||
self
|
||||
}
|
||||
|
||||
/// Construct a [`RawLightClient`] from a raw smoldot client.
|
||||
///
|
||||
/// The provided `chain_id` is the chain with which the current instance of light client will interact.
|
||||
/// To target a different chain call the [`LightClient::target_chain`] method.
|
||||
pub async fn build<TPlatform: smoldot::PlatformRef>(
|
||||
self,
|
||||
client: smoldot::Client<TPlatform>,
|
||||
) -> Result<RawLightClient, Error> {
|
||||
// The raw subxt light client that spawns the smoldot background task.
|
||||
let raw_rpc: subxt_lightclient::RawLightClientRpc =
|
||||
subxt_lightclient::LightClientRpc::new_from_client(client, self.chains.into_iter());
|
||||
|
||||
// The crate implementation of `RpcClientT` over the raw subxt light client.
|
||||
let raw_rpc = crate::client::light_client::rpc::RawLightClientRpc::from_inner(raw_rpc);
|
||||
|
||||
Ok(RawLightClient { raw_rpc })
|
||||
}
|
||||
}
|
||||
|
||||
/// Build the light client from a raw rpc client.
|
||||
async fn build_client_from_rpc<T: Config>(
|
||||
raw_rpc: LightClientRpc,
|
||||
) -> Result<LightClient<T>, Error> {
|
||||
let chain_id = raw_rpc.chain_id();
|
||||
let rpc_client = RpcClient::new(raw_rpc);
|
||||
let client = OnlineClient::<T>::from_rpc_client(rpc_client).await?;
|
||||
|
||||
Ok(LightClient { client, chain_id })
|
||||
}
|
||||
|
||||
/// Fetch the chain spec from the URL.
|
||||
#[cfg(feature = "jsonrpsee")]
|
||||
async fn fetch_url(url: impl AsRef<str>) -> Result<serde_json::Value, Error> {
|
||||
|
||||
Reference in New Issue
Block a user