subxt_metadata/
lib.rs

1// Copyright 2019-2023 Parity Technologies (UK) Ltd.
2// This file is dual-licensed as Apache-2.0 or GPL-3.0.
3// see LICENSE for license details.
4
5//! A representation of the metadata provided by a substrate based node.
6//! This representation is optimized to be used by Subxt and related crates,
7//! and is independent of the different versions of metadata that can be
8//! provided from a node.
9//!
10//! Typically, this will be constructed by either:
11//!
12//! 1. Calling `Metadata::decode()` given some metadata bytes obtained
13//!    from a node (this uses [`codec::Decode`]).
14//! 2. Obtaining [`frame_metadata::RuntimeMetadataPrefixed`], and then
15//!    using `.try_into()` to convert it into [`Metadata`].
16
17#![cfg_attr(not(feature = "std"), no_std)]
18#![deny(missing_docs)]
19
20extern crate alloc;
21
22mod from_into;
23mod utils;
24
25use alloc::borrow::Cow;
26use alloc::string::String;
27use alloc::sync::Arc;
28use alloc::vec::Vec;
29use frame_decode::extrinsics::{
30    ExtrinsicCallInfo, ExtrinsicExtensionInfo, ExtrinsicInfoArg, ExtrinsicInfoError,
31    ExtrinsicSignatureInfo,
32};
33use hashbrown::HashMap;
34use scale_info::{form::PortableForm, PortableRegistry, Variant};
35use utils::variant_index::VariantIndex;
36use utils::{ordered_map::OrderedMap, validation::outer_enum_hashes::OuterEnumHashes};
37
38type ArcStr = Arc<str>;
39
40use crate::utils::validation::{get_custom_value_hash, HASH_LEN};
41pub use from_into::TryFromError;
42pub use utils::validation::MetadataHasher;
43
44/// Node metadata. This can be constructed by providing some compatible [`frame_metadata`]
45/// which is then decoded into this. We aim to preserve all of the existing information in
46/// the incoming metadata while optimizing the format a little for Subxt's use cases.
47#[derive(Debug, Clone)]
48pub struct Metadata {
49    /// Type registry containing all types used in the metadata.
50    types: PortableRegistry,
51    /// Metadata of all the pallets.
52    pallets: OrderedMap<ArcStr, PalletMetadataInner>,
53    /// Find the location in the pallet Vec by pallet index.
54    pallets_by_index: HashMap<u8, usize>,
55    /// Metadata of the extrinsic.
56    extrinsic: ExtrinsicMetadata,
57    /// The type ID of the `Runtime` type.
58    runtime_ty: u32,
59    /// The types of the outer enums.
60    outer_enums: OuterEnumsMetadata,
61    /// The type Id of the `DispatchError` type, which Subxt makes use of.
62    dispatch_error_ty: Option<u32>,
63    /// Details about each of the runtime API traits.
64    apis: OrderedMap<ArcStr, RuntimeApiMetadataInner>,
65    /// Allows users to add custom types to the metadata. A map that associates a string key to a `CustomValueMetadata`.
66    custom: frame_metadata::v15::CustomMetadata<PortableForm>,
67}
68
69// Since we've abstracted away from frame-metadatas, we impl this on our custom Metadata
70// so that it can be used by `frame-decode` to obtain the relevant extrinsic info.
71impl frame_decode::extrinsics::ExtrinsicTypeInfo for Metadata {
72    type TypeId = u32;
73
74    fn get_call_info(
75        &self,
76        pallet_index: u8,
77        call_index: u8,
78    ) -> Result<ExtrinsicCallInfo<'_, Self::TypeId>, ExtrinsicInfoError<'_>> {
79        let pallet = self.pallet_by_index(pallet_index).ok_or({
80            ExtrinsicInfoError::PalletNotFound {
81                index: pallet_index,
82            }
83        })?;
84
85        let call = pallet.call_variant_by_index(call_index).ok_or_else(|| {
86            ExtrinsicInfoError::CallNotFound {
87                index: call_index,
88                pallet_index,
89                pallet_name: Cow::Borrowed(pallet.name()),
90            }
91        })?;
92
93        Ok(ExtrinsicCallInfo {
94            pallet_name: Cow::Borrowed(pallet.name()),
95            call_name: Cow::Borrowed(&call.name),
96            args: call
97                .fields
98                .iter()
99                .map(|f| ExtrinsicInfoArg {
100                    name: Cow::Borrowed(f.name.as_deref().unwrap_or("")),
101                    id: f.ty.id,
102                })
103                .collect(),
104        })
105    }
106
107    fn get_signature_info(
108        &self,
109    ) -> Result<ExtrinsicSignatureInfo<Self::TypeId>, ExtrinsicInfoError<'_>> {
110        Ok(ExtrinsicSignatureInfo {
111            address_id: self.extrinsic().address_ty(),
112            signature_id: self.extrinsic().signature_ty(),
113        })
114    }
115
116    fn get_extension_info(
117        &self,
118        extension_version: Option<u8>,
119    ) -> Result<ExtrinsicExtensionInfo<'_, Self::TypeId>, ExtrinsicInfoError<'_>> {
120        // For now, if there exists an extension version that's non-zero, we say we don't know
121        // how to decode it. When multiple extension versions exist, we may have to tighten up
122        // on this and require V16 metadata to decode.
123        if let Some(extension_version) = extension_version {
124            if extension_version != 0 {
125                return Err(ExtrinsicInfoError::ExtrinsicExtensionVersionNotSupported {
126                    extension_version,
127                });
128            }
129        }
130
131        Ok(ExtrinsicExtensionInfo {
132            extension_ids: self
133                .extrinsic()
134                .signed_extensions()
135                .iter()
136                .map(|f| ExtrinsicInfoArg {
137                    name: Cow::Borrowed(f.identifier()),
138                    id: f.extra_ty(),
139                })
140                .collect(),
141        })
142    }
143}
144
145impl Metadata {
146    /// Access the underlying type registry.
147    pub fn types(&self) -> &PortableRegistry {
148        &self.types
149    }
150
151    /// Mutable access to the underlying type registry.
152    pub fn types_mut(&mut self) -> &mut PortableRegistry {
153        &mut self.types
154    }
155
156    /// The type ID of the `Runtime` type.
157    pub fn runtime_ty(&self) -> u32 {
158        self.runtime_ty
159    }
160
161    /// The type ID of the `DispatchError` type, if it exists.
162    pub fn dispatch_error_ty(&self) -> Option<u32> {
163        self.dispatch_error_ty
164    }
165
166    /// Return details about the extrinsic format.
167    pub fn extrinsic(&self) -> &ExtrinsicMetadata {
168        &self.extrinsic
169    }
170
171    /// Return details about the outer enums.
172    pub fn outer_enums(&self) -> OuterEnumsMetadata {
173        self.outer_enums
174    }
175
176    /// An iterator over all of the available pallets.
177    pub fn pallets(&self) -> impl ExactSizeIterator<Item = PalletMetadata<'_>> {
178        self.pallets.values().iter().map(|inner| PalletMetadata {
179            inner,
180            types: self.types(),
181        })
182    }
183
184    /// Access a pallet given its encoded variant index.
185    pub fn pallet_by_index(&self, variant_index: u8) -> Option<PalletMetadata<'_>> {
186        let inner = self
187            .pallets_by_index
188            .get(&variant_index)
189            .and_then(|i| self.pallets.get_by_index(*i))?;
190
191        Some(PalletMetadata {
192            inner,
193            types: self.types(),
194        })
195    }
196
197    /// Access a pallet given its name.
198    pub fn pallet_by_name(&self, pallet_name: &str) -> Option<PalletMetadata<'_>> {
199        let inner = self.pallets.get_by_key(pallet_name)?;
200
201        Some(PalletMetadata {
202            inner,
203            types: self.types(),
204        })
205    }
206
207    /// An iterator over all of the runtime APIs.
208    pub fn runtime_api_traits(&self) -> impl ExactSizeIterator<Item = RuntimeApiMetadata<'_>> {
209        self.apis.values().iter().map(|inner| RuntimeApiMetadata {
210            inner,
211            types: self.types(),
212        })
213    }
214
215    /// Access a runtime API trait given its name.
216    pub fn runtime_api_trait_by_name(&'_ self, name: &str) -> Option<RuntimeApiMetadata<'_>> {
217        let inner = self.apis.get_by_key(name)?;
218        Some(RuntimeApiMetadata {
219            inner,
220            types: self.types(),
221        })
222    }
223
224    /// Returns custom user defined types
225    pub fn custom(&self) -> CustomMetadata<'_> {
226        CustomMetadata {
227            types: self.types(),
228            inner: &self.custom,
229        }
230    }
231
232    /// Obtain a unique hash representing this metadata or specific parts of it.
233    pub fn hasher(&self) -> MetadataHasher {
234        MetadataHasher::new(self)
235    }
236
237    /// Filter out any pallets and/or runtime_apis that we don't want to keep, retaining only those that we do.
238    /// Note:
239    /// only filter by `pallet`s will not lead to significant metadata size reduction because the return types are kept to ensure that those can be decoded.
240    ///
241    pub fn retain<F, G>(&mut self, pallet_filter: F, api_filter: G)
242    where
243        F: FnMut(&str) -> bool,
244        G: FnMut(&str) -> bool,
245    {
246        utils::retain::retain_metadata(self, pallet_filter, api_filter);
247    }
248
249    /// Get type hash for a type in the registry
250    pub fn type_hash(&self, id: u32) -> Option<[u8; HASH_LEN]> {
251        self.types.resolve(id)?;
252        Some(crate::utils::validation::get_type_hash(
253            &self.types,
254            id,
255            &OuterEnumHashes::empty(),
256        ))
257    }
258}
259
260/// Metadata for a specific pallet.
261#[derive(Debug, Clone, Copy)]
262pub struct PalletMetadata<'a> {
263    inner: &'a PalletMetadataInner,
264    types: &'a PortableRegistry,
265}
266
267impl<'a> PalletMetadata<'a> {
268    /// The pallet name.
269    pub fn name(&self) -> &'a str {
270        &self.inner.name
271    }
272
273    /// The pallet index.
274    pub fn index(&self) -> u8 {
275        self.inner.index
276    }
277
278    /// The pallet docs.
279    pub fn docs(&self) -> &'a [String] {
280        &self.inner.docs
281    }
282
283    /// Type ID for the pallet's Call type, if it exists.
284    pub fn call_ty_id(&self) -> Option<u32> {
285        self.inner.call_ty
286    }
287
288    /// Type ID for the pallet's Event type, if it exists.
289    pub fn event_ty_id(&self) -> Option<u32> {
290        self.inner.event_ty
291    }
292
293    /// Type ID for the pallet's Error type, if it exists.
294    pub fn error_ty_id(&self) -> Option<u32> {
295        self.inner.error_ty
296    }
297
298    /// Return metadata about the pallet's storage entries.
299    pub fn storage(&self) -> Option<&'a StorageMetadata> {
300        self.inner.storage.as_ref()
301    }
302
303    /// Return all of the event variants, if an event type exists.
304    pub fn event_variants(&self) -> Option<&'a [Variant<PortableForm>]> {
305        VariantIndex::get(self.inner.event_ty, self.types)
306    }
307
308    /// Return an event variant given it's encoded variant index.
309    pub fn event_variant_by_index(&self, variant_index: u8) -> Option<&'a Variant<PortableForm>> {
310        self.inner.event_variant_index.lookup_by_index(
311            variant_index,
312            self.inner.event_ty,
313            self.types,
314        )
315    }
316
317    /// Return all of the call variants, if a call type exists.
318    pub fn call_variants(&self) -> Option<&'a [Variant<PortableForm>]> {
319        VariantIndex::get(self.inner.call_ty, self.types)
320    }
321
322    /// Return a call variant given it's encoded variant index.
323    pub fn call_variant_by_index(&self, variant_index: u8) -> Option<&'a Variant<PortableForm>> {
324        self.inner
325            .call_variant_index
326            .lookup_by_index(variant_index, self.inner.call_ty, self.types)
327    }
328
329    /// Return a call variant given it's name.
330    pub fn call_variant_by_name(&self, call_name: &str) -> Option<&'a Variant<PortableForm>> {
331        self.inner
332            .call_variant_index
333            .lookup_by_name(call_name, self.inner.call_ty, self.types)
334    }
335
336    /// Return all of the error variants, if an error type exists.
337    pub fn error_variants(&self) -> Option<&'a [Variant<PortableForm>]> {
338        VariantIndex::get(self.inner.error_ty, self.types)
339    }
340
341    /// Return an error variant given it's encoded variant index.
342    pub fn error_variant_by_index(&self, variant_index: u8) -> Option<&'a Variant<PortableForm>> {
343        self.inner.error_variant_index.lookup_by_index(
344            variant_index,
345            self.inner.error_ty,
346            self.types,
347        )
348    }
349
350    /// Return constant details given the constant name.
351    pub fn constant_by_name(&self, name: &str) -> Option<&'a ConstantMetadata> {
352        self.inner.constants.get_by_key(name)
353    }
354
355    /// An iterator over the constants in this pallet.
356    pub fn constants(&self) -> impl ExactSizeIterator<Item = &'a ConstantMetadata> {
357        self.inner.constants.values().iter()
358    }
359
360    /// Return a hash for the storage entry, or None if it was not found.
361    pub fn storage_hash(&self, entry_name: &str) -> Option<[u8; HASH_LEN]> {
362        crate::utils::validation::get_storage_hash(self, entry_name)
363    }
364
365    /// Return a hash for the constant, or None if it was not found.
366    pub fn constant_hash(&self, constant_name: &str) -> Option<[u8; HASH_LEN]> {
367        crate::utils::validation::get_constant_hash(self, constant_name)
368    }
369
370    /// Return a hash for the call, or None if it was not found.
371    pub fn call_hash(&self, call_name: &str) -> Option<[u8; HASH_LEN]> {
372        crate::utils::validation::get_call_hash(self, call_name)
373    }
374
375    /// Return a hash for the entire pallet.
376    pub fn hash(&self) -> [u8; HASH_LEN] {
377        crate::utils::validation::get_pallet_hash(*self, &OuterEnumHashes::empty())
378    }
379}
380
381#[derive(Debug, Clone)]
382struct PalletMetadataInner {
383    /// Pallet name.
384    name: ArcStr,
385    /// Pallet index.
386    index: u8,
387    /// Pallet storage metadata.
388    storage: Option<StorageMetadata>,
389    /// Type ID for the pallet Call enum.
390    call_ty: Option<u32>,
391    /// Call variants by name/u8.
392    call_variant_index: VariantIndex,
393    /// Type ID for the pallet Event enum.
394    event_ty: Option<u32>,
395    /// Event variants by name/u8.
396    event_variant_index: VariantIndex,
397    /// Type ID for the pallet Error enum.
398    error_ty: Option<u32>,
399    /// Error variants by name/u8.
400    error_variant_index: VariantIndex,
401    /// Map from constant name to constant details.
402    constants: OrderedMap<ArcStr, ConstantMetadata>,
403    /// Pallet documentation.
404    docs: Vec<String>,
405}
406
407/// Metadata for the storage entries in a pallet.
408#[derive(Debug, Clone)]
409pub struct StorageMetadata {
410    /// The common prefix used by all storage entries.
411    prefix: String,
412    /// Map from storage entry name to details.
413    entries: OrderedMap<ArcStr, StorageEntryMetadata>,
414}
415
416impl StorageMetadata {
417    /// The common prefix used by all storage entries.
418    pub fn prefix(&self) -> &str {
419        &self.prefix
420    }
421
422    /// An iterator over the storage entries.
423    pub fn entries(&self) -> &[StorageEntryMetadata] {
424        self.entries.values()
425    }
426
427    /// Return a specific storage entry given its name.
428    pub fn entry_by_name(&self, name: &str) -> Option<&StorageEntryMetadata> {
429        self.entries.get_by_key(name)
430    }
431}
432
433/// Metadata for a single storage entry.
434#[derive(Debug, Clone)]
435pub struct StorageEntryMetadata {
436    /// Variable name of the storage entry.
437    name: ArcStr,
438    /// An `Option` modifier of that storage entry.
439    modifier: StorageEntryModifier,
440    /// Type of the value stored in the entry.
441    entry_type: StorageEntryType,
442    /// Default value (SCALE encoded).
443    default: Vec<u8>,
444    /// Storage entry documentation.
445    docs: Vec<String>,
446}
447
448impl StorageEntryMetadata {
449    /// Name of this entry.
450    pub fn name(&self) -> &str {
451        &self.name
452    }
453    /// Is the entry value optional or does it have a default value.
454    pub fn modifier(&self) -> StorageEntryModifier {
455        self.modifier
456    }
457    /// Type of the storage entry.
458    pub fn entry_type(&self) -> &StorageEntryType {
459        &self.entry_type
460    }
461    /// The SCALE encoded default value for this entry.
462    pub fn default_bytes(&self) -> &[u8] {
463        &self.default
464    }
465    /// Storage entry documentation.
466    pub fn docs(&self) -> &[String] {
467        &self.docs
468    }
469}
470
471/// The type of a storage entry.
472#[derive(Debug, Clone)]
473pub enum StorageEntryType {
474    /// Plain storage entry (just the value).
475    Plain(u32),
476    /// A storage map.
477    Map {
478        /// One or more hashers, should be one hasher per key element.
479        hashers: Vec<StorageHasher>,
480        /// The type of the key, can be a tuple with elements for each of the hashers.
481        key_ty: u32,
482        /// The type of the value.
483        value_ty: u32,
484    },
485}
486
487impl StorageEntryType {
488    /// The type of the value.
489    pub fn value_ty(&self) -> u32 {
490        match self {
491            StorageEntryType::Map { value_ty, .. } | StorageEntryType::Plain(value_ty) => *value_ty,
492        }
493    }
494
495    /// The type of the key, can be a tuple with elements for each of the hashers. None for a Plain storage entry.
496    pub fn key_ty(&self) -> Option<u32> {
497        match self {
498            StorageEntryType::Map { key_ty, .. } => Some(*key_ty),
499            StorageEntryType::Plain(_) => None,
500        }
501    }
502}
503
504/// Hasher used by storage maps.
505#[derive(Debug, Clone, Copy)]
506pub enum StorageHasher {
507    /// 128-bit Blake2 hash.
508    Blake2_128,
509    /// 256-bit Blake2 hash.
510    Blake2_256,
511    /// Multiple 128-bit Blake2 hashes concatenated.
512    Blake2_128Concat,
513    /// 128-bit XX hash.
514    Twox128,
515    /// 256-bit XX hash.
516    Twox256,
517    /// Multiple 64-bit XX hashes concatenated.
518    Twox64Concat,
519    /// Identity hashing (no hashing).
520    Identity,
521}
522
523impl StorageHasher {
524    /// The hash produced by a [`StorageHasher`] can have these two components, in order:
525    ///
526    /// 1. A fixed size hash. (not present for [`StorageHasher::Identity`]).
527    /// 2. The SCALE encoded key that was used as an input to the hasher (only present for
528    ///    [`StorageHasher::Twox64Concat`], [`StorageHasher::Blake2_128Concat`] or [`StorageHasher::Identity`]).
529    ///
530    /// This function returns the number of bytes used to represent the first of these.
531    pub fn len_excluding_key(&self) -> usize {
532        match self {
533            StorageHasher::Blake2_128Concat => 16,
534            StorageHasher::Twox64Concat => 8,
535            StorageHasher::Blake2_128 => 16,
536            StorageHasher::Blake2_256 => 32,
537            StorageHasher::Twox128 => 16,
538            StorageHasher::Twox256 => 32,
539            StorageHasher::Identity => 0,
540        }
541    }
542
543    /// Returns true if the key used to produce the hash is appended to the hash itself.
544    pub fn ends_with_key(&self) -> bool {
545        matches!(
546            self,
547            StorageHasher::Blake2_128Concat | StorageHasher::Twox64Concat | StorageHasher::Identity
548        )
549    }
550}
551
552/// Is the storage entry optional, or does it have a default value.
553#[derive(Debug, Clone, Copy, Eq, PartialEq)]
554pub enum StorageEntryModifier {
555    /// The storage entry returns an `Option<T>`, with `None` if the key is not present.
556    Optional,
557    /// The storage entry returns `T::Default` if the key is not present.
558    Default,
559}
560
561/// Metadata for a single constant.
562#[derive(Debug, Clone)]
563pub struct ConstantMetadata {
564    /// Name of the pallet constant.
565    name: ArcStr,
566    /// Type of the pallet constant.
567    ty: u32,
568    /// Value stored in the constant (SCALE encoded).
569    value: Vec<u8>,
570    /// Constant documentation.
571    docs: Vec<String>,
572}
573
574impl ConstantMetadata {
575    /// Name of the pallet constant.
576    pub fn name(&self) -> &str {
577        &self.name
578    }
579    /// Type of the pallet constant.
580    pub fn ty(&self) -> u32 {
581        self.ty
582    }
583    /// Value stored in the constant (SCALE encoded).
584    pub fn value(&self) -> &[u8] {
585        &self.value
586    }
587    /// Constant documentation.
588    pub fn docs(&self) -> &[String] {
589        &self.docs
590    }
591}
592
593/// Metadata for the extrinsic type.
594#[derive(Debug, Clone)]
595pub struct ExtrinsicMetadata {
596    /// The type of the address that signs the extrinsic
597    address_ty: u32,
598    /// The type of the outermost Call enum.
599    call_ty: u32,
600    /// The type of the extrinsic's signature.
601    signature_ty: u32,
602    /// The type of the outermost Extra enum.
603    extra_ty: u32,
604    /// Extrinsic version.
605    version: u8,
606    /// The signed extensions in the order they appear in the extrinsic.
607    signed_extensions: Vec<SignedExtensionMetadata>,
608}
609
610impl ExtrinsicMetadata {
611    /// The type of the address that signs the extrinsic
612    pub fn address_ty(&self) -> u32 {
613        self.address_ty
614    }
615
616    /// The type of the outermost Call enum.
617    pub fn call_ty(&self) -> u32 {
618        self.call_ty
619    }
620    /// The type of the extrinsic's signature.
621    pub fn signature_ty(&self) -> u32 {
622        self.signature_ty
623    }
624    /// The type of the outermost Extra enum.
625    pub fn extra_ty(&self) -> u32 {
626        self.extra_ty
627    }
628
629    /// Extrinsic version.
630    pub fn version(&self) -> u8 {
631        self.version
632    }
633
634    /// The extra/additional information associated with the extrinsic.
635    pub fn signed_extensions(&self) -> &[SignedExtensionMetadata] {
636        &self.signed_extensions
637    }
638}
639
640/// Metadata for the signed extensions used by extrinsics.
641#[derive(Debug, Clone)]
642pub struct SignedExtensionMetadata {
643    /// The unique signed extension identifier, which may be different from the type name.
644    identifier: String,
645    /// The type of the signed extension, with the data to be included in the extrinsic.
646    extra_ty: u32,
647    /// The type of the additional signed data, with the data to be included in the signed payload
648    additional_ty: u32,
649}
650
651impl SignedExtensionMetadata {
652    /// The unique signed extension identifier, which may be different from the type name.
653    pub fn identifier(&self) -> &str {
654        &self.identifier
655    }
656    /// The type of the signed extension, with the data to be included in the extrinsic.
657    pub fn extra_ty(&self) -> u32 {
658        self.extra_ty
659    }
660    /// The type of the additional signed data, with the data to be included in the signed payload
661    pub fn additional_ty(&self) -> u32 {
662        self.additional_ty
663    }
664}
665
666/// Metadata for the outer enums.
667#[derive(Debug, Clone, Copy)]
668pub struct OuterEnumsMetadata {
669    /// The type of the outer call enum.
670    call_enum_ty: u32,
671    /// The type of the outer event enum.
672    event_enum_ty: u32,
673    /// The type of the outer error enum.
674    error_enum_ty: u32,
675}
676
677impl OuterEnumsMetadata {
678    /// The type of the outer call enum.
679    pub fn call_enum_ty(&self) -> u32 {
680        self.call_enum_ty
681    }
682
683    /// The type of the outer event enum.
684    pub fn event_enum_ty(&self) -> u32 {
685        self.event_enum_ty
686    }
687
688    /// The type of the outer error enum.
689    pub fn error_enum_ty(&self) -> u32 {
690        self.error_enum_ty
691    }
692}
693
694/// Metadata for the available runtime APIs.
695#[derive(Debug, Clone, Copy)]
696pub struct RuntimeApiMetadata<'a> {
697    inner: &'a RuntimeApiMetadataInner,
698    types: &'a PortableRegistry,
699}
700
701impl<'a> RuntimeApiMetadata<'a> {
702    /// Trait name.
703    pub fn name(&self) -> &'a str {
704        &self.inner.name
705    }
706    /// Trait documentation.
707    pub fn docs(&self) -> &[String] {
708        &self.inner.docs
709    }
710    /// An iterator over the trait methods.
711    pub fn methods(&self) -> impl ExactSizeIterator<Item = &'a RuntimeApiMethodMetadata> {
712        self.inner.methods.values().iter()
713    }
714    /// Get a specific trait method given its name.
715    pub fn method_by_name(&self, name: &str) -> Option<&'a RuntimeApiMethodMetadata> {
716        self.inner.methods.get_by_key(name)
717    }
718    /// Return a hash for the constant, or None if it was not found.
719    pub fn method_hash(&self, method_name: &str) -> Option<[u8; HASH_LEN]> {
720        crate::utils::validation::get_runtime_api_hash(self, method_name)
721    }
722
723    /// Return a hash for the runtime API trait.
724    pub fn hash(&self) -> [u8; HASH_LEN] {
725        crate::utils::validation::get_runtime_trait_hash(*self, &OuterEnumHashes::empty())
726    }
727}
728
729#[derive(Debug, Clone)]
730struct RuntimeApiMetadataInner {
731    /// Trait name.
732    name: ArcStr,
733    /// Trait methods.
734    methods: OrderedMap<ArcStr, RuntimeApiMethodMetadata>,
735    /// Trait documentation.
736    docs: Vec<String>,
737}
738
739/// Metadata for a single runtime API method.
740#[derive(Debug, Clone)]
741pub struct RuntimeApiMethodMetadata {
742    /// Method name.
743    name: ArcStr,
744    /// Method parameters.
745    inputs: Vec<RuntimeApiMethodParamMetadata>,
746    /// Method output type.
747    output_ty: u32,
748    /// Method documentation.
749    docs: Vec<String>,
750}
751
752impl RuntimeApiMethodMetadata {
753    /// Method name.
754    pub fn name(&self) -> &str {
755        &self.name
756    }
757    /// Method documentation.
758    pub fn docs(&self) -> &[String] {
759        &self.docs
760    }
761    /// Method inputs.
762    pub fn inputs(&self) -> impl ExactSizeIterator<Item = &RuntimeApiMethodParamMetadata> {
763        self.inputs.iter()
764    }
765    /// Method return type.
766    pub fn output_ty(&self) -> u32 {
767        self.output_ty
768    }
769}
770
771/// Metadata for a single input parameter to a runtime API method.
772#[derive(Debug, Clone)]
773pub struct RuntimeApiMethodParamMetadata {
774    /// Parameter name.
775    pub name: String,
776    /// Parameter type.
777    pub ty: u32,
778}
779
780/// Metadata of custom types with custom values, basically the same as `frame_metadata::v15::CustomMetadata<PortableForm>>`.
781#[derive(Debug, Clone)]
782pub struct CustomMetadata<'a> {
783    types: &'a PortableRegistry,
784    inner: &'a frame_metadata::v15::CustomMetadata<PortableForm>,
785}
786
787impl<'a> CustomMetadata<'a> {
788    /// Get a certain [CustomValueMetadata] by its name.
789    pub fn get(&self, name: &str) -> Option<CustomValueMetadata<'a>> {
790        self.inner
791            .map
792            .get_key_value(name)
793            .map(|(name, e)| CustomValueMetadata {
794                types: self.types,
795                type_id: e.ty.id,
796                data: &e.value,
797                name,
798            })
799    }
800
801    /// Iterates over names (keys) and associated custom values
802    pub fn iter(&self) -> impl Iterator<Item = CustomValueMetadata> {
803        self.inner.map.iter().map(|(name, e)| CustomValueMetadata {
804            types: self.types,
805            type_id: e.ty.id,
806            data: &e.value,
807            name: name.as_ref(),
808        })
809    }
810
811    /// Access the underlying type registry.
812    pub fn types(&self) -> &PortableRegistry {
813        self.types
814    }
815}
816
817/// Basically the same as `frame_metadata::v15::CustomValueMetadata<PortableForm>>`, but borrowed.
818pub struct CustomValueMetadata<'a> {
819    types: &'a PortableRegistry,
820    type_id: u32,
821    data: &'a [u8],
822    name: &'a str,
823}
824
825impl<'a> CustomValueMetadata<'a> {
826    /// Access the underlying type registry.
827    pub fn types(&self) -> &PortableRegistry {
828        self.types
829    }
830
831    /// The scale encoded value
832    pub fn bytes(&self) -> &'a [u8] {
833        self.data
834    }
835
836    /// The type id in the TypeRegistry
837    pub fn type_id(&self) -> u32 {
838        self.type_id
839    }
840
841    /// The name under which the custom value is registered.
842    pub fn name(&self) -> &str {
843        self.name
844    }
845
846    /// Calculates the hash for the CustomValueMetadata.
847    pub fn hash(&self) -> [u8; HASH_LEN] {
848        get_custom_value_hash(self, &OuterEnumHashes::empty())
849    }
850}
851
852// Support decoding metadata from the "wire" format directly into this.
853// Errors may be lost in the case that the metadata content is somehow invalid.
854impl codec::Decode for Metadata {
855    fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
856        let metadata = frame_metadata::RuntimeMetadataPrefixed::decode(input)?;
857        let metadata = match metadata.1 {
858            frame_metadata::RuntimeMetadata::V14(md) => md.try_into(),
859            frame_metadata::RuntimeMetadata::V15(md) => md.try_into(),
860            _ => return Err("Cannot try_into() to Metadata: unsupported metadata version".into()),
861        };
862
863        metadata.map_err(|_e| "Cannot try_into() to Metadata.".into())
864    }
865}
866
867// Metadata can be encoded, too. It will encode into a format that's compatible with what
868// Subxt requires, and that it can be decoded back from. The actual specifics of the format
869// can change over time.
870impl codec::Encode for Metadata {
871    fn encode_to<T: codec::Output + ?Sized>(&self, dest: &mut T) {
872        let m: frame_metadata::v15::RuntimeMetadataV15 = self.clone().into();
873        let m: frame_metadata::RuntimeMetadataPrefixed = m.into();
874        m.encode_to(dest)
875    }
876}
877
878#[cfg(test)]
879mod test {
880    use super::*;
881    use codec::{Decode, Encode};
882
883    fn load_metadata() -> Vec<u8> {
884        std::fs::read("../artifacts/polkadot_metadata_full.scale").unwrap()
885    }
886
887    // We don't expect to lose any information converting back and forth between
888    // our own representation and the latest version emitted from a node that we can
889    // work with.
890    #[test]
891    fn is_isomorphic_to_v15() {
892        let bytes = load_metadata();
893
894        // Decode into our metadata struct:
895        let metadata = Metadata::decode(&mut &*bytes).unwrap();
896
897        // Convert into v15 metadata:
898        let v15: frame_metadata::v15::RuntimeMetadataV15 = metadata.into();
899        let prefixed = frame_metadata::RuntimeMetadataPrefixed::from(v15);
900
901        // Re-encode that:
902        let new_bytes = prefixed.encode();
903
904        // The bytes should be identical:
905        assert_eq!(bytes, new_bytes);
906    }
907}