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;
23mod utils;
24
25use alloc::borrow::Cow;
26use alloc::collections::BTreeMap;
27use alloc::string::{String, ToString};
28use alloc::sync::Arc;
29use alloc::vec::Vec;
30use frame_decode::constants::{ConstantEntry, ConstantInfo, ConstantInfoError};
31use frame_decode::custom_values::{CustomValue, CustomValueInfo, CustomValueInfoError};
32use frame_decode::extrinsics::{
33    ExtrinsicCallInfo, ExtrinsicExtensionInfo, ExtrinsicInfoArg, ExtrinsicInfoError,
34    ExtrinsicSignatureInfo,
35};
36use frame_decode::runtime_apis::{
37    RuntimeApiEntry, RuntimeApiInfo, RuntimeApiInfoError, RuntimeApiInput,
38};
39use frame_decode::storage::{StorageEntry, StorageInfo, StorageInfoError, StorageKeyInfo};
40use frame_decode::view_functions::{
41    ViewFunctionEntry, ViewFunctionInfo, ViewFunctionInfoError, ViewFunctionInput,
42};
43
44use hashbrown::HashMap;
45use scale_info::{PortableRegistry, Variant, form::PortableForm};
46use utils::{
47    ordered_map::OrderedMap,
48    validation::{HASH_LEN, get_custom_value_hash},
49    variant_index::VariantIndex,
50};
51
52pub use frame_decode::storage::StorageHasher;
53pub use from::SUPPORTED_METADATA_VERSIONS;
54pub use from::TryFromError;
55pub use utils::validation::MetadataHasher;
56
57#[cfg(feature = "legacy")]
58pub use from::legacy::Error as LegacyFromError;
59
60type CustomMetadataInner = frame_metadata::v15::CustomMetadata<PortableForm>;
61
62/// Metadata is often passed around wrapped in an [`Arc`] so that it can be cloned.
63pub type ArcMetadata = Arc<Metadata>;
64
65/// Node metadata. This can be constructed by providing some compatible [`frame_metadata`]
66/// which is then decoded into this. We aim to preserve all of the existing information in
67/// the incoming metadata while optimizing the format a little for Subxt's use cases.
68#[derive(Debug)]
69pub struct Metadata {
70    /// Type registry containing all types used in the metadata.
71    types: PortableRegistry,
72    /// Metadata of all the pallets.
73    pallets: OrderedMap<String, PalletMetadataInner>,
74    /// Find the pallet for a given call index.
75    pallets_by_call_index: HashMap<u8, usize>,
76    /// Find the pallet for a given event index.
77    ///
78    /// for modern metadatas, this is the same as pallets_by_call_index,
79    /// but for old metadatas this can vary.
80    pallets_by_event_index: HashMap<u8, usize>,
81    /// Find the pallet for a given error index.
82    ///
83    /// for modern metadatas, this is the same as pallets_by_call_index,
84    /// but for old metadatas this can vary.
85    pallets_by_error_index: HashMap<u8, usize>,
86    /// Metadata of the extrinsic.
87    extrinsic: ExtrinsicMetadata,
88    /// The types of the outer enums.
89    outer_enums: OuterEnumsMetadata,
90    /// The type Id of the `DispatchError` type, which Subxt makes use of.
91    dispatch_error_ty: Option<u32>,
92    /// Details about each of the runtime API traits.
93    apis: OrderedMap<String, RuntimeApiMetadataInner>,
94    /// Allows users to add custom types to the metadata. A map that associates a string key to a `CustomValueMetadata`.
95    custom: CustomMetadataInner,
96}
97
98// Since we've abstracted away from frame-metadatas, we impl this on our custom Metadata
99// so that it can be used by `frame-decode` to obtain the relevant extrinsic info.
100impl frame_decode::extrinsics::ExtrinsicTypeInfo for Metadata {
101    type TypeId = u32;
102
103    fn extrinsic_call_info(
104        &self,
105        pallet_index: u8,
106        call_index: u8,
107    ) -> Result<ExtrinsicCallInfo<'_, Self::TypeId>, ExtrinsicInfoError<'_>> {
108        let pallet = self.pallet_by_call_index(pallet_index).ok_or({
109            ExtrinsicInfoError::PalletNotFound {
110                index: pallet_index,
111            }
112        })?;
113
114        let call = pallet.call_variant_by_index(call_index).ok_or_else(|| {
115            ExtrinsicInfoError::CallNotFound {
116                index: call_index,
117                pallet_index,
118                pallet_name: Cow::Borrowed(pallet.name()),
119            }
120        })?;
121
122        Ok(ExtrinsicCallInfo {
123            pallet_name: Cow::Borrowed(pallet.name()),
124            call_name: Cow::Borrowed(&call.name),
125            args: call
126                .fields
127                .iter()
128                .map(|f| ExtrinsicInfoArg {
129                    name: Cow::Borrowed(f.name.as_deref().unwrap_or("")),
130                    id: f.ty.id,
131                })
132                .collect(),
133        })
134    }
135
136    fn extrinsic_signature_info(
137        &self,
138    ) -> Result<ExtrinsicSignatureInfo<Self::TypeId>, ExtrinsicInfoError<'_>> {
139        Ok(ExtrinsicSignatureInfo {
140            address_id: self.extrinsic().address_ty,
141            signature_id: self.extrinsic().signature_ty,
142        })
143    }
144
145    fn extrinsic_extension_info(
146        &self,
147        extension_version: Option<u8>,
148    ) -> Result<ExtrinsicExtensionInfo<'_, Self::TypeId>, ExtrinsicInfoError<'_>> {
149        let extension_version = extension_version.unwrap_or_else(|| {
150            // We have some transaction, probably a V4 one with no extension version,
151            // but our metadata may support multiple versions. Use the metadata to decide
152            // what version to assume we'll decode it as.
153            self.extrinsic()
154                .transaction_extension_version_to_use_for_decoding()
155        });
156
157        let extension_ids = self
158            .extrinsic()
159            .transaction_extensions_by_version(extension_version)
160            .ok_or(ExtrinsicInfoError::ExtrinsicExtensionVersionNotFound { extension_version })?
161            .map(|f| ExtrinsicInfoArg {
162                name: Cow::Borrowed(f.identifier()),
163                id: f.extra_ty(),
164            })
165            .collect();
166
167        Ok(ExtrinsicExtensionInfo { extension_ids })
168    }
169}
170impl frame_decode::storage::StorageTypeInfo for Metadata {
171    type TypeId = u32;
172
173    fn storage_info(
174        &self,
175        pallet_name: &str,
176        storage_entry: &str,
177    ) -> Result<StorageInfo<'_, Self::TypeId>, StorageInfoError<'_>> {
178        let pallet =
179            self.pallet_by_name(pallet_name)
180                .ok_or_else(|| StorageInfoError::PalletNotFound {
181                    pallet_name: pallet_name.to_string(),
182                })?;
183        let entry = pallet
184            .storage()
185            .and_then(|storage| storage.entry_by_name(storage_entry))
186            .ok_or_else(|| StorageInfoError::StorageNotFound {
187                name: storage_entry.to_string(),
188                pallet_name: Cow::Borrowed(pallet.name()),
189            })?;
190
191        let info = StorageInfo {
192            keys: Cow::Borrowed(&*entry.info.keys),
193            value_id: entry.info.value_id,
194            default_value: entry
195                .info
196                .default_value
197                .as_ref()
198                .map(|def| Cow::Borrowed(&**def)),
199            use_old_v9_storage_hashers: false,
200        };
201
202        Ok(info)
203    }
204}
205impl frame_decode::storage::StorageEntryInfo for Metadata {
206    fn storage_entries(&self) -> impl Iterator<Item = StorageEntry<'_>> {
207        self.pallets().flat_map(|pallet| {
208            let pallet_name = pallet.name();
209            let pallet_iter = core::iter::once(StorageEntry::In(pallet_name.into()));
210            let entries_iter = pallet.storage().into_iter().flat_map(|storage| {
211                storage
212                    .entries()
213                    .iter()
214                    .map(|entry| StorageEntry::Name(entry.name().into()))
215            });
216
217            pallet_iter.chain(entries_iter)
218        })
219    }
220}
221impl frame_decode::runtime_apis::RuntimeApiTypeInfo for Metadata {
222    type TypeId = u32;
223
224    fn runtime_api_info(
225        &self,
226        trait_name: &str,
227        method_name: &str,
228    ) -> Result<RuntimeApiInfo<'_, Self::TypeId>, RuntimeApiInfoError<'_>> {
229        let api_trait =
230            self.apis
231                .get_by_key(trait_name)
232                .ok_or_else(|| RuntimeApiInfoError::TraitNotFound {
233                    trait_name: trait_name.to_string(),
234                })?;
235        let api_method = api_trait.methods.get_by_key(method_name).ok_or_else(|| {
236            RuntimeApiInfoError::MethodNotFound {
237                trait_name: Cow::Borrowed(&api_trait.name),
238                method_name: method_name.to_string(),
239            }
240        })?;
241
242        let info = RuntimeApiInfo {
243            inputs: Cow::Borrowed(&api_method.info.inputs),
244            output_id: api_method.info.output_id,
245        };
246
247        Ok(info)
248    }
249}
250impl frame_decode::runtime_apis::RuntimeApiEntryInfo for Metadata {
251    fn runtime_api_entries(&self) -> impl Iterator<Item = RuntimeApiEntry<'_>> {
252        self.runtime_api_traits().flat_map(|api_trait| {
253            let trait_name = api_trait.name();
254            let trait_iter = core::iter::once(RuntimeApiEntry::In(trait_name.into()));
255            let method_iter = api_trait
256                .methods()
257                .map(|method| RuntimeApiEntry::Name(method.name().into()));
258
259            trait_iter.chain(method_iter)
260        })
261    }
262}
263impl frame_decode::view_functions::ViewFunctionTypeInfo for Metadata {
264    type TypeId = u32;
265
266    fn view_function_info(
267        &self,
268        pallet_name: &str,
269        function_name: &str,
270    ) -> Result<ViewFunctionInfo<'_, Self::TypeId>, ViewFunctionInfoError<'_>> {
271        let pallet = self.pallet_by_name(pallet_name).ok_or_else(|| {
272            ViewFunctionInfoError::PalletNotFound {
273                pallet_name: pallet_name.to_string(),
274            }
275        })?;
276        let function = pallet.view_function_by_name(function_name).ok_or_else(|| {
277            ViewFunctionInfoError::FunctionNotFound {
278                pallet_name: Cow::Borrowed(pallet.name()),
279                function_name: function_name.to_string(),
280            }
281        })?;
282
283        let info = ViewFunctionInfo {
284            inputs: Cow::Borrowed(&function.inner.info.inputs),
285            output_id: function.inner.info.output_id,
286            query_id: *function.query_id(),
287        };
288
289        Ok(info)
290    }
291}
292impl frame_decode::view_functions::ViewFunctionEntryInfo for Metadata {
293    fn view_function_entries(&self) -> impl Iterator<Item = ViewFunctionEntry<'_>> {
294        self.pallets().flat_map(|pallet| {
295            let pallet_name = pallet.name();
296            let pallet_iter = core::iter::once(ViewFunctionEntry::In(pallet_name.into()));
297            let fn_iter = pallet
298                .view_functions()
299                .map(|function| ViewFunctionEntry::Name(function.name().into()));
300
301            pallet_iter.chain(fn_iter)
302        })
303    }
304}
305impl frame_decode::constants::ConstantTypeInfo for Metadata {
306    type TypeId = u32;
307
308    fn constant_info(
309        &self,
310        pallet_name: &str,
311        constant_name: &str,
312    ) -> Result<ConstantInfo<'_, Self::TypeId>, ConstantInfoError<'_>> {
313        let pallet =
314            self.pallet_by_name(pallet_name)
315                .ok_or_else(|| ConstantInfoError::PalletNotFound {
316                    pallet_name: pallet_name.to_string(),
317                })?;
318        let constant = pallet.constant_by_name(constant_name).ok_or_else(|| {
319            ConstantInfoError::ConstantNotFound {
320                pallet_name: Cow::Borrowed(pallet.name()),
321                constant_name: constant_name.to_string(),
322            }
323        })?;
324
325        let info = ConstantInfo {
326            bytes: &constant.value,
327            type_id: constant.ty,
328        };
329
330        Ok(info)
331    }
332}
333impl frame_decode::constants::ConstantEntryInfo for Metadata {
334    fn constant_entries(&self) -> impl Iterator<Item = ConstantEntry<'_>> {
335        self.pallets().flat_map(|pallet| {
336            let pallet_name = pallet.name();
337            let pallet_iter = core::iter::once(ConstantEntry::In(pallet_name.into()));
338            let constant_iter = pallet
339                .constants()
340                .map(|constant| ConstantEntry::Name(constant.name().into()));
341
342            pallet_iter.chain(constant_iter)
343        })
344    }
345}
346impl frame_decode::custom_values::CustomValueTypeInfo for Metadata {
347    type TypeId = u32;
348
349    fn custom_value_info(
350        &self,
351        name: &str,
352    ) -> Result<CustomValueInfo<'_, Self::TypeId>, CustomValueInfoError> {
353        let custom_value = self
354            .custom()
355            .get(name)
356            .ok_or_else(|| CustomValueInfoError {
357                not_found: name.to_string(),
358            })?;
359
360        let info = CustomValueInfo {
361            bytes: custom_value.data,
362            type_id: custom_value.type_id,
363        };
364
365        Ok(info)
366    }
367}
368impl frame_decode::custom_values::CustomValueEntryInfo for Metadata {
369    fn custom_values(&self) -> impl Iterator<Item = CustomValue<'_>> {
370        self.custom.map.keys().map(|name| CustomValue {
371            name: Cow::Borrowed(name),
372        })
373    }
374}
375
376impl Metadata {
377    /// Metadata tends to be passed around wrapped in an [`Arc`] so that it can be
378    /// cheaply cloned. This is a shorthand to return that.
379    pub fn arc(self) -> ArcMetadata {
380        Arc::new(self)
381    }
382
383    /// This is essentially an alias for `<Metadata as codec::Decode>::decode(&mut bytes)`
384    pub fn decode_from(mut bytes: &[u8]) -> Result<Self, codec::Error> {
385        <Self as codec::Decode>::decode(&mut bytes)
386    }
387
388    /// Convert V16 metadata into [`Metadata`].
389    pub fn from_v16(
390        metadata: frame_metadata::v16::RuntimeMetadataV16,
391    ) -> Result<Self, TryFromError> {
392        metadata.try_into()
393    }
394
395    /// Convert V15 metadata into [`Metadata`].
396    pub fn from_v15(
397        metadata: frame_metadata::v15::RuntimeMetadataV15,
398    ) -> Result<Self, TryFromError> {
399        metadata.try_into()
400    }
401
402    /// Convert V14 metadata into [`Metadata`].
403    pub fn from_v14(
404        metadata: frame_metadata::v14::RuntimeMetadataV14,
405    ) -> Result<Self, TryFromError> {
406        metadata.try_into()
407    }
408
409    /// Convert V13 metadata into [`Metadata`], given the necessary extra type information.
410    #[cfg(feature = "legacy")]
411    pub fn from_v13(
412        metadata: &frame_metadata::v13::RuntimeMetadataV13,
413        types: &scale_info_legacy::TypeRegistrySet<'_>,
414    ) -> Result<Self, LegacyFromError> {
415        from::legacy::from_v13(metadata, types, from::legacy::Opts::compat())
416    }
417
418    /// Convert V12 metadata into [`Metadata`], given the necessary extra type information.
419    #[cfg(feature = "legacy")]
420    pub fn from_v12(
421        metadata: &frame_metadata::v12::RuntimeMetadataV12,
422        types: &scale_info_legacy::TypeRegistrySet<'_>,
423    ) -> Result<Self, LegacyFromError> {
424        from::legacy::from_v12(metadata, types, from::legacy::Opts::compat())
425    }
426
427    /// Convert V13 metadata into [`Metadata`], given the necessary extra type information.
428    #[cfg(feature = "legacy")]
429    pub fn from_v11(
430        metadata: &frame_metadata::v11::RuntimeMetadataV11,
431        types: &scale_info_legacy::TypeRegistrySet<'_>,
432    ) -> Result<Self, LegacyFromError> {
433        from::legacy::from_v11(metadata, types, from::legacy::Opts::compat())
434    }
435
436    /// Convert V13 metadata into [`Metadata`], given the necessary extra type information.
437    #[cfg(feature = "legacy")]
438    pub fn from_v10(
439        metadata: &frame_metadata::v10::RuntimeMetadataV10,
440        types: &scale_info_legacy::TypeRegistrySet<'_>,
441    ) -> Result<Self, LegacyFromError> {
442        from::legacy::from_v10(metadata, types, from::legacy::Opts::compat())
443    }
444
445    /// Convert V9 metadata into [`Metadata`], given the necessary extra type information.
446    #[cfg(feature = "legacy")]
447    pub fn from_v9(
448        metadata: &frame_metadata::v9::RuntimeMetadataV9,
449        types: &scale_info_legacy::TypeRegistrySet<'_>,
450    ) -> Result<Self, LegacyFromError> {
451        from::legacy::from_v9(metadata, types, from::legacy::Opts::compat())
452    }
453
454    /// Convert V8 metadata into [`Metadata`], given the necessary extra type information.
455    #[cfg(feature = "legacy")]
456    pub fn from_v8(
457        metadata: &frame_metadata::v8::RuntimeMetadataV8,
458        types: &scale_info_legacy::TypeRegistrySet<'_>,
459    ) -> Result<Self, LegacyFromError> {
460        from::legacy::from_v8(metadata, types, from::legacy::Opts::compat())
461    }
462
463    /// Access the underlying type registry.
464    pub fn types(&self) -> &PortableRegistry {
465        &self.types
466    }
467
468    /// Mutable access to the underlying type registry.
469    pub fn types_mut(&mut self) -> &mut PortableRegistry {
470        &mut self.types
471    }
472
473    /// The type ID of the `DispatchError` type, if it exists.
474    pub fn dispatch_error_ty(&self) -> Option<u32> {
475        self.dispatch_error_ty
476    }
477
478    /// Return details about the extrinsic format.
479    pub fn extrinsic(&self) -> &ExtrinsicMetadata {
480        &self.extrinsic
481    }
482
483    /// Return details about the outer enums.
484    pub fn outer_enums(&self) -> OuterEnumsMetadata {
485        self.outer_enums
486    }
487
488    /// An iterator over all of the available pallets.
489    pub fn pallets(&self) -> impl ExactSizeIterator<Item = PalletMetadata<'_>> {
490        self.pallets.values().iter().map(|inner| PalletMetadata {
491            inner,
492            types: self.types(),
493        })
494    }
495
496    /// Access a pallet given some call/extrinsic pallet index byte
497    pub fn pallet_by_call_index(&self, variant_index: u8) -> Option<PalletMetadata<'_>> {
498        let inner = self
499            .pallets_by_call_index
500            .get(&variant_index)
501            .and_then(|i| self.pallets.get_by_index(*i))?;
502
503        Some(PalletMetadata {
504            inner,
505            types: self.types(),
506        })
507    }
508
509    /// Access a pallet given some event pallet index byte
510    pub fn pallet_by_event_index(&self, variant_index: u8) -> Option<PalletMetadata<'_>> {
511        let inner = self
512            .pallets_by_event_index
513            .get(&variant_index)
514            .and_then(|i| self.pallets.get_by_index(*i))?;
515
516        Some(PalletMetadata {
517            inner,
518            types: self.types(),
519        })
520    }
521
522    /// Access a pallet given some error pallet index byte
523    pub fn pallet_by_error_index(&self, variant_index: u8) -> Option<PalletMetadata<'_>> {
524        let inner = self
525            .pallets_by_error_index
526            .get(&variant_index)
527            .and_then(|i| self.pallets.get_by_index(*i))?;
528
529        Some(PalletMetadata {
530            inner,
531            types: self.types(),
532        })
533    }
534
535    /// Access a pallet given its name.
536    pub fn pallet_by_name(&self, pallet_name: &str) -> Option<PalletMetadata<'_>> {
537        let inner = self.pallets.get_by_key(pallet_name)?;
538
539        Some(PalletMetadata {
540            inner,
541            types: self.types(),
542        })
543    }
544
545    /// An iterator over all of the runtime APIs.
546    pub fn runtime_api_traits(&self) -> impl ExactSizeIterator<Item = RuntimeApiMetadata<'_>> {
547        self.apis.values().iter().map(|inner| RuntimeApiMetadata {
548            inner,
549            types: self.types(),
550        })
551    }
552
553    /// Access a runtime API trait given its name.
554    pub fn runtime_api_trait_by_name(&'_ self, name: &str) -> Option<RuntimeApiMetadata<'_>> {
555        let inner = self.apis.get_by_key(name)?;
556        Some(RuntimeApiMetadata {
557            inner,
558            types: self.types(),
559        })
560    }
561
562    /// Returns custom user defined types
563    pub fn custom(&self) -> CustomMetadata<'_> {
564        CustomMetadata {
565            types: self.types(),
566            inner: &self.custom,
567        }
568    }
569
570    /// Obtain a unique hash representing this metadata or specific parts of it.
571    pub fn hasher(&self) -> MetadataHasher<'_> {
572        MetadataHasher::new(self)
573    }
574
575    /// Get type hash for a type in the registry
576    pub fn type_hash(&self, id: u32) -> Option<[u8; HASH_LEN]> {
577        self.types.resolve(id)?;
578        Some(crate::utils::validation::get_type_hash(&self.types, id))
579    }
580}
581
582/// Metadata for a specific pallet.
583#[derive(Debug, Clone, Copy)]
584pub struct PalletMetadata<'a> {
585    inner: &'a PalletMetadataInner,
586    types: &'a PortableRegistry,
587}
588
589impl<'a> PalletMetadata<'a> {
590    /// The pallet name.
591    pub fn name(&self) -> &'a str {
592        &self.inner.name
593    }
594
595    /// The index to use for calls in this pallet.
596    pub fn call_index(&self) -> u8 {
597        self.inner.call_index
598    }
599
600    /// The index to use for events in this pallet.
601    pub fn event_index(&self) -> u8 {
602        self.inner.event_index
603    }
604
605    /// The index to use for errors in this pallet.
606    pub fn error_index(&self) -> u8 {
607        self.inner.error_index
608    }
609
610    /// The pallet docs.
611    pub fn docs(&self) -> &'a [String] {
612        &self.inner.docs
613    }
614
615    /// Type ID for the pallet's Call type, if it exists.
616    pub fn call_ty_id(&self) -> Option<u32> {
617        self.inner.call_ty
618    }
619
620    /// Type ID for the pallet's Event type, if it exists.
621    pub fn event_ty_id(&self) -> Option<u32> {
622        self.inner.event_ty
623    }
624
625    /// Type ID for the pallet's Error type, if it exists.
626    pub fn error_ty_id(&self) -> Option<u32> {
627        self.inner.error_ty
628    }
629
630    /// Return metadata about the pallet's storage entries.
631    pub fn storage(&self) -> Option<&'a StorageMetadata> {
632        self.inner.storage.as_ref()
633    }
634
635    /// Return all of the event variants, if an event type exists.
636    pub fn event_variants(&self) -> Option<&'a [Variant<PortableForm>]> {
637        VariantIndex::get(self.inner.event_ty, self.types)
638    }
639
640    /// Return an event variant given it's encoded variant index.
641    pub fn event_variant_by_index(&self, variant_index: u8) -> Option<&'a Variant<PortableForm>> {
642        self.inner.event_variant_index.lookup_by_index(
643            variant_index,
644            self.inner.event_ty,
645            self.types,
646        )
647    }
648
649    /// Does this pallet have any view functions?
650    pub fn has_view_functions(&self) -> bool {
651        !self.inner.view_functions.is_empty()
652    }
653
654    /// Return an iterator over the View Functions in this pallet, if any.
655    pub fn view_functions(
656        &self,
657    ) -> impl ExactSizeIterator<Item = ViewFunctionMetadata<'a>> + use<'a> {
658        self.inner
659            .view_functions
660            .values()
661            .iter()
662            .map(|vf: &'a _| ViewFunctionMetadata {
663                inner: vf,
664                types: self.types,
665            })
666    }
667
668    /// Return the view function with a given name, if any
669    pub fn view_function_by_name(&self, name: &str) -> Option<ViewFunctionMetadata<'a>> {
670        self.inner
671            .view_functions
672            .get_by_key(name)
673            .map(|vf: &'a _| ViewFunctionMetadata {
674                inner: vf,
675                types: self.types,
676            })
677    }
678
679    /// Iterate (in no particular order) over the associated type names and type IDs for this pallet.
680    pub fn associated_types(&self) -> impl ExactSizeIterator<Item = (&'a str, u32)> + use<'a> {
681        self.inner
682            .associated_types
683            .iter()
684            .map(|(name, ty)| (&**name, *ty))
685    }
686
687    /// Fetch an associated type ID given the associated type name.
688    pub fn associated_type_id(&self, name: &str) -> Option<u32> {
689        self.inner.associated_types.get(name).copied()
690    }
691
692    /// Return all of the call variants, if a call type exists.
693    pub fn call_variants(&self) -> Option<&'a [Variant<PortableForm>]> {
694        VariantIndex::get(self.inner.call_ty, self.types)
695    }
696
697    /// Return a call variant given it's encoded variant index.
698    pub fn call_variant_by_index(&self, variant_index: u8) -> Option<&'a Variant<PortableForm>> {
699        self.inner
700            .call_variant_index
701            .lookup_by_index(variant_index, self.inner.call_ty, self.types)
702    }
703
704    /// Return a call variant given it's name.
705    pub fn call_variant_by_name(&self, call_name: &str) -> Option<&'a Variant<PortableForm>> {
706        self.inner
707            .call_variant_index
708            .lookup_by_name(call_name, self.inner.call_ty, self.types)
709    }
710
711    /// Return all of the error variants, if an error type exists.
712    pub fn error_variants(&self) -> Option<&'a [Variant<PortableForm>]> {
713        VariantIndex::get(self.inner.error_ty, self.types)
714    }
715
716    /// Return an error variant given it's encoded variant index.
717    pub fn error_variant_by_index(&self, variant_index: u8) -> Option<&'a Variant<PortableForm>> {
718        self.inner.error_variant_index.lookup_by_index(
719            variant_index,
720            self.inner.error_ty,
721            self.types,
722        )
723    }
724
725    /// Return constant details given the constant name.
726    pub fn constant_by_name(&self, name: &str) -> Option<&'a ConstantMetadata> {
727        self.inner.constants.get_by_key(name)
728    }
729
730    /// An iterator over the constants in this pallet.
731    pub fn constants(&self) -> impl ExactSizeIterator<Item = &'a ConstantMetadata> + use<'a> {
732        self.inner.constants.values().iter()
733    }
734
735    /// Return a hash for the storage entry, or None if it was not found.
736    pub fn storage_hash(&self, entry_name: &str) -> Option<[u8; HASH_LEN]> {
737        crate::utils::validation::get_storage_hash(self, entry_name)
738    }
739
740    /// Return a hash for the constant, or None if it was not found.
741    pub fn constant_hash(&self, constant_name: &str) -> Option<[u8; HASH_LEN]> {
742        crate::utils::validation::get_constant_hash(self, constant_name)
743    }
744
745    /// Return a hash for the call, or None if it was not found.
746    pub fn call_hash(&self, call_name: &str) -> Option<[u8; HASH_LEN]> {
747        crate::utils::validation::get_call_hash(self, call_name)
748    }
749
750    /// Return a hash for the entire pallet.
751    pub fn hash(&self) -> [u8; HASH_LEN] {
752        crate::utils::validation::get_pallet_hash(*self)
753    }
754}
755
756#[derive(Debug, Clone)]
757struct PalletMetadataInner {
758    /// Pallet name.
759    name: String,
760    /// The index for calls in the pallet.
761    call_index: u8,
762    /// The index for events in the pallet.
763    ///
764    /// This is the same as `call_index` for modern metadatas,
765    /// but can be different for older metadatas (pre-V12).
766    event_index: u8,
767    /// The index for errors in the pallet.
768    ///
769    /// This is the same as `call_index` for modern metadatas,
770    /// but can be different for older metadatas (pre-V12).
771    error_index: u8,
772    /// Pallet storage metadata.
773    storage: Option<StorageMetadata>,
774    /// Type ID for the pallet Call enum.
775    call_ty: Option<u32>,
776    /// Call variants by name/u8.
777    call_variant_index: VariantIndex,
778    /// Type ID for the pallet Event enum.
779    event_ty: Option<u32>,
780    /// Event variants by name/u8.
781    event_variant_index: VariantIndex,
782    /// Type ID for the pallet Error enum.
783    error_ty: Option<u32>,
784    /// Error variants by name/u8.
785    error_variant_index: VariantIndex,
786    /// Map from constant name to constant details.
787    constants: OrderedMap<String, ConstantMetadata>,
788    /// Details about each of the pallet view functions.
789    view_functions: OrderedMap<String, ViewFunctionMetadataInner>,
790    /// Mapping from associated type to type ID describing its shape.
791    associated_types: BTreeMap<String, u32>,
792    /// Pallet documentation.
793    docs: Vec<String>,
794}
795
796/// Metadata for the storage entries in a pallet.
797#[derive(Debug, Clone)]
798pub struct StorageMetadata {
799    /// The common prefix used by all storage entries.
800    prefix: String,
801    /// Map from storage entry name to details.
802    entries: OrderedMap<String, StorageEntryMetadata>,
803}
804
805impl StorageMetadata {
806    /// The common prefix used by all storage entries.
807    pub fn prefix(&self) -> &str {
808        &self.prefix
809    }
810
811    /// An iterator over the storage entries.
812    pub fn entries(&self) -> &[StorageEntryMetadata] {
813        self.entries.values()
814    }
815
816    /// Return a specific storage entry given its name.
817    pub fn entry_by_name(&self, name: &str) -> Option<&StorageEntryMetadata> {
818        self.entries.get_by_key(name)
819    }
820}
821
822/// Metadata for a single storage entry.
823#[derive(Debug, Clone)]
824pub struct StorageEntryMetadata {
825    /// Variable name of the storage entry.
826    name: String,
827    /// Information about the storage entry.
828    info: StorageInfo<'static, u32>,
829    /// Storage entry documentation.
830    docs: Vec<String>,
831}
832
833impl StorageEntryMetadata {
834    /// Name of this entry.
835    pub fn name(&self) -> &str {
836        &self.name
837    }
838    /// Keys in this storage entry.
839    pub fn keys(&self) -> impl ExactSizeIterator<Item = &StorageKeyInfo<u32>> {
840        let keys = &*self.info.keys;
841        keys.iter()
842    }
843    /// Value type for this storage entry.
844    pub fn value_ty(&self) -> u32 {
845        self.info.value_id
846    }
847    /// The default value, if one exists, for this entry.
848    pub fn default_value(&self) -> Option<&[u8]> {
849        self.info.default_value.as_deref()
850    }
851    /// Storage entry documentation.
852    pub fn docs(&self) -> &[String] {
853        &self.docs
854    }
855}
856
857/// Metadata for a single constant.
858#[derive(Debug, Clone)]
859pub struct ConstantMetadata {
860    /// Name of the pallet constant.
861    name: String,
862    /// Type of the pallet constant.
863    ty: u32,
864    /// Value stored in the constant (SCALE encoded).
865    value: Vec<u8>,
866    /// Constant documentation.
867    docs: Vec<String>,
868}
869
870impl ConstantMetadata {
871    /// Name of the pallet constant.
872    pub fn name(&self) -> &str {
873        &self.name
874    }
875    /// Type of the pallet constant.
876    pub fn ty(&self) -> u32 {
877        self.ty
878    }
879    /// Value stored in the constant (SCALE encoded).
880    pub fn value(&self) -> &[u8] {
881        &self.value
882    }
883    /// Constant documentation.
884    pub fn docs(&self) -> &[String] {
885        &self.docs
886    }
887}
888
889/// Metadata for the extrinsic type.
890#[derive(Debug, Clone)]
891pub struct ExtrinsicMetadata {
892    /// The type of the address that signs the extrinsic.
893    /// Used to help decode tx signatures.
894    address_ty: u32,
895    /// The type of the extrinsic's signature.
896    /// Used to help decode tx signatures.
897    signature_ty: u32,
898    /// Which extrinsic versions are supported by this chain.
899    supported_versions: Vec<u8>,
900    /// The signed extensions in the order they appear in the extrinsic.
901    transaction_extensions: Vec<TransactionExtensionMetadataInner>,
902    /// Different versions of transaction extensions can exist. Each version
903    /// is a u8 which corresponds to the indexes of the transaction extensions
904    /// seen in the above Vec, in order, that exist at that version.
905    transaction_extensions_by_version: BTreeMap<u8, Vec<u32>>,
906}
907
908impl ExtrinsicMetadata {
909    /// Which extrinsic versions are supported.
910    pub fn supported_versions(&self) -> &[u8] {
911        &self.supported_versions
912    }
913
914    /// The extra/additional information associated with the extrinsic.
915    pub fn transaction_extensions_by_version(
916        &self,
917        version: u8,
918    ) -> Option<impl Iterator<Item = TransactionExtensionMetadata<'_>>> {
919        let extension_indexes = self.transaction_extensions_by_version.get(&version)?;
920        let iter = extension_indexes.iter().map(|index| {
921            let tx_metadata = self
922                .transaction_extensions
923                .get(*index as usize)
924                .expect("transaction extension should exist if index is in transaction_extensions_by_version");
925
926            TransactionExtensionMetadata {
927                identifier: &tx_metadata.identifier,
928                extra_ty: tx_metadata.extra_ty,
929                additional_ty: tx_metadata.additional_ty,
930            }
931        });
932
933        Some(iter)
934    }
935
936    /// When constructing a v5 extrinsic, use this transaction extensions version.
937    pub fn transaction_extension_version_to_use_for_encoding(&self) -> u8 {
938        *self
939            .transaction_extensions_by_version
940            .keys()
941            .max()
942            .expect("At least one version of transaction extensions is expected")
943    }
944
945    /// An iterator of the transaction extensions to use when encoding a transaction. Basically equivalent to
946    /// `self.transaction_extensions_by_version(self.transaction_extension_version_to_use_for_encoding()).unwrap()`
947    pub fn transaction_extensions_to_use_for_encoding(
948        &self,
949    ) -> impl Iterator<Item = TransactionExtensionMetadata<'_>> {
950        let encoding_version = self.transaction_extension_version_to_use_for_encoding();
951        self.transaction_extensions_by_version(encoding_version)
952            .unwrap()
953    }
954
955    /// When presented with a v4 extrinsic that has no version, treat it as being this version.
956    pub fn transaction_extension_version_to_use_for_decoding(&self) -> u8 {
957        *self
958            .transaction_extensions_by_version
959            .keys()
960            .max()
961            .expect("At least one version of transaction extensions is expected")
962    }
963}
964
965/// Metadata for the signed extensions used by extrinsics.
966#[derive(Debug, Clone)]
967pub struct TransactionExtensionMetadata<'a> {
968    /// The unique transaction extension identifier, which may be different from the type name.
969    identifier: &'a str,
970    /// The type of the transaction extension, with the data to be included in the extrinsic.
971    extra_ty: u32,
972    /// The type of the additional signed data, with the data to be included in the signed payload.
973    additional_ty: u32,
974}
975
976#[derive(Debug, Clone)]
977struct TransactionExtensionMetadataInner {
978    identifier: String,
979    extra_ty: u32,
980    additional_ty: u32,
981}
982
983impl<'a> TransactionExtensionMetadata<'a> {
984    /// The unique signed extension identifier, which may be different from the type name.
985    pub fn identifier(&self) -> &'a str {
986        self.identifier
987    }
988    /// The type of the signed extension, with the data to be included in the extrinsic.
989    pub fn extra_ty(&self) -> u32 {
990        self.extra_ty
991    }
992    /// The type of the additional signed data, with the data to be included in the signed payload
993    pub fn additional_ty(&self) -> u32 {
994        self.additional_ty
995    }
996}
997
998/// Metadata for the outer enums.
999#[derive(Debug, Clone, Copy)]
1000pub struct OuterEnumsMetadata {
1001    /// The type of the outer call enum.
1002    call_enum_ty: u32,
1003    /// The type of the outer event enum.
1004    event_enum_ty: u32,
1005    /// The type of the outer error enum.
1006    error_enum_ty: u32,
1007}
1008
1009impl OuterEnumsMetadata {
1010    /// The type of the outer call enum.
1011    pub fn call_enum_ty(&self) -> u32 {
1012        self.call_enum_ty
1013    }
1014
1015    /// The type of the outer event enum.
1016    pub fn event_enum_ty(&self) -> u32 {
1017        self.event_enum_ty
1018    }
1019
1020    /// The type of the outer error enum.
1021    pub fn error_enum_ty(&self) -> u32 {
1022        self.error_enum_ty
1023    }
1024}
1025
1026/// Metadata for the available runtime APIs.
1027#[derive(Debug, Clone, Copy)]
1028pub struct RuntimeApiMetadata<'a> {
1029    inner: &'a RuntimeApiMetadataInner,
1030    types: &'a PortableRegistry,
1031}
1032
1033impl<'a> RuntimeApiMetadata<'a> {
1034    /// Trait name.
1035    pub fn name(&self) -> &'a str {
1036        &self.inner.name
1037    }
1038    /// Trait documentation.
1039    pub fn docs(&self) -> &[String] {
1040        &self.inner.docs
1041    }
1042    /// An iterator over the trait methods.
1043    pub fn methods(&self) -> impl ExactSizeIterator<Item = RuntimeApiMethodMetadata<'a>> + use<'a> {
1044        self.inner
1045            .methods
1046            .values()
1047            .iter()
1048            .map(|item| RuntimeApiMethodMetadata {
1049                trait_name: &self.inner.name,
1050                inner: item,
1051                types: self.types,
1052            })
1053    }
1054    /// Get a specific trait method given its name.
1055    pub fn method_by_name(&self, name: &str) -> Option<RuntimeApiMethodMetadata<'a>> {
1056        self.inner
1057            .methods
1058            .get_by_key(name)
1059            .map(|item| RuntimeApiMethodMetadata {
1060                trait_name: &self.inner.name,
1061                inner: item,
1062                types: self.types,
1063            })
1064    }
1065    /// Return a hash for the runtime API trait.
1066    pub fn hash(&self) -> [u8; HASH_LEN] {
1067        crate::utils::validation::get_runtime_apis_hash(*self)
1068    }
1069}
1070
1071#[derive(Debug, Clone)]
1072struct RuntimeApiMetadataInner {
1073    /// Trait name.
1074    name: String,
1075    /// Trait methods.
1076    methods: OrderedMap<String, RuntimeApiMethodMetadataInner>,
1077    /// Trait documentation.
1078    docs: Vec<String>,
1079}
1080
1081/// Metadata for a single runtime API method.
1082#[derive(Debug, Clone)]
1083pub struct RuntimeApiMethodMetadata<'a> {
1084    trait_name: &'a str,
1085    inner: &'a RuntimeApiMethodMetadataInner,
1086    types: &'a PortableRegistry,
1087}
1088
1089impl<'a> RuntimeApiMethodMetadata<'a> {
1090    /// Method name.
1091    pub fn name(&self) -> &'a str {
1092        &self.inner.name
1093    }
1094    /// Method documentation.
1095    pub fn docs(&self) -> &[String] {
1096        &self.inner.docs
1097    }
1098    /// Method inputs.
1099    pub fn inputs(
1100        &self,
1101    ) -> impl ExactSizeIterator<Item = &'a RuntimeApiInput<'static, u32>> + use<'a> {
1102        let inputs = &*self.inner.info.inputs;
1103        inputs.iter()
1104    }
1105    /// Method return type.
1106    pub fn output_ty(&self) -> u32 {
1107        self.inner.info.output_id
1108    }
1109    /// Return a hash for the method.
1110    pub fn hash(&self) -> [u8; HASH_LEN] {
1111        crate::utils::validation::get_runtime_api_hash(self)
1112    }
1113}
1114
1115#[derive(Debug, Clone)]
1116struct RuntimeApiMethodMetadataInner {
1117    /// Method name.
1118    name: String,
1119    /// Info.
1120    info: RuntimeApiInfo<'static, u32>,
1121    /// Method documentation.
1122    docs: Vec<String>,
1123}
1124
1125/// Metadata for the available View Functions. Currently these exist only
1126/// at the pallet level, but eventually they could exist at the runtime level too.
1127#[derive(Debug, Clone, Copy)]
1128pub struct ViewFunctionMetadata<'a> {
1129    inner: &'a ViewFunctionMetadataInner,
1130    types: &'a PortableRegistry,
1131}
1132
1133impl<'a> ViewFunctionMetadata<'a> {
1134    /// Method name.
1135    pub fn name(&self) -> &'a str {
1136        &self.inner.name
1137    }
1138    /// Query ID. This is used to query the function. Roughly, it is constructed by doing
1139    /// `twox_128(pallet_name) ++ twox_128("fn_name(fnarg_types) -> return_ty")` .
1140    pub fn query_id(&self) -> &'a [u8; 32] {
1141        &self.inner.info.query_id
1142    }
1143    /// Method documentation.
1144    pub fn docs(&self) -> &'a [String] {
1145        &self.inner.docs
1146    }
1147    /// Method inputs.
1148    pub fn inputs(
1149        &self,
1150    ) -> impl ExactSizeIterator<Item = &'a ViewFunctionInput<'static, u32>> + use<'a> {
1151        let inputs = &*self.inner.info.inputs;
1152        inputs.iter()
1153    }
1154    /// Method return type.
1155    pub fn output_ty(&self) -> u32 {
1156        self.inner.info.output_id
1157    }
1158    /// Return a hash for the method. The query ID of a view function validates it to some
1159    /// degree, but only takes type _names_ into account. This hash takes into account the
1160    /// actual _shape_ of each argument and the return type.
1161    pub fn hash(&self) -> [u8; HASH_LEN] {
1162        crate::utils::validation::get_view_function_hash(self)
1163    }
1164}
1165
1166#[derive(Debug, Clone)]
1167struct ViewFunctionMetadataInner {
1168    /// View function name.
1169    name: String,
1170    /// Info.
1171    info: ViewFunctionInfo<'static, u32>,
1172    /// Documentation.
1173    docs: Vec<String>,
1174}
1175
1176/// Metadata for a single input parameter to a runtime API method / pallet view function.
1177#[derive(Debug, Clone)]
1178pub struct MethodParamMetadata {
1179    /// Parameter name.
1180    pub name: String,
1181    /// Parameter type.
1182    pub ty: u32,
1183}
1184
1185/// Metadata of custom types with custom values, basically the same as `frame_metadata::v15::CustomMetadata<PortableForm>>`.
1186#[derive(Debug, Clone)]
1187pub struct CustomMetadata<'a> {
1188    types: &'a PortableRegistry,
1189    inner: &'a CustomMetadataInner,
1190}
1191
1192impl<'a> CustomMetadata<'a> {
1193    /// Get a certain [CustomValueMetadata] by its name.
1194    pub fn get(&self, name: &str) -> Option<CustomValueMetadata<'a>> {
1195        self.inner
1196            .map
1197            .get_key_value(name)
1198            .map(|(name, e)| CustomValueMetadata {
1199                types: self.types,
1200                type_id: e.ty.id,
1201                data: &e.value,
1202                name,
1203            })
1204    }
1205
1206    /// Iterates over names (keys) and associated custom values
1207    pub fn iter(&self) -> impl Iterator<Item = CustomValueMetadata<'a>> + use<'a> {
1208        self.inner.map.iter().map(|(name, e)| CustomValueMetadata {
1209            types: self.types,
1210            type_id: e.ty.id,
1211            data: &e.value,
1212            name: name.as_ref(),
1213        })
1214    }
1215
1216    /// Access the underlying type registry.
1217    pub fn types(&self) -> &PortableRegistry {
1218        self.types
1219    }
1220}
1221
1222/// Basically the same as `frame_metadata::v15::CustomValueMetadata<PortableForm>>`, but borrowed.
1223pub struct CustomValueMetadata<'a> {
1224    types: &'a PortableRegistry,
1225    type_id: u32,
1226    data: &'a [u8],
1227    name: &'a str,
1228}
1229
1230impl<'a> CustomValueMetadata<'a> {
1231    /// Access the underlying type registry.
1232    pub fn types(&self) -> &PortableRegistry {
1233        self.types
1234    }
1235
1236    /// The scale encoded value
1237    pub fn bytes(&self) -> &'a [u8] {
1238        self.data
1239    }
1240
1241    /// The type id in the TypeRegistry
1242    pub fn type_id(&self) -> u32 {
1243        self.type_id
1244    }
1245
1246    /// The name under which the custom value is registered.
1247    pub fn name(&self) -> &str {
1248        self.name
1249    }
1250
1251    /// Calculates the hash for the CustomValueMetadata.
1252    pub fn hash(&self) -> [u8; HASH_LEN] {
1253        get_custom_value_hash(self)
1254    }
1255}
1256
1257/// Decode SCALE encoded metadata.
1258///
1259/// - The default assumption is that metadata is encoded as [`frame_metadata::RuntimeMetadataPrefixed`]. This is the
1260///   expected format that metadata is encoded into.
1261/// - if this fails, we also try to decode as [`frame_metadata::RuntimeMetadata`].
1262/// - If this all fails, we also try to decode as [`frame_metadata::OpaqueMetadata`].
1263pub fn decode_runtime_metadata(
1264    input: &[u8],
1265) -> Result<frame_metadata::RuntimeMetadata, codec::Error> {
1266    use codec::Decode;
1267
1268    let err = match frame_metadata::RuntimeMetadataPrefixed::decode(&mut &*input) {
1269        Ok(md) => return Ok(md.1),
1270        Err(e) => e,
1271    };
1272
1273    if let Ok(md) = frame_metadata::RuntimeMetadata::decode(&mut &*input) {
1274        return Ok(md);
1275    }
1276
1277    // frame_metadata::OpaqueMetadata is a vec of bytes. If we can decode the length, AND
1278    // the length definitely corresponds to the number of remaining bytes, then we try to
1279    // decode the inner bytes.
1280    if let Ok(len) = codec::Compact::<u64>::decode(&mut &*input) {
1281        if input.len() == len.0 as usize {
1282            return decode_runtime_metadata(input);
1283        }
1284    }
1285
1286    Err(err)
1287}
1288
1289// Support decoding metadata from the "wire" format directly into this.
1290// Errors may be lost in the case that the metadata content is somehow invalid.
1291impl codec::Decode for Metadata {
1292    fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
1293        let metadata = frame_metadata::RuntimeMetadataPrefixed::decode(input)?;
1294        let metadata = match metadata.1 {
1295            frame_metadata::RuntimeMetadata::V14(md) => md.try_into(),
1296            frame_metadata::RuntimeMetadata::V15(md) => md.try_into(),
1297            frame_metadata::RuntimeMetadata::V16(md) => md.try_into(),
1298            _ => {
1299                return Err("Metadata::decode failed: Cannot try_into() to Metadata: unsupported metadata version".into())
1300            },
1301        };
1302
1303        metadata.map_err(|_| "Metadata::decode failed: Cannot try_into() to Metadata".into())
1304    }
1305}