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, 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}
58
59impl IntoPortable for RuntimeApiMetadataIR {
60	type Output = RuntimeApiMetadataIR<PortableForm>;
61
62	fn into_portable(self, registry: &mut Registry) -> Self::Output {
63		RuntimeApiMetadataIR {
64			name: self.name.into_portable(registry),
65			methods: registry.map_into_portable(self.methods),
66			docs: registry.map_into_portable(self.docs),
67			deprecation_info: self.deprecation_info.into_portable(registry),
68		}
69	}
70}
71
72/// Metadata of a runtime method.
73#[derive(Clone, PartialEq, Eq, Encode, Debug)]
74pub struct RuntimeApiMethodMetadataIR<T: Form = MetaForm> {
75	/// Method name.
76	pub name: T::String,
77	/// Method parameters.
78	pub inputs: Vec<RuntimeApiMethodParamMetadataIR<T>>,
79	/// Method output.
80	pub output: T::Type,
81	/// Method documentation.
82	pub docs: Vec<T::String>,
83	/// Deprecation info
84	pub deprecation_info: DeprecationStatusIR<T>,
85}
86
87impl IntoPortable for RuntimeApiMethodMetadataIR {
88	type Output = RuntimeApiMethodMetadataIR<PortableForm>;
89
90	fn into_portable(self, registry: &mut Registry) -> Self::Output {
91		RuntimeApiMethodMetadataIR {
92			name: self.name.into_portable(registry),
93			inputs: registry.map_into_portable(self.inputs),
94			output: registry.register_type(&self.output),
95			docs: registry.map_into_portable(self.docs),
96			deprecation_info: self.deprecation_info.into_portable(registry),
97		}
98	}
99}
100
101/// Metadata of a runtime method parameter.
102#[derive(Clone, PartialEq, Eq, Encode, Debug)]
103pub struct RuntimeApiMethodParamMetadataIR<T: Form = MetaForm> {
104	/// Parameter name.
105	pub name: T::String,
106	/// Parameter type.
107	pub ty: T::Type,
108}
109
110impl IntoPortable for RuntimeApiMethodParamMetadataIR {
111	type Output = RuntimeApiMethodParamMetadataIR<PortableForm>;
112
113	fn into_portable(self, registry: &mut Registry) -> Self::Output {
114		RuntimeApiMethodParamMetadataIR {
115			name: self.name.into_portable(registry),
116			ty: registry.register_type(&self.ty),
117		}
118	}
119}
120
121/// The intermediate representation for a pallet metadata.
122#[derive(Clone, PartialEq, Eq, Encode, Debug)]
123pub struct PalletMetadataIR<T: Form = MetaForm> {
124	/// Pallet name.
125	pub name: T::String,
126	/// Pallet storage metadata.
127	pub storage: Option<PalletStorageMetadataIR<T>>,
128	/// Pallet calls metadata.
129	pub calls: Option<PalletCallMetadataIR<T>>,
130	/// Pallet event metadata.
131	pub event: Option<PalletEventMetadataIR<T>>,
132	/// Pallet constants metadata.
133	pub constants: Vec<PalletConstantMetadataIR<T>>,
134	/// Pallet error metadata.
135	pub error: Option<PalletErrorMetadataIR<T>>,
136	/// Define the index of the pallet, this index will be used for the encoding of pallet event,
137	/// call and origin variants.
138	pub index: u8,
139	/// Pallet documentation.
140	pub docs: Vec<T::String>,
141	/// Deprecation info
142	pub deprecation_info: DeprecationStatusIR<T>,
143}
144
145impl IntoPortable for PalletMetadataIR {
146	type Output = PalletMetadataIR<PortableForm>;
147
148	fn into_portable(self, registry: &mut Registry) -> Self::Output {
149		PalletMetadataIR {
150			name: self.name.into_portable(registry),
151			storage: self.storage.map(|storage| storage.into_portable(registry)),
152			calls: self.calls.map(|calls| calls.into_portable(registry)),
153			event: self.event.map(|event| event.into_portable(registry)),
154			constants: registry.map_into_portable(self.constants),
155			error: self.error.map(|error| error.into_portable(registry)),
156			index: self.index,
157			docs: registry.map_into_portable(self.docs),
158			deprecation_info: self.deprecation_info.into_portable(registry),
159		}
160	}
161}
162
163/// Metadata of the extrinsic used by the runtime.
164#[derive(Clone, PartialEq, Eq, Encode, Debug)]
165pub struct ExtrinsicMetadataIR<T: Form = MetaForm> {
166	/// The type of the extrinsic.
167	///
168	/// Note: Field used for metadata V14 only.
169	pub ty: T::Type,
170	/// Extrinsic version.
171	pub version: u8,
172	/// The type of the address that signs the extrinsic
173	pub address_ty: T::Type,
174	/// The type of the outermost Call enum.
175	pub call_ty: T::Type,
176	/// The type of the extrinsic's signature.
177	pub signature_ty: T::Type,
178	/// The type of the outermost Extra enum.
179	pub extra_ty: T::Type,
180	/// The signed extensions in the order they appear in the extrinsic.
181	pub signed_extensions: Vec<SignedExtensionMetadataIR<T>>,
182}
183
184impl IntoPortable for ExtrinsicMetadataIR {
185	type Output = ExtrinsicMetadataIR<PortableForm>;
186
187	fn into_portable(self, registry: &mut Registry) -> Self::Output {
188		ExtrinsicMetadataIR {
189			ty: registry.register_type(&self.ty),
190			version: self.version,
191			address_ty: registry.register_type(&self.address_ty),
192			call_ty: registry.register_type(&self.call_ty),
193			signature_ty: registry.register_type(&self.signature_ty),
194			extra_ty: registry.register_type(&self.extra_ty),
195			signed_extensions: registry.map_into_portable(self.signed_extensions),
196		}
197	}
198}
199
200/// Metadata of an extrinsic's signed extension.
201#[derive(Clone, PartialEq, Eq, Encode, Debug)]
202pub struct SignedExtensionMetadataIR<T: Form = MetaForm> {
203	/// The unique signed extension identifier, which may be different from the type name.
204	pub identifier: T::String,
205	/// The type of the signed extension, with the data to be included in the extrinsic.
206	pub ty: T::Type,
207	/// The type of the additional signed data, with the data to be included in the signed payload
208	pub additional_signed: T::Type,
209}
210
211impl IntoPortable for SignedExtensionMetadataIR {
212	type Output = SignedExtensionMetadataIR<PortableForm>;
213
214	fn into_portable(self, registry: &mut Registry) -> Self::Output {
215		SignedExtensionMetadataIR {
216			identifier: self.identifier.into_portable(registry),
217			ty: registry.register_type(&self.ty),
218			additional_signed: registry.register_type(&self.additional_signed),
219		}
220	}
221}
222
223/// All metadata of the pallet's storage.
224#[derive(Clone, PartialEq, Eq, Encode, Debug)]
225/// The common prefix used by all storage entries.
226pub struct PalletStorageMetadataIR<T: Form = MetaForm> {
227	/// The common prefix used by all storage entries.
228	pub prefix: T::String,
229	/// Metadata for all storage entries.
230	pub entries: Vec<StorageEntryMetadataIR<T>>,
231}
232
233impl IntoPortable for PalletStorageMetadataIR {
234	type Output = PalletStorageMetadataIR<PortableForm>;
235
236	fn into_portable(self, registry: &mut Registry) -> Self::Output {
237		PalletStorageMetadataIR {
238			prefix: self.prefix.into_portable(registry),
239			entries: registry.map_into_portable(self.entries),
240		}
241	}
242}
243
244/// Metadata about one storage entry.
245#[derive(Clone, PartialEq, Eq, Encode, Debug)]
246pub struct StorageEntryMetadataIR<T: Form = MetaForm> {
247	/// Variable name of the storage entry.
248	pub name: T::String,
249	/// An `Option` modifier of that storage entry.
250	pub modifier: StorageEntryModifierIR,
251	/// Type of the value stored in the entry.
252	pub ty: StorageEntryTypeIR<T>,
253	/// Default value (SCALE encoded).
254	pub default: Vec<u8>,
255	/// Storage entry documentation.
256	pub docs: Vec<T::String>,
257	/// Deprecation info
258	pub deprecation_info: DeprecationStatusIR<T>,
259}
260
261impl IntoPortable for StorageEntryMetadataIR {
262	type Output = StorageEntryMetadataIR<PortableForm>;
263
264	fn into_portable(self, registry: &mut Registry) -> Self::Output {
265		StorageEntryMetadataIR {
266			name: self.name.into_portable(registry),
267			modifier: self.modifier,
268			ty: self.ty.into_portable(registry),
269			default: self.default,
270			docs: registry.map_into_portable(self.docs),
271			deprecation_info: self.deprecation_info.into_portable(registry),
272		}
273	}
274}
275
276/// A storage entry modifier indicates how a storage entry is returned when fetched and what the
277/// value will be if the key is not present. Specifically this refers to the "return type" when
278/// fetching a storage entry, and what the value will be if the key is not present.
279///
280/// `Optional` means you should expect an `Option<T>`, with `None` returned if the key is not
281/// present. `Default` means you should expect a `T` with the default value of default if the key is
282/// not present.
283#[derive(Clone, PartialEq, Eq, Encode, Debug)]
284pub enum StorageEntryModifierIR {
285	/// The storage entry returns an `Option<T>`, with `None` if the key is not present.
286	Optional,
287	/// The storage entry returns `T::Default` if the key is not present.
288	Default,
289}
290
291/// Hasher used by storage maps
292#[derive(Clone, PartialEq, Eq, Encode, Debug)]
293pub enum StorageHasherIR {
294	/// 128-bit Blake2 hash.
295	Blake2_128,
296	/// 256-bit Blake2 hash.
297	Blake2_256,
298	/// Multiple 128-bit Blake2 hashes concatenated.
299	Blake2_128Concat,
300	/// 128-bit XX hash.
301	Twox128,
302	/// 256-bit XX hash.
303	Twox256,
304	/// Multiple 64-bit XX hashes concatenated.
305	Twox64Concat,
306	/// Identity hashing (no hashing).
307	Identity,
308}
309
310/// A type of storage value.
311#[derive(Clone, PartialEq, Eq, Encode, Debug)]
312pub enum StorageEntryTypeIR<T: Form = MetaForm> {
313	/// Plain storage entry (just the value).
314	Plain(T::Type),
315	/// A storage map.
316	Map {
317		/// One or more hashers, should be one hasher per key element.
318		hashers: Vec<StorageHasherIR>,
319		/// The type of the key, can be a tuple with elements for each of the hashers.
320		key: T::Type,
321		/// The type of the value.
322		value: T::Type,
323	},
324}
325
326impl IntoPortable for StorageEntryTypeIR {
327	type Output = StorageEntryTypeIR<PortableForm>;
328
329	fn into_portable(self, registry: &mut Registry) -> Self::Output {
330		match self {
331			Self::Plain(plain) => StorageEntryTypeIR::Plain(registry.register_type(&plain)),
332			Self::Map { hashers, key, value } => StorageEntryTypeIR::Map {
333				hashers,
334				key: registry.register_type(&key),
335				value: registry.register_type(&value),
336			},
337		}
338	}
339}
340
341/// Metadata for all calls in a pallet
342#[derive(Clone, PartialEq, Eq, Encode, Debug)]
343pub struct PalletCallMetadataIR<T: Form = MetaForm> {
344	/// The corresponding enum type for the pallet call.
345	pub ty: T::Type,
346	/// Deprecation status of the pallet call
347	pub deprecation_info: DeprecationInfoIR<T>,
348}
349
350impl IntoPortable for PalletCallMetadataIR {
351	type Output = PalletCallMetadataIR<PortableForm>;
352
353	fn into_portable(self, registry: &mut Registry) -> Self::Output {
354		PalletCallMetadataIR {
355			ty: registry.register_type(&self.ty),
356			deprecation_info: self.deprecation_info.into_portable(registry),
357		}
358	}
359}
360
361/// Metadata about the pallet Event type.
362#[derive(Clone, PartialEq, Eq, Encode, Debug)]
363pub struct PalletEventMetadataIR<T: Form = MetaForm> {
364	/// The Event type.
365	pub ty: T::Type,
366	/// Deprecation info of the event
367	pub deprecation_info: DeprecationInfoIR<T>,
368}
369
370impl IntoPortable for PalletEventMetadataIR {
371	type Output = PalletEventMetadataIR<PortableForm>;
372
373	fn into_portable(self, registry: &mut Registry) -> Self::Output {
374		PalletEventMetadataIR {
375			ty: registry.register_type(&self.ty),
376			deprecation_info: self.deprecation_info.into_portable(registry),
377		}
378	}
379}
380
381/// Metadata about one pallet constant.
382#[derive(Clone, PartialEq, Eq, Encode, Debug)]
383pub struct PalletConstantMetadataIR<T: Form = MetaForm> {
384	/// Name of the pallet constant.
385	pub name: T::String,
386	/// Type of the pallet constant.
387	pub ty: T::Type,
388	/// Value stored in the constant (SCALE encoded).
389	pub value: Vec<u8>,
390	/// Documentation of the constant.
391	pub docs: Vec<T::String>,
392	/// Deprecation info
393	pub deprecation_info: DeprecationStatusIR<T>,
394}
395
396impl IntoPortable for PalletConstantMetadataIR {
397	type Output = PalletConstantMetadataIR<PortableForm>;
398
399	fn into_portable(self, registry: &mut Registry) -> Self::Output {
400		PalletConstantMetadataIR {
401			name: self.name.into_portable(registry),
402			ty: registry.register_type(&self.ty),
403			value: self.value,
404			docs: registry.map_into_portable(self.docs),
405			deprecation_info: self.deprecation_info.into_portable(registry),
406		}
407	}
408}
409
410/// Metadata about a pallet error.
411#[derive(Clone, PartialEq, Eq, Encode, Debug)]
412pub struct PalletErrorMetadataIR<T: Form = MetaForm> {
413	/// The error type information.
414	pub ty: T::Type,
415	/// Deprecation info
416	pub deprecation_info: DeprecationInfoIR<T>,
417}
418
419impl IntoPortable for PalletErrorMetadataIR {
420	type Output = PalletErrorMetadataIR<PortableForm>;
421
422	fn into_portable(self, registry: &mut Registry) -> Self::Output {
423		PalletErrorMetadataIR {
424			ty: registry.register_type(&self.ty),
425			deprecation_info: self.deprecation_info.into_portable(registry),
426		}
427	}
428}
429
430/// The type of the outer enums.
431#[derive(Clone, PartialEq, Eq, Encode, Debug)]
432pub struct OuterEnumsIR<T: Form = MetaForm> {
433	/// The type of the outer `RuntimeCall` enum.
434	pub call_enum_ty: T::Type,
435	/// The type of the outer `RuntimeEvent` enum.
436	pub event_enum_ty: T::Type,
437	/// The module error type of the
438	/// [`DispatchError::Module`](https://docs.rs/sp-runtime/24.0.0/sp_runtime/enum.DispatchError.html#variant.Module) variant.
439	///
440	/// The `Module` variant will be 5 scale encoded bytes which are normally decoded into
441	/// an `{ index: u8, error: [u8; 4] }` struct. This type ID points to an enum type which
442	/// instead interprets the first `index` byte as a pallet variant, and the remaining `error`
443	/// bytes as the appropriate `pallet::Error` type. It is an equally valid way to decode the
444	/// error bytes, and can be more informative.
445	///
446	/// # Note
447	///
448	/// - This type cannot be used directly to decode `sp_runtime::DispatchError` from the chain.
449	///   It provides just the information needed to decode `sp_runtime::DispatchError::Module`.
450	/// - Decoding the 5 error bytes into this type will not always lead to all of the bytes being
451	///   consumed; many error types do not require all of the bytes to represent them fully.
452	pub error_enum_ty: T::Type,
453}
454
455impl IntoPortable for OuterEnumsIR {
456	type Output = OuterEnumsIR<PortableForm>;
457
458	fn into_portable(self, registry: &mut Registry) -> Self::Output {
459		OuterEnumsIR {
460			call_enum_ty: registry.register_type(&self.call_enum_ty),
461			event_enum_ty: registry.register_type(&self.event_enum_ty),
462			error_enum_ty: registry.register_type(&self.error_enum_ty),
463		}
464	}
465}
466
467/// Deprecation status for an entry inside MetadataIR
468#[derive(Clone, PartialEq, Eq, Encode, Debug)]
469pub enum DeprecationStatusIR<T: Form = MetaForm> {
470	/// Entry is not deprecated
471	NotDeprecated,
472	/// Deprecated without a note.
473	DeprecatedWithoutNote,
474	/// Entry is deprecated with an note and an optional `since` field.
475	Deprecated {
476		/// Note explaining the deprecation
477		note: T::String,
478		/// Optional value for denoting version when the deprecation occured
479		since: Option<T::String>,
480	},
481}
482impl IntoPortable for DeprecationStatusIR {
483	type Output = DeprecationStatusIR<PortableForm>;
484
485	fn into_portable(self, registry: &mut Registry) -> Self::Output {
486		match self {
487			Self::Deprecated { note, since } => {
488				let note = note.into_portable(registry);
489				let since = since.map(|x| x.into_portable(registry));
490				DeprecationStatusIR::Deprecated { note, since }
491			},
492			Self::DeprecatedWithoutNote => DeprecationStatusIR::DeprecatedWithoutNote,
493			Self::NotDeprecated => DeprecationStatusIR::NotDeprecated,
494		}
495	}
496}
497/// Deprecation info for an enums/errors/calls.
498/// Denotes full/partial deprecation of the type
499#[derive(Clone, PartialEq, Eq, Encode, Debug)]
500pub enum DeprecationInfoIR<T: Form = MetaForm> {
501	/// Type is not deprecated
502	NotDeprecated,
503	/// Entry is fully deprecated.
504	ItemDeprecated(DeprecationStatusIR<T>),
505	/// Entry is partially deprecated.
506	VariantsDeprecated(BTreeMap<Compact<u8>, DeprecationStatusIR<T>>),
507}
508impl IntoPortable for DeprecationInfoIR {
509	type Output = DeprecationInfoIR<PortableForm>;
510
511	fn into_portable(self, registry: &mut Registry) -> Self::Output {
512		match self {
513			Self::VariantsDeprecated(entries) => {
514				let entries =
515					entries.into_iter().map(|(k, entry)| (k, entry.into_portable(registry)));
516				DeprecationInfoIR::VariantsDeprecated(entries.collect())
517			},
518			Self::ItemDeprecated(deprecation) =>
519				DeprecationInfoIR::ItemDeprecated(deprecation.into_portable(registry)),
520			Self::NotDeprecated => DeprecationInfoIR::NotDeprecated,
521		}
522	}
523}