From 21491e707982e439e0adb5b0a33f9d8b3e0e3801 Mon Sep 17 00:00:00 2001 From: James Wilson Date: Wed, 18 Jan 2023 11:24:45 +0000 Subject: [PATCH 1/4] Add _at and _with methods to OnlineClient to allow for more instantiation options --- subxt/src/client/online_client.rs | 89 +++++++++++++++++++++++++++---- 1 file changed, 80 insertions(+), 9 deletions(-) diff --git a/subxt/src/client/online_client.rs b/subxt/src/client/online_client.rs index 01ea563fbe..aa20c6f082 100644 --- a/subxt/src/client/online_client.rs +++ b/subxt/src/client/online_client.rs @@ -71,16 +71,43 @@ impl OnlineClient { /// Construct a new [`OnlineClient`] using default settings which /// point to a locally running node on `ws://127.0.0.1:9944`. pub async fn new() -> Result, Error> { + OnlineClient::new_at(None).await + } + + /// Construct a new [`OnlineClient`] using default settings which + /// point to a locally running node on `ws://127.0.0.1:9944`. + /// + /// # Warning + /// + /// If you use this function, you take responsibility for knowing which blocks this + /// client will be capable of interacting with successfully. For example, subscriptions + /// to recent blocks and submitting transactions may fail. + pub async fn new_at(block_hash: Option) -> Result, Error> { let url = "ws://127.0.0.1:9944"; - OnlineClient::from_url(url).await + OnlineClient::from_url_at(url, block_hash).await } /// Construct a new [`OnlineClient`], providing a URL to connect to. pub async fn from_url(url: impl AsRef) -> Result, Error> { + OnlineClient::from_url_at(url, None).await + } + + /// Construct a new [`OnlineClient`], providing a URL to connect to and a block + /// hash from which to load metadata and runtime information. + /// + /// # Warning + /// + /// If you use this function, you take responsibility for knowing which blocks this + /// client will be capable of interacting with successfully. For example, subscriptions + /// to recent blocks and submitting transactions may fail. + pub async fn from_url_at( + url: impl AsRef, + block_hash: Option, + ) -> Result, Error> { 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 + OnlineClient::from_rpc_client_at(Arc::new(client), block_hash).await } } @@ -90,22 +117,66 @@ impl OnlineClient { pub async fn from_rpc_client( rpc_client: Arc, ) -> Result, Error> { - let rpc = Rpc::new(rpc_client); + OnlineClient::from_rpc_client_at(rpc_client, None).await + } + /// Construct a new [`OnlineClient`] by providing an underlying [`RpcClientT`] + /// implementation to drive the connection, as well as a block hash from which to + /// obtain the metadata information from. + /// + /// # Warning + /// + /// If you use this function, you take responsibility for knowing which blocks this + /// client will be capable of interacting with successfully. For example, subscriptions + /// to recent blocks and submitting transactions may fail. + pub async fn from_rpc_client_at( + rpc_client: Arc, + block_hash: Option, + ) -> Result, Error> { + let rpc = Rpc::::new(rpc_client.clone()); let (genesis_hash, runtime_version, metadata) = future::join3( rpc.genesis_hash(), - rpc.runtime_version(None), - rpc.metadata(None), + // This _could_ always be the latest runtime version, but offhand it makes sense to keep + // it consistent with the block hash provided, so that if we were to ask for it, we'd see + // it at that point. + rpc.runtime_version(block_hash), + rpc.metadata(block_hash), ) .await; + OnlineClient::from_rpc_client_with( + genesis_hash?, + runtime_version?, + metadata?, + rpc_client, + ) + } + + /// Construct a new [`OnlineClient`] by providing all of the underlying details needed + /// to make it work. + /// + /// # Warning + /// + /// This is considered the most primitive and also error prone way to + /// instantiate a client; the genesis hash, metadata and runtime version provided will + /// entirely determine which node and blocks this client will be able to interact with, + /// and whether it will be able to successfully do things like submit transactions. + /// + /// If you're unsure what you're doing, prefer one of the alternate methods to instantiate + /// a client. + pub fn from_rpc_client_with( + genesis_hash: T::Hash, + runtime_version: RuntimeVersion, + metadata: Metadata, + rpc_client: Arc, + ) -> Result, Error> { Ok(OnlineClient { inner: Arc::new(RwLock::new(Inner { - genesis_hash: genesis_hash?, - runtime_version: runtime_version?, - metadata: metadata?, + genesis_hash, + runtime_version, + metadata, })), - rpc, + rpc: Rpc::new(rpc_client), }) } From a7e38d4cbf649125616579345819dcdb5e240885 Mon Sep 17 00:00:00 2001 From: James Wilson Date: Wed, 18 Jan 2023 11:30:21 +0000 Subject: [PATCH 2/4] tweak warnings --- subxt/src/client/online_client.rs | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/subxt/src/client/online_client.rs b/subxt/src/client/online_client.rs index aa20c6f082..a2782929eb 100644 --- a/subxt/src/client/online_client.rs +++ b/subxt/src/client/online_client.rs @@ -79,9 +79,12 @@ impl OnlineClient { /// /// # Warning /// - /// If you use this function, you take responsibility for knowing which blocks this - /// client will be capable of interacting with successfully. For example, subscriptions - /// to recent blocks and submitting transactions may fail. + /// - If you use this function, subxt will be unable to work with blocks that aren't + /// compatible with the metadata at the provided block hash, and if the block hash is + /// not recent, things like subscribing to the head of the chain and submitting + /// transactions will likely fail or encounter errors. + /// - Subxt does not support blocks using pre-V14 metadata and will error if you attempt + /// to instantiate a client at such a block. pub async fn new_at(block_hash: Option) -> Result, Error> { let url = "ws://127.0.0.1:9944"; OnlineClient::from_url_at(url, block_hash).await @@ -97,9 +100,12 @@ impl OnlineClient { /// /// # Warning /// - /// If you use this function, you take responsibility for knowing which blocks this - /// client will be capable of interacting with successfully. For example, subscriptions - /// to recent blocks and submitting transactions may fail. + /// - If you use this function, subxt will be unable to work with blocks that aren't + /// compatible with the metadata at the provided block hash, and if the block hash is + /// not recent, things like subscribing to the head of the chain and submitting + /// transactions will likely fail or encounter errors. + /// - Subxt does not support blocks using pre-V14 metadata and will error if you attempt + /// to instantiate a client at such a block. pub async fn from_url_at( url: impl AsRef, block_hash: Option, @@ -126,9 +132,12 @@ impl OnlineClient { /// /// # Warning /// - /// If you use this function, you take responsibility for knowing which blocks this - /// client will be capable of interacting with successfully. For example, subscriptions - /// to recent blocks and submitting transactions may fail. + /// - If you use this function, subxt will be unable to work with blocks that aren't + /// compatible with the metadata at the provided block hash, and if the block hash is + /// not recent, things like subscribing to the head of the chain and submitting + /// transactions will likely fail or encounter errors. + /// - Subxt does not support blocks using pre-V14 metadata and will error if you attempt + /// to instantiate a client at such a block. pub async fn from_rpc_client_at( rpc_client: Arc, block_hash: Option, From 6c20eafb34d62a9f8498aacafc0e754201ccf16b Mon Sep 17 00:00:00 2001 From: James Wilson Date: Wed, 18 Jan 2023 15:18:01 +0000 Subject: [PATCH 3/4] move a confusing comment --- subxt/src/client/online_client.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/subxt/src/client/online_client.rs b/subxt/src/client/online_client.rs index a2782929eb..4915fae994 100644 --- a/subxt/src/client/online_client.rs +++ b/subxt/src/client/online_client.rs @@ -145,9 +145,6 @@ impl OnlineClient { let rpc = Rpc::::new(rpc_client.clone()); let (genesis_hash, runtime_version, metadata) = future::join3( rpc.genesis_hash(), - // This _could_ always be the latest runtime version, but offhand it makes sense to keep - // it consistent with the block hash provided, so that if we were to ask for it, we'd see - // it at that point. rpc.runtime_version(block_hash), rpc.metadata(block_hash), ) From acf21f0ca20988f460d74eb0966cbc84b45b8504 Mon Sep 17 00:00:00 2001 From: James Wilson Date: Wed, 18 Jan 2023 16:01:43 +0000 Subject: [PATCH 4/4] expose ability to set metadata and such in OnlineClient, but remove most _at methods --- subxt/src/client/mod.rs | 6 ++ subxt/src/client/online_client.rs | 109 ++++++++++++++---------------- 2 files changed, 56 insertions(+), 59 deletions(-) diff --git a/subxt/src/client/mod.rs b/subxt/src/client/mod.rs index 8ec0d3c78c..f056abde9d 100644 --- a/subxt/src/client/mod.rs +++ b/subxt/src/client/mod.rs @@ -23,3 +23,9 @@ pub use online_client::{ Update, UpgradeError, }; + +#[cfg(any( + feature = "jsonrpsee-ws", + all(feature = "jsonrpsee-web", target_arch = "wasm32") +))] +pub use online_client::default_rpc_client; diff --git a/subxt/src/client/online_client.rs b/subxt/src/client/online_client.rs index 4915fae994..303487a8b6 100644 --- a/subxt/src/client/online_client.rs +++ b/subxt/src/client/online_client.rs @@ -62,6 +62,18 @@ impl std::fmt::Debug for OnlineClient { } } +/// The default RPC client that's used (based on [`jsonrpsee`]). +#[cfg(any( + feature = "jsonrpsee-ws", + all(feature = "jsonrpsee-web", target_arch = "wasm32") +))] +pub async fn default_rpc_client>(url: U) -> Result { + let client = jsonrpsee_helpers::client(url.as_ref()) + .await + .map_err(|e| crate::error::RpcError::ClientError(Box::new(e)))?; + Ok(client) +} + // The default constructors assume Jsonrpsee. #[cfg(any( feature = "jsonrpsee-ws", @@ -71,49 +83,14 @@ impl OnlineClient { /// Construct a new [`OnlineClient`] using default settings which /// point to a locally running node on `ws://127.0.0.1:9944`. pub async fn new() -> Result, Error> { - OnlineClient::new_at(None).await - } - - /// Construct a new [`OnlineClient`] using default settings which - /// point to a locally running node on `ws://127.0.0.1:9944`. - /// - /// # Warning - /// - /// - If you use this function, subxt will be unable to work with blocks that aren't - /// compatible with the metadata at the provided block hash, and if the block hash is - /// not recent, things like subscribing to the head of the chain and submitting - /// transactions will likely fail or encounter errors. - /// - Subxt does not support blocks using pre-V14 metadata and will error if you attempt - /// to instantiate a client at such a block. - pub async fn new_at(block_hash: Option) -> Result, Error> { let url = "ws://127.0.0.1:9944"; - OnlineClient::from_url_at(url, block_hash).await + OnlineClient::from_url(url).await } /// Construct a new [`OnlineClient`], providing a URL to connect to. pub async fn from_url(url: impl AsRef) -> Result, Error> { - OnlineClient::from_url_at(url, None).await - } - - /// Construct a new [`OnlineClient`], providing a URL to connect to and a block - /// hash from which to load metadata and runtime information. - /// - /// # Warning - /// - /// - If you use this function, subxt will be unable to work with blocks that aren't - /// compatible with the metadata at the provided block hash, and if the block hash is - /// not recent, things like subscribing to the head of the chain and submitting - /// transactions will likely fail or encounter errors. - /// - Subxt does not support blocks using pre-V14 metadata and will error if you attempt - /// to instantiate a client at such a block. - pub async fn from_url_at( - url: impl AsRef, - block_hash: Option, - ) -> Result, Error> { - let client = jsonrpsee_helpers::client(url.as_ref()) - .await - .map_err(|e| crate::error::RpcError::ClientError(Box::new(e)))?; - OnlineClient::from_rpc_client_at(Arc::new(client), block_hash).await + let client = default_rpc_client(url).await?; + OnlineClient::from_rpc_client(Arc::new(client)).await } } @@ -122,31 +99,12 @@ impl OnlineClient { /// implementation to drive the connection. pub async fn from_rpc_client( rpc_client: Arc, - ) -> Result, Error> { - OnlineClient::from_rpc_client_at(rpc_client, None).await - } - - /// Construct a new [`OnlineClient`] by providing an underlying [`RpcClientT`] - /// implementation to drive the connection, as well as a block hash from which to - /// obtain the metadata information from. - /// - /// # Warning - /// - /// - If you use this function, subxt will be unable to work with blocks that aren't - /// compatible with the metadata at the provided block hash, and if the block hash is - /// not recent, things like subscribing to the head of the chain and submitting - /// transactions will likely fail or encounter errors. - /// - Subxt does not support blocks using pre-V14 metadata and will error if you attempt - /// to instantiate a client at such a block. - pub async fn from_rpc_client_at( - rpc_client: Arc, - block_hash: Option, ) -> Result, Error> { let rpc = Rpc::::new(rpc_client.clone()); let (genesis_hash, runtime_version, metadata) = future::join3( rpc.genesis_hash(), - rpc.runtime_version(block_hash), - rpc.metadata(block_hash), + rpc.runtime_version(None), + rpc.metadata(None), ) .await; @@ -237,18 +195,51 @@ impl OnlineClient { inner.metadata.clone() } + /// Change the [`Metadata`] used in this client. + /// + /// # Warning + /// + /// Setting custom metadata may leave Subxt unable to work with certain blocks, + /// subscribe to latest blocks or submit valid transactions. + pub fn set_metadata(&self, metadata: Metadata) { + let mut inner = self.inner.write(); + inner.metadata = metadata; + } + /// Return the genesis hash. pub fn genesis_hash(&self) -> T::Hash { let inner = self.inner.read(); inner.genesis_hash } + /// Change the genesis hash used in this client. + /// + /// # Warning + /// + /// Setting a custom genesis hash may leave Subxt unable to + /// submit valid transactions. + pub fn set_genesis_hash(&self, genesis_hash: T::Hash) { + let mut inner = self.inner.write(); + inner.genesis_hash = genesis_hash; + } + /// Return the runtime version. pub fn runtime_version(&self) -> RuntimeVersion { let inner = self.inner.read(); inner.runtime_version.clone() } + /// Change the [`RuntimeVersion`] used in this client. + /// + /// # Warning + /// + /// Setting a custom runtime version may leave Subxt unable to + /// submit valid transactions. + pub fn set_runtime_version(&self, runtime_version: RuntimeVersion) { + let mut inner = self.inner.write(); + inner.runtime_version = runtime_version; + } + /// Return an RPC client to make raw requests with. pub fn rpc(&self) -> &Rpc { &self.rpc