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 metadata = expand::expand_runtime_metadata(
404		&name,
405		&pallets,
406		&scrate,
407		&unchecked_extrinsic,
408		&system_pallet.path,
409	);
410	let outer_config = expand::expand_outer_config(&name, &pallets, &scrate);
411	let inherent =
412		expand::expand_outer_inherent(&name, &block, &unchecked_extrinsic, &pallets, &scrate);
413	let validate_unsigned = expand::expand_outer_validate_unsigned(&name, &pallets, &scrate);
414	let freeze_reason = expand::expand_outer_freeze_reason(&pallets, &scrate);
415	let hold_reason = expand::expand_outer_hold_reason(&pallets, &scrate);
416	let lock_id = expand::expand_outer_lock_id(&pallets, &scrate);
417	let slash_reason = expand::expand_outer_slash_reason(&pallets, &scrate);
418	let integrity_test = decl_integrity_test(&scrate);
419	let static_assertions = decl_static_assertions(&name, &pallets, &scrate);
420
421	let warning = where_section.map_or(None, |where_section| {
422		Some(
423			proc_macro_warning::Warning::new_deprecated("WhereSection")
424				.old("use a `where` clause in `construct_runtime`")
425				.new(
426					"use `frame_system::Config` to set the `Block` type and delete this clause.
427				It is planned to be removed in December 2023",
428				)
429				.help_links(&["https://github.com/paritytech/substrate/pull/14437"])
430				.span(where_section.span)
431				.build_or_panic(),
432		)
433	});
434
435	let res = quote!(
436		#warning
437
438		#scrate_decl
439
440		// Prevent UncheckedExtrinsic to print unused warning.
441		const _: () = {
442			#[allow(unused)]
443			type __hidden_use_of_unchecked_extrinsic = #unchecked_extrinsic;
444		};
445
446		#[derive(
447			Clone, Copy, PartialEq, Eq, #scrate::sp_runtime::RuntimeDebug,
448			#scrate::__private::scale_info::TypeInfo
449		)]
450		pub struct #name;
451		impl #scrate::sp_runtime::traits::GetRuntimeBlockType for #name {
452			type RuntimeBlock = #block;
453		}
454
455		// Each runtime must expose the `runtime_metadata()` to fetch the runtime API metadata.
456		// The function is implemented by calling `impl_runtime_apis!`.
457		//
458		// However, the `construct_runtime!` may be called without calling `impl_runtime_apis!`.
459		// Rely on the `Deref` trait to differentiate between a runtime that implements
460		// APIs (by macro impl_runtime_apis!) and a runtime that is simply created (by macro construct_runtime!).
461		//
462		// Both `InternalConstructRuntime` and `InternalImplRuntimeApis` expose a `runtime_metadata()` function.
463		// `InternalConstructRuntime` is implemented by the `construct_runtime!` for Runtime references (`& Runtime`),
464		// while `InternalImplRuntimeApis` is implemented by the `impl_runtime_apis!` for Runtime (`Runtime`).
465		//
466		// Therefore, the `Deref` trait will resolve the `runtime_metadata` from `impl_runtime_apis!`
467		// when both macros are called; and will resolve an empty `runtime_metadata` when only the `construct_runtime!`
468		// is called.
469
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		#outer_event
481
482		#outer_error
483
484		#outer_origin
485
486		#all_pallets
487
488		#pallet_to_index
489
490		#dispatch
491
492		#tasks
493
494		#metadata
495
496		#outer_config
497
498		#inherent
499
500		#validate_unsigned
501
502		#freeze_reason
503
504		#hold_reason
505
506		#lock_id
507
508		#slash_reason
509
510		#integrity_test
511
512		#static_assertions
513	);
514
515	Ok(res)
516}
517
518pub(crate) fn decl_all_pallets<'a>(
519	runtime: &'a Ident,
520	pallet_declarations: impl Iterator<Item = &'a Pallet>,
521	features: &HashSet<&str>,
522) -> TokenStream2 {
523	let mut types = TokenStream2::new();
524
525	// Every feature set to the pallet names that should be included by this feature set.
526	let mut features_to_names = features
527		.iter()
528		.map(|f| *f)
529		.powerset()
530		.map(|feat| (HashSet::from_iter(feat), Vec::new()))
531		.collect::<Vec<(HashSet<_>, Vec<_>)>>();
532
533	for pallet_declaration in pallet_declarations {
534		let type_name = &pallet_declaration.name;
535		let pallet = &pallet_declaration.path;
536		let docs = &pallet_declaration.docs;
537		let mut generics = vec![quote!(#runtime)];
538		generics.extend(pallet_declaration.instance.iter().map(|name| quote!(#pallet::#name)));
539		let mut attrs = Vec::new();
540		for cfg in &pallet_declaration.cfg_pattern {
541			let feat = format!("#[cfg({})]\n", cfg.original());
542			attrs.extend(TokenStream2::from_str(&feat).expect("was parsed successfully; qed"));
543		}
544		let type_decl = quote!(
545			#( #[doc = #docs] )*
546			#(#attrs)*
547			pub type #type_name = #pallet::Pallet <#(#generics),*>;
548		);
549		types.extend(type_decl);
550
551		if pallet_declaration.cfg_pattern.is_empty() {
552			for (_, names) in features_to_names.iter_mut() {
553				names.push(&pallet_declaration.name);
554			}
555		} else {
556			for (feature_set, names) in &mut features_to_names {
557				// Rust tidbit: if we have multiple `#[cfg]` feature on the same item, then the
558				// predicates listed in all `#[cfg]` attributes are effectively joined by `and()`,
559				// meaning that all of them must match in order to activate the item
560				let is_feature_active = pallet_declaration.cfg_pattern.iter().all(|expr| {
561					expr.eval(|pred| match pred {
562						Predicate::Feature(f) => feature_set.contains(f),
563						Predicate::Test => feature_set.contains(&"test"),
564						_ => false,
565					})
566				});
567
568				if is_feature_active {
569					names.push(&pallet_declaration.name);
570				}
571			}
572		}
573	}
574
575	// All possible features. This will be used below for the empty feature set.
576	let mut all_features = features_to_names
577		.iter()
578		.flat_map(|f| f.0.iter().cloned())
579		.collect::<HashSet<_>>();
580	let attribute_to_names = features_to_names
581		.into_iter()
582		.map(|(mut features, names)| {
583			// If this is the empty feature set, it needs to be changed to negate all available
584			// features. So, we ensure that there is some type declared when all features are not
585			// enabled.
586			if features.is_empty() {
587				let test_cfg = all_features.remove("test").then_some(quote!(test)).into_iter();
588				let features = all_features.iter();
589				let attr = quote!(#[cfg(all( #(not(#test_cfg)),* #(not(feature = #features)),* ))]);
590
591				(attr, names)
592			} else {
593				let test_cfg = features.remove("test").then_some(quote!(test)).into_iter();
594				let disabled_features = all_features.difference(&features);
595				let features = features.iter();
596				let attr = quote!(#[cfg(all( #(#test_cfg,)* #(feature = #features,)* #(not(feature = #disabled_features)),* ))]);
597
598				(attr, names)
599			}
600		})
601		.collect::<Vec<_>>();
602
603	let all_pallets_without_system = attribute_to_names.iter().map(|(attr, names)| {
604		let names = names.iter().filter(|n| **n != SYSTEM_PALLET_NAME);
605		quote! {
606			#attr
607			/// All pallets included in the runtime as a nested tuple of types.
608			/// Excludes the System pallet.
609			pub type AllPalletsWithoutSystem = ( #(#names,)* );
610		}
611	});
612
613	let all_pallets_with_system = attribute_to_names.iter().map(|(attr, names)| {
614		quote! {
615			#attr
616			/// All pallets included in the runtime as a nested tuple of types.
617			pub type AllPalletsWithSystem = ( #(#names,)* );
618		}
619	});
620
621	quote!(
622		#types
623
624		#( #all_pallets_with_system )*
625
626		#( #all_pallets_without_system )*
627	)
628}
629
630pub(crate) fn decl_pallet_runtime_setup(
631	runtime: &Ident,
632	pallet_declarations: &[Pallet],
633	scrate: &TokenStream2,
634) -> TokenStream2 {
635	let names = pallet_declarations.iter().map(|d| &d.name).collect::<Vec<_>>();
636	let name_strings = pallet_declarations.iter().map(|d| d.name.to_string());
637	let name_hashes = pallet_declarations.iter().map(|d| two128_str(&d.name.to_string()));
638	let module_names = pallet_declarations.iter().map(|d| d.path.module_name());
639	let indices = pallet_declarations.iter().map(|pallet| pallet.index as usize);
640	let pallet_structs = pallet_declarations
641		.iter()
642		.map(|pallet| {
643			let path = &pallet.path;
644			match pallet.instance.as_ref() {
645				Some(inst) => quote!(#path::Pallet<#runtime, #path::#inst>),
646				None => quote!(#path::Pallet<#runtime>),
647			}
648		})
649		.collect::<Vec<_>>();
650	let pallet_attrs = pallet_declarations
651		.iter()
652		.map(|pallet| {
653			pallet.cfg_pattern.iter().fold(TokenStream2::new(), |acc, pattern| {
654				let attr = TokenStream2::from_str(&format!("#[cfg({})]", pattern.original()))
655					.expect("was successfully parsed before; qed");
656				quote! {
657					#acc
658					#attr
659				}
660			})
661		})
662		.collect::<Vec<_>>();
663
664	quote!(
665		/// Provides an implementation of `PalletInfo` to provide information
666		/// about the pallet setup in the runtime.
667		pub struct PalletInfo;
668
669		impl #scrate::traits::PalletInfo for PalletInfo {
670
671			fn index<P: 'static>() -> Option<usize> {
672				let type_id = core::any::TypeId::of::<P>();
673				#(
674					#pallet_attrs
675					if type_id == core::any::TypeId::of::<#names>() {
676						return Some(#indices)
677					}
678				)*
679
680				None
681			}
682
683			fn name<P: 'static>() -> Option<&'static str> {
684				let type_id = core::any::TypeId::of::<P>();
685				#(
686					#pallet_attrs
687					if type_id == core::any::TypeId::of::<#names>() {
688						return Some(#name_strings)
689					}
690				)*
691
692				None
693			}
694
695			fn name_hash<P: 'static>() -> Option<[u8; 16]> {
696				let type_id = core::any::TypeId::of::<P>();
697				#(
698					#pallet_attrs
699					if type_id == core::any::TypeId::of::<#names>() {
700						return Some(#name_hashes)
701					}
702				)*
703
704				None
705			}
706
707			fn module_name<P: 'static>() -> Option<&'static str> {
708				let type_id = core::any::TypeId::of::<P>();
709				#(
710					#pallet_attrs
711					if type_id == core::any::TypeId::of::<#names>() {
712						return Some(#module_names)
713					}
714				)*
715
716				None
717			}
718
719			fn crate_version<P: 'static>() -> Option<#scrate::traits::CrateVersion> {
720				let type_id = core::any::TypeId::of::<P>();
721				#(
722					#pallet_attrs
723					if type_id == core::any::TypeId::of::<#names>() {
724						return Some(
725							<#pallet_structs as #scrate::traits::PalletInfoAccess>::crate_version()
726						)
727					}
728				)*
729
730				None
731			}
732		}
733	)
734}
735
736pub(crate) fn decl_integrity_test(scrate: &TokenStream2) -> TokenStream2 {
737	quote!(
738		#[cfg(test)]
739		mod __construct_runtime_integrity_test {
740			use super::*;
741
742			#[test]
743			pub fn runtime_integrity_tests() {
744				#scrate::__private::sp_tracing::try_init_simple();
745				<AllPalletsWithSystem as #scrate::traits::IntegrityTest>::integrity_test();
746			}
747		}
748	)
749}
750
751pub(crate) fn decl_static_assertions(
752	runtime: &Ident,
753	pallet_decls: &[Pallet],
754	scrate: &TokenStream2,
755) -> TokenStream2 {
756	let error_encoded_size_check = pallet_decls.iter().map(|decl| {
757		let path = &decl.path;
758		let assert_message = format!(
759			"The maximum encoded size of the error type in the `{}` pallet exceeds \
760			`MAX_MODULE_ERROR_ENCODED_SIZE`",
761			decl.name,
762		);
763
764		quote! {
765			#scrate::__private::tt_call! {
766				macro = [{ #path::tt_error_token }]
767				your_tt_return = [{ #scrate::__private::tt_return }]
768				~~> #scrate::assert_error_encoded_size! {
769					path = [{ #path }]
770					runtime = [{ #runtime }]
771					assert_message = [{ #assert_message }]
772				}
773			}
774		}
775	});
776
777	quote! {
778		#(#error_encoded_size_check)*
779	}
780}
781
782pub(crate) fn check_pallet_number(input: TokenStream2, pallet_num: usize) -> Result<()> {
783	let max_pallet_num = {
784		if cfg!(feature = "tuples-96") {
785			96
786		} else if cfg!(feature = "tuples-128") {
787			128
788		} else {
789			64
790		}
791	};
792
793	if pallet_num > max_pallet_num {
794		let no_feature = max_pallet_num == 128;
795		return Err(syn::Error::new(
796			input.span(),
797			format!(
798				"{} To increase this limit, enable the tuples-{} feature of [frame_support]. {}",
799				"The number of pallets exceeds the maximum number of tuple elements.",
800				max_pallet_num + 32,
801				if no_feature {
802					"If the feature does not exist - it needs to be implemented."
803				} else {
804					""
805				},
806			),
807		))
808	}
809
810	Ok(())
811}