subxt_metadata/
lib.rs

1// Copyright 2019-2025 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                .transaction_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    /// Which extrinsic versions are supported by this chain.
605    supported_versions: Vec<u8>,
606    /// The signed extensions in the order they appear in the extrinsic.
607    transaction_extensions: Vec<TransactionExtensionMetadata>,
608    /// Version of the transaction extensions.
609    // TODO [jsdw]: V16 metadata groups transaction extensions by version.
610    // need to work out what to do once there is more than one version to deal with.
611    transaction_extensions_version: u8,
612}
613
614impl ExtrinsicMetadata {
615    /// The type of the address that signs the extrinsic
616    pub fn address_ty(&self) -> u32 {
617        self.address_ty
618    }
619
620    /// The type of the outermost Call enum.
621    pub fn call_ty(&self) -> u32 {
622        self.call_ty
623    }
624    /// The type of the extrinsic's signature.
625    pub fn signature_ty(&self) -> u32 {
626        self.signature_ty
627    }
628    /// The type of the outermost Extra enum.
629    pub fn extra_ty(&self) -> u32 {
630        self.extra_ty
631    }
632
633    /// Which extrinsic versions are supported.
634    pub fn supported_versions(&self) -> &[u8] {
635        &self.supported_versions
636    }
637
638    /// The extra/additional information associated with the extrinsic.
639    pub fn transaction_extensions(&self) -> &[TransactionExtensionMetadata] {
640        &self.transaction_extensions
641    }
642
643    /// Which version are these transaction extensions?
644    pub fn transaction_extensions_version(&self) -> u8 {
645        self.transaction_extensions_version
646    }
647}
648
649/// Metadata for the signed extensions used by extrinsics.
650#[derive(Debug, Clone)]
651pub struct TransactionExtensionMetadata {
652    /// The unique signed extension identifier, which may be different from the type name.
653    identifier: String,
654    /// The type of the signed extension, with the data to be included in the extrinsic.
655    extra_ty: u32,
656    /// The type of the additional signed data, with the data to be included in the signed payload
657    additional_ty: u32,
658}
659
660impl TransactionExtensionMetadata {
661    /// The unique signed extension identifier, which may be different from the type name.
662    pub fn identifier(&self) -> &str {
663        &self.identifier
664    }
665    /// The type of the signed extension, with the data to be included in the extrinsic.
666    pub fn extra_ty(&self) -> u32 {
667        self.extra_ty
668    }
669    /// The type of the additional signed data, with the data to be included in the signed payload
670    pub fn additional_ty(&self) -> u32 {
671        self.additional_ty
672    }
673}
674
675/// Metadata for the outer enums.
676#[derive(Debug, Clone, Copy)]
677pub struct OuterEnumsMetadata {
678    /// The type of the outer call enum.
679    call_enum_ty: u32,
680    /// The type of the outer event enum.
681    event_enum_ty: u32,
682    /// The type of the outer error enum.
683    error_enum_ty: u32,
684}
685
686impl OuterEnumsMetadata {
687    /// The type of the outer call enum.
688    pub fn call_enum_ty(&self) -> u32 {
689        self.call_enum_ty
690    }
691
692    /// The type of the outer event enum.
693    pub fn event_enum_ty(&self) -> u32 {
694        self.event_enum_ty
695    }
696
697    /// The type of the outer error enum.
698    pub fn error_enum_ty(&self) -> u32 {
699        self.error_enum_ty
700    }
701}
702
703/// Metadata for the available runtime APIs.
704#[derive(Debug, Clone, Copy)]
705pub struct RuntimeApiMetadata<'a> {
706    inner: &'a RuntimeApiMetadataInner,
707    types: &'a PortableRegistry,
708}
709
710impl<'a> RuntimeApiMetadata<'a> {
711    /// Trait name.
712    pub fn name(&self) -> &'a str {
713        &self.inner.name
714    }
715    /// Trait documentation.
716    pub fn docs(&self) -> &[String] {
717        &self.inner.docs
718    }
719    /// An iterator over the trait methods.
720    pub fn methods(&self) -> impl ExactSizeIterator<Item = &'a RuntimeApiMethodMetadata> {
721        self.inner.methods.values().iter()
722    }
723    /// Get a specific trait method given its name.
724    pub fn method_by_name(&self, name: &str) -> Option<&'a RuntimeApiMethodMetadata> {
725        self.inner.methods.get_by_key(name)
726    }
727    /// Return a hash for the constant, or None if it was not found.
728    pub fn method_hash(&self, method_name: &str) -> Option<[u8; HASH_LEN]> {
729        crate::utils::validation::get_runtime_api_hash(self, method_name)
730    }
731
732    /// Return a hash for the runtime API trait.
733    pub fn hash(&self) -> [u8; HASH_LEN] {
734        crate::utils::validation::get_runtime_trait_hash(*self, &OuterEnumHashes::empty())
735    }
736}
737
738#[derive(Debug, Clone)]
739struct RuntimeApiMetadataInner {
740    /// Trait name.
741    name: ArcStr,
742    /// Trait methods.
743    methods: OrderedMap<ArcStr, RuntimeApiMethodMetadata>,
744    /// Trait documentation.
745    docs: Vec<String>,
746}
747
748/// Metadata for a single runtime API method.
749#[derive(Debug, Clone)]
750pub struct RuntimeApiMethodMetadata {
751    /// Method name.
752    name: ArcStr,
753    /// Method parameters.
754    inputs: Vec<RuntimeApiMethodParamMetadata>,
755    /// Method output type.
756    output_ty: u32,
757    /// Method documentation.
758    docs: Vec<String>,
759}
760
761impl RuntimeApiMethodMetadata {
762    /// Method name.
763    pub fn name(&self) -> &str {
764        &self.name
765    }
766    /// Method documentation.
767    pub fn docs(&self) -> &[String] {
768        &self.docs
769    }
770    /// Method inputs.
771    pub fn inputs(&self) -> impl ExactSizeIterator<Item = &RuntimeApiMethodParamMetadata> {
772        self.inputs.iter()
773    }
774    /// Method return type.
775    pub fn output_ty(&self) -> u32 {
776        self.output_ty
777    }
778}
779
780/// Metadata for a single input parameter to a runtime API method.
781#[derive(Debug, Clone)]
782pub struct RuntimeApiMethodParamMetadata {
783    /// Parameter name.
784    pub name: String,
785    /// Parameter type.
786    pub ty: u32,
787}
788
789/// Metadata of custom types with custom values, basically the same as `frame_metadata::v15::CustomMetadata<PortableForm>>`.
790#[derive(Debug, Clone)]
791pub struct CustomMetadata<'a> {
792    types: &'a PortableRegistry,
793    inner: &'a frame_metadata::v15::CustomMetadata<PortableForm>,
794}
795
796impl<'a> CustomMetadata<'a> {
797    /// Get a certain [CustomValueMetadata] by its name.
798    pub fn get(&self, name: &str) -> Option<CustomValueMetadata<'a>> {
799        self.inner
800            .map
801            .get_key_value(name)
802            .map(|(name, e)| CustomValueMetadata {
803                types: self.types,
804                type_id: e.ty.id,
805                data: &e.value,
806                name,
807            })
808    }
809
810    /// Iterates over names (keys) and associated custom values
811    pub fn iter(&self) -> impl Iterator<Item = CustomValueMetadata> {
812        self.inner.map.iter().map(|(name, e)| CustomValueMetadata {
813            types: self.types,
814            type_id: e.ty.id,
815            data: &e.value,
816            name: name.as_ref(),
817        })
818    }
819
820    /// Access the underlying type registry.
821    pub fn types(&self) -> &PortableRegistry {
822        self.types
823    }
824}
825
826/// Basically the same as `frame_metadata::v15::CustomValueMetadata<PortableForm>>`, but borrowed.
827pub struct CustomValueMetadata<'a> {
828    types: &'a PortableRegistry,
829    type_id: u32,
830    data: &'a [u8],
831    name: &'a str,
832}
833
834impl<'a> CustomValueMetadata<'a> {
835    /// Access the underlying type registry.
836    pub fn types(&self) -> &PortableRegistry {
837        self.types
838    }
839
840    /// The scale encoded value
841    pub fn bytes(&self) -> &'a [u8] {
842        self.data
843    }
844
845    /// The type id in the TypeRegistry
846    pub fn type_id(&self) -> u32 {
847        self.type_id
848    }
849
850    /// The name under which the custom value is registered.
851    pub fn name(&self) -> &str {
852        self.name
853    }
854
855    /// Calculates the hash for the CustomValueMetadata.
856    pub fn hash(&self) -> [u8; HASH_LEN] {
857        get_custom_value_hash(self, &OuterEnumHashes::empty())
858    }
859}
860
861// Support decoding metadata from the "wire" format directly into this.
862// Errors may be lost in the case that the metadata content is somehow invalid.
863impl codec::Decode for Metadata {
864    fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
865        let metadata = frame_metadata::RuntimeMetadataPrefixed::decode(input)?;
866        let metadata = match metadata.1 {
867            frame_metadata::RuntimeMetadata::V14(md) => md.try_into(),
868            frame_metadata::RuntimeMetadata::V15(md) => md.try_into(),
869            _ => return Err("Cannot try_into() to Metadata: unsupported metadata version".into()),
870        };
871
872        metadata.map_err(|_e| "Cannot try_into() to Metadata.".into())
873    }
874}
875
876// Metadata can be encoded, too. It will encode into a format that's compatible with what
877// Subxt requires, and that it can be decoded back from. The actual specifics of the format
878// can change over time.
879impl codec::Encode for Metadata {
880    fn encode_to<T: codec::Output + ?Sized>(&self, dest: &mut T) {
881        let m: frame_metadata::v15::RuntimeMetadataV15 = self.clone().into();
882        let m: frame_metadata::RuntimeMetadataPrefixed = m.into();
883        m.encode_to(dest)
884    }
885}
886
887#[cfg(test)]
888mod test {
889    use super::*;
890    use codec::{Decode, Encode};
891
892    fn load_metadata() -> Vec<u8> {
893        std::fs::read("../artifacts/polkadot_metadata_full.scale").unwrap()
894    }
895
896    // We don't expect to lose any information converting back and forth between
897    // our own representation and the latest version emitted from a node that we can
898    // work with.
899    #[test]
900    fn is_isomorphic_to_v15() {
901        let bytes = load_metadata();
902
903        // Decode into our metadata struct:
904        let metadata = Metadata::decode(&mut &*bytes).unwrap();
905
906        // Convert into v15 metadata:
907        let v15: frame_metadata::v15::RuntimeMetadataV15 = metadata.into();
908        let prefixed = frame_metadata::RuntimeMetadataPrefixed::from(v15);
909
910        // Re-encode that:
911        let new_bytes = prefixed.encode();
912
913        // The bytes should be identical:
914        assert_eq!(bytes, new_bytes);
915    }
916}