1#![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;
28use alloc::sync::Arc;
29use alloc::vec::Vec;
30use frame_decode::extrinsics::{
31 ExtrinsicCallInfo, ExtrinsicExtensionInfo, ExtrinsicInfoArg, ExtrinsicInfoError,
32 ExtrinsicSignatureInfo,
33};
34use hashbrown::HashMap;
35use scale_info::{PortableRegistry, Variant, form::PortableForm};
36use utils::{
37 ordered_map::OrderedMap,
38 validation::{HASH_LEN, get_custom_value_hash},
39 variant_index::VariantIndex,
40};
41
42type ArcStr = Arc<str>;
43
44pub use from::SUPPORTED_METADATA_VERSIONS;
45pub use from::TryFromError;
46pub use utils::validation::MetadataHasher;
47
48type CustomMetadataInner = frame_metadata::v15::CustomMetadata<PortableForm>;
49
50#[derive(Debug, Clone)]
54pub struct Metadata {
55 types: PortableRegistry,
57 pallets: OrderedMap<ArcStr, PalletMetadataInner>,
59 pallets_by_index: HashMap<u8, usize>,
61 extrinsic: ExtrinsicMetadata,
63 outer_enums: OuterEnumsMetadata,
65 dispatch_error_ty: Option<u32>,
67 apis: OrderedMap<ArcStr, RuntimeApiMetadataInner>,
69 custom: CustomMetadataInner,
71}
72
73impl frame_decode::extrinsics::ExtrinsicTypeInfo for Metadata {
76 type TypeId = u32;
77
78 fn get_call_info(
79 &self,
80 pallet_index: u8,
81 call_index: u8,
82 ) -> Result<ExtrinsicCallInfo<'_, Self::TypeId>, ExtrinsicInfoError<'_>> {
83 let pallet = self.pallet_by_index(pallet_index).ok_or({
84 ExtrinsicInfoError::PalletNotFound {
85 index: pallet_index,
86 }
87 })?;
88
89 let call = pallet.call_variant_by_index(call_index).ok_or_else(|| {
90 ExtrinsicInfoError::CallNotFound {
91 index: call_index,
92 pallet_index,
93 pallet_name: Cow::Borrowed(pallet.name()),
94 }
95 })?;
96
97 Ok(ExtrinsicCallInfo {
98 pallet_name: Cow::Borrowed(pallet.name()),
99 call_name: Cow::Borrowed(&call.name),
100 args: call
101 .fields
102 .iter()
103 .map(|f| ExtrinsicInfoArg {
104 name: Cow::Borrowed(f.name.as_deref().unwrap_or("")),
105 id: f.ty.id,
106 })
107 .collect(),
108 })
109 }
110
111 fn get_signature_info(
112 &self,
113 ) -> Result<ExtrinsicSignatureInfo<Self::TypeId>, ExtrinsicInfoError<'_>> {
114 Ok(ExtrinsicSignatureInfo {
115 address_id: self.extrinsic().address_ty,
116 signature_id: self.extrinsic().signature_ty,
117 })
118 }
119
120 fn get_extension_info(
121 &self,
122 extension_version: Option<u8>,
123 ) -> Result<ExtrinsicExtensionInfo<'_, Self::TypeId>, ExtrinsicInfoError<'_>> {
124 let extension_version = extension_version.unwrap_or_else(|| {
125 self.extrinsic()
129 .transaction_extension_version_to_use_for_decoding()
130 });
131
132 let extension_ids = self
133 .extrinsic()
134 .transaction_extensions_by_version(extension_version)
135 .ok_or(ExtrinsicInfoError::ExtrinsicExtensionVersionNotFound { extension_version })?
136 .map(|f| ExtrinsicInfoArg {
137 name: Cow::Borrowed(f.identifier()),
138 id: f.extra_ty(),
139 })
140 .collect();
141
142 Ok(ExtrinsicExtensionInfo { extension_ids })
143 }
144}
145
146impl Metadata {
147 pub fn types(&self) -> &PortableRegistry {
149 &self.types
150 }
151
152 pub fn types_mut(&mut self) -> &mut PortableRegistry {
154 &mut self.types
155 }
156
157 pub fn dispatch_error_ty(&self) -> Option<u32> {
159 self.dispatch_error_ty
160 }
161
162 pub fn extrinsic(&self) -> &ExtrinsicMetadata {
164 &self.extrinsic
165 }
166
167 pub fn outer_enums(&self) -> OuterEnumsMetadata {
169 self.outer_enums
170 }
171
172 pub fn pallets(&self) -> impl ExactSizeIterator<Item = PalletMetadata<'_>> {
174 self.pallets.values().iter().map(|inner| PalletMetadata {
175 inner,
176 types: self.types(),
177 })
178 }
179
180 pub fn pallet_by_index(&self, variant_index: u8) -> Option<PalletMetadata<'_>> {
182 let inner = self
183 .pallets_by_index
184 .get(&variant_index)
185 .and_then(|i| self.pallets.get_by_index(*i))?;
186
187 Some(PalletMetadata {
188 inner,
189 types: self.types(),
190 })
191 }
192
193 pub fn pallet_by_name(&self, pallet_name: &str) -> Option<PalletMetadata<'_>> {
195 let inner = self.pallets.get_by_key(pallet_name)?;
196
197 Some(PalletMetadata {
198 inner,
199 types: self.types(),
200 })
201 }
202
203 pub fn runtime_api_traits(&self) -> impl ExactSizeIterator<Item = RuntimeApiMetadata<'_>> {
205 self.apis.values().iter().map(|inner| RuntimeApiMetadata {
206 inner,
207 types: self.types(),
208 })
209 }
210
211 pub fn runtime_api_trait_by_name(&'_ self, name: &str) -> Option<RuntimeApiMetadata<'_>> {
213 let inner = self.apis.get_by_key(name)?;
214 Some(RuntimeApiMetadata {
215 inner,
216 types: self.types(),
217 })
218 }
219
220 pub fn view_function_by_query_id(
222 &'_ self,
223 query_id: &[u8; 32],
224 ) -> Option<ViewFunctionMetadata<'_>> {
225 self.pallets()
230 .flat_map(|p| p.view_functions())
231 .find(|vf| vf.query_id() == query_id)
232 }
233
234 pub fn custom(&self) -> CustomMetadata<'_> {
236 CustomMetadata {
237 types: self.types(),
238 inner: &self.custom,
239 }
240 }
241
242 pub fn hasher(&self) -> MetadataHasher {
244 MetadataHasher::new(self)
245 }
246
247 pub fn type_hash(&self, id: u32) -> Option<[u8; HASH_LEN]> {
249 self.types.resolve(id)?;
250 Some(crate::utils::validation::get_type_hash(&self.types, id))
251 }
252}
253
254#[derive(Debug, Clone, Copy)]
256pub struct PalletMetadata<'a> {
257 inner: &'a PalletMetadataInner,
258 types: &'a PortableRegistry,
259}
260
261impl<'a> PalletMetadata<'a> {
262 pub fn name(&self) -> &'a str {
264 &self.inner.name
265 }
266
267 pub fn index(&self) -> u8 {
269 self.inner.index
270 }
271
272 pub fn docs(&self) -> &'a [String] {
274 &self.inner.docs
275 }
276
277 pub fn call_ty_id(&self) -> Option<u32> {
279 self.inner.call_ty
280 }
281
282 pub fn event_ty_id(&self) -> Option<u32> {
284 self.inner.event_ty
285 }
286
287 pub fn error_ty_id(&self) -> Option<u32> {
289 self.inner.error_ty
290 }
291
292 pub fn storage(&self) -> Option<&'a StorageMetadata> {
294 self.inner.storage.as_ref()
295 }
296
297 pub fn event_variants(&self) -> Option<&'a [Variant<PortableForm>]> {
299 VariantIndex::get(self.inner.event_ty, self.types)
300 }
301
302 pub fn event_variant_by_index(&self, variant_index: u8) -> Option<&'a Variant<PortableForm>> {
304 self.inner.event_variant_index.lookup_by_index(
305 variant_index,
306 self.inner.event_ty,
307 self.types,
308 )
309 }
310
311 pub fn has_view_functions(&self) -> bool {
313 !self.inner.view_functions.is_empty()
314 }
315
316 pub fn view_functions(
318 &self,
319 ) -> impl ExactSizeIterator<Item = ViewFunctionMetadata<'a>> + use<'a> {
320 self.inner
321 .view_functions
322 .values()
323 .iter()
324 .map(|vf: &'a _| ViewFunctionMetadata {
325 inner: vf,
326 types: self.types,
327 })
328 }
329
330 pub fn view_function_by_name(&self, name: &str) -> Option<ViewFunctionMetadata<'a>> {
332 self.inner
333 .view_functions
334 .get_by_key(name)
335 .map(|vf: &'a _| ViewFunctionMetadata {
336 inner: vf,
337 types: self.types,
338 })
339 }
340
341 pub fn associated_types(&self) -> impl ExactSizeIterator<Item = (&'a str, u32)> + use<'a> {
343 self.inner
344 .associated_types
345 .iter()
346 .map(|(name, ty)| (&**name, *ty))
347 }
348
349 pub fn associated_type_id(&self, name: &str) -> Option<u32> {
351 self.inner.associated_types.get(name).copied()
352 }
353
354 pub fn call_variants(&self) -> Option<&'a [Variant<PortableForm>]> {
356 VariantIndex::get(self.inner.call_ty, self.types)
357 }
358
359 pub fn call_variant_by_index(&self, variant_index: u8) -> Option<&'a Variant<PortableForm>> {
361 self.inner
362 .call_variant_index
363 .lookup_by_index(variant_index, self.inner.call_ty, self.types)
364 }
365
366 pub fn call_variant_by_name(&self, call_name: &str) -> Option<&'a Variant<PortableForm>> {
368 self.inner
369 .call_variant_index
370 .lookup_by_name(call_name, self.inner.call_ty, self.types)
371 }
372
373 pub fn error_variants(&self) -> Option<&'a [Variant<PortableForm>]> {
375 VariantIndex::get(self.inner.error_ty, self.types)
376 }
377
378 pub fn error_variant_by_index(&self, variant_index: u8) -> Option<&'a Variant<PortableForm>> {
380 self.inner.error_variant_index.lookup_by_index(
381 variant_index,
382 self.inner.error_ty,
383 self.types,
384 )
385 }
386
387 pub fn constant_by_name(&self, name: &str) -> Option<&'a ConstantMetadata> {
389 self.inner.constants.get_by_key(name)
390 }
391
392 pub fn constants(&self) -> impl ExactSizeIterator<Item = &'a ConstantMetadata> + use<'a> {
394 self.inner.constants.values().iter()
395 }
396
397 pub fn storage_hash(&self, entry_name: &str) -> Option<[u8; HASH_LEN]> {
399 crate::utils::validation::get_storage_hash(self, entry_name)
400 }
401
402 pub fn constant_hash(&self, constant_name: &str) -> Option<[u8; HASH_LEN]> {
404 crate::utils::validation::get_constant_hash(self, constant_name)
405 }
406
407 pub fn call_hash(&self, call_name: &str) -> Option<[u8; HASH_LEN]> {
409 crate::utils::validation::get_call_hash(self, call_name)
410 }
411
412 pub fn hash(&self) -> [u8; HASH_LEN] {
414 crate::utils::validation::get_pallet_hash(*self)
415 }
416}
417
418#[derive(Debug, Clone)]
419struct PalletMetadataInner {
420 name: ArcStr,
422 index: u8,
424 storage: Option<StorageMetadata>,
426 call_ty: Option<u32>,
428 call_variant_index: VariantIndex,
430 event_ty: Option<u32>,
432 event_variant_index: VariantIndex,
434 error_ty: Option<u32>,
436 error_variant_index: VariantIndex,
438 constants: OrderedMap<ArcStr, ConstantMetadata>,
440 view_functions: OrderedMap<ArcStr, ViewFunctionMetadataInner>,
442 associated_types: BTreeMap<String, u32>,
444 docs: Vec<String>,
446}
447
448#[derive(Debug, Clone)]
450pub struct StorageMetadata {
451 prefix: String,
453 entries: OrderedMap<ArcStr, StorageEntryMetadata>,
455}
456
457impl StorageMetadata {
458 pub fn prefix(&self) -> &str {
460 &self.prefix
461 }
462
463 pub fn entries(&self) -> &[StorageEntryMetadata] {
465 self.entries.values()
466 }
467
468 pub fn entry_by_name(&self, name: &str) -> Option<&StorageEntryMetadata> {
470 self.entries.get_by_key(name)
471 }
472}
473
474#[derive(Debug, Clone)]
476pub struct StorageEntryMetadata {
477 name: ArcStr,
479 modifier: StorageEntryModifier,
481 entry_type: StorageEntryType,
483 default: Vec<u8>,
485 docs: Vec<String>,
487}
488
489impl StorageEntryMetadata {
490 pub fn name(&self) -> &str {
492 &self.name
493 }
494 pub fn modifier(&self) -> StorageEntryModifier {
496 self.modifier
497 }
498 pub fn entry_type(&self) -> &StorageEntryType {
500 &self.entry_type
501 }
502 pub fn default_bytes(&self) -> &[u8] {
504 &self.default
505 }
506 pub fn docs(&self) -> &[String] {
508 &self.docs
509 }
510}
511
512#[derive(Debug, Clone)]
514pub enum StorageEntryType {
515 Plain(u32),
517 Map {
519 hashers: Vec<StorageHasher>,
521 key_ty: u32,
523 value_ty: u32,
525 },
526}
527
528impl StorageEntryType {
529 pub fn value_ty(&self) -> u32 {
531 match self {
532 StorageEntryType::Map { value_ty, .. } | StorageEntryType::Plain(value_ty) => *value_ty,
533 }
534 }
535
536 pub fn key_ty(&self) -> Option<u32> {
538 match self {
539 StorageEntryType::Map { key_ty, .. } => Some(*key_ty),
540 StorageEntryType::Plain(_) => None,
541 }
542 }
543}
544
545#[derive(Debug, Clone, Copy)]
547pub enum StorageHasher {
548 Blake2_128,
550 Blake2_256,
552 Blake2_128Concat,
554 Twox128,
556 Twox256,
558 Twox64Concat,
560 Identity,
562}
563
564impl StorageHasher {
565 pub fn len_excluding_key(&self) -> usize {
573 match self {
574 StorageHasher::Blake2_128Concat => 16,
575 StorageHasher::Twox64Concat => 8,
576 StorageHasher::Blake2_128 => 16,
577 StorageHasher::Blake2_256 => 32,
578 StorageHasher::Twox128 => 16,
579 StorageHasher::Twox256 => 32,
580 StorageHasher::Identity => 0,
581 }
582 }
583
584 pub fn ends_with_key(&self) -> bool {
586 matches!(
587 self,
588 StorageHasher::Blake2_128Concat | StorageHasher::Twox64Concat | StorageHasher::Identity
589 )
590 }
591}
592
593#[derive(Debug, Clone, Copy, Eq, PartialEq)]
595pub enum StorageEntryModifier {
596 Optional,
598 Default,
600}
601
602#[derive(Debug, Clone)]
604pub struct ConstantMetadata {
605 name: ArcStr,
607 ty: u32,
609 value: Vec<u8>,
611 docs: Vec<String>,
613}
614
615impl ConstantMetadata {
616 pub fn name(&self) -> &str {
618 &self.name
619 }
620 pub fn ty(&self) -> u32 {
622 self.ty
623 }
624 pub fn value(&self) -> &[u8] {
626 &self.value
627 }
628 pub fn docs(&self) -> &[String] {
630 &self.docs
631 }
632}
633
634#[derive(Debug, Clone)]
636pub struct ExtrinsicMetadata {
637 address_ty: u32,
640 signature_ty: u32,
643 supported_versions: Vec<u8>,
645 transaction_extensions: Vec<TransactionExtensionMetadataInner>,
647 transaction_extensions_by_version: BTreeMap<u8, Vec<u32>>,
651}
652
653impl ExtrinsicMetadata {
654 pub fn supported_versions(&self) -> &[u8] {
656 &self.supported_versions
657 }
658
659 pub fn transaction_extensions_by_version(
661 &self,
662 version: u8,
663 ) -> Option<impl Iterator<Item = TransactionExtensionMetadata<'_>>> {
664 let extension_indexes = self.transaction_extensions_by_version.get(&version)?;
665 let iter = extension_indexes.iter().map(|index| {
666 let tx_metadata = self
667 .transaction_extensions
668 .get(*index as usize)
669 .expect("transaction extension should exist if index is in transaction_extensions_by_version");
670
671 TransactionExtensionMetadata {
672 identifier: &tx_metadata.identifier,
673 extra_ty: tx_metadata.extra_ty,
674 additional_ty: tx_metadata.additional_ty,
675 }
676 });
677
678 Some(iter)
679 }
680
681 pub fn transaction_extension_version_to_use_for_encoding(&self) -> u8 {
683 *self
684 .transaction_extensions_by_version
685 .keys()
686 .max()
687 .expect("At least one version of transaction extensions is expected")
688 }
689
690 pub fn transaction_extensions_to_use_for_encoding(
693 &self,
694 ) -> impl Iterator<Item = TransactionExtensionMetadata<'_>> {
695 let encoding_version = self.transaction_extension_version_to_use_for_encoding();
696 self.transaction_extensions_by_version(encoding_version)
697 .unwrap()
698 }
699
700 pub fn transaction_extension_version_to_use_for_decoding(&self) -> u8 {
702 *self
703 .transaction_extensions_by_version
704 .keys()
705 .max()
706 .expect("At least one version of transaction extensions is expected")
707 }
708}
709
710#[derive(Debug, Clone)]
712pub struct TransactionExtensionMetadata<'a> {
713 identifier: &'a str,
715 extra_ty: u32,
717 additional_ty: u32,
719}
720
721#[derive(Debug, Clone)]
722struct TransactionExtensionMetadataInner {
723 identifier: String,
724 extra_ty: u32,
725 additional_ty: u32,
726}
727
728impl<'a> TransactionExtensionMetadata<'a> {
729 pub fn identifier(&self) -> &'a str {
731 self.identifier
732 }
733 pub fn extra_ty(&self) -> u32 {
735 self.extra_ty
736 }
737 pub fn additional_ty(&self) -> u32 {
739 self.additional_ty
740 }
741}
742
743#[derive(Debug, Clone, Copy)]
745pub struct OuterEnumsMetadata {
746 call_enum_ty: u32,
748 event_enum_ty: u32,
750 error_enum_ty: u32,
752}
753
754impl OuterEnumsMetadata {
755 pub fn call_enum_ty(&self) -> u32 {
757 self.call_enum_ty
758 }
759
760 pub fn event_enum_ty(&self) -> u32 {
762 self.event_enum_ty
763 }
764
765 pub fn error_enum_ty(&self) -> u32 {
767 self.error_enum_ty
768 }
769}
770
771#[derive(Debug, Clone, Copy)]
773pub struct RuntimeApiMetadata<'a> {
774 inner: &'a RuntimeApiMetadataInner,
775 types: &'a PortableRegistry,
776}
777
778impl<'a> RuntimeApiMetadata<'a> {
779 pub fn name(&self) -> &'a str {
781 &self.inner.name
782 }
783 pub fn docs(&self) -> &[String] {
785 &self.inner.docs
786 }
787 pub fn methods(&self) -> impl ExactSizeIterator<Item = RuntimeApiMethodMetadata<'a>> + use<'a> {
789 self.inner
790 .methods
791 .values()
792 .iter()
793 .map(|item| RuntimeApiMethodMetadata {
794 trait_name: &self.inner.name,
795 inner: item,
796 types: self.types,
797 })
798 }
799 pub fn method_by_name(&self, name: &str) -> Option<RuntimeApiMethodMetadata<'a>> {
801 self.inner
802 .methods
803 .get_by_key(name)
804 .map(|item| RuntimeApiMethodMetadata {
805 trait_name: &self.inner.name,
806 inner: item,
807 types: self.types,
808 })
809 }
810 pub fn hash(&self) -> [u8; HASH_LEN] {
812 crate::utils::validation::get_runtime_apis_hash(*self)
813 }
814}
815
816#[derive(Debug, Clone)]
817struct RuntimeApiMetadataInner {
818 name: ArcStr,
820 methods: OrderedMap<ArcStr, RuntimeApiMethodMetadataInner>,
822 docs: Vec<String>,
824}
825
826#[derive(Debug, Clone)]
828pub struct RuntimeApiMethodMetadata<'a> {
829 trait_name: &'a str,
830 inner: &'a RuntimeApiMethodMetadataInner,
831 types: &'a PortableRegistry,
832}
833
834impl<'a> RuntimeApiMethodMetadata<'a> {
835 pub fn name(&self) -> &'a str {
837 &self.inner.name
838 }
839 pub fn docs(&self) -> &[String] {
841 &self.inner.docs
842 }
843 pub fn inputs(&self) -> impl ExactSizeIterator<Item = &'a MethodParamMetadata> + use<'a> {
845 self.inner.inputs.iter()
846 }
847 pub fn output_ty(&self) -> u32 {
849 self.inner.output_ty
850 }
851 pub fn hash(&self) -> [u8; HASH_LEN] {
853 crate::utils::validation::get_runtime_api_hash(self)
854 }
855}
856
857#[derive(Debug, Clone)]
858struct RuntimeApiMethodMetadataInner {
859 name: ArcStr,
861 inputs: Vec<MethodParamMetadata>,
863 output_ty: u32,
865 docs: Vec<String>,
867}
868
869#[derive(Debug, Clone, Copy)]
872pub struct ViewFunctionMetadata<'a> {
873 inner: &'a ViewFunctionMetadataInner,
874 types: &'a PortableRegistry,
875}
876
877impl<'a> ViewFunctionMetadata<'a> {
878 pub fn name(&self) -> &'a str {
880 &self.inner.name
881 }
882 pub fn query_id(&self) -> &'a [u8; 32] {
885 &self.inner.query_id
886 }
887 pub fn docs(&self) -> &'a [String] {
889 &self.inner.docs
890 }
891 pub fn inputs(&self) -> impl ExactSizeIterator<Item = &'a MethodParamMetadata> + use<'a> {
893 self.inner.inputs.iter()
894 }
895 pub fn output_ty(&self) -> u32 {
897 self.inner.output_ty
898 }
899 pub fn hash(&self) -> [u8; HASH_LEN] {
903 crate::utils::validation::get_view_function_hash(self)
904 }
905}
906
907#[derive(Debug, Clone)]
908struct ViewFunctionMetadataInner {
909 name: ArcStr,
911 query_id: [u8; 32],
913 inputs: Vec<MethodParamMetadata>,
915 output_ty: u32,
917 docs: Vec<String>,
919}
920
921#[derive(Debug, Clone)]
923pub struct MethodParamMetadata {
924 pub name: String,
926 pub ty: u32,
928}
929
930#[derive(Debug, Clone)]
932pub struct CustomMetadata<'a> {
933 types: &'a PortableRegistry,
934 inner: &'a CustomMetadataInner,
935}
936
937impl<'a> CustomMetadata<'a> {
938 pub fn get(&self, name: &str) -> Option<CustomValueMetadata<'a>> {
940 self.inner
941 .map
942 .get_key_value(name)
943 .map(|(name, e)| CustomValueMetadata {
944 types: self.types,
945 type_id: e.ty.id,
946 data: &e.value,
947 name,
948 })
949 }
950
951 pub fn iter(&self) -> impl Iterator<Item = CustomValueMetadata<'a>> + use<'a> {
953 self.inner.map.iter().map(|(name, e)| CustomValueMetadata {
954 types: self.types,
955 type_id: e.ty.id,
956 data: &e.value,
957 name: name.as_ref(),
958 })
959 }
960
961 pub fn types(&self) -> &PortableRegistry {
963 self.types
964 }
965}
966
967pub struct CustomValueMetadata<'a> {
969 types: &'a PortableRegistry,
970 type_id: u32,
971 data: &'a [u8],
972 name: &'a str,
973}
974
975impl<'a> CustomValueMetadata<'a> {
976 pub fn types(&self) -> &PortableRegistry {
978 self.types
979 }
980
981 pub fn bytes(&self) -> &'a [u8] {
983 self.data
984 }
985
986 pub fn type_id(&self) -> u32 {
988 self.type_id
989 }
990
991 pub fn name(&self) -> &str {
993 self.name
994 }
995
996 pub fn hash(&self) -> [u8; HASH_LEN] {
998 get_custom_value_hash(self)
999 }
1000}
1001
1002impl codec::Decode for Metadata {
1005 fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
1006 let metadata = frame_metadata::RuntimeMetadataPrefixed::decode(input)?;
1007 let metadata = match metadata.1 {
1008 frame_metadata::RuntimeMetadata::V14(md) => md.try_into(),
1009 frame_metadata::RuntimeMetadata::V15(md) => md.try_into(),
1010 frame_metadata::RuntimeMetadata::V16(md) => md.try_into(),
1011 _ => return Err("Cannot try_into() to Metadata: unsupported metadata version".into()),
1012 };
1013
1014 metadata.map_err(|_e| "Cannot try_into() to Metadata.".into())
1015 }
1016}