avail_rust_client/clients/
online_client.rs

1//! Thin cached view of chain metadata and runtime versions fetched from an RPC endpoint.
2
3use crate::{subxt_core::Metadata, subxt_rpcs::RpcClient};
4use avail_rust_core::{H256, RpcError, ext::codec::Decode, rpc};
5use std::sync::{Arc, RwLock};
6
7/// Shared handle holding runtime metadata and version information.
8#[derive(Clone)]
9pub struct OnlineClient(pub Arc<RwLock<OnlineClientInner>>);
10
11#[derive(Clone)]
12pub struct OnlineClientInner {
13	genesis_hash: H256,
14	spec_version: u32,
15	transaction_version: u32,
16	metadata: Metadata,
17	global_retries: bool,
18}
19
20impl OnlineClient {
21	/// Fetches metadata, runtime version, and genesis hash from the node to bootstrap the client.
22	///
23	/// # Errors
24	/// Propagates any underlying [`RpcError`] raised while querying the node or decoding metadata.
25	pub async fn new(rpc_client: &RpcClient) -> Result<Self, RpcError> {
26		let finalized_hash = rpc::chain::get_finalized_head(rpc_client).await?;
27		let rpc_metadata = rpc::state::get_metadata(rpc_client, Some(finalized_hash)).await?;
28		let genesis_hash = rpc::chainspec::v1_genesishash(rpc_client).await?;
29		let runtime_version = rpc::state::get_runtime_version(rpc_client, Some(finalized_hash)).await?;
30
31		let frame_metadata = frame_metadata::RuntimeMetadataPrefixed::decode(&mut rpc_metadata.as_slice())
32			.map_err(|e| RpcError::DecodingFailed(e.to_string()))?;
33		let metadata = Metadata::try_from(frame_metadata).map_err(|e| RpcError::DecodingFailed(e.to_string()))?;
34		let inner = OnlineClientInner {
35			genesis_hash,
36			spec_version: runtime_version.spec_version,
37			transaction_version: runtime_version.transaction_version,
38			metadata,
39			global_retries: true,
40		};
41		Ok(Self(Arc::new(RwLock::new(inner))))
42	}
43}
44
45impl OnlineClient {
46	/// Returns the cached genesis hash.
47	pub fn genesis_hash(&self) -> H256 {
48		let lock = self.0.read().expect("Should not be poisoned");
49		lock.genesis_hash
50	}
51
52	/// Returns the cached runtime spec version.
53	pub fn spec_version(&self) -> u32 {
54		let lock = self.0.read().expect("Should not be poisoned");
55		lock.spec_version
56	}
57
58	/// Returns the cached runtime transaction version.
59	pub fn transaction_version(&self) -> u32 {
60		let lock = self.0.read().expect("Should not be poisoned");
61		lock.transaction_version
62	}
63
64	/// Returns the cached metadata handle.
65	pub fn metadata(&self) -> Metadata {
66		let lock = self.0.read().expect("Should not be poisoned");
67		lock.metadata.clone()
68	}
69
70	/// Updates the cached genesis hash.
71	pub fn set_genesis_hash(&self, value: H256) {
72		let mut lock = self.0.write().expect("Should not be poisoned");
73		lock.genesis_hash = value;
74	}
75
76	/// Updates the cached runtime spec version.
77	pub fn set_spec_version(&self, value: u32) {
78		let mut lock = self.0.write().expect("Should not be poisoned");
79		lock.spec_version = value;
80	}
81
82	/// Updates the cached runtime transaction version.
83	pub fn set_transaction_version(&self, value: u32) {
84		let mut lock = self.0.write().expect("Should not be poisoned");
85		lock.transaction_version = value;
86	}
87
88	/// Replaces the cached metadata object.
89	pub fn set_metadata(&self, value: Metadata) {
90		let mut lock = self.0.write().expect("Should not be poisoned");
91		lock.metadata = value;
92	}
93
94	/// Reports whether new RPC helpers should retry by default.
95	pub fn is_global_retries_enabled(&self) -> bool {
96		self.0.read().map(|x| x.global_retries).unwrap_or(true)
97	}
98
99	/// Updates the default retry preference for newly created helpers.
100	pub fn set_global_retries_enabled(&self, value: bool) {
101		let mut lock = self.0.write().expect("Should not be poisoned");
102		lock.global_retries = value;
103	}
104}