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, 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
61pub type ArcMetadata = Arc<Metadata>;
63
64#[derive(Debug)]
68pub struct Metadata {
69 types: PortableRegistry,
71 pallets: OrderedMap<String, PalletMetadataInner>,
73 pallets_by_call_index: HashMap<u8, usize>,
75 pallets_by_event_index: HashMap<u8, usize>,
80 pallets_by_error_index: HashMap<u8, usize>,
85 extrinsic: ExtrinsicMetadata,
87 outer_enums: OuterEnumsMetadata,
89 dispatch_error_ty: Option<u32>,
91 apis: OrderedMap<String, RuntimeApiMetadataInner>,
93 custom: CustomMetadataInner,
95}
96
97impl 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 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 pub fn arc(self) -> ArcMetadata {
428 Arc::new(self)
429 }
430
431 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 pub fn from_v16(
445 metadata: frame_metadata::v16::RuntimeMetadataV16,
446 ) -> Result<Self, TryFromError> {
447 metadata.try_into()
448 }
449
450 pub fn from_v15(
452 metadata: frame_metadata::v15::RuntimeMetadataV15,
453 ) -> Result<Self, TryFromError> {
454 metadata.try_into()
455 }
456
457 pub fn from_v14(
459 metadata: frame_metadata::v14::RuntimeMetadataV14,
460 ) -> Result<Self, TryFromError> {
461 metadata.try_into()
462 }
463
464 #[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 #[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 #[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 #[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 #[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 #[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 pub fn types(&self) -> &PortableRegistry {
520 &self.types
521 }
522
523 pub fn types_mut(&mut self) -> &mut PortableRegistry {
525 &mut self.types
526 }
527
528 pub fn dispatch_error_ty(&self) -> Option<u32> {
530 self.dispatch_error_ty
531 }
532
533 pub fn extrinsic(&self) -> &ExtrinsicMetadata {
535 &self.extrinsic
536 }
537
538 pub fn outer_enums(&self) -> OuterEnumsMetadata {
540 self.outer_enums
541 }
542
543 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 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 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 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 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 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 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 pub fn custom(&self) -> CustomMetadata<'_> {
619 CustomMetadata {
620 types: self.types(),
621 inner: &self.custom,
622 }
623 }
624
625 pub fn hasher(&self) -> MetadataHasher<'_> {
627 MetadataHasher::new(self)
628 }
629
630 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#[derive(Debug, Clone, Copy)]
639pub struct PalletMetadata<'a> {
640 inner: &'a PalletMetadataInner,
641 types: &'a PortableRegistry,
642}
643
644impl<'a> PalletMetadata<'a> {
645 pub fn name(&self) -> &'a str {
647 &self.inner.name
648 }
649
650 pub fn call_index(&self) -> u8 {
652 self.inner.call_index
653 }
654
655 pub fn event_index(&self) -> u8 {
657 self.inner.event_index
658 }
659
660 pub fn error_index(&self) -> u8 {
662 self.inner.error_index
663 }
664
665 pub fn docs(&self) -> &'a [String] {
667 &self.inner.docs
668 }
669
670 pub fn call_ty_id(&self) -> Option<u32> {
672 self.inner.call_ty
673 }
674
675 pub fn event_ty_id(&self) -> Option<u32> {
677 self.inner.event_ty
678 }
679
680 pub fn error_ty_id(&self) -> Option<u32> {
682 self.inner.error_ty
683 }
684
685 pub fn storage(&self) -> Option<&'a StorageMetadata> {
687 self.inner.storage.as_ref()
688 }
689
690 pub fn event_variants(&self) -> Option<&'a [Variant<PortableForm>]> {
692 VariantIndex::get(self.inner.event_ty, self.types)
693 }
694
695 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 pub fn has_view_functions(&self) -> bool {
706 !self.inner.view_functions.is_empty()
707 }
708
709 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 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 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 pub fn associated_type_id(&self, name: &str) -> Option<u32> {
744 self.inner.associated_types.get(name).copied()
745 }
746
747 pub fn call_variants(&self) -> Option<&'a [Variant<PortableForm>]> {
749 VariantIndex::get(self.inner.call_ty, self.types)
750 }
751
752 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 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 pub fn error_variants(&self) -> Option<&'a [Variant<PortableForm>]> {
768 VariantIndex::get(self.inner.error_ty, self.types)
769 }
770
771 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 pub fn constant_by_name(&self, name: &str) -> Option<&'a ConstantMetadata> {
782 self.inner.constants.get_by_key(name)
783 }
784
785 pub fn constants(&self) -> impl ExactSizeIterator<Item = &'a ConstantMetadata> + use<'a> {
787 self.inner.constants.values().iter()
788 }
789
790 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 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 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 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 name: String,
815 call_index: u8,
817 event_index: u8,
822 error_index: u8,
827 storage: Option<StorageMetadata>,
829 call_ty: Option<u32>,
831 call_variant_index: VariantIndex,
833 event_ty: Option<u32>,
835 event_variant_index: VariantIndex,
837 error_ty: Option<u32>,
839 error_variant_index: VariantIndex,
841 constants: OrderedMap<String, ConstantMetadata>,
843 view_functions: OrderedMap<String, ViewFunctionMetadataInner>,
845 associated_types: BTreeMap<String, u32>,
847 docs: Vec<String>,
849}
850
851#[derive(Debug, Clone)]
853pub struct StorageMetadata {
854 prefix: String,
856 entries: OrderedMap<String, StorageEntryMetadata>,
858}
859
860impl StorageMetadata {
861 pub fn prefix(&self) -> &str {
863 &self.prefix
864 }
865
866 pub fn entries(&self) -> &[StorageEntryMetadata] {
868 self.entries.values()
869 }
870
871 pub fn entry_by_name(&self, name: &str) -> Option<&StorageEntryMetadata> {
873 self.entries.get_by_key(name)
874 }
875}
876
877#[derive(Debug, Clone)]
879pub struct StorageEntryMetadata {
880 name: String,
882 info: StorageInfo<'static, u32>,
884 docs: Vec<String>,
886}
887
888impl StorageEntryMetadata {
889 pub fn name(&self) -> &str {
891 &self.name
892 }
893 pub fn keys(&self) -> impl ExactSizeIterator<Item = &StorageKeyInfo<u32>> {
895 let keys = &*self.info.keys;
896 keys.iter()
897 }
898 pub fn value_ty(&self) -> u32 {
900 self.info.value_id
901 }
902 pub fn default_value(&self) -> Option<&[u8]> {
904 self.info.default_value.as_deref()
905 }
906 pub fn docs(&self) -> &[String] {
908 &self.docs
909 }
910}
911
912#[derive(Debug, Clone)]
914pub struct ConstantMetadata {
915 name: String,
917 ty: u32,
919 value: Vec<u8>,
921 docs: Vec<String>,
923}
924
925impl ConstantMetadata {
926 pub fn name(&self) -> &str {
928 &self.name
929 }
930 pub fn ty(&self) -> u32 {
932 self.ty
933 }
934 pub fn value(&self) -> &[u8] {
936 &self.value
937 }
938 pub fn docs(&self) -> &[String] {
940 &self.docs
941 }
942}
943
944#[derive(Debug, Clone)]
946pub struct ExtrinsicMetadata {
947 address_ty: u32,
950 signature_ty: u32,
953 supported_versions: Vec<u8>,
955 transaction_extensions: Vec<TransactionExtensionMetadataInner>,
957 transaction_extensions_by_version: BTreeMap<u8, Vec<u32>>,
961}
962
963impl ExtrinsicMetadata {
964 pub fn supported_versions(&self) -> &[u8] {
966 &self.supported_versions
967 }
968
969 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 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 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 pub fn transaction_extension_version_to_use_for_decoding(&self) -> u8 {
1017 0
1018 }
1019}
1020
1021#[derive(Debug, Clone)]
1023pub struct TransactionExtensionMetadata<'a> {
1024 identifier: &'a str,
1026 extra_ty: u32,
1028 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 pub fn identifier(&self) -> &'a str {
1042 self.identifier
1043 }
1044 pub fn extra_ty(&self) -> u32 {
1046 self.extra_ty
1047 }
1048 pub fn additional_ty(&self) -> u32 {
1050 self.additional_ty
1051 }
1052}
1053
1054#[derive(Debug, Clone, Copy)]
1056pub struct OuterEnumsMetadata {
1057 call_enum_ty: u32,
1059 event_enum_ty: u32,
1061 error_enum_ty: u32,
1063}
1064
1065impl OuterEnumsMetadata {
1066 pub fn call_enum_ty(&self) -> u32 {
1068 self.call_enum_ty
1069 }
1070
1071 pub fn event_enum_ty(&self) -> u32 {
1073 self.event_enum_ty
1074 }
1075
1076 pub fn error_enum_ty(&self) -> u32 {
1078 self.error_enum_ty
1079 }
1080}
1081
1082#[derive(Debug, Clone, Copy)]
1084pub struct RuntimeApiMetadata<'a> {
1085 inner: &'a RuntimeApiMetadataInner,
1086 types: &'a PortableRegistry,
1087}
1088
1089impl<'a> RuntimeApiMetadata<'a> {
1090 pub fn name(&self) -> &'a str {
1092 &self.inner.name
1093 }
1094 pub fn docs(&self) -> &[String] {
1096 &self.inner.docs
1097 }
1098 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 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 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 name: String,
1131 methods: OrderedMap<String, RuntimeApiMethodMetadataInner>,
1133 docs: Vec<String>,
1135}
1136
1137#[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 pub fn name(&self) -> &'a str {
1148 &self.inner.name
1149 }
1150 pub fn docs(&self) -> &[String] {
1152 &self.inner.docs
1153 }
1154 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 pub fn output_ty(&self) -> u32 {
1163 self.inner.info.output_id
1164 }
1165 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 name: String,
1175 info: RuntimeApiInfo<'static, u32>,
1177 docs: Vec<String>,
1179}
1180
1181#[derive(Debug, Clone, Copy)]
1184pub struct ViewFunctionMetadata<'a> {
1185 inner: &'a ViewFunctionMetadataInner,
1186 types: &'a PortableRegistry,
1187}
1188
1189impl<'a> ViewFunctionMetadata<'a> {
1190 pub fn name(&self) -> &'a str {
1192 &self.inner.name
1193 }
1194 pub fn query_id(&self) -> &'a [u8; 32] {
1197 &self.inner.info.query_id
1198 }
1199 pub fn docs(&self) -> &'a [String] {
1201 &self.inner.docs
1202 }
1203 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 pub fn output_ty(&self) -> u32 {
1212 self.inner.info.output_id
1213 }
1214 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 name: String,
1226 info: ViewFunctionInfo<'static, u32>,
1228 docs: Vec<String>,
1230}
1231
1232#[derive(Debug, Clone)]
1234pub struct MethodParamMetadata {
1235 pub name: String,
1237 pub ty: u32,
1239}
1240
1241#[derive(Debug, Clone)]
1243pub struct CustomMetadata<'a> {
1244 types: &'a PortableRegistry,
1245 inner: &'a CustomMetadataInner,
1246}
1247
1248impl<'a> CustomMetadata<'a> {
1249 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 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 pub fn types(&self) -> &PortableRegistry {
1274 self.types
1275 }
1276}
1277
1278pub 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 pub fn types(&self) -> &PortableRegistry {
1289 self.types
1290 }
1291
1292 pub fn bytes(&self) -> &'a [u8] {
1294 self.data
1295 }
1296
1297 pub fn type_id(&self) -> u32 {
1299 self.type_id
1300 }
1301
1302 pub fn name(&self) -> &str {
1304 self.name
1305 }
1306
1307 pub fn hash(&self) -> [u8; HASH_LEN] {
1309 get_custom_value_hash(self)
1310 }
1311}
1312
1313impl 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
1321pub 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 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
1354fn 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 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 #[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 #[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 #[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}