1#![cfg_attr(not(feature = "std"), no_std)]
21
22#[cfg(feature = "std")]
23use serde::{Serialize, Deserialize};
24#[cfg(feature = "std")]
25use std::fmt;
26#[cfg(feature = "std")]
27use std::collections::HashSet;
28
29use codec::{Encode, Decode};
30use tp_runtime::RuntimeString;
31pub use tp_runtime::create_runtime_str;
32#[doc(hidden)]
33pub use tetcore_std;
34
35#[cfg(feature = "std")]
36use tp_runtime::{traits::Block as BlockT, generic::BlockId};
37
38pub type ApiId = [u8; 8];
40
41pub type ApisVec = tetcore_std::borrow::Cow<'static, [(ApiId, u32)]>;
43
44#[macro_export]
46macro_rules! create_apis_vec {
47 ( $y:expr ) => { $crate::tetcore_std::borrow::Cow::Borrowed(& $y) }
48}
49
50#[derive(Clone, PartialEq, Eq, Encode, Decode, Default, tp_runtime::RuntimeDebug)]
56#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
57#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))]
58pub struct RuntimeVersion {
59 pub spec_name: RuntimeString,
63
64 pub impl_name: RuntimeString,
70
71 pub authoring_version: u32,
74
75 pub spec_version: u32,
79
80 pub impl_version: u32,
87
88 #[cfg_attr(
90 feature = "std",
91 serde(
92 serialize_with = "apis_serialize::serialize",
93 deserialize_with = "apis_serialize::deserialize",
94 )
95 )]
96 pub apis: ApisVec,
97
98 pub transaction_version: u32,
108}
109
110#[cfg(feature = "std")]
111impl fmt::Display for RuntimeVersion {
112 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
113 write!(f, "{}-{} ({}-{}.tx{}.au{})",
114 self.spec_name,
115 self.spec_version,
116 self.impl_name,
117 self.impl_version,
118 self.transaction_version,
119 self.authoring_version,
120 )
121 }
122}
123
124#[cfg(feature = "std")]
125impl RuntimeVersion {
126 pub fn can_call_with(&self, other: &RuntimeVersion) -> bool {
128 self.spec_version == other.spec_version &&
129 self.spec_name == other.spec_name &&
130 self.authoring_version == other.authoring_version
131 }
132
133 pub fn has_api_with<P: Fn(u32) -> bool>(
136 &self,
137 id: &ApiId,
138 predicate: P,
139 ) -> bool {
140 self.apis.iter().any(|(s, v)| s == id && predicate(*v))
141 }
142}
143
144#[cfg(feature = "std")]
145#[derive(Debug)]
146pub struct NativeVersion {
147 pub runtime_version: RuntimeVersion,
149 pub can_author_with: HashSet<u32>,
151}
152
153#[cfg(feature = "std")]
154impl NativeVersion {
155 pub fn can_author_with(&self, other: &RuntimeVersion) -> Result<(), String> {
162 if self.runtime_version.spec_name != other.spec_name {
163 Err(format!(
164 "`spec_name` does not match `{}` vs `{}`",
165 self.runtime_version.spec_name,
166 other.spec_name,
167 ))
168 } else if self.runtime_version.authoring_version != other.authoring_version
169 && !self.can_author_with.contains(&other.authoring_version)
170 {
171 Err(format!(
172 "`authoring_version` does not match `{version}` vs `{other_version}` and \
173 `can_author_with` not contains `{other_version}`",
174 version = self.runtime_version.authoring_version,
175 other_version = other.authoring_version,
176 ))
177 } else {
178 Ok(())
179 }
180 }
181}
182
183#[cfg(feature = "std")]
185pub trait GetRuntimeVersion<Block: BlockT> {
186 fn native_version(&self) -> &NativeVersion;
188
189 fn runtime_version(&self, at: &BlockId<Block>) -> Result<RuntimeVersion, String>;
191}
192
193#[cfg(feature = "std")]
194impl<T: GetRuntimeVersion<Block>, Block: BlockT> GetRuntimeVersion<Block> for std::sync::Arc<T> {
195 fn native_version(&self) -> &NativeVersion {
196 (&**self).native_version()
197 }
198
199 fn runtime_version(&self, at: &BlockId<Block>) -> Result<RuntimeVersion, String> {
200 (&**self).runtime_version(at)
201 }
202}
203
204#[cfg(feature = "std")]
205mod apis_serialize {
206 use super::*;
207 use impl_serde::serialize as bytes;
208 use serde::{Serializer, de, ser::SerializeTuple};
209
210 #[derive(Serialize)]
211 struct ApiId<'a>(
212 #[serde(serialize_with="serialize_bytesref")] &'a super::ApiId,
213 &'a u32,
214 );
215
216 pub fn serialize<S>(apis: &ApisVec, ser: S) -> Result<S::Ok, S::Error> where
217 S: Serializer,
218 {
219 let len = apis.len();
220 let mut seq = ser.serialize_tuple(len)?;
221 for (api, ver) in &**apis {
222 seq.serialize_element(&ApiId(api, ver))?;
223 }
224 seq.end()
225 }
226
227 pub fn serialize_bytesref<S>(&apis: &&super::ApiId, ser: S) -> Result<S::Ok, S::Error> where
228 S: Serializer,
229 {
230 bytes::serialize(apis, ser)
231 }
232
233 #[derive(Deserialize)]
234 struct ApiIdOwned(
235 #[serde(deserialize_with="deserialize_bytes")]
236 super::ApiId,
237 u32,
238 );
239
240 pub fn deserialize<'de, D>(deserializer: D) -> Result<ApisVec, D::Error> where
241 D: de::Deserializer<'de>,
242 {
243 struct Visitor;
244 impl<'de> de::Visitor<'de> for Visitor {
245 type Value = ApisVec;
246
247 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
248 formatter.write_str("a sequence of api id and version tuples")
249 }
250
251 fn visit_seq<V>(self, mut visitor: V) -> Result<Self::Value, V::Error> where
252 V: de::SeqAccess<'de>,
253 {
254 let mut apis = Vec::new();
255 while let Some(value) = visitor.next_element::<ApiIdOwned>()? {
256 apis.push((value.0, value.1));
257 }
258 Ok(apis.into())
259 }
260 }
261 deserializer.deserialize_seq(Visitor)
262 }
263
264 pub fn deserialize_bytes<'de, D>(d: D) -> Result<super::ApiId, D::Error> where
265 D: de::Deserializer<'de>
266 {
267 let mut arr = [0; 8];
268 bytes::deserialize_check_len(d, bytes::ExpectedLen::Exact(&mut arr[..]))?;
269 Ok(arr)
270 }
271}