sp_metadata_ir/
types.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18use codec::{Compact, Decode, Encode};
19use scale_info::{
20	form::{Form, MetaForm, PortableForm},
21	prelude::{collections::BTreeMap, vec::Vec},
22	IntoPortable, Registry,
23};
24
25/// The intermediate representation for the runtime metadata.
26/// Contains the needed context that allows conversion to multiple metadata versions.
27///
28/// # Note
29///
30/// Further fields could be added or removed to ensure proper conversion.
31/// When the IR does not contain enough information to generate a specific version
32/// of the runtime metadata an appropriate default value is used (ie, empty vector).
33pub struct MetadataIR<T: Form = MetaForm> {
34	/// Pallet metadata.
35	pub pallets: Vec<PalletMetadataIR<T>>,
36	/// Metadata of the extrinsic.
37	pub extrinsic: ExtrinsicMetadataIR<T>,
38	/// The type of the `Runtime`.
39	pub ty: T::Type,
40	/// Metadata of the Runtime API.
41	pub apis: Vec<RuntimeApiMetadataIR<T>>,
42	/// The outer enums types as found in the runtime.
43	pub outer_enums: OuterEnumsIR<T>,
44}
45
46/// Metadata of a runtime trait.
47#[derive(Clone, PartialEq, Eq, Encode, Debug)]
48pub struct RuntimeApiMetadataIR<T: Form = MetaForm> {
49	/// Trait name.
50	pub name: T::String,
51	/// Trait methods.
52	pub methods: Vec<RuntimeApiMethodMetadataIR<T>>,
53	/// Trait documentation.
54	pub docs: Vec<T::String>,
55	/// Deprecation info.
56	pub deprecation_info: DeprecationStatusIR<T>,
57	/// Runtime API version.
58	pub version: Compact<u32>,
59}
60
61impl IntoPortable for RuntimeApiMetadataIR {
62	type Output = RuntimeApiMetadataIR<PortableForm>;
63
64	fn into_portable(self, registry: &mut Registry) -> Self::Output {
65		RuntimeApiMetadataIR {
66			name: self.name.into_portable(registry),
67			methods: registry.map_into_portable(self.methods),
68			docs: registry.map_into_portable(self.docs),
69			deprecation_info: self.deprecation_info.into_portable(registry),
70			version: self.version,
71		}
72	}
73}
74
75/// Metadata of a runtime method.
76#[derive(Clone, PartialEq, Eq, Encode, Debug)]
77pub struct RuntimeApiMethodMetadataIR<T: Form = MetaForm> {
78	/// Method name.
79	pub name: T::String,
80	/// Method parameters.
81	pub inputs: Vec<RuntimeApiMethodParamMetadataIR<T>>,
82	/// Method output.
83	pub output: T::Type,
84	/// Method documentation.
85	pub docs: Vec<T::String>,
86	/// Deprecation info
87	pub deprecation_info: DeprecationStatusIR<T>,
88}
89
90impl IntoPortable for RuntimeApiMethodMetadataIR {
91	type Output = RuntimeApiMethodMetadataIR<PortableForm>;
92
93	fn into_portable(self, registry: &mut Registry) -> Self::Output {
94		RuntimeApiMethodMetadataIR {
95			name: self.name.into_portable(registry),
96			inputs: registry.map_into_portable(self.inputs),
97			output: registry.register_type(&self.output),
98			docs: registry.map_into_portable(self.docs),
99			deprecation_info: self.deprecation_info.into_portable(registry),
100		}
101	}
102}
103
104/// Metadata of a runtime method parameter.
105#[derive(Clone, PartialEq, Eq, Encode, Debug)]
106pub struct RuntimeApiMethodParamMetadataIR<T: Form = MetaForm> {
107	/// Parameter name.
108	pub name: T::String,
109	/// Parameter type.
110	pub ty: T::Type,
111}
112
113impl IntoPortable for RuntimeApiMethodParamMetadataIR {
114	type Output = RuntimeApiMethodParamMetadataIR<PortableForm>;
115
116	fn into_portable(self, registry: &mut Registry) -> Self::Output {
117		RuntimeApiMethodParamMetadataIR {
118			name: self.name.into_portable(registry),
119			ty: registry.register_type(&self.ty),
120		}
121	}
122}
123
124/// Metadata of a pallet view function method.
125#[derive(Clone, PartialEq, Eq, Encode, Decode, Debug)]
126pub struct PalletViewFunctionMetadataIR<T: Form = MetaForm> {
127	/// Method name.
128	pub name: T::String,
129	/// Method id.
130	pub id: [u8; 32],
131	/// Method parameters.
132	pub inputs: Vec<PalletViewFunctionParamMetadataIR<T>>,
133	/// Method output.
134	pub output: T::Type,
135	/// Method documentation.
136	pub docs: Vec<T::String>,
137	/// Deprecation info
138	pub deprecation_info: DeprecationStatusIR<T>,
139}
140
141impl IntoPortable for PalletViewFunctionMetadataIR {
142	type Output = PalletViewFunctionMetadataIR<PortableForm>;
143
144	fn into_portable(self, registry: &mut Registry) -> Self::Output {
145		PalletViewFunctionMetadataIR {
146			name: self.name.into_portable(registry),
147			id: self.id,
148			inputs: registry.map_into_portable(self.inputs),
149			output: registry.register_type(&self.output),
150			docs: registry.map_into_portable(self.docs),
151			deprecation_info: self.deprecation_info.into_portable(registry),
152		}
153	}
154}
155
156/// Metadata of a pallet view function method argument.
157#[derive(Clone, PartialEq, Eq, Encode, Decode, Debug)]
158pub struct PalletViewFunctionParamMetadataIR<T: Form = MetaForm> {
159	/// Parameter name.
160	pub name: T::String,
161	/// Parameter type.
162	pub ty: T::Type,
163}
164
165impl IntoPortable for PalletViewFunctionParamMetadataIR {
166	type Output = PalletViewFunctionParamMetadataIR<PortableForm>;
167
168	fn into_portable(self, registry: &mut Registry) -> Self::Output {
169		PalletViewFunctionParamMetadataIR {
170			name: self.name.into_portable(registry),
171			ty: registry.register_type(&self.ty),
172		}
173	}
174}
175
176/// The intermediate representation for a pallet metadata.
177#[derive(Clone, PartialEq, Eq, Encode, Debug)]
178pub struct PalletMetadataIR<T: Form = MetaForm> {
179	/// Pallet name.
180	pub name: T::String,
181	/// Pallet storage metadata.
182	pub storage: Option<PalletStorageMetadataIR<T>>,
183	/// Pallet calls metadata.
184	pub calls: Option<PalletCallMetadataIR<T>>,
185	/// Pallet view functions metadata.
186	pub view_functions: Vec<PalletViewFunctionMetadataIR<T>>,
187	/// Pallet event metadata.
188	pub event: Option<PalletEventMetadataIR<T>>,
189	/// Pallet constants metadata.
190	pub constants: Vec<PalletConstantMetadataIR<T>>,
191	/// Pallet error metadata.
192	pub error: Option<PalletErrorMetadataIR<T>>,
193	/// Config's trait associated types.
194	pub associated_types: Vec<PalletAssociatedTypeMetadataIR<T>>,
195	/// Define the index of the pallet, this index will be used for the encoding of pallet event,
196	/// call and origin variants.
197	pub index: u8,
198	/// Pallet documentation.
199	pub docs: Vec<T::String>,
200	/// Deprecation info
201	pub deprecation_info: DeprecationStatusIR<T>,
202}
203
204impl IntoPortable for PalletMetadataIR {
205	type Output = PalletMetadataIR<PortableForm>;
206
207	fn into_portable(self, registry: &mut Registry) -> Self::Output {
208		PalletMetadataIR {
209			name: self.name.into_portable(registry),
210			storage: self.storage.map(|storage| storage.into_portable(registry)),
211			calls: self.calls.map(|calls| calls.into_portable(registry)),
212			view_functions: self
213				.view_functions
214				.into_iter()
215				.map(|view_functions| view_functions.into_portable(registry))
216				.collect(),
217			event: self.event.map(|event| event.into_portable(registry)),
218			constants: registry.map_into_portable(self.constants),
219			error: self.error.map(|error| error.into_portable(registry)),
220			associated_types: registry.map_into_portable(self.associated_types),
221			index: self.index,
222			docs: registry.map_into_portable(self.docs),
223			deprecation_info: self.deprecation_info.into_portable(registry),
224		}
225	}
226}
227
228/// Metadata of the extrinsic used by the runtime.
229#[derive(Clone, PartialEq, Eq, Encode, Debug)]
230pub struct ExtrinsicMetadataIR<T: Form = MetaForm> {
231	/// The type of the extrinsic.
232	///
233	/// Note: Field used for metadata V14 only.
234	pub ty: T::Type,
235	/// Extrinsic versions.
236	pub versions: Vec<u8>,
237	/// The type of the address that signs the extrinsic
238	pub address_ty: T::Type,
239	/// The type of the outermost Call enum.
240	pub call_ty: T::Type,
241	/// The type of the extrinsic's signature.
242	pub signature_ty: T::Type,
243	/// The type of the outermost Extra/Extensions enum.
244	// TODO: metadata-v16: remove this, the `implicit` type can be found in `extensions::implicit`.
245	pub extra_ty: T::Type,
246	/// The transaction extensions in the order they appear in the extrinsic.
247	pub extensions: Vec<TransactionExtensionMetadataIR<T>>,
248}
249
250impl IntoPortable for ExtrinsicMetadataIR {
251	type Output = ExtrinsicMetadataIR<PortableForm>;
252
253	fn into_portable(self, registry: &mut Registry) -> Self::Output {
254		ExtrinsicMetadataIR {
255			ty: registry.register_type(&self.ty),
256			versions: self.versions,
257			address_ty: registry.register_type(&self.address_ty),
258			call_ty: registry.register_type(&self.call_ty),
259			signature_ty: registry.register_type(&self.signature_ty),
260			extra_ty: registry.register_type(&self.extra_ty),
261			extensions: registry.map_into_portable(self.extensions),
262		}
263	}
264}
265
266/// Metadata of a pallet's associated type.
267#[derive(Clone, PartialEq, Eq, Encode, Debug)]
268pub struct PalletAssociatedTypeMetadataIR<T: Form = MetaForm> {
269	/// The name of the associated type.
270	pub name: T::String,
271	/// The type of the associated type.
272	pub ty: T::Type,
273	/// The documentation of the associated type.
274	pub docs: Vec<T::String>,
275}
276
277impl IntoPortable for PalletAssociatedTypeMetadataIR {
278	type Output = PalletAssociatedTypeMetadataIR<PortableForm>;
279
280	fn into_portable(self, registry: &mut Registry) -> Self::Output {
281		PalletAssociatedTypeMetadataIR {
282			name: self.name.into_portable(registry),
283			ty: registry.register_type(&self.ty),
284			docs: registry.map_into_portable(self.docs),
285		}
286	}
287}
288
289/// Metadata of an extrinsic's signed extension.
290#[derive(Clone, PartialEq, Eq, Encode, Debug)]
291pub struct TransactionExtensionMetadataIR<T: Form = MetaForm> {
292	/// The unique signed extension identifier, which may be different from the type name.
293	pub identifier: T::String,
294	/// The type of the signed extension, with the data to be included in the extrinsic.
295	pub ty: T::Type,
296	/// The type of the implicit data, with the data to be included in the signed payload.
297	pub implicit: T::Type,
298}
299
300impl IntoPortable for TransactionExtensionMetadataIR {
301	type Output = TransactionExtensionMetadataIR<PortableForm>;
302
303	fn into_portable(self, registry: &mut Registry) -> Self::Output {
304		TransactionExtensionMetadataIR {
305			identifier: self.identifier.into_portable(registry),
306			ty: registry.register_type(&self.ty),
307			implicit: registry.register_type(&self.implicit),
308		}
309	}
310}
311
312/// All metadata of the pallet's storage.
313#[derive(Clone, PartialEq, Eq, Encode, Debug)]
314/// The common prefix used by all storage entries.
315pub struct PalletStorageMetadataIR<T: Form = MetaForm> {
316	/// The common prefix used by all storage entries.
317	pub prefix: T::String,
318	/// Metadata for all storage entries.
319	pub entries: Vec<StorageEntryMetadataIR<T>>,
320}
321
322impl IntoPortable for PalletStorageMetadataIR {
323	type Output = PalletStorageMetadataIR<PortableForm>;
324
325	fn into_portable(self, registry: &mut Registry) -> Self::Output {
326		PalletStorageMetadataIR {
327			prefix: self.prefix.into_portable(registry),
328			entries: registry.map_into_portable(self.entries),
329		}
330	}
331}
332
333/// Metadata about one storage entry.
334#[derive(Clone, PartialEq, Eq, Encode, Debug)]
335pub struct StorageEntryMetadataIR<T: Form = MetaForm> {
336	/// Variable name of the storage entry.
337	pub name: T::String,
338	/// An `Option` modifier of that storage entry.
339	pub modifier: StorageEntryModifierIR,
340	/// Type of the value stored in the entry.
341	pub ty: StorageEntryTypeIR<T>,
342	/// Default value (SCALE encoded).
343	pub default: Vec<u8>,
344	/// Storage entry documentation.
345	pub docs: Vec<T::String>,
346	/// Deprecation info
347	pub deprecation_info: DeprecationStatusIR<T>,
348}
349
350impl IntoPortable for StorageEntryMetadataIR {
351	type Output = StorageEntryMetadataIR<PortableForm>;
352
353	fn into_portable(self, registry: &mut Registry) -> Self::Output {
354		StorageEntryMetadataIR {
355			name: self.name.into_portable(registry),
356			modifier: self.modifier,
357			ty: self.ty.into_portable(registry),
358			default: self.default,
359			docs: registry.map_into_portable(self.docs),
360			deprecation_info: self.deprecation_info.into_portable(registry),
361		}
362	}
363}
364
365/// A storage entry modifier indicates how a storage entry is returned when fetched and what the
366/// value will be if the key is not present. Specifically this refers to the "return type" when
367/// fetching a storage entry, and what the value will be if the key is not present.
368///
369/// `Optional` means you should expect an `Option<T>`, with `None` returned if the key is not
370/// present. `Default` means you should expect a `T` with the default value of default if the key is
371/// not present.
372#[derive(Clone, PartialEq, Eq, Encode, Debug)]
373pub enum StorageEntryModifierIR {
374	/// The storage entry returns an `Option<T>`, with `None` if the key is not present.
375	Optional,
376	/// The storage entry returns `T::Default` if the key is not present.
377	Default,
378}
379
380/// Hasher used by storage maps
381#[derive(Clone, PartialEq, Eq, Encode, Debug)]
382pub enum StorageHasherIR {
383	/// 128-bit Blake2 hash.
384	Blake2_128,
385	/// 256-bit Blake2 hash.
386	Blake2_256,
387	/// Multiple 128-bit Blake2 hashes concatenated.
388	Blake2_128Concat,
389	/// 128-bit XX hash.
390	Twox128,
391	/// 256-bit XX hash.
392	Twox256,
393	/// Multiple 64-bit XX hashes concatenated.
394	Twox64Concat,
395	/// Identity hashing (no hashing).
396	Identity,
397}
398
399/// A type of storage value.
400#[derive(Clone, PartialEq, Eq, Encode, Debug)]
401pub enum StorageEntryTypeIR<T: Form = MetaForm> {
402	/// Plain storage entry (just the value).
403	Plain(T::Type),
404	/// A storage map.
405	Map {
406		/// One or more hashers, should be one hasher per key element.
407		hashers: Vec<StorageHasherIR>,
408		/// The type of the key, can be a tuple with elements for each of the hashers.
409		key: T::Type,
410		/// The type of the value.
411		value: T::Type,
412	},
413}
414
415impl IntoPortable for StorageEntryTypeIR {
416	type Output = StorageEntryTypeIR<PortableForm>;
417
418	fn into_portable(self, registry: &mut Registry) -> Self::Output {
419		match self {
420			Self::Plain(plain) => StorageEntryTypeIR::Plain(registry.register_type(&plain)),
421			Self::Map { hashers, key, value } => StorageEntryTypeIR::Map {
422				hashers,
423				key: registry.register_type(&key),
424				value: registry.register_type(&value),
425			},
426		}
427	}
428}
429
430/// Metadata for all calls in a pallet
431#[derive(Clone, PartialEq, Eq, Encode, Debug)]
432pub struct PalletCallMetadataIR<T: Form = MetaForm> {
433	/// The corresponding enum type for the pallet call.
434	pub ty: T::Type,
435	/// Deprecation status of the pallet call
436	pub deprecation_info: DeprecationInfoIR<T>,
437}
438
439impl IntoPortable for PalletCallMetadataIR {
440	type Output = PalletCallMetadataIR<PortableForm>;
441
442	fn into_portable(self, registry: &mut Registry) -> Self::Output {
443		PalletCallMetadataIR {
444			ty: registry.register_type(&self.ty),
445			deprecation_info: self.deprecation_info.into_portable(registry),
446		}
447	}
448}
449
450/// Metadata about the pallet Event type.
451#[derive(Clone, PartialEq, Eq, Encode, Debug)]
452pub struct PalletEventMetadataIR<T: Form = MetaForm> {
453	/// The Event type.
454	pub ty: T::Type,
455	/// Deprecation info of the event
456	pub deprecation_info: DeprecationInfoIR<T>,
457}
458
459impl IntoPortable for PalletEventMetadataIR {
460	type Output = PalletEventMetadataIR<PortableForm>;
461
462	fn into_portable(self, registry: &mut Registry) -> Self::Output {
463		PalletEventMetadataIR {
464			ty: registry.register_type(&self.ty),
465			deprecation_info: self.deprecation_info.into_portable(registry),
466		}
467	}
468}
469
470/// Metadata about one pallet constant.
471#[derive(Clone, PartialEq, Eq, Encode, Debug)]
472pub struct PalletConstantMetadataIR<T: Form = MetaForm> {
473	/// Name of the pallet constant.
474	pub name: T::String,
475	/// Type of the pallet constant.
476	pub ty: T::Type,
477	/// Value stored in the constant (SCALE encoded).
478	pub value: Vec<u8>,
479	/// Documentation of the constant.
480	pub docs: Vec<T::String>,
481	/// Deprecation info
482	pub deprecation_info: DeprecationStatusIR<T>,
483}
484
485impl IntoPortable for PalletConstantMetadataIR {
486	type Output = PalletConstantMetadataIR<PortableForm>;
487
488	fn into_portable(self, registry: &mut Registry) -> Self::Output {
489		PalletConstantMetadataIR {
490			name: self.name.into_portable(registry),
491			ty: registry.register_type(&self.ty),
492			value: self.value,
493			docs: registry.map_into_portable(self.docs),
494			deprecation_info: self.deprecation_info.into_portable(registry),
495		}
496	}
497}
498
499/// Metadata about a pallet error.
500#[derive(Clone, PartialEq, Eq, Encode, Debug)]
501pub struct PalletErrorMetadataIR<T: Form = MetaForm> {
502	/// The error type information.
503	pub ty: T::Type,
504	/// Deprecation info
505	pub deprecation_info: DeprecationInfoIR<T>,
506}
507
508impl IntoPortable for PalletErrorMetadataIR {
509	type Output = PalletErrorMetadataIR<PortableForm>;
510
511	fn into_portable(self, registry: &mut Registry) -> Self::Output {
512		PalletErrorMetadataIR {
513			ty: registry.register_type(&self.ty),
514			deprecation_info: self.deprecation_info.into_portable(registry),
515		}
516	}
517}
518
519/// The type of the outer enums.
520#[derive(Clone, PartialEq, Eq, Encode, Debug)]
521pub struct OuterEnumsIR<T: Form = MetaForm> {
522	/// The type of the outer `RuntimeCall` enum.
523	pub call_enum_ty: T::Type,
524	/// The type of the outer `RuntimeEvent` enum.
525	pub event_enum_ty: T::Type,
526	/// The module error type of the
527	/// [`DispatchError::Module`](https://docs.rs/sp-runtime/24.0.0/sp_runtime/enum.DispatchError.html#variant.Module) variant.
528	///
529	/// The `Module` variant will be 5 scale encoded bytes which are normally decoded into
530	/// an `{ index: u8, error: [u8; 4] }` struct. This type ID points to an enum type which
531	/// instead interprets the first `index` byte as a pallet variant, and the remaining `error`
532	/// bytes as the appropriate `pallet::Error` type. It is an equally valid way to decode the
533	/// error bytes, and can be more informative.
534	///
535	/// # Note
536	///
537	/// - This type cannot be used directly to decode `sp_runtime::DispatchError` from the chain.
538	///   It provides just the information needed to decode `sp_runtime::DispatchError::Module`.
539	/// - Decoding the 5 error bytes into this type will not always lead to all of the bytes being
540	///   consumed; many error types do not require all of the bytes to represent them fully.
541	pub error_enum_ty: T::Type,
542}
543
544impl IntoPortable for OuterEnumsIR {
545	type Output = OuterEnumsIR<PortableForm>;
546
547	fn into_portable(self, registry: &mut Registry) -> Self::Output {
548		OuterEnumsIR {
549			call_enum_ty: registry.register_type(&self.call_enum_ty),
550			event_enum_ty: registry.register_type(&self.event_enum_ty),
551			error_enum_ty: registry.register_type(&self.error_enum_ty),
552		}
553	}
554}
555
556/// Deprecation status for an entry inside MetadataIR
557#[derive(Clone, PartialEq, Eq, Encode, Debug)]
558pub enum DeprecationStatusIR<T: Form = MetaForm> {
559	/// Entry is not deprecated
560	NotDeprecated,
561	/// Deprecated without a note.
562	DeprecatedWithoutNote,
563	/// Entry is deprecated with an note and an optional `since` field.
564	Deprecated {
565		/// Note explaining the deprecation
566		note: T::String,
567		/// Optional value for denoting version when the deprecation occured
568		since: Option<T::String>,
569	},
570}
571impl IntoPortable for DeprecationStatusIR {
572	type Output = DeprecationStatusIR<PortableForm>;
573
574	fn into_portable(self, registry: &mut Registry) -> Self::Output {
575		match self {
576			Self::Deprecated { note, since } => {
577				let note = note.into_portable(registry);
578				let since = since.map(|x| x.into_portable(registry));
579				DeprecationStatusIR::Deprecated { note, since }
580			},
581			Self::DeprecatedWithoutNote => DeprecationStatusIR::DeprecatedWithoutNote,
582			Self::NotDeprecated => DeprecationStatusIR::NotDeprecated,
583		}
584	}
585}
586/// Deprecation info for an enums/errors/calls.
587/// Denotes full/partial deprecation of the type
588#[derive(Clone, PartialEq, Eq, Encode, Debug)]
589pub enum DeprecationInfoIR<T: Form = MetaForm> {
590	/// Type is not deprecated
591	NotDeprecated,
592	/// Entry is fully deprecated.
593	ItemDeprecated(DeprecationStatusIR<T>),
594	/// Entry is partially deprecated.
595	VariantsDeprecated(BTreeMap<Compact<u8>, DeprecationStatusIR<T>>),
596}
597impl IntoPortable for DeprecationInfoIR {
598	type Output = DeprecationInfoIR<PortableForm>;
599
600	fn into_portable(self, registry: &mut Registry) -> Self::Output {
601		match self {
602			Self::VariantsDeprecated(entries) => {
603				let entries =
604					entries.into_iter().map(|(k, entry)| (k, entry.into_portable(registry)));
605				DeprecationInfoIR::VariantsDeprecated(entries.collect())
606			},
607			Self::ItemDeprecated(deprecation) =>
608				DeprecationInfoIR::ItemDeprecated(deprecation.into_portable(registry)),
609			Self::NotDeprecated => DeprecationInfoIR::NotDeprecated,
610		}
611	}
612}