frame_support_procedural/construct_runtime/expand/
call.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::Pallet;
19use proc_macro2::TokenStream;
20use quote::quote;
21use std::str::FromStr;
22use syn::Ident;
23
24pub fn expand_outer_dispatch(
25	runtime: &Ident,
26	system_pallet: &Pallet,
27	pallet_decls: &[Pallet],
28	scrate: &TokenStream,
29) -> TokenStream {
30	let mut variant_defs = TokenStream::new();
31	let mut variant_patterns = Vec::new();
32	let mut query_call_part_macros = Vec::new();
33	let mut pallet_names = Vec::new();
34	let mut pallet_attrs = Vec::new();
35	let system_path = &system_pallet.path;
36
37	let pallets_with_call = pallet_decls.iter().filter(|decl| decl.exists_part("Call"));
38
39	for pallet_declaration in pallets_with_call {
40		let name = &pallet_declaration.name;
41		let path = &pallet_declaration.path;
42		let index = pallet_declaration.index;
43		let attr =
44			pallet_declaration.cfg_pattern.iter().fold(TokenStream::new(), |acc, pattern| {
45				let attr = TokenStream::from_str(&format!("#[cfg({})]", pattern.original()))
46					.expect("was successfully parsed before; qed");
47				quote! {
48					#acc
49					#attr
50				}
51			});
52
53		variant_defs.extend(quote! {
54			#attr
55			#[codec(index = #index)]
56			#name( #scrate::dispatch::CallableCallFor<#name, #runtime> ),
57		});
58		variant_patterns.push(quote!(RuntimeCall::#name(call)));
59		pallet_names.push(name);
60		pallet_attrs.push(attr);
61		query_call_part_macros.push(quote! {
62			#path::__substrate_call_check::is_call_part_defined!(#name);
63		});
64	}
65
66	quote! {
67		#( #query_call_part_macros )*
68
69		/// The aggregated runtime call type.
70		#[derive(
71			Clone, PartialEq, Eq,
72			#scrate::__private::codec::Encode,
73			#scrate::__private::codec::Decode,
74			#scrate::__private::scale_info::TypeInfo,
75			#scrate::__private::RuntimeDebug,
76		)]
77		pub enum RuntimeCall {
78			#variant_defs
79		}
80		#[cfg(test)]
81		impl RuntimeCall {
82			/// Return a list of the module names together with their size in memory.
83			pub const fn sizes() -> &'static [( &'static str, usize )] {
84				use #scrate::dispatch::Callable;
85				use core::mem::size_of;
86				&[#(
87					#pallet_attrs
88					(
89						stringify!(#pallet_names),
90						size_of::< <#pallet_names as Callable<#runtime>>::RuntimeCall >(),
91					),
92				)*]
93			}
94
95			/// Panics with diagnostic information if the size is greater than the given `limit`.
96			pub fn assert_size_under(limit: usize) {
97				let size = core::mem::size_of::<Self>();
98				let call_oversize = size > limit;
99				if call_oversize {
100					println!("Size of `Call` is {} bytes (provided limit is {} bytes)", size, limit);
101					let mut sizes = Self::sizes().to_vec();
102					sizes.sort_by_key(|x| -(x.1 as isize));
103					for (i, &(name, size)) in sizes.iter().enumerate().take(5) {
104						println!("Offender #{}: {} at {} bytes", i + 1, name, size);
105					}
106					if let Some((_, next_size)) = sizes.get(5) {
107						println!("{} others of size {} bytes or less", sizes.len() - 5, next_size);
108					}
109					panic!(
110						"Size of `Call` is more than limit; use `Box` on complex parameter types to reduce the
111						size of `Call`.
112						If the limit is too strong, maybe consider providing a higher limit."
113					);
114				}
115			}
116		}
117		impl #scrate::dispatch::GetDispatchInfo for RuntimeCall {
118			fn get_dispatch_info(&self) -> #scrate::dispatch::DispatchInfo {
119				match self {
120					#(
121						#pallet_attrs
122						#variant_patterns => call.get_dispatch_info(),
123					)*
124				}
125			}
126		}
127
128		impl #scrate::dispatch::CheckIfFeeless for RuntimeCall {
129			type Origin = #system_path::pallet_prelude::OriginFor<#runtime>;
130			fn is_feeless(&self, origin: &Self::Origin) -> bool {
131				match self {
132					#(
133						#pallet_attrs
134						#variant_patterns => call.is_feeless(origin),
135					)*
136				}
137			}
138		}
139
140		impl #scrate::traits::GetCallMetadata for RuntimeCall {
141			fn get_call_metadata(&self) -> #scrate::traits::CallMetadata {
142				use #scrate::traits::GetCallName;
143				match self {
144					#(
145						#pallet_attrs
146						#variant_patterns => {
147							let function_name = call.get_call_name();
148							let pallet_name = stringify!(#pallet_names);
149							#scrate::traits::CallMetadata { function_name, pallet_name }
150						}
151					)*
152				}
153			}
154
155			fn get_module_names() -> &'static [&'static str] {
156				&[#(
157					#pallet_attrs
158					stringify!(#pallet_names),
159				)*]
160			}
161
162			fn get_call_names(module: &str) -> &'static [&'static str] {
163				use #scrate::{dispatch::Callable, traits::GetCallName};
164				match module {
165					#(
166						#pallet_attrs
167						stringify!(#pallet_names) =>
168							<<#pallet_names as Callable<#runtime>>::RuntimeCall
169								as GetCallName>::get_call_names(),
170					)*
171					_ => unreachable!(),
172				}
173			}
174		}
175		impl #scrate::__private::Dispatchable for RuntimeCall {
176			type RuntimeOrigin = RuntimeOrigin;
177			type Config = RuntimeCall;
178			type Info = #scrate::dispatch::DispatchInfo;
179			type PostInfo = #scrate::dispatch::PostDispatchInfo;
180			fn dispatch(self, origin: RuntimeOrigin) -> #scrate::dispatch::DispatchResultWithPostInfo {
181				if !<Self::RuntimeOrigin as #scrate::traits::OriginTrait>::filter_call(&origin, &self) {
182					return ::core::result::Result::Err(
183						#system_path::Error::<#runtime>::CallFiltered.into()
184					);
185				}
186
187				#scrate::traits::UnfilteredDispatchable::dispatch_bypass_filter(self, origin)
188			}
189		}
190		impl #scrate::traits::UnfilteredDispatchable for RuntimeCall {
191			type RuntimeOrigin = RuntimeOrigin;
192			fn dispatch_bypass_filter(self, origin: RuntimeOrigin) -> #scrate::dispatch::DispatchResultWithPostInfo {
193				match self {
194					#(
195						#pallet_attrs
196						#variant_patterns =>
197							#scrate::traits::UnfilteredDispatchable::dispatch_bypass_filter(call, origin),
198					)*
199				}
200			}
201		}
202
203		#(
204			#pallet_attrs
205			impl #scrate::traits::IsSubType<#scrate::dispatch::CallableCallFor<#pallet_names, #runtime>> for RuntimeCall {
206				#[allow(unreachable_patterns)]
207				fn is_sub_type(&self) -> Option<&#scrate::dispatch::CallableCallFor<#pallet_names, #runtime>> {
208					match self {
209						#variant_patterns => Some(call),
210						// May be unreachable
211						_ => None,
212					}
213				}
214			}
215
216			#pallet_attrs
217			impl From<#scrate::dispatch::CallableCallFor<#pallet_names, #runtime>> for RuntimeCall {
218				fn from(call: #scrate::dispatch::CallableCallFor<#pallet_names, #runtime>) -> Self {
219					#variant_patterns
220				}
221			}
222		)*
223	}
224}