referrerpolicy=no-referrer-when-downgrade

frame_support_procedural/construct_runtime/
mod.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
18//! Implementation of `construct_runtime`.
19//!
20//! `construct_runtime` implementation is recursive and can generate code which will call itself in
21//! order to get all the pallet parts for each pallet.
22//!
23//! Pallets can define their parts:
24//!  - Implicitly: `System: frame_system`
25//!  - Explicitly: `System: frame_system::{Pallet, Call}`
26//!
27//! The `construct_runtime` transitions from the implicit definition to the explicit one.
28//! From the explicit state, Substrate expands the pallets with additional information
29//! that is to be included in the runtime metadata. This expansion makes visible some extra
30//! parts of the pallets, mainly the `Error` if defined. The expanded state looks like
31//! `System: frame_system expanded::{Error} ::{Pallet, Call}` and concatenates the extra expanded
32//! parts with the user-provided parts. For example, the `Pallet`, `Call` and `Error` parts are
33//! collected.
34//!
35//! Pallets must provide the `tt_extra_parts` and `tt_default_parts` macros for these transitions.
36//! These are automatically implemented by the `#[pallet::pallet]` macro.
37//!
38//! This macro also generates the following enums for ease of decoding:
39//!  - `enum RuntimeCall`: This type contains the information needed to decode extrinsics.
40//!  - `enum RuntimeEvent`: This type contains the information needed to decode events.
41//!  - `enum RuntimeError`: While this cannot be used directly to decode `sp_runtime::DispatchError`
42//!    from the chain, it contains the information needed to decode the
43//!    `sp_runtime::DispatchError::Module`.
44//!
45//! # State Transitions
46//!
47//! ```ignore
48//!  +----------+
49//!  | Implicit | -----------+
50//!  +----------+            |
51//!      |                   |
52//!      v                   v
53//!  +----------+     +------------------+
54//!  | Explicit | --> | ExplicitExpanded |
55//!  +----------+     +------------------+
56//! ```
57//!
58//! When all pallet parts are implicit, then the `construct_runtime!` macro expands to its final
59//! state, the `ExplicitExpanded`. Otherwise, all implicit parts are converted to an explicit
60//! expanded part allow the `construct_runtime!` to expand any remaining explicit parts to an
61//! explicit expanded part.
62//!
63//! # Implicit to Explicit
64//!
65//! The `construct_runtime` macro transforms the implicit declaration of each pallet
66//! `System: frame_system` to an explicit one `System: frame_system::{Pallet, Call}` using the
67//! `tt_default_parts` macro.
68//!
69//! The `tt_default_parts` macro exposes a comma separated list of pallet parts. For example, the
70//! `Event` part is exposed only if the pallet implements an event via `#[pallet::event]` macro.
71//! The tokens generated by this macro are ` expanded :: { Pallet, Call }` for our example.
72//!
73//! The `match_and_insert` macro takes in 3 arguments:
74//!  - target: This is the `TokenStream` that contains the `construct_runtime!` macro.
75//!  - pattern: The pattern to match against in the target stream.
76//!  - tokens: The tokens to added after the pattern match.
77//!
78//! The `construct_runtime` macro uses the `tt_call` to get the default pallet parts via
79//! the `tt_default_parts` macro defined by each pallet. The pallet parts are then returned as
80//! input to the `match_and_replace` macro.
81//! The `match_and_replace` then will modify the the `construct_runtime!` to expand the implicit
82//! definition to the explicit one.
83//!
84//! For example,
85//!
86//! ```ignore
87//! construct_runtime!(
88//! 	//...
89//! 	{
90//! 		System: frame_system = 0, // Implicit definition of parts
91//! 		Balances: pallet_balances = 1, // Implicit definition of parts
92//! 	}
93//! );
94//! ```
95//! This call has some implicit pallet parts, thus it will expand to:
96//! ```ignore
97//! frame_support::__private::tt_call! {
98//! 	macro = [{ pallet_balances::tt_default_parts }]
99//! 	~~> frame_support::match_and_insert! {
100//! 		target = [{
101//! 			frame_support::__private::tt_call! {
102//! 				macro = [{ frame_system::tt_default_parts }]
103//! 				~~> frame_support::match_and_insert! {
104//! 					target = [{
105//! 						construct_runtime!(
106//! 							//...
107//! 							{
108//! 								System: frame_system = 0,
109//! 								Balances: pallet_balances = 1,
110//! 							}
111//! 						);
112//! 					}]
113//! 					pattern = [{ System: frame_system }]
114//! 				}
115//! 			}
116//! 		}]
117//! 		pattern = [{ Balances: pallet_balances }]
118//! 	}
119//! }
120//! ```
121//! `tt_default_parts` must be defined. It returns the pallet parts inside some tokens, and
122//! then `tt_call` will pipe the returned pallet parts into the input of `match_and_insert`.
123//! Thus `match_and_insert` will initially receive the following inputs:
124//! ```ignore
125//! frame_support::match_and_insert! {
126//! 	target = [{
127//! 		frame_support::match_and_insert! {
128//! 			target = [{
129//! 				construct_runtime!(
130//! 					//...
131//! 					{
132//! 						System: frame_system = 0,
133//! 						Balances: pallet_balances = 1,
134//! 					}
135//! 				)
136//! 			}]
137//! 			pattern = [{ System: frame_system }]
138//! 			tokens = [{ ::{Pallet, Call} }]
139//! 		}
140//! 	}]
141//! 	pattern = [{ Balances: pallet_balances }]
142//! 	tokens = [{ ::{Pallet, Call} }]
143//! }
144//! ```
145//! After dealing with `pallet_balances`, the inner `match_and_insert` will expand to:
146//! ```ignore
147//! frame_support::match_and_insert! {
148//! 	target = [{
149//! 		construct_runtime!(
150//! 			//...
151//! 			{
152//! 				System: frame_system = 0, // Implicit definition of parts
153//! 				Balances: pallet_balances::{Pallet, Call} = 1, // Explicit definition of parts
154//! 			}
155//! 		)
156//! 	}]
157//! 	pattern = [{ System: frame_system }]
158//! 	tokens = [{ ::{Pallet, Call} }]
159//! }
160//! ```
161//!
162//! Which will then finally expand to the following:
163//! ```ignore
164//! construct_runtime!(
165//! 	//...
166//! 	{
167//! 		System: frame_system::{Pallet, Call},
168//! 		Balances: pallet_balances::{Pallet, Call},
169//! 	}
170//! )
171//! ```
172//!
173//! This call has no implicit pallet parts, thus it will expand to the runtime construction:
174//! ```ignore
175//! pub enum Runtime { ... }
176//! pub struct Call { ... }
177//! impl Call ...
178//! pub enum Origin { ... }
179//! ...
180//! ```
181//!
182//! Visualizing the entire flow of `construct_runtime!`, it would look like the following:
183//!
184//! ```ignore
185//! +--------------------+     +---------------------+     +-------------------+
186//! |                    |     | (defined in pallet) |     |                   |
187//! | construct_runtime! | --> |  tt_default_parts!  | --> | match_and_insert! |
188//! | w/ no pallet parts |     |                     |     |                   |
189//! +--------------------+     +---------------------+     +-------------------+
190//!
191//!     +--------------------+
192//!     |                    |
193//! --> | construct_runtime! |
194//!     |  w/ pallet parts   |
195//!     +--------------------+
196//! ```
197//!
198//! # Explicit to Explicit Expanded
199//!
200//! Users normally do not care about this transition.
201//!
202//! Similarly to the previous transition, the macro expansion transforms `System:
203//! frame_system::{Pallet, Call}` into  `System: frame_system expanded::{Error} ::{Pallet, Call}`.
204//! The `expanded` section adds extra parts that the Substrate would like to expose for each pallet
205//! by default. This is done to expose the appropriate types for metadata construction.
206//!
207//! This time, instead of calling `tt_default_parts` we are using the `tt_extra_parts` macro.
208//! This macro returns the ` :: expanded { Error }` list of additional parts we would like to
209//! expose.
210
211pub(crate) mod expand;
212pub(crate) mod parse;
213
214use crate::pallet::parse::helper::two128_str;
215use cfg_expr::Predicate;
216use frame_support_procedural_tools::{
217	generate_access_from_frame_or_crate, generate_crate_access, generate_hidden_includes,
218};
219use itertools::Itertools;
220use parse::{ExplicitRuntimeDeclaration, ImplicitRuntimeDeclaration, Pallet, RuntimeDeclaration};
221use proc_macro::TokenStream;
222use proc_macro2::TokenStream as TokenStream2;
223use quote::quote;
224use std::{collections::HashSet, str::FromStr};
225use syn::{spanned::Spanned, Ident, Result};
226
227/// The fixed name of the system pallet.
228const SYSTEM_PALLET_NAME: &str = "System";
229
230/// Implementation of `construct_runtime` macro. Either expand to some code which will call
231/// `construct_runtime` again, or expand to the final runtime definition.
232pub fn construct_runtime(input: TokenStream) -> TokenStream {
233	let input_copy = input.clone();
234	let definition = syn::parse_macro_input!(input as RuntimeDeclaration);
235
236	let (check_pallet_number_res, res) = match definition {
237		RuntimeDeclaration::Implicit(implicit_def) => (
238			check_pallet_number(input_copy.clone().into(), implicit_def.pallets.len()),
239			construct_runtime_implicit_to_explicit(input_copy.into(), implicit_def),
240		),
241		RuntimeDeclaration::Explicit(explicit_decl) => (
242			check_pallet_number(input_copy.clone().into(), explicit_decl.pallets.len()),
243			construct_runtime_explicit_to_explicit_expanded(input_copy.into(), explicit_decl),
244		),
245		RuntimeDeclaration::ExplicitExpanded(explicit_decl) => (
246			check_pallet_number(input_copy.into(), explicit_decl.pallets.len()),
247			construct_runtime_final_expansion(explicit_decl),
248		),
249	};
250
251	let res = res.unwrap_or_else(|e| e.to_compile_error());
252
253	// We want to provide better error messages to the user and thus, handle the error here
254	// separately. If there is an error, we print the error and still generate all of the code to
255	// get in overall less errors for the user.
256	let res = if let Err(error) = check_pallet_number_res {
257		let error = error.to_compile_error();
258
259		quote! {
260			#error
261
262			#res
263		}
264	} else {
265		res
266	};
267
268	let res = expander::Expander::new("construct_runtime")
269		.dry(std::env::var("EXPAND_MACROS").is_err())
270		.verbose(true)
271		.write_to_out_dir(res)
272		.expect("Does not fail because of IO in OUT_DIR; qed");
273
274	res.into()
275}
276
277/// All pallets that have implicit pallet parts (ie `System: frame_system`) are
278/// expanded with the default parts defined by the pallet's `tt_default_parts` macro.
279///
280/// This function transforms the [`RuntimeDeclaration::Implicit`] into
281/// [`RuntimeDeclaration::Explicit`] that is not yet fully expanded.
282///
283/// For more details, please refer to the root documentation.
284fn construct_runtime_implicit_to_explicit(
285	input: TokenStream2,
286	definition: ImplicitRuntimeDeclaration,
287) -> Result<TokenStream2> {
288	let frame_support = generate_access_from_frame_or_crate("frame-support")?;
289	let mut expansion = quote::quote!(
290		#frame_support::construct_runtime! { #input }
291	);
292	for pallet in definition.pallets.iter().filter(|pallet| pallet.pallet_parts.is_none()) {
293		let pallet_path = &pallet.path;
294		let pallet_name = &pallet.name;
295		let pallet_instance = pallet.instance.as_ref().map(|instance| quote::quote!(::<#instance>));
296		expansion = quote::quote!(
297			#frame_support::__private::tt_call! {
298				macro = [{ #pallet_path::tt_default_parts }]
299				your_tt_return = [{ #frame_support::__private::tt_return }]
300				~~> #frame_support::match_and_insert! {
301					target = [{ #expansion }]
302					pattern = [{ #pallet_name: #pallet_path #pallet_instance }]
303				}
304			}
305		);
306	}
307
308	Ok(expansion)
309}
310
311/// All pallets that have
312///   (I): explicit pallet parts (ie `System: frame_system::{Pallet, Call}`) and
313///   (II): are not fully expanded (ie do not include the `Error` expansion part)
314/// are fully expanded by including the parts from the pallet's `tt_extra_parts` macro.
315///
316/// This function transforms the [`RuntimeDeclaration::Explicit`] that is not yet fully expanded
317/// into [`RuntimeDeclaration::ExplicitExpanded`] fully expanded.
318///
319/// For more details, please refer to the root documentation.
320fn construct_runtime_explicit_to_explicit_expanded(
321	input: TokenStream2,
322	definition: ExplicitRuntimeDeclaration,
323) -> Result<TokenStream2> {
324	let frame_support = generate_access_from_frame_or_crate("frame-support")?;
325	let mut expansion = quote::quote!(
326		#frame_support::construct_runtime! { #input }
327	);
328	for pallet in definition.pallets.iter().filter(|pallet| !pallet.is_expanded) {
329		let pallet_path = &pallet.path;
330		let pallet_name = &pallet.name;
331		let pallet_instance = pallet.instance.as_ref().map(|instance| quote::quote!(::<#instance>));
332		expansion = quote::quote!(
333			#frame_support::__private::tt_call! {
334				macro = [{ #pallet_path::tt_extra_parts }]
335				your_tt_return = [{ #frame_support::__private::tt_return }]
336				~~> #frame_support::match_and_insert! {
337					target = [{ #expansion }]
338					pattern = [{ #pallet_name: #pallet_path #pallet_instance }]
339				}
340			}
341		);
342	}
343
344	Ok(expansion)
345}
346
347/// All pallets have explicit definition of parts, this will expand to the runtime declaration.
348fn construct_runtime_final_expansion(
349	definition: ExplicitRuntimeDeclaration,
350) -> Result<TokenStream2> {
351	let ExplicitRuntimeDeclaration { name, pallets, pallets_token, where_section } = definition;
352
353	let system_pallet =
354		pallets.iter().find(|decl| decl.name == SYSTEM_PALLET_NAME).ok_or_else(|| {
355			syn::Error::new(
356				pallets_token.span.join(),
357				"`System` pallet declaration is missing. \
358			 Please add this line: `System: frame_system,`",
359			)
360		})?;
361	if !system_pallet.cfg_pattern.is_empty() {
362		return Err(syn::Error::new(
363			system_pallet.name.span(),
364			"`System` pallet declaration is feature gated, please remove any `#[cfg]` attributes",
365		))
366	}
367
368	let features = pallets
369		.iter()
370		.filter_map(|decl| {
371			(!decl.cfg_pattern.is_empty()).then(|| {
372				decl.cfg_pattern.iter().flat_map(|attr| {
373					attr.predicates().filter_map(|pred| match pred {
374						Predicate::Feature(feat) => Some(feat),
375						Predicate::Test => Some("test"),
376						_ => None,
377					})
378				})
379			})
380		})
381		.flatten()
382		.collect::<HashSet<_>>();
383
384	let hidden_crate_name = "construct_runtime";
385	let scrate = generate_crate_access(hidden_crate_name, "frame-support");
386	let scrate_decl = generate_hidden_includes(hidden_crate_name, "frame-support");
387
388	let frame_system = generate_access_from_frame_or_crate("frame-system")?;
389	let block = quote!(<#name as #frame_system::Config>::Block);
390	let unchecked_extrinsic = quote!(<#block as #scrate::sp_runtime::traits::Block>::Extrinsic);
391
392	let outer_event =
393		expand::expand_outer_enum(&name, &pallets, &scrate, expand::OuterEnumType::Event)?;
394	let outer_error =
395		expand::expand_outer_enum(&name, &pallets, &scrate, expand::OuterEnumType::Error)?;
396
397	let outer_origin = expand::expand_outer_origin(&name, system_pallet, &pallets, &scrate)?;
398	let all_pallets = decl_all_pallets(&name, pallets.iter(), &features);
399	let pallet_to_index = decl_pallet_runtime_setup(&name, &pallets, &scrate);
400
401	let dispatch = expand::expand_outer_dispatch(&name, system_pallet, &pallets, &scrate);
402	let tasks = expand::expand_outer_task(&name, &pallets, &scrate);
403	let query = expand::expand_outer_query(&name, &pallets, &scrate);
404	let metadata = expand::expand_runtime_metadata(
405		&name,
406		&pallets,
407		&scrate,
408		&unchecked_extrinsic,
409		&system_pallet.path,
410	);
411	let outer_config = expand::expand_outer_config(&name, &pallets, &scrate);
412	let inherent =
413		expand::expand_outer_inherent(&name, &block, &unchecked_extrinsic, &pallets, &scrate);
414	let validate_unsigned = expand::expand_outer_validate_unsigned(&name, &pallets, &scrate);
415	let freeze_reason = expand::expand_outer_freeze_reason(&pallets, &scrate);
416	let hold_reason = expand::expand_outer_hold_reason(&pallets, &scrate);
417	let lock_id = expand::expand_outer_lock_id(&pallets, &scrate);
418	let slash_reason = expand::expand_outer_slash_reason(&pallets, &scrate);
419	let integrity_test = decl_integrity_test(&scrate);
420	let static_assertions = decl_static_assertions(&name, &pallets, &scrate);
421
422	let warning = where_section.map_or(None, |where_section| {
423		Some(
424			proc_macro_warning::Warning::new_deprecated("WhereSection")
425				.old("use a `where` clause in `construct_runtime`")
426				.new(
427					"use `frame_system::Config` to set the `Block` type and delete this clause.
428				It is planned to be removed in December 2023",
429				)
430				.help_links(&["https://github.com/paritytech/substrate/pull/14437"])
431				.span(where_section.span)
432				.build_or_panic(),
433		)
434	});
435
436	let res = quote!(
437		#warning
438
439		#scrate_decl
440
441		// Prevent UncheckedExtrinsic to print unused warning.
442		const _: () = {
443			#[allow(unused)]
444			type __hidden_use_of_unchecked_extrinsic = #unchecked_extrinsic;
445		};
446
447		#[derive(
448			Clone, Copy, PartialEq, Eq, #scrate::sp_runtime::RuntimeDebug,
449			#scrate::__private::scale_info::TypeInfo
450		)]
451		pub struct #name;
452		impl #scrate::sp_runtime::traits::GetRuntimeBlockType for #name {
453			type RuntimeBlock = #block;
454		}
455
456		// Each runtime must expose the `runtime_metadata()` to fetch the runtime API metadata.
457		// The function is implemented by calling `impl_runtime_apis!`.
458		//
459		// However, the `construct_runtime!` may be called without calling `impl_runtime_apis!`.
460		// Rely on the `Deref` trait to differentiate between a runtime that implements
461		// APIs (by macro impl_runtime_apis!) and a runtime that is simply created (by macro construct_runtime!).
462		//
463		// Both `InternalConstructRuntime` and `InternalImplRuntimeApis` expose a `runtime_metadata()` function.
464		// `InternalConstructRuntime` is implemented by the `construct_runtime!` for Runtime references (`& Runtime`),
465		// while `InternalImplRuntimeApis` is implemented by the `impl_runtime_apis!` for Runtime (`Runtime`).
466		//
467		// Therefore, the `Deref` trait will resolve the `runtime_metadata` from `impl_runtime_apis!`
468		// when both macros are called; and will resolve an empty `runtime_metadata` when only the `construct_runtime!`
469		// is called.
470		#[doc(hidden)]
471		trait InternalConstructRuntime {
472			#[inline(always)]
473			fn runtime_metadata(&self) -> #scrate::__private::Vec<#scrate::__private::metadata_ir::RuntimeApiMetadataIR> {
474				Default::default()
475			}
476		}
477		#[doc(hidden)]
478		impl InternalConstructRuntime for &#name {}
479
480		use #scrate::__private::metadata_ir::InternalImplRuntimeApis;
481
482		#outer_event
483
484		#outer_error
485
486		#outer_origin
487
488		#all_pallets
489
490		#pallet_to_index
491
492		#dispatch
493
494		#tasks
495
496		#query
497
498		#metadata
499
500		#outer_config
501
502		#inherent
503
504		#validate_unsigned
505
506		#freeze_reason
507
508		#hold_reason
509
510		#lock_id
511
512		#slash_reason
513
514		#integrity_test
515
516		#static_assertions
517	);
518
519	Ok(res)
520}
521
522pub(crate) fn decl_all_pallets<'a>(
523	runtime: &'a Ident,
524	pallet_declarations: impl Iterator<Item = &'a Pallet>,
525	features: &HashSet<&str>,
526) -> TokenStream2 {
527	let mut types = TokenStream2::new();
528
529	// Every feature set to the pallet names that should be included by this feature set.
530	let mut features_to_names = features
531		.iter()
532		.map(|f| *f)
533		.powerset()
534		.map(|feat| (HashSet::from_iter(feat), Vec::new()))
535		.collect::<Vec<(HashSet<_>, Vec<_>)>>();
536
537	for pallet_declaration in pallet_declarations {
538		let type_name = &pallet_declaration.name;
539		let pallet = &pallet_declaration.path;
540		let docs = &pallet_declaration.docs;
541		let mut generics = vec![quote!(#runtime)];
542		generics.extend(pallet_declaration.instance.iter().map(|name| quote!(#pallet::#name)));
543		let mut attrs = Vec::new();
544		for cfg in &pallet_declaration.cfg_pattern {
545			let feat = format!("#[cfg({})]\n", cfg.original());
546			attrs.extend(TokenStream2::from_str(&feat).expect("was parsed successfully; qed"));
547		}
548		let type_decl = quote!(
549			#( #[doc = #docs] )*
550			#(#attrs)*
551			pub type #type_name = #pallet::Pallet <#(#generics),*>;
552		);
553		types.extend(type_decl);
554
555		if pallet_declaration.cfg_pattern.is_empty() {
556			for (_, names) in features_to_names.iter_mut() {
557				names.push(&pallet_declaration.name);
558			}
559		} else {
560			for (feature_set, names) in &mut features_to_names {
561				// Rust tidbit: if we have multiple `#[cfg]` feature on the same item, then the
562				// predicates listed in all `#[cfg]` attributes are effectively joined by `and()`,
563				// meaning that all of them must match in order to activate the item
564				let is_feature_active = pallet_declaration.cfg_pattern.iter().all(|expr| {
565					expr.eval(|pred| match pred {
566						Predicate::Feature(f) => feature_set.contains(f),
567						Predicate::Test => feature_set.contains(&"test"),
568						_ => false,
569					})
570				});
571
572				if is_feature_active {
573					names.push(&pallet_declaration.name);
574				}
575			}
576		}
577	}
578
579	// All possible features. This will be used below for the empty feature set.
580	let mut all_features = features_to_names
581		.iter()
582		.flat_map(|f| f.0.iter().cloned())
583		.collect::<HashSet<_>>();
584	let attribute_to_names = features_to_names
585		.into_iter()
586		.map(|(mut features, names)| {
587			// If this is the empty feature set, it needs to be changed to negate all available
588			// features. So, we ensure that there is some type declared when all features are not
589			// enabled.
590			if features.is_empty() {
591				let test_cfg = all_features.remove("test").then_some(quote!(test)).into_iter();
592				let features = all_features.iter();
593				let attr = quote!(#[cfg(all( #(not(#test_cfg)),* #(not(feature = #features)),* ))]);
594
595				(attr, names)
596			} else {
597				let test_cfg = features.remove("test").then_some(quote!(test)).into_iter();
598				let disabled_features = all_features.difference(&features);
599				let features = features.iter();
600				let attr = quote!(#[cfg(all( #(#test_cfg,)* #(feature = #features,)* #(not(feature = #disabled_features)),* ))]);
601
602				(attr, names)
603			}
604		})
605		.collect::<Vec<_>>();
606
607	let all_pallets_without_system = attribute_to_names.iter().map(|(attr, names)| {
608		let names = names.iter().filter(|n| **n != SYSTEM_PALLET_NAME);
609		quote! {
610			#attr
611			/// All pallets included in the runtime as a nested tuple of types.
612			/// Excludes the System pallet.
613			pub type AllPalletsWithoutSystem = ( #(#names,)* );
614		}
615	});
616
617	let all_pallets_with_system = attribute_to_names.iter().map(|(attr, names)| {
618		quote! {
619			#attr
620			/// All pallets included in the runtime as a nested tuple of types.
621			pub type AllPalletsWithSystem = ( #(#names,)* );
622		}
623	});
624
625	quote!(
626		#types
627
628		#( #all_pallets_with_system )*
629
630		#( #all_pallets_without_system )*
631	)
632}
633
634pub(crate) fn decl_pallet_runtime_setup(
635	runtime: &Ident,
636	pallet_declarations: &[Pallet],
637	scrate: &TokenStream2,
638) -> TokenStream2 {
639	let names = pallet_declarations.iter().map(|d| &d.name).collect::<Vec<_>>();
640	let name_strings = pallet_declarations.iter().map(|d| d.name.to_string());
641	let name_hashes = pallet_declarations.iter().map(|d| two128_str(&d.name.to_string()));
642	let module_names = pallet_declarations.iter().map(|d| d.path.module_name());
643	let indices = pallet_declarations.iter().map(|pallet| pallet.index as usize);
644	let pallet_structs = pallet_declarations
645		.iter()
646		.map(|pallet| {
647			let path = &pallet.path;
648			match pallet.instance.as_ref() {
649				Some(inst) => quote!(#path::Pallet<#runtime, #path::#inst>),
650				None => quote!(#path::Pallet<#runtime>),
651			}
652		})
653		.collect::<Vec<_>>();
654	let pallet_attrs = pallet_declarations
655		.iter()
656		.map(|pallet| pallet.get_attributes())
657		.collect::<Vec<_>>();
658
659	quote!(
660		/// Provides an implementation of `PalletInfo` to provide information
661		/// about the pallet setup in the runtime.
662		pub struct PalletInfo;
663
664		impl #scrate::traits::PalletInfo for PalletInfo {
665
666			fn index<P: 'static>() -> Option<usize> {
667				let type_id = core::any::TypeId::of::<P>();
668				#(
669					#pallet_attrs
670					if type_id == core::any::TypeId::of::<#names>() {
671						return Some(#indices)
672					}
673				)*
674
675				None
676			}
677
678			fn name<P: 'static>() -> Option<&'static str> {
679				let type_id = core::any::TypeId::of::<P>();
680				#(
681					#pallet_attrs
682					if type_id == core::any::TypeId::of::<#names>() {
683						return Some(#name_strings)
684					}
685				)*
686
687				None
688			}
689
690			fn name_hash<P: 'static>() -> Option<[u8; 16]> {
691				let type_id = core::any::TypeId::of::<P>();
692				#(
693					#pallet_attrs
694					if type_id == core::any::TypeId::of::<#names>() {
695						return Some(#name_hashes)
696					}
697				)*
698
699				None
700			}
701
702			fn module_name<P: 'static>() -> Option<&'static str> {
703				let type_id = core::any::TypeId::of::<P>();
704				#(
705					#pallet_attrs
706					if type_id == core::any::TypeId::of::<#names>() {
707						return Some(#module_names)
708					}
709				)*
710
711				None
712			}
713
714			fn crate_version<P: 'static>() -> Option<#scrate::traits::CrateVersion> {
715				let type_id = core::any::TypeId::of::<P>();
716				#(
717					#pallet_attrs
718					if type_id == core::any::TypeId::of::<#names>() {
719						return Some(
720							<#pallet_structs as #scrate::traits::PalletInfoAccess>::crate_version()
721						)
722					}
723				)*
724
725				None
726			}
727		}
728	)
729}
730
731pub(crate) fn decl_integrity_test(scrate: &TokenStream2) -> TokenStream2 {
732	quote!(
733		#[cfg(test)]
734		mod __construct_runtime_integrity_test {
735			use super::*;
736
737			#[test]
738			pub fn runtime_integrity_tests() {
739				#scrate::__private::sp_tracing::try_init_simple();
740				<AllPalletsWithSystem as #scrate::traits::IntegrityTest>::integrity_test();
741			}
742		}
743	)
744}
745
746pub(crate) fn decl_static_assertions(
747	runtime: &Ident,
748	pallet_decls: &[Pallet],
749	scrate: &TokenStream2,
750) -> TokenStream2 {
751	let error_encoded_size_check = pallet_decls.iter().map(|decl| {
752		let path = &decl.path;
753		let assert_message = format!(
754			"The maximum encoded size of the error type in the `{}` pallet exceeds \
755			`MAX_MODULE_ERROR_ENCODED_SIZE`",
756			decl.name,
757		);
758
759		quote! {
760			#[allow(deprecated)]
761			#scrate::__private::tt_call! {
762				macro = [{ #path::tt_error_token }]
763				your_tt_return = [{ #scrate::__private::tt_return }]
764				~~> #scrate::assert_error_encoded_size! {
765					path = [{ #path }]
766					runtime = [{ #runtime }]
767					assert_message = [{ #assert_message }]
768				}
769			}
770		}
771	});
772
773	quote! {
774		#(#error_encoded_size_check)*
775	}
776}
777
778pub(crate) fn check_pallet_number(input: TokenStream2, pallet_num: usize) -> Result<()> {
779	let max_pallet_num = {
780		if cfg!(feature = "tuples-96") {
781			96
782		} else if cfg!(feature = "tuples-128") {
783			128
784		} else {
785			64
786		}
787	};
788
789	if pallet_num > max_pallet_num {
790		let no_feature = max_pallet_num == 128;
791		return Err(syn::Error::new(
792			input.span(),
793			format!(
794				"{} To increase this limit, enable the tuples-{} feature of [frame_support]. {}",
795				"The number of pallets exceeds the maximum number of tuple elements.",
796				max_pallet_num + 32,
797				if no_feature {
798					"If the feature does not exist - it needs to be implemented."
799				} else {
800					""
801				},
802			),
803		))
804	}
805
806	Ok(())
807}