referrerpolicy=no-referrer-when-downgrade

frame_support_procedural/construct_runtime/expand/
metadata.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 crate::construct_runtime::{parse::PalletPath, Pallet};
19use proc_macro2::TokenStream;
20use quote::quote;
21use syn::Ident;
22
23pub fn expand_runtime_metadata(
24	runtime: &Ident,
25	pallet_declarations: &[Pallet],
26	scrate: &TokenStream,
27	extrinsic: &TokenStream,
28	system_path: &PalletPath,
29) -> TokenStream {
30	let pallets = pallet_declarations
31		.iter()
32		.filter_map(|pallet_declaration| {
33			pallet_declaration.find_part("Pallet").map(|_| {
34				let filtered_names: Vec<_> = pallet_declaration
35					.pallet_parts()
36					.iter()
37					.filter(|part| part.name() != "Pallet")
38					.map(|part| part.name())
39					.collect();
40				(pallet_declaration, filtered_names)
41			})
42		})
43		.map(|(decl, filtered_names)| {
44			let name = &decl.name;
45			let index = &decl.index;
46			let storage = expand_pallet_metadata_storage(&filtered_names, runtime, decl);
47			let calls = expand_pallet_metadata_calls(&filtered_names, runtime, decl);
48			let view_functions = expand_pallet_metadata_view_functions(runtime, decl);
49			let event = expand_pallet_metadata_events(&filtered_names, runtime, decl);
50			let constants = expand_pallet_metadata_constants(runtime, decl);
51			let errors = expand_pallet_metadata_errors(runtime, decl);
52			let associated_types = expand_pallet_metadata_associated_types(runtime, decl);
53			let docs = expand_pallet_metadata_docs(runtime, decl);
54			let attr = decl.get_attributes();
55			let deprecation_info = expand_pallet_metadata_deprecation(runtime, decl);
56			quote! {
57				#attr
58				#scrate::__private::metadata_ir::PalletMetadataIR {
59					name: stringify!(#name),
60					index: #index,
61					storage: #storage,
62					calls: #calls,
63					view_functions: #view_functions,
64					event: #event,
65					constants: #constants,
66					error: #errors,
67					docs: #docs,
68					associated_types: #associated_types,
69					deprecation_info: #deprecation_info,
70				}
71			}
72		})
73		.collect::<Vec<_>>();
74
75	quote! {
76		impl #runtime {
77			#[allow(deprecated)]
78			fn metadata_ir() -> #scrate::__private::metadata_ir::MetadataIR {
79				// Each runtime must expose the `runtime_metadata()` to fetch the runtime API metadata.
80				// The function is implemented by calling `impl_runtime_apis!`.
81				//
82				// However, the `construct_runtime!` may be called without calling `impl_runtime_apis!`.
83				// Rely on the `Deref` trait to differentiate between a runtime that implements
84				// APIs (by macro impl_runtime_apis!) and a runtime that is simply created (by macro construct_runtime!).
85				//
86				// Both `InternalConstructRuntime` and `InternalImplRuntimeApis` expose a `runtime_metadata()` function.
87				// `InternalConstructRuntime` is implemented by the `construct_runtime!` for Runtime references (`& Runtime`),
88				// while `InternalImplRuntimeApis` is implemented by the `impl_runtime_apis!` for Runtime (`Runtime`).
89				//
90				// Therefore, the `Deref` trait will resolve the `runtime_metadata` from `impl_runtime_apis!`
91				// when both macros are called; and will resolve an empty `runtime_metadata` when only the `construct_runtime!`
92				// is called.
93				//
94				// `Deref` needs a reference for resolving the function call.
95				let rt = #runtime;
96
97				let ty = #scrate::__private::scale_info::meta_type::<#extrinsic>();
98				let address_ty = #scrate::__private::scale_info::meta_type::<
99						<#extrinsic as #scrate::traits::SignedTransactionBuilder>::Address
100					>();
101				let call_ty = #scrate::__private::scale_info::meta_type::<
102						<#extrinsic as #scrate::sp_runtime::traits::ExtrinsicCall>::Call
103					>();
104				let signature_ty = #scrate::__private::scale_info::meta_type::<
105						<#extrinsic as #scrate::traits::SignedTransactionBuilder>::Signature
106					>();
107				let extra_ty = #scrate::__private::scale_info::meta_type::<
108						<#extrinsic as #scrate::traits::SignedTransactionBuilder>::Extension
109					>();
110
111				use #scrate::__private::metadata_ir::InternalImplRuntimeApis;
112
113				#scrate::__private::metadata_ir::MetadataIR {
114					pallets: #scrate::__private::vec![ #(#pallets),* ],
115					extrinsic: #scrate::__private::metadata_ir::ExtrinsicMetadataIR {
116						ty,
117						versions: <#extrinsic as #scrate::sp_runtime::traits::ExtrinsicMetadata>::VERSIONS.into_iter().map(|ref_version| *ref_version).collect(),
118						address_ty,
119						call_ty,
120						signature_ty,
121						extra_ty,
122						extensions: <
123								<
124									#extrinsic as #scrate::sp_runtime::traits::ExtrinsicMetadata
125								>::TransactionExtensions
126								as
127								#scrate::sp_runtime::traits::TransactionExtension::<
128									<#runtime as #system_path::Config>::RuntimeCall
129								>
130							>::metadata()
131								.into_iter()
132								.map(|meta| #scrate::__private::metadata_ir::TransactionExtensionMetadataIR {
133									identifier: meta.identifier,
134									ty: meta.ty,
135									implicit: meta.implicit,
136								})
137								.collect(),
138					},
139					ty: #scrate::__private::scale_info::meta_type::<#runtime>(),
140					apis: (&rt).runtime_metadata(),
141					outer_enums: #scrate::__private::metadata_ir::OuterEnumsIR {
142						call_enum_ty: #scrate::__private::scale_info::meta_type::<
143								<#runtime as #system_path::Config>::RuntimeCall
144							>(),
145						event_enum_ty: #scrate::__private::scale_info::meta_type::<RuntimeEvent>(),
146						error_enum_ty: #scrate::__private::scale_info::meta_type::<RuntimeError>(),
147					},
148				}
149			}
150
151			pub fn metadata() -> #scrate::__private::metadata::RuntimeMetadataPrefixed {
152				// Note: this always returns the V14 version. The runtime API function
153				// must be deprecated.
154				#scrate::__private::metadata_ir::into_v14(#runtime::metadata_ir())
155			}
156
157			pub fn metadata_at_version(version: u32) -> Option<#scrate::__private::OpaqueMetadata> {
158				#scrate::__private::metadata_ir::into_version(#runtime::metadata_ir(), version).map(|prefixed| {
159					#scrate::__private::OpaqueMetadata::new(prefixed.into())
160				})
161			}
162
163			pub fn metadata_versions() -> #scrate::__private::Vec<u32> {
164				#scrate::__private::metadata_ir::supported_versions()
165			}
166		}
167	}
168}
169
170fn expand_pallet_metadata_storage(
171	filtered_names: &[&'static str],
172	runtime: &Ident,
173	decl: &Pallet,
174) -> TokenStream {
175	if filtered_names.contains(&"Storage") {
176		let instance = decl.instance.as_ref().into_iter();
177		let path = &decl.path;
178
179		quote! {
180			Some(#path::Pallet::<#runtime #(, #path::#instance)*>::storage_metadata())
181		}
182	} else {
183		quote!(None)
184	}
185}
186
187fn expand_pallet_metadata_calls(
188	filtered_names: &[&'static str],
189	runtime: &Ident,
190	decl: &Pallet,
191) -> TokenStream {
192	if filtered_names.contains(&"Call") {
193		let instance = decl.instance.as_ref().into_iter();
194		let path = &decl.path;
195
196		quote! {
197			Some(#path::Pallet::<#runtime #(, #path::#instance)*>::call_functions())
198		}
199	} else {
200		quote!(None)
201	}
202}
203
204fn expand_pallet_metadata_view_functions(runtime: &Ident, decl: &Pallet) -> TokenStream {
205	let path = &decl.path;
206	let instance = decl.instance.as_ref().into_iter();
207
208	quote! {
209		#path::Pallet::<#runtime #(, #path::#instance)*>::pallet_view_functions_metadata()
210	}
211}
212
213fn expand_pallet_metadata_events(
214	filtered_names: &[&'static str],
215	runtime: &Ident,
216	decl: &Pallet,
217) -> TokenStream {
218	if filtered_names.contains(&"Event") {
219		let path = &decl.path;
220		let part_is_generic = !decl
221			.find_part("Event")
222			.expect("Event part exists; qed")
223			.generics
224			.params
225			.is_empty();
226		let pallet_event = match (decl.instance.as_ref(), part_is_generic) {
227			(Some(inst), true) => quote!(#path::Event::<#runtime, #path::#inst>),
228			(Some(inst), false) => quote!(#path::Event::<#path::#inst>),
229			(None, true) => quote!(#path::Event::<#runtime>),
230			(None, false) => quote!(#path::Event),
231		};
232
233		quote! {
234			Some(
235				#pallet_event::event_metadata::<#pallet_event>()
236			)
237		}
238	} else {
239		quote!(None)
240	}
241}
242
243fn expand_pallet_metadata_deprecation(runtime: &Ident, decl: &Pallet) -> TokenStream {
244	let path = &decl.path;
245	let instance = decl.instance.as_ref().into_iter();
246
247	quote! { #path::Pallet::<#runtime #(, #path::#instance)*>::deprecation_info() }
248}
249
250fn expand_pallet_metadata_constants(runtime: &Ident, decl: &Pallet) -> TokenStream {
251	let path = &decl.path;
252	let instance = decl.instance.as_ref().into_iter();
253
254	quote! {
255		#path::Pallet::<#runtime #(, #path::#instance)*>::pallet_constants_metadata()
256	}
257}
258
259fn expand_pallet_metadata_errors(runtime: &Ident, decl: &Pallet) -> TokenStream {
260	let path = &decl.path;
261	let instance = decl.instance.as_ref().into_iter();
262
263	quote! {
264		#path::Pallet::<#runtime #(, #path::#instance)*>::error_metadata()
265	}
266}
267
268fn expand_pallet_metadata_docs(runtime: &Ident, decl: &Pallet) -> TokenStream {
269	let path = &decl.path;
270	let instance = decl.instance.as_ref().into_iter();
271
272	quote! {
273		#path::Pallet::<#runtime #(, #path::#instance)*>::pallet_documentation_metadata()
274	}
275}
276
277fn expand_pallet_metadata_associated_types(runtime: &Ident, decl: &Pallet) -> TokenStream {
278	let path = &decl.path;
279	let instance = decl.instance.as_ref().into_iter();
280
281	quote! {
282		#path::Pallet::<#runtime #(, #path::#instance)*>::pallet_associated_types_metadata()
283	}
284}