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