referrerpolicy=no-referrer-when-downgrade

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