substrate_api_client/api/runtime_api/
metadata.rs

1/*
2   Copyright 2024 Supercomputing Systems AG
3   Licensed under the Apache License, Version 2.0 (the "License");
4   you may not use this file except in compliance with the License.
5   You may obtain a copy of the License at
6	   http://www.apache.org/licenses/LICENSE-2.0
7   Unless required by applicable law or agreed to in writing, software
8   distributed under the License is distributed on an "AS IS" BASIS,
9   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10   See the License for the specific language governing permissions and
11   limitations under the License.
12*/
13
14use super::{RuntimeApi, RuntimeApiClient};
15use crate::{api::Result, rpc::Request};
16use ac_node_api::{error::MetadataError, Metadata};
17use ac_primitives::config::Config;
18#[cfg(all(not(feature = "sync-api"), not(feature = "std")))]
19use alloc::boxed::Box;
20use alloc::{
21	string::{String, ToString},
22	vec,
23	vec::Vec,
24};
25use codec::Decode;
26use sp_core::{Encode, OpaqueMetadata};
27
28#[maybe_async::maybe_async(?Send)]
29pub trait MetadataApi: RuntimeApi {
30	type OpaqueMetadata;
31
32	/// Returns the metadata of a runtime.
33	async fn metadata(&self, at_block: Option<Self::Hash>) -> Result<Metadata>;
34
35	/// Returns the opaque metadata of a runtime.
36	async fn opaque_metadata(&self, at_block: Option<Self::Hash>) -> Result<Self::OpaqueMetadata>;
37
38	/// Returns the metadata at a given version.
39	async fn metadata_at_version(
40		&self,
41		version: u32,
42		at_block: Option<Self::Hash>,
43	) -> Result<Option<Metadata>>;
44
45	/// Returns the opaque metadata at a given version.
46	async fn opaque_metadata_at_version(
47		&self,
48		version: u32,
49		at_block: Option<Self::Hash>,
50	) -> Result<Option<Self::OpaqueMetadata>>;
51
52	/// Returns the supported metadata versions.
53	async fn metadata_versions(&self, at_block: Option<Self::Hash>) -> Result<Vec<u32>>;
54
55	// Returns a list of the all available api traits.
56	async fn list_traits(&self, at_block: Option<Self::Hash>) -> Result<Vec<String>>;
57
58	// Returns a list of the method names of a specific trait.
59	async fn list_methods_of_trait(
60		&self,
61		trait_name: &str,
62		at_block: Option<Self::Hash>,
63	) -> Result<Vec<String>>;
64}
65
66#[maybe_async::maybe_async(?Send)]
67impl<T, Client> MetadataApi for RuntimeApiClient<T, Client>
68where
69	T: Config,
70	Client: Request,
71{
72	type OpaqueMetadata = OpaqueMetadata;
73
74	async fn metadata(&self, at_block: Option<Self::Hash>) -> Result<Metadata> {
75		let metadata_bytes = self.opaque_metadata(at_block).await?;
76		let metadata = Metadata::decode(&mut metadata_bytes.as_slice())?;
77		Ok(metadata)
78	}
79
80	async fn opaque_metadata(&self, at_block: Option<Self::Hash>) -> Result<Self::OpaqueMetadata> {
81		self.runtime_call("Metadata_metadata", vec![], at_block).await
82	}
83
84	async fn metadata_at_version(
85		&self,
86		version: u32,
87		at_block: Option<Self::Hash>,
88	) -> Result<Option<Metadata>> {
89		let metadata_bytes = self.opaque_metadata_at_version(version, at_block).await?;
90		let metadata = match metadata_bytes {
91			Some(bytes) => Some(Metadata::decode(&mut bytes.as_slice())?),
92			None => None,
93		};
94		Ok(metadata)
95	}
96
97	async fn opaque_metadata_at_version(
98		&self,
99		version: u32,
100		at_block: Option<Self::Hash>,
101	) -> Result<Option<Self::OpaqueMetadata>> {
102		self.runtime_call("Metadata_metadata_at_version", vec![version.encode()], at_block)
103			.await
104	}
105
106	async fn metadata_versions(&self, at_block: Option<Self::Hash>) -> Result<Vec<u32>> {
107		self.runtime_call("Metadata_metadata_versions", vec![], at_block).await
108	}
109
110	async fn list_traits(&self, at_block: Option<Self::Hash>) -> Result<Vec<String>> {
111		let metadata = self.get_metadata_v15(at_block).await?;
112		let trait_names = metadata
113			.runtime_api_traits()
114			.map(|substrate_trait| substrate_trait.name().to_string())
115			.collect();
116
117		Ok(trait_names)
118	}
119
120	async fn list_methods_of_trait(
121		&self,
122		trait_name: &str,
123		at_block: Option<Self::Hash>,
124	) -> Result<Vec<String>> {
125		let metadata = self.get_metadata_v15(at_block).await?;
126		let maybe_runtime_api_metadata = metadata
127			.runtime_api_traits()
128			.find(|substrate_trait| substrate_trait.name() == trait_name);
129
130		let methods = match maybe_runtime_api_metadata {
131			Some(trait_metadata) =>
132				trait_metadata.methods().map(|method| method.name.clone()).collect(),
133			None => return Err(MetadataError::RuntimeApiNotFound(trait_name.to_string()).into()),
134		};
135		Ok(methods)
136	}
137}
138
139impl<T, Client> RuntimeApiClient<T, Client>
140where
141	T: Config,
142	Client: Request,
143{
144	#[maybe_async::maybe_async(?Send)]
145	async fn get_metadata_v15(&self, at_block: Option<T::Hash>) -> Result<Metadata> {
146		self.metadata_at_version(15, at_block)
147			.await?
148			.ok_or(MetadataError::RuntimeApiNotFound("No metadata v15 found".to_string()).into())
149	}
150}