pezkuwi_subxt_metadata/
lib.rs

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