Skip to main content

subxt_metadata/
lib.rs

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