1#![cfg_attr(not(feature = "std"), no_std)]
18#![deny(missing_docs)]
19
20extern crate alloc;
21
22mod from_into;
23mod utils;
24
25use alloc::borrow::Cow;
26use alloc::string::String;
27use alloc::sync::Arc;
28use alloc::vec::Vec;
29use frame_decode::extrinsics::{
30 ExtrinsicCallInfo, ExtrinsicExtensionInfo, ExtrinsicInfoArg, ExtrinsicInfoError,
31 ExtrinsicSignatureInfo,
32};
33use hashbrown::HashMap;
34use scale_info::{form::PortableForm, PortableRegistry, Variant};
35use utils::variant_index::VariantIndex;
36use utils::{ordered_map::OrderedMap, validation::outer_enum_hashes::OuterEnumHashes};
37
38type ArcStr = Arc<str>;
39
40use crate::utils::validation::{get_custom_value_hash, HASH_LEN};
41pub use from_into::TryFromError;
42pub use utils::validation::MetadataHasher;
43
44#[derive(Debug, Clone)]
48pub struct Metadata {
49 types: PortableRegistry,
51 pallets: OrderedMap<ArcStr, PalletMetadataInner>,
53 pallets_by_index: HashMap<u8, usize>,
55 extrinsic: ExtrinsicMetadata,
57 runtime_ty: u32,
59 outer_enums: OuterEnumsMetadata,
61 dispatch_error_ty: Option<u32>,
63 apis: OrderedMap<ArcStr, RuntimeApiMetadataInner>,
65 custom: frame_metadata::v15::CustomMetadata<PortableForm>,
67}
68
69impl frame_decode::extrinsics::ExtrinsicTypeInfo for Metadata {
72 type TypeId = u32;
73
74 fn get_call_info(
75 &self,
76 pallet_index: u8,
77 call_index: u8,
78 ) -> Result<ExtrinsicCallInfo<'_, Self::TypeId>, ExtrinsicInfoError<'_>> {
79 let pallet = self.pallet_by_index(pallet_index).ok_or({
80 ExtrinsicInfoError::PalletNotFound {
81 index: pallet_index,
82 }
83 })?;
84
85 let call = pallet.call_variant_by_index(call_index).ok_or_else(|| {
86 ExtrinsicInfoError::CallNotFound {
87 index: call_index,
88 pallet_index,
89 pallet_name: Cow::Borrowed(pallet.name()),
90 }
91 })?;
92
93 Ok(ExtrinsicCallInfo {
94 pallet_name: Cow::Borrowed(pallet.name()),
95 call_name: Cow::Borrowed(&call.name),
96 args: call
97 .fields
98 .iter()
99 .map(|f| ExtrinsicInfoArg {
100 name: Cow::Borrowed(f.name.as_deref().unwrap_or("")),
101 id: f.ty.id,
102 })
103 .collect(),
104 })
105 }
106
107 fn get_signature_info(
108 &self,
109 ) -> Result<ExtrinsicSignatureInfo<Self::TypeId>, ExtrinsicInfoError<'_>> {
110 Ok(ExtrinsicSignatureInfo {
111 address_id: self.extrinsic().address_ty(),
112 signature_id: self.extrinsic().signature_ty(),
113 })
114 }
115
116 fn get_extension_info(
117 &self,
118 extension_version: Option<u8>,
119 ) -> Result<ExtrinsicExtensionInfo<'_, Self::TypeId>, ExtrinsicInfoError<'_>> {
120 if let Some(extension_version) = extension_version {
124 if extension_version != 0 {
125 return Err(ExtrinsicInfoError::ExtrinsicExtensionVersionNotSupported {
126 extension_version,
127 });
128 }
129 }
130
131 Ok(ExtrinsicExtensionInfo {
132 extension_ids: self
133 .extrinsic()
134 .signed_extensions()
135 .iter()
136 .map(|f| ExtrinsicInfoArg {
137 name: Cow::Borrowed(f.identifier()),
138 id: f.extra_ty(),
139 })
140 .collect(),
141 })
142 }
143}
144
145impl Metadata {
146 pub fn types(&self) -> &PortableRegistry {
148 &self.types
149 }
150
151 pub fn types_mut(&mut self) -> &mut PortableRegistry {
153 &mut self.types
154 }
155
156 pub fn runtime_ty(&self) -> u32 {
158 self.runtime_ty
159 }
160
161 pub fn dispatch_error_ty(&self) -> Option<u32> {
163 self.dispatch_error_ty
164 }
165
166 pub fn extrinsic(&self) -> &ExtrinsicMetadata {
168 &self.extrinsic
169 }
170
171 pub fn outer_enums(&self) -> OuterEnumsMetadata {
173 self.outer_enums
174 }
175
176 pub fn pallets(&self) -> impl ExactSizeIterator<Item = PalletMetadata<'_>> {
178 self.pallets.values().iter().map(|inner| PalletMetadata {
179 inner,
180 types: self.types(),
181 })
182 }
183
184 pub fn pallet_by_index(&self, variant_index: u8) -> Option<PalletMetadata<'_>> {
186 let inner = self
187 .pallets_by_index
188 .get(&variant_index)
189 .and_then(|i| self.pallets.get_by_index(*i))?;
190
191 Some(PalletMetadata {
192 inner,
193 types: self.types(),
194 })
195 }
196
197 pub fn pallet_by_name(&self, pallet_name: &str) -> Option<PalletMetadata<'_>> {
199 let inner = self.pallets.get_by_key(pallet_name)?;
200
201 Some(PalletMetadata {
202 inner,
203 types: self.types(),
204 })
205 }
206
207 pub fn runtime_api_traits(&self) -> impl ExactSizeIterator<Item = RuntimeApiMetadata<'_>> {
209 self.apis.values().iter().map(|inner| RuntimeApiMetadata {
210 inner,
211 types: self.types(),
212 })
213 }
214
215 pub fn runtime_api_trait_by_name(&'_ self, name: &str) -> Option<RuntimeApiMetadata<'_>> {
217 let inner = self.apis.get_by_key(name)?;
218 Some(RuntimeApiMetadata {
219 inner,
220 types: self.types(),
221 })
222 }
223
224 pub fn custom(&self) -> CustomMetadata<'_> {
226 CustomMetadata {
227 types: self.types(),
228 inner: &self.custom,
229 }
230 }
231
232 pub fn hasher(&self) -> MetadataHasher {
234 MetadataHasher::new(self)
235 }
236
237 pub fn retain<F, G>(&mut self, pallet_filter: F, api_filter: G)
242 where
243 F: FnMut(&str) -> bool,
244 G: FnMut(&str) -> bool,
245 {
246 utils::retain::retain_metadata(self, pallet_filter, api_filter);
247 }
248
249 pub fn type_hash(&self, id: u32) -> Option<[u8; HASH_LEN]> {
251 self.types.resolve(id)?;
252 Some(crate::utils::validation::get_type_hash(
253 &self.types,
254 id,
255 &OuterEnumHashes::empty(),
256 ))
257 }
258}
259
260#[derive(Debug, Clone, Copy)]
262pub struct PalletMetadata<'a> {
263 inner: &'a PalletMetadataInner,
264 types: &'a PortableRegistry,
265}
266
267impl<'a> PalletMetadata<'a> {
268 pub fn name(&self) -> &'a str {
270 &self.inner.name
271 }
272
273 pub fn index(&self) -> u8 {
275 self.inner.index
276 }
277
278 pub fn docs(&self) -> &'a [String] {
280 &self.inner.docs
281 }
282
283 pub fn call_ty_id(&self) -> Option<u32> {
285 self.inner.call_ty
286 }
287
288 pub fn event_ty_id(&self) -> Option<u32> {
290 self.inner.event_ty
291 }
292
293 pub fn error_ty_id(&self) -> Option<u32> {
295 self.inner.error_ty
296 }
297
298 pub fn storage(&self) -> Option<&'a StorageMetadata> {
300 self.inner.storage.as_ref()
301 }
302
303 pub fn event_variants(&self) -> Option<&'a [Variant<PortableForm>]> {
305 VariantIndex::get(self.inner.event_ty, self.types)
306 }
307
308 pub fn event_variant_by_index(&self, variant_index: u8) -> Option<&'a Variant<PortableForm>> {
310 self.inner.event_variant_index.lookup_by_index(
311 variant_index,
312 self.inner.event_ty,
313 self.types,
314 )
315 }
316
317 pub fn call_variants(&self) -> Option<&'a [Variant<PortableForm>]> {
319 VariantIndex::get(self.inner.call_ty, self.types)
320 }
321
322 pub fn call_variant_by_index(&self, variant_index: u8) -> Option<&'a Variant<PortableForm>> {
324 self.inner
325 .call_variant_index
326 .lookup_by_index(variant_index, self.inner.call_ty, self.types)
327 }
328
329 pub fn call_variant_by_name(&self, call_name: &str) -> Option<&'a Variant<PortableForm>> {
331 self.inner
332 .call_variant_index
333 .lookup_by_name(call_name, self.inner.call_ty, self.types)
334 }
335
336 pub fn error_variants(&self) -> Option<&'a [Variant<PortableForm>]> {
338 VariantIndex::get(self.inner.error_ty, self.types)
339 }
340
341 pub fn error_variant_by_index(&self, variant_index: u8) -> Option<&'a Variant<PortableForm>> {
343 self.inner.error_variant_index.lookup_by_index(
344 variant_index,
345 self.inner.error_ty,
346 self.types,
347 )
348 }
349
350 pub fn constant_by_name(&self, name: &str) -> Option<&'a ConstantMetadata> {
352 self.inner.constants.get_by_key(name)
353 }
354
355 pub fn constants(&self) -> impl ExactSizeIterator<Item = &'a ConstantMetadata> {
357 self.inner.constants.values().iter()
358 }
359
360 pub fn storage_hash(&self, entry_name: &str) -> Option<[u8; HASH_LEN]> {
362 crate::utils::validation::get_storage_hash(self, entry_name)
363 }
364
365 pub fn constant_hash(&self, constant_name: &str) -> Option<[u8; HASH_LEN]> {
367 crate::utils::validation::get_constant_hash(self, constant_name)
368 }
369
370 pub fn call_hash(&self, call_name: &str) -> Option<[u8; HASH_LEN]> {
372 crate::utils::validation::get_call_hash(self, call_name)
373 }
374
375 pub fn hash(&self) -> [u8; HASH_LEN] {
377 crate::utils::validation::get_pallet_hash(*self, &OuterEnumHashes::empty())
378 }
379}
380
381#[derive(Debug, Clone)]
382struct PalletMetadataInner {
383 name: ArcStr,
385 index: u8,
387 storage: Option<StorageMetadata>,
389 call_ty: Option<u32>,
391 call_variant_index: VariantIndex,
393 event_ty: Option<u32>,
395 event_variant_index: VariantIndex,
397 error_ty: Option<u32>,
399 error_variant_index: VariantIndex,
401 constants: OrderedMap<ArcStr, ConstantMetadata>,
403 docs: Vec<String>,
405}
406
407#[derive(Debug, Clone)]
409pub struct StorageMetadata {
410 prefix: String,
412 entries: OrderedMap<ArcStr, StorageEntryMetadata>,
414}
415
416impl StorageMetadata {
417 pub fn prefix(&self) -> &str {
419 &self.prefix
420 }
421
422 pub fn entries(&self) -> &[StorageEntryMetadata] {
424 self.entries.values()
425 }
426
427 pub fn entry_by_name(&self, name: &str) -> Option<&StorageEntryMetadata> {
429 self.entries.get_by_key(name)
430 }
431}
432
433#[derive(Debug, Clone)]
435pub struct StorageEntryMetadata {
436 name: ArcStr,
438 modifier: StorageEntryModifier,
440 entry_type: StorageEntryType,
442 default: Vec<u8>,
444 docs: Vec<String>,
446}
447
448impl StorageEntryMetadata {
449 pub fn name(&self) -> &str {
451 &self.name
452 }
453 pub fn modifier(&self) -> StorageEntryModifier {
455 self.modifier
456 }
457 pub fn entry_type(&self) -> &StorageEntryType {
459 &self.entry_type
460 }
461 pub fn default_bytes(&self) -> &[u8] {
463 &self.default
464 }
465 pub fn docs(&self) -> &[String] {
467 &self.docs
468 }
469}
470
471#[derive(Debug, Clone)]
473pub enum StorageEntryType {
474 Plain(u32),
476 Map {
478 hashers: Vec<StorageHasher>,
480 key_ty: u32,
482 value_ty: u32,
484 },
485}
486
487impl StorageEntryType {
488 pub fn value_ty(&self) -> u32 {
490 match self {
491 StorageEntryType::Map { value_ty, .. } | StorageEntryType::Plain(value_ty) => *value_ty,
492 }
493 }
494
495 pub fn key_ty(&self) -> Option<u32> {
497 match self {
498 StorageEntryType::Map { key_ty, .. } => Some(*key_ty),
499 StorageEntryType::Plain(_) => None,
500 }
501 }
502}
503
504#[derive(Debug, Clone, Copy)]
506pub enum StorageHasher {
507 Blake2_128,
509 Blake2_256,
511 Blake2_128Concat,
513 Twox128,
515 Twox256,
517 Twox64Concat,
519 Identity,
521}
522
523impl StorageHasher {
524 pub fn len_excluding_key(&self) -> usize {
532 match self {
533 StorageHasher::Blake2_128Concat => 16,
534 StorageHasher::Twox64Concat => 8,
535 StorageHasher::Blake2_128 => 16,
536 StorageHasher::Blake2_256 => 32,
537 StorageHasher::Twox128 => 16,
538 StorageHasher::Twox256 => 32,
539 StorageHasher::Identity => 0,
540 }
541 }
542
543 pub fn ends_with_key(&self) -> bool {
545 matches!(
546 self,
547 StorageHasher::Blake2_128Concat | StorageHasher::Twox64Concat | StorageHasher::Identity
548 )
549 }
550}
551
552#[derive(Debug, Clone, Copy, Eq, PartialEq)]
554pub enum StorageEntryModifier {
555 Optional,
557 Default,
559}
560
561#[derive(Debug, Clone)]
563pub struct ConstantMetadata {
564 name: ArcStr,
566 ty: u32,
568 value: Vec<u8>,
570 docs: Vec<String>,
572}
573
574impl ConstantMetadata {
575 pub fn name(&self) -> &str {
577 &self.name
578 }
579 pub fn ty(&self) -> u32 {
581 self.ty
582 }
583 pub fn value(&self) -> &[u8] {
585 &self.value
586 }
587 pub fn docs(&self) -> &[String] {
589 &self.docs
590 }
591}
592
593#[derive(Debug, Clone)]
595pub struct ExtrinsicMetadata {
596 address_ty: u32,
598 call_ty: u32,
600 signature_ty: u32,
602 extra_ty: u32,
604 version: u8,
606 signed_extensions: Vec<SignedExtensionMetadata>,
608}
609
610impl ExtrinsicMetadata {
611 pub fn address_ty(&self) -> u32 {
613 self.address_ty
614 }
615
616 pub fn call_ty(&self) -> u32 {
618 self.call_ty
619 }
620 pub fn signature_ty(&self) -> u32 {
622 self.signature_ty
623 }
624 pub fn extra_ty(&self) -> u32 {
626 self.extra_ty
627 }
628
629 pub fn version(&self) -> u8 {
631 self.version
632 }
633
634 pub fn signed_extensions(&self) -> &[SignedExtensionMetadata] {
636 &self.signed_extensions
637 }
638}
639
640#[derive(Debug, Clone)]
642pub struct SignedExtensionMetadata {
643 identifier: String,
645 extra_ty: u32,
647 additional_ty: u32,
649}
650
651impl SignedExtensionMetadata {
652 pub fn identifier(&self) -> &str {
654 &self.identifier
655 }
656 pub fn extra_ty(&self) -> u32 {
658 self.extra_ty
659 }
660 pub fn additional_ty(&self) -> u32 {
662 self.additional_ty
663 }
664}
665
666#[derive(Debug, Clone, Copy)]
668pub struct OuterEnumsMetadata {
669 call_enum_ty: u32,
671 event_enum_ty: u32,
673 error_enum_ty: u32,
675}
676
677impl OuterEnumsMetadata {
678 pub fn call_enum_ty(&self) -> u32 {
680 self.call_enum_ty
681 }
682
683 pub fn event_enum_ty(&self) -> u32 {
685 self.event_enum_ty
686 }
687
688 pub fn error_enum_ty(&self) -> u32 {
690 self.error_enum_ty
691 }
692}
693
694#[derive(Debug, Clone, Copy)]
696pub struct RuntimeApiMetadata<'a> {
697 inner: &'a RuntimeApiMetadataInner,
698 types: &'a PortableRegistry,
699}
700
701impl<'a> RuntimeApiMetadata<'a> {
702 pub fn name(&self) -> &'a str {
704 &self.inner.name
705 }
706 pub fn docs(&self) -> &[String] {
708 &self.inner.docs
709 }
710 pub fn methods(&self) -> impl ExactSizeIterator<Item = &'a RuntimeApiMethodMetadata> {
712 self.inner.methods.values().iter()
713 }
714 pub fn method_by_name(&self, name: &str) -> Option<&'a RuntimeApiMethodMetadata> {
716 self.inner.methods.get_by_key(name)
717 }
718 pub fn method_hash(&self, method_name: &str) -> Option<[u8; HASH_LEN]> {
720 crate::utils::validation::get_runtime_api_hash(self, method_name)
721 }
722
723 pub fn hash(&self) -> [u8; HASH_LEN] {
725 crate::utils::validation::get_runtime_trait_hash(*self, &OuterEnumHashes::empty())
726 }
727}
728
729#[derive(Debug, Clone)]
730struct RuntimeApiMetadataInner {
731 name: ArcStr,
733 methods: OrderedMap<ArcStr, RuntimeApiMethodMetadata>,
735 docs: Vec<String>,
737}
738
739#[derive(Debug, Clone)]
741pub struct RuntimeApiMethodMetadata {
742 name: ArcStr,
744 inputs: Vec<RuntimeApiMethodParamMetadata>,
746 output_ty: u32,
748 docs: Vec<String>,
750}
751
752impl RuntimeApiMethodMetadata {
753 pub fn name(&self) -> &str {
755 &self.name
756 }
757 pub fn docs(&self) -> &[String] {
759 &self.docs
760 }
761 pub fn inputs(&self) -> impl ExactSizeIterator<Item = &RuntimeApiMethodParamMetadata> {
763 self.inputs.iter()
764 }
765 pub fn output_ty(&self) -> u32 {
767 self.output_ty
768 }
769}
770
771#[derive(Debug, Clone)]
773pub struct RuntimeApiMethodParamMetadata {
774 pub name: String,
776 pub ty: u32,
778}
779
780#[derive(Debug, Clone)]
782pub struct CustomMetadata<'a> {
783 types: &'a PortableRegistry,
784 inner: &'a frame_metadata::v15::CustomMetadata<PortableForm>,
785}
786
787impl<'a> CustomMetadata<'a> {
788 pub fn get(&self, name: &str) -> Option<CustomValueMetadata<'a>> {
790 self.inner
791 .map
792 .get_key_value(name)
793 .map(|(name, e)| CustomValueMetadata {
794 types: self.types,
795 type_id: e.ty.id,
796 data: &e.value,
797 name,
798 })
799 }
800
801 pub fn iter(&self) -> impl Iterator<Item = CustomValueMetadata> {
803 self.inner.map.iter().map(|(name, e)| CustomValueMetadata {
804 types: self.types,
805 type_id: e.ty.id,
806 data: &e.value,
807 name: name.as_ref(),
808 })
809 }
810
811 pub fn types(&self) -> &PortableRegistry {
813 self.types
814 }
815}
816
817pub struct CustomValueMetadata<'a> {
819 types: &'a PortableRegistry,
820 type_id: u32,
821 data: &'a [u8],
822 name: &'a str,
823}
824
825impl<'a> CustomValueMetadata<'a> {
826 pub fn types(&self) -> &PortableRegistry {
828 self.types
829 }
830
831 pub fn bytes(&self) -> &'a [u8] {
833 self.data
834 }
835
836 pub fn type_id(&self) -> u32 {
838 self.type_id
839 }
840
841 pub fn name(&self) -> &str {
843 self.name
844 }
845
846 pub fn hash(&self) -> [u8; HASH_LEN] {
848 get_custom_value_hash(self, &OuterEnumHashes::empty())
849 }
850}
851
852impl codec::Decode for Metadata {
855 fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
856 let metadata = frame_metadata::RuntimeMetadataPrefixed::decode(input)?;
857 let metadata = match metadata.1 {
858 frame_metadata::RuntimeMetadata::V14(md) => md.try_into(),
859 frame_metadata::RuntimeMetadata::V15(md) => md.try_into(),
860 _ => return Err("Cannot try_into() to Metadata: unsupported metadata version".into()),
861 };
862
863 metadata.map_err(|_e| "Cannot try_into() to Metadata.".into())
864 }
865}
866
867impl codec::Encode for Metadata {
871 fn encode_to<T: codec::Output + ?Sized>(&self, dest: &mut T) {
872 let m: frame_metadata::v15::RuntimeMetadataV15 = self.clone().into();
873 let m: frame_metadata::RuntimeMetadataPrefixed = m.into();
874 m.encode_to(dest)
875 }
876}
877
878#[cfg(test)]
879mod test {
880 use super::*;
881 use codec::{Decode, Encode};
882
883 fn load_metadata() -> Vec<u8> {
884 std::fs::read("../artifacts/polkadot_metadata_full.scale").unwrap()
885 }
886
887 #[test]
891 fn is_isomorphic_to_v15() {
892 let bytes = load_metadata();
893
894 let metadata = Metadata::decode(&mut &*bytes).unwrap();
896
897 let v15: frame_metadata::v15::RuntimeMetadataV15 = metadata.into();
899 let prefixed = frame_metadata::RuntimeMetadataPrefixed::from(v15);
900
901 let new_bytes = prefixed.encode();
903
904 assert_eq!(bytes, new_bytes);
906 }
907}