scale_info_legacy/
chain_types.rs

1// Copyright (C) 2024 Parity Technologies (UK) Ltd. (admin@parity.io)
2// This file is a part of the scale-info-legacy crate.
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8//         http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16//! This module provides a [`ChainTypeRegistry`], which is constructed by deserializing
17//! some data into it. JSON is the expected input format, though in theory others can be
18//! used too.
19
20use crate::type_registry_set::TypeRegistrySet;
21use crate::type_shape::{Field, TypeShape, Variant, VariantDesc};
22use crate::{InsertName, LookupName, RuntimeApiInput, TypeRegistry};
23use alloc::borrow::{Cow, ToOwned};
24use alloc::format;
25use alloc::string::String;
26use alloc::vec;
27use alloc::vec::Vec;
28use hashbrown::HashMap;
29use serde::de::Deserialize;
30use serde::de::Error;
31
32/// A registry of types that's been defined for a specific chain.
33///
34/// Use [`ChainTypeRegistry::for_spec_version()`] to get back something that implements
35/// [`scale_type_resolver::TypeResolver`]. Use [`serde`] to deserialize something into this
36/// struct (the deserialization logic is tuned to work best with `serde_json`, but any self
37/// describing format should work so long as it's the right shape).
38///
39/// # Example
40///
41/// ```rust
42/// use scale_info_legacy::ChainTypeRegistry;
43///
44/// let json = serde_json::json!({
45///     // Types that are present globally, regardless of spec version:
46///     "global": {
47///         // Types here exist across all pallets.
48///         "types": {
49///             // A simple type alias:
50///             "Foo": "u8",
51///             // A tuple:
52///             "TupleOf": "(bool, Vec<String>)",
53///             // An unnamed struct (basically a tuple like "(bool, Vec<String>)" but with a path):
54///             "UnnamedStructOf": ["bool", "Vec<String>"],
55///             // A struct with 2 fields, a and b, and a generic type.
56///             "StructOf<T>": {
57///                 "a": "bool",
58///                 "b": "T"
59///             },
60///             // The simplest way to list enum variants when none have associated data:
61///             "EnumWithoutData": {
62///                 "_enum": ["One", "Two", "Three"]
63///             },
64///             // We can also use a struct form to specify the data that each variant has:
65///             "EnumWithData": {
66///                 "_enum": {
67///                     "A": "u64",
68///                     "B": ["bool", "char"],
69///                     "C": { "field_a": "String", "field_b": "bool" }
70///                 }
71///             },
72///             // We can be very explicit if we want to specify the enum variant indexes:
73///             "EnumWithExplicitDetails": {
74///                 "_enum": [
75///                     { "name": "A", "index": 0, "fields": "u64" },
76///                     { "name": "B", "index": 1, "fields": ["bool", "char"] },
77///                     { "name": "C", "index": 2, "fields": { "field_a": "String", "field_b": "bool" } }
78///                 ]
79///             }
80///         },
81///         // Any type in palletTypes only exists within a certain pallet.
82///         "palletTypes": {
83///             // The Balance type only exists in the balances pallet.
84///             "balances": {
85///                 "Balance": "u64"
86///             },
87///             // Fee and AssetsEnum only exist in the assets pallet.
88///             "assets": {
89///                 "Fee": "u32",
90///                 "AssetsEnum": {
91///                     "_enum": ["One", "Two", "Three"]
92///                 }
93///             }
94///         },
95///         // We can also define runtime APIs. For each runtime API we point to
96///         // types declared elsewhere, rather than defining any new types.
97///         "runtimeApis": {
98///             "Metadata": {
99///                 "metadata_versions": {
100///                     "inputs": [],
101///                     "output": "Vec<u32>"
102///                 },
103///                 "metadata_at_version": {
104///                     "inputs": ["u32"],
105///                     "output": "Option<Vec<u8>>"
106///                 }
107///             }
108///         },
109///     },
110///     // We can define types that are only relevant in a specific spec range.
111///     // We can have overlaps here; later definitions trump earlier ones if so.
112///     "forSpec": [
113///         {
114///             // From 0-1000 (inclusive), we'll use these types.
115///             "range": [null, 1000],
116///             "types": {
117///                 "Foo": "u64",
118///                 "UnnamedStructOf": ["bool", "Vec<String>"],
119///                 "StructOf<T>": { "a": "bool", "b": "T" },
120///             },
121///             "palletTypes": {
122///                 "balances": {
123///                     "Balance": "u128"
124///                 },
125///             }
126///         },
127///         {
128///             // From 1001-2000 (inclusive), we'll use these types.
129///             "range": [1001, 2000],
130///             "types": {
131///                 "Foo": "String",
132///                 "UnnamedStructOf": ["bool", "Vec<String>"],
133///                 "StructOf<T>": { "a": "bool", "b": "T" },
134///             },
135///             // Runtime APIs can also be defined per spec range.
136///             "runtimeApis": {
137///                 "Core": {
138///                     "version": {
139///                         "inputs": [],
140///                         "output": "RuntimeVersion"
141///                     }
142///                 }
143///             }
144///         }
145///     ]
146/// });
147///
148/// let tys: ChainTypeRegistry = serde_json::from_value(json).unwrap();
149/// let resolver = tys.for_spec_version(12345);
150/// ```
151#[derive(Debug, serde::Deserialize)]
152pub struct ChainTypeRegistry {
153    // We always include the built in types at a bare minimum, which we'll put here
154    // so that we can lend it out as a `TypeRegistrySet` when needed.
155    #[serde(skip, default = "TypeRegistry::basic")]
156    basics: TypeRegistry,
157    #[serde(deserialize_with = "deserialize_global")]
158    global: TypeRegistry,
159    #[serde(default, deserialize_with = "deserialize_for_spec", rename = "forSpec")]
160    for_spec: Vec<((u64, u64), TypeRegistry)>,
161}
162
163impl ChainTypeRegistry {
164    /// Create a new empty [`ChainTypeRegistry`]. This does not allocate and can be used as a placeholder
165    /// when no type information is available.
166    pub fn empty() -> Self {
167        ChainTypeRegistry {
168            basics: TypeRegistry::empty(),
169            global: TypeRegistry::empty(),
170            for_spec: Vec::new(),
171        }
172    }
173
174    /// Hand back a [`TypeRegistrySet`] that is able to resolve types for the given spec version.
175    pub fn for_spec_version(&self, spec_version: u64) -> TypeRegistrySet<'_> {
176        let basics = core::iter::once(&self.basics);
177        let globals = core::iter::once(&self.global);
178        let for_spec = self
179            .for_spec
180            .iter()
181            .filter(|((min, max), _)| spec_version >= *min && spec_version <= *max)
182            .map(|(_, types)| types);
183
184        let all = basics.chain(globals).chain(for_spec);
185        TypeRegistrySet::from_iter(all)
186    }
187
188    /// Return the specific spec version ranges that we've defined types for.
189    pub fn spec_version_ranges(&self) -> impl Iterator<Item = (u64, u64)> + use<'_> {
190        self.for_spec.iter().map(|(range, _)| *range)
191    }
192
193    /// Extend this chain type registry with the one provided. In case of any matches, the provided types
194    /// will overwrite the existing ones.
195    pub fn extend(&mut self, other: ChainTypeRegistry) {
196        self.global.extend(other.global);
197        self.for_spec.extend(other.for_spec);
198    }
199}
200
201// Dev note: Everything below relates to deserializing into the above type. Look at the tests to
202// see exactly how each part of the deserializing code works.
203
204fn deserialize_global<'de, D: serde::Deserializer<'de>>(
205    deserializer: D,
206) -> Result<TypeRegistry, D::Error> {
207    let chain_types = DeserializableChainTypes::deserialize(deserializer)?;
208    Ok(chain_types.into_type_registry())
209}
210
211#[allow(clippy::type_complexity)]
212fn deserialize_for_spec<'de, D: serde::Deserializer<'de>>(
213    deserializer: D,
214) -> Result<Vec<((u64, u64), TypeRegistry)>, D::Error> {
215    let for_spec = <Vec<DeserializableChainTypesForSpec>>::deserialize(deserializer)?;
216    Ok(for_spec.into_iter().map(|s| (s.range, s.types.into_type_registry())).collect())
217}
218
219/// This represents the global and per-pallet types for a chain.
220#[derive(serde::Deserialize, Default)]
221pub struct DeserializableChainTypes {
222    #[serde(default)]
223    types: HashMap<InsertName, DeserializableShape>,
224    #[serde(default, rename = "palletTypes")]
225    pallet_types: HashMap<String, HashMap<InsertName, DeserializableShape>>,
226    #[serde(default, rename = "runtimeApis")]
227    runtime_apis: HashMap<String, HashMap<String, DeserializableRuntimeApi>>,
228}
229
230impl DeserializableChainTypes {
231    /// Convert the types that we've deserialized into a [`TypeRegistry`].
232    fn into_type_registry(self) -> TypeRegistry {
233        let global_types = self.types.into_iter().map(|(k, v)| (k, v.into()));
234        let pallet_types = self.pallet_types.into_iter().flat_map(|(pallet, types)| {
235            types.into_iter().map(move |(k, v)| (k.in_pallet(pallet.clone()), v.into()))
236        });
237
238        let mut registry = TypeRegistry::from_iter(global_types.chain(pallet_types));
239
240        // Insert runtime APIs:
241        for (trait_name, methods) in self.runtime_apis {
242            for (method_name, api) in methods {
243                registry.insert_runtime_api(
244                    trait_name.clone(),
245                    method_name,
246                    api.inputs.inputs,
247                    api.output,
248                );
249            }
250        }
251
252        registry
253    }
254}
255
256/// The global and per-pallet types for a chain used within the given spec versions
257#[derive(serde::Deserialize)]
258pub struct DeserializableChainTypesForSpec {
259    #[serde(deserialize_with = "deserialize_spec_range")]
260    range: (u64, u64),
261    #[serde(flatten)]
262    types: DeserializableChainTypes,
263}
264
265// If nulls are given in spec range, we use min or max value for either side.
266fn deserialize_spec_range<'de, D: serde::Deserializer<'de>>(
267    deserializer: D,
268) -> Result<(u64, u64), D::Error> {
269    let (min, max) = <(Option<u64>, Option<u64>)>::deserialize(deserializer)?;
270    Ok((min.unwrap_or(u64::MIN), max.unwrap_or(u64::MAX)))
271}
272
273/// A runtime API method description. A method has 0 or more inputs and some output type.
274#[derive(serde::Deserialize)]
275struct DeserializableRuntimeApi {
276    inputs: DeserializableRuntimeApiInputs,
277    output: LookupName,
278}
279
280/// The inputs to a runtime API, which can be either named or unnamed, either:
281///
282/// - { "name1": "TypeId1", "name2": "TypeId2" }
283/// - ["TypeId1", "TypeId2"]
284struct DeserializableRuntimeApiInputs {
285    inputs: Vec<RuntimeApiInput>,
286}
287
288impl<'de> serde::Deserialize<'de> for DeserializableRuntimeApiInputs {
289    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
290    where
291        D: serde::Deserializer<'de>,
292    {
293        struct DeserializableShapeVisitor;
294        impl<'de> serde::de::Visitor<'de> for DeserializableShapeVisitor {
295            type Value = DeserializableRuntimeApiInputs;
296
297            fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
298                formatter.write_str("a struct or array")
299            }
300
301            // Allow { "argument_name": "ArgumentType", "another_argument_name": "AnotherType" }.
302            // The order of elements _does_ matter here, contrary to how eg JSON objects are interpreted.
303            fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
304            where
305                A: serde::de::MapAccess<'de>,
306            {
307                let mut inputs = vec![];
308                while let Some((name, id)) = map.next_entry::<String, LookupName>()? {
309                    inputs.push(RuntimeApiInput { name, id })
310                }
311                Ok(DeserializableRuntimeApiInputs { inputs })
312            }
313
314            // Allow ["ArgumentType", "AnotherType"].
315            fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
316            where
317                A: serde::de::SeqAccess<'de>,
318            {
319                let mut inputs = vec![];
320                while let Some(lookup_name) = seq.next_element::<LookupName>()? {
321                    inputs.push(lookup_name.into())
322                }
323                Ok(DeserializableRuntimeApiInputs { inputs })
324            }
325
326            // 'null' values are equivalent to no inputs.
327            fn visit_unit<E>(self) -> Result<Self::Value, E>
328            where
329                E: Error,
330            {
331                Ok(DeserializableRuntimeApiInputs { inputs: vec![] })
332            }
333        }
334
335        deserializer.deserialize_any(DeserializableShapeVisitor)
336    }
337}
338
339/// The shape of a type.
340#[allow(clippy::enum_variant_names)]
341#[derive(Debug)]
342#[cfg_attr(test, derive(PartialEq))]
343enum DeserializableShape {
344    AliasOf(LookupName),
345    NamedStructOf(Vec<Field>),
346    UnnamedStructOf(Vec<LookupName>),
347    EnumOf(Vec<Variant>),
348}
349
350impl From<DeserializableShape> for TypeShape {
351    fn from(value: DeserializableShape) -> Self {
352        match value {
353            DeserializableShape::AliasOf(a) => TypeShape::AliasOf(a),
354            DeserializableShape::NamedStructOf(a) => TypeShape::NamedStructOf(a),
355            DeserializableShape::EnumOf(a) => TypeShape::EnumOf(a),
356            DeserializableShape::UnnamedStructOf(a) => TypeShape::UnnamedStructOf(a),
357        }
358    }
359}
360
361impl<'de> serde::Deserialize<'de> for DeserializableShape {
362    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
363    where
364        D: serde::Deserializer<'de>,
365    {
366        struct DeserializableShapeVisitor;
367        impl<'de> serde::de::Visitor<'de> for DeserializableShapeVisitor {
368            type Value = DeserializableShape;
369
370            fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
371                formatter.write_str("a string, struct or array")
372            }
373
374            // A simple alias type name like 'Vec<T>', '(u64, bool)' or 'Foo'.
375            fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
376            where
377                E: serde::de::Error,
378            {
379                let name = LookupName::parse(v)
380                    .map_err(|e| E::custom(format!("Could not deserialize into AliasOf: {e}")))?;
381                Ok(DeserializableShape::AliasOf(name))
382            }
383
384            // Either '{ _enum: ... }' for enum descriptions, or '{ a: ..., b: ... }' for struct descriptions.
385            fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
386            where
387                A: serde::de::MapAccess<'de>,
388            {
389                let Some(name) = map.next_key::<String>()? else {
390                    // Empty map; treat it as an empty struct then:
391                    return Ok(DeserializableShape::NamedStructOf(Vec::new()));
392                };
393
394                // Is the value an enum thing?
395                if name == "_enum" {
396                    let variants: DeserializableEnum = map.next_value()?;
397                    return Ok(DeserializableShape::EnumOf(variants.0));
398                }
399
400                // Otherwise, treat as a struct and deserialize each field, remembering
401                // to deserialize the value for the key we've already deserialized
402                let mut fields = Vec::new();
403                fields.push(Field { name, value: map.next_value()? });
404
405                while let Some((name, value)) = map.next_entry()? {
406                    fields.push(Field { name, value });
407                }
408
409                Ok(DeserializableShape::NamedStructOf(fields))
410            }
411
412            // An array like '["Vec<T>", "bool"]'. Ultimately similar to writing '(Vec<T>, bool)'
413            // to alias to a tuple.
414            fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
415            where
416                A: serde::de::SeqAccess<'de>,
417            {
418                let mut tuple_types = Vec::new();
419                while let Some(lookup_name) = seq.next_element()? {
420                    tuple_types.push(lookup_name)
421                }
422                Ok(DeserializableShape::UnnamedStructOf(tuple_types))
423            }
424
425            // 'null' values are equivalent to '()'.
426            fn visit_unit<E>(self) -> Result<Self::Value, E>
427            where
428                E: Error,
429            {
430                Ok(DeserializableShape::UnnamedStructOf(vec![]))
431            }
432        }
433
434        deserializer.deserialize_any(DeserializableShapeVisitor)
435    }
436}
437
438struct DeserializableEnum(Vec<Variant>);
439
440impl<'de> serde::Deserialize<'de> for DeserializableEnum {
441    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
442    where
443        D: serde::Deserializer<'de>,
444    {
445        struct DeserializableEnumVisitor;
446        impl<'de> serde::de::Visitor<'de> for DeserializableEnumVisitor {
447            type Value = DeserializableEnum;
448
449            fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
450                formatter.write_str("a struct or array of enum variants")
451            }
452
453            fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
454            where
455                A: serde::de::MapAccess<'de>,
456            {
457                let mut variants = Vec::new();
458                let mut index = 0;
459                while let Some((name, value)) =
460                    map.next_entry::<String, DeserializableEnumFields>()?
461                {
462                    variants.push(Variant { index, name, fields: value.0 });
463                    index = index.saturating_add(1);
464                }
465                Ok(DeserializableEnum(variants))
466            }
467
468            fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
469            where
470                A: serde::de::SeqAccess<'de>,
471            {
472                let mut variants = Vec::new();
473                let mut index = 0;
474                while let Some(field) = seq.next_element::<DeserializableEnumSeq>()? {
475                    let variant = match field {
476                        DeserializableEnumSeq::Name(name) => {
477                            Variant { index, name, fields: VariantDesc::UnnamedStructOf(vec![]) }
478                        }
479                        DeserializableEnumSeq::Explicit(variant) => variant,
480                    };
481                    variants.push(variant);
482                    index = index.saturating_add(1);
483                }
484                Ok(DeserializableEnum(variants))
485            }
486        }
487
488        deserializer.deserialize_any(DeserializableEnumVisitor)
489    }
490}
491
492struct DeserializableEnumFields(VariantDesc);
493
494impl<'de> serde::Deserialize<'de> for DeserializableEnumFields {
495    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
496    where
497        D: serde::Deserializer<'de>,
498    {
499        let variant_desc = match DeserializableShape::deserialize(deserializer)? {
500            DeserializableShape::AliasOf(lookup_name) => {
501                VariantDesc::UnnamedStructOf(vec![lookup_name])
502            }
503            DeserializableShape::NamedStructOf(fields) => VariantDesc::NamedStructOf(fields),
504            DeserializableShape::UnnamedStructOf(fields) => VariantDesc::UnnamedStructOf(fields),
505            DeserializableShape::EnumOf(_) => return Err(D::Error::custom("")),
506        };
507        Ok(DeserializableEnumFields(variant_desc))
508    }
509}
510
511enum DeserializableEnumSeq {
512    Name(String),
513    Explicit(Variant),
514}
515
516impl<'de> serde::Deserialize<'de> for DeserializableEnumSeq {
517    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
518    where
519        D: serde::Deserializer<'de>,
520    {
521        struct DeserializableEnumSeqVisitor;
522        impl<'de> serde::de::Visitor<'de> for DeserializableEnumSeqVisitor {
523            type Value = DeserializableEnumSeq;
524
525            fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
526                formatter.write_str("a string representing a variant name, or a struct of variant name, index and fields")
527            }
528
529            fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
530            where
531                E: Error,
532            {
533                Ok(DeserializableEnumSeq::Name(v))
534            }
535
536            fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
537            where
538                E: Error,
539            {
540                self.visit_string(v.to_owned())
541            }
542
543            fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
544            where
545                A: serde::de::MapAccess<'de>,
546            {
547                let mut index: Option<u8> = None;
548                let mut name: Option<String> = None;
549                let mut fields: Option<DeserializableEnumFields> = None;
550
551                while let Some(key) = map.next_key::<Cow<'de, str>>()? {
552                    match &*key {
553                        "index" => {
554                            index = Some(map.next_value()?);
555                        }
556                        "name" => {
557                            name = Some(map.next_value()?);
558                        }
559                        "fields" => {
560                            fields = Some(map.next_value()?);
561                        }
562                        other => {
563                            return Err(A::Error::custom(format!(
564                            "field '{other}' not expected. Expecting 'index', 'name' or 'fields'"
565                        )))
566                        }
567                    }
568                }
569
570                Ok(DeserializableEnumSeq::Explicit(Variant {
571                    index: index.ok_or_else(|| A::Error::custom("field 'index' is missing"))?,
572                    name: name.ok_or_else(|| A::Error::custom("field 'name' is missing"))?,
573                    fields: fields
574                        .unwrap_or(DeserializableEnumFields(VariantDesc::UnnamedStructOf(vec![])))
575                        .0,
576                }))
577            }
578        }
579
580        deserializer.deserialize_any(DeserializableEnumSeqVisitor)
581    }
582}
583
584#[cfg(test)]
585mod test {
586    use super::*;
587    use crate::test_utils::{to_resolved_info, ResolvedTypeInfo};
588    use crate::LookupName;
589    use scale_type_resolver::Primitive;
590
591    fn ln(s: &str) -> LookupName {
592        LookupName::parse(s).unwrap()
593    }
594
595    #[test]
596    fn deserialize_spec_range_works() {
597        let cases = [
598            ("[12, 30]", (12, 30)),
599            ("[null, 30]", (u64::MIN, 30)),
600            ("[1000, null]", (1000, u64::MAX)),
601            ("[null, null]", (u64::MIN, u64::MAX)),
602        ];
603
604        for (range, expected) in cases {
605            let json = format!(r#"{{ "range": {range}, "types": {{}}, "palletTypes": {{}} }}"#);
606            let res = serde_json::from_str::<DeserializableChainTypesForSpec>(&json).unwrap();
607            assert_eq!(res.range, expected);
608        }
609    }
610
611    #[test]
612    fn deserializable_shape_enum_mixed_up_fails() {
613        // Can't mix _enum with other props.
614        let this_should_fail = r#"{ "_enum": ["One", "Two", "Three"], "foo": "u64" }"#;
615        let _ =
616            serde_json::from_str::<DeserializableShape>(this_should_fail).expect_err("should fail");
617    }
618
619    #[test]
620    fn deserializable_shape_works() {
621        let examples = [
622            // Basic alias to some type
623            (r#""Vec<T>""#, DeserializableShape::AliasOf(ln("Vec<T>"))),
624            // Tuples of types
625            (
626                r#"["Vec<T>", "bool"]"#,
627                DeserializableShape::UnnamedStructOf(vec![ln("Vec<T>"), ln("bool")]),
628            ),
629            // Structs of types
630            (
631                r#"{ "a": "Vec<T>", "b": "bool" }"#,
632                DeserializableShape::NamedStructOf(vec![
633                    Field { name: "a".to_owned(), value: ln("Vec<T>") },
634                    Field { name: "b".to_owned(), value: ln("bool") },
635                ]),
636            ),
637            // Enum variants without data
638            (
639                r#"{ "_enum": ["One", "Two", "Three"] }"#,
640                DeserializableShape::EnumOf(vec![
641                    Variant {
642                        index: 0,
643                        name: "One".to_owned(),
644                        fields: VariantDesc::UnnamedStructOf(vec![]),
645                    },
646                    Variant {
647                        index: 1,
648                        name: "Two".to_owned(),
649                        fields: VariantDesc::UnnamedStructOf(vec![]),
650                    },
651                    Variant {
652                        index: 2,
653                        name: "Three".to_owned(),
654                        fields: VariantDesc::UnnamedStructOf(vec![]),
655                    },
656                ]),
657            ),
658            // Enum variants with data
659            (
660                r#"{ "_enum": {"One": ["Vec<T>", "bool"], "Two": null, "Three": {"a": "Vec<T>", "b": "bool"} } }"#,
661                DeserializableShape::EnumOf(vec![
662                    Variant {
663                        index: 0,
664                        name: "One".to_owned(),
665                        fields: VariantDesc::UnnamedStructOf(vec![ln("Vec<T>"), ln("bool")]),
666                    },
667                    Variant {
668                        index: 1,
669                        name: "Two".to_owned(),
670                        fields: VariantDesc::UnnamedStructOf(vec![]),
671                    },
672                    Variant {
673                        index: 2,
674                        name: "Three".to_owned(),
675                        fields: VariantDesc::NamedStructOf(vec![
676                            Field { name: "a".to_owned(), value: ln("Vec<T>") },
677                            Field { name: "b".to_owned(), value: ln("bool") },
678                        ]),
679                    },
680                ]),
681            ),
682            // Enum variants with explicit name, index and fields
683            (
684                r#"{ "_enum": [{ "name": "One", "index": 3, "fields": ["Vec<T>", "bool"] }] }"#,
685                DeserializableShape::EnumOf(vec![Variant {
686                    index: 3,
687                    name: "One".to_owned(),
688                    fields: VariantDesc::UnnamedStructOf(vec![ln("Vec<T>"), ln("bool")]),
689                }]),
690            ),
691        ];
692
693        for (json, expected) in examples {
694            let actual: DeserializableShape =
695                serde_json::from_str(json).unwrap_or_else(|_| panic!("{json} should parse"));
696            assert_eq!(actual, expected);
697        }
698    }
699
700    // Overall sanity check that we can deserialize and work with the whole thing.
701    #[test]
702    fn can_deserialize_from_json() {
703        let json = serde_json::json!({
704            // Types that are present globally, regardless of spec version:
705            "global": {
706                // Types here exist across all pallets.
707                "types": {
708                    // A simple type alias:
709                    "Foo": "u8",
710                    // A tuple:
711                    "TupleOf": "(bool, Vec<String>)",
712                    // An unnamed struct (like a tuple but with a struct name/path):
713                    "UnnamedStructOf": ["bool", "Vec<String>"],
714                    // A struct with 2 fields, a and b, and a generic type.
715                    "StructOf<T>": {
716                        "a": "bool",
717                        "b": "T"
718                    },
719                    // The simplest way to list enum variants when none have associated data:
720                    "EnumWithoutData": {
721                        "_enum": ["One", "Two", "Three"]
722                    },
723                    // We can also use a struct form to specify the data that each variant has:
724                    "EnumWithData": {
725                        "_enum": {
726                            "A": "u64",
727                            "B": ["bool", "char"],
728                            "C": { "field_a": "String", "field_b": "bool" }
729                        }
730                    },
731                    // We can be very explicit if we want to specify the enum variant indexes:
732                    "EnumWithExplicitDetails": {
733                        "_enum": [
734                            { "name": "A", "index": 0, "fields": "u64" },
735                            { "name": "B", "index": 1, "fields": ["bool", "char"] },
736                            { "name": "C", "index": 2, "fields": { "field_a": "String", "field_b": "bool" } }
737                        ]
738                    }
739                },
740                // Any type in palletTypes only exists within a certain pallet.
741                "palletTypes": {
742                    // The Balance type only exists in the balances pallet.
743                    "balances": {
744                        "Balance": "u64"
745                    },
746                    // Fee and AssetsEnum only exist in the assets pallet.
747                    "assets": {
748                        "Fee": "u32",
749                        "AssetsEnum": {
750                            "_enum": ["One", "Two", "Three"]
751                        }
752                    }
753                },
754                // Runtime APIs can be defined too which point to types defined elsewhere.
755                "runtimeApis": {
756                    "Metadata": {
757                        "foo": {
758                            // Inputs can be given as named key/value args.
759                            "inputs": { "a": "u32", "b": "bool", "c": "u16" },
760                            "output": "Vec<u32>"
761                        },
762                        "bar": {
763                            // Inputs can be null
764                            "inputs": null,
765                            "output": "bool"
766                        },
767                        "metadata_at_version": {
768                            // Inputs can be unnamed args.
769                            "inputs": ["u32"],
770                            "output": "Option<Vec<u8>>"
771                        }
772                    }
773                },
774            },
775            // We can define types that are only relevant in a specific spec range.
776            // We can have overlaps here; later definitions trump earlier ones if so.
777            "forSpec": [
778                {
779                    // From 0-1000 (inclusive), we'll use these types.
780                    "range": [null, 1000],
781                    "types": {
782                        "Foo": "u64",
783                        "UnnamedStructOf": ["bool", "Vec<String>"],
784                        "StructOf<T>": { "a": "bool", "b": "T" },
785                    },
786                    "palletTypes": {
787                        "balances": {
788                            "Balance": "u128"
789                        },
790                    }
791                },
792                {
793                    // From 1001-2000 (inclusive), we'll use these types.
794                    "range": [1001, 2000],
795                    "types": {
796                        "Foo": "String",
797                        "UnnamedStructOf": ["bool", "Vec<String>"],
798                        "StructOf<T>": { "a": "bool", "b": "T" },
799                    },
800                    "runtimeApis": {
801                        "Metadata": {
802                            "metadata_at_version": {
803                                "inputs": ["u32"],
804                                "output": "Foo"
805                            }
806                        }
807                    },
808                }
809            ]
810        });
811
812        let tys: ChainTypeRegistry = serde_json::from_value(json).unwrap();
813
814        let resolver = tys.for_spec_version(12345);
815        assert_eq!(to_resolved_info("Foo", &resolver), ResolvedTypeInfo::Primitive(Primitive::U8));
816        assert_eq!(
817            to_resolved_info(ln("Balance").in_pallet("balances"), &resolver),
818            ResolvedTypeInfo::Primitive(Primitive::U64)
819        );
820
821        // Check that named runtime API args work ok:
822        let runtime_api = resolver.runtime_api("Metadata", "foo").expect("Can find Runtime API");
823        assert_eq!(
824            &runtime_api.inputs,
825            &[
826                RuntimeApiInput { name: "a".into(), id: ln("u32") },
827                RuntimeApiInput { name: "b".into(), id: ln("bool") },
828                RuntimeApiInput { name: "c".into(), id: ln("u16") },
829            ]
830        );
831        assert_eq!(&runtime_api.output, &ln("Vec<u32>"));
832
833        // Check that null runtime API args work ok:
834        let runtime_api = resolver.runtime_api("Metadata", "bar").expect("Can find Runtime API");
835        assert_eq!(&runtime_api.inputs, &[]);
836        assert_eq!(&runtime_api.output, &ln("bool"));
837
838        // Check that unnamed runtime APi args work too:
839        let runtime_api =
840            resolver.runtime_api("Metadata", "metadata_at_version").expect("Can find Runtime API");
841        assert_eq!(&runtime_api.inputs, &[RuntimeApiInput { name: "".into(), id: ln("u32") }]);
842        assert_eq!(&runtime_api.output, &ln("Option<Vec<u8>>"));
843
844        let resolver = tys.for_spec_version(500);
845        assert_eq!(to_resolved_info("Foo", &resolver), ResolvedTypeInfo::Primitive(Primitive::U64));
846        assert_eq!(
847            to_resolved_info(ln("Balance").in_pallet("balances"), &resolver),
848            ResolvedTypeInfo::Primitive(Primitive::U128)
849        );
850
851        let runtime_api =
852            resolver.runtime_api("Metadata", "metadata_at_version").expect("Can find Runtime API");
853        assert_eq!(&runtime_api.inputs, &[ln("u32").into()]);
854        assert_eq!(&runtime_api.output, &ln("Option<Vec<u8>>"));
855
856        let resolver = tys.for_spec_version(2000);
857        assert_eq!(to_resolved_info("Foo", &resolver), ResolvedTypeInfo::Primitive(Primitive::Str));
858
859        let runtime_api =
860            resolver.runtime_api("Metadata", "metadata_at_version").expect("Can find Runtime API");
861        assert_eq!(&runtime_api.inputs, &[ln("u32").into()]);
862        assert_eq!(&runtime_api.output, &ln("Foo"));
863    }
864}