referrerpolicy=no-referrer-when-downgrade

frame_support_procedural/construct_runtime/expand/
origin.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, SYSTEM_PALLET_NAME};
19use proc_macro2::TokenStream;
20use quote::quote;
21use syn::{Generics, Ident};
22
23pub fn expand_outer_origin(
24	runtime: &Ident,
25	system_pallet: &Pallet,
26	pallets: &[Pallet],
27	scrate: &TokenStream,
28) -> syn::Result<TokenStream> {
29	let mut caller_variants = TokenStream::new();
30	let mut pallet_conversions = TokenStream::new();
31	let mut query_origin_part_macros = Vec::new();
32
33	for pallet_decl in pallets.iter().filter(|pallet| pallet.name != SYSTEM_PALLET_NAME) {
34		if let Some(pallet_entry) = pallet_decl.find_part("Origin") {
35			let instance = pallet_decl.instance.as_ref();
36			let index = pallet_decl.index;
37			let generics = &pallet_entry.generics;
38			let name = &pallet_decl.name;
39			let path = &pallet_decl.path;
40
41			if instance.is_some() && generics.params.is_empty() {
42				let msg = format!(
43					"Instantiable pallet with no generic `Origin` cannot \
44					 be constructed: pallet `{}` must have generic `Origin`",
45					name
46				);
47				return Err(syn::Error::new(name.span(), msg))
48			}
49
50			caller_variants.extend(expand_origin_caller_variant(
51				runtime,
52				pallet_decl,
53				index,
54				instance,
55				generics,
56			));
57			pallet_conversions.extend(expand_origin_pallet_conversions(
58				scrate,
59				runtime,
60				pallet_decl,
61				instance,
62				generics,
63			));
64			query_origin_part_macros.push(quote! {
65				#path::__substrate_origin_check::is_origin_part_defined!(#name);
66			});
67		}
68	}
69
70	let system_path = &system_pallet.path;
71
72	let system_index = system_pallet.index;
73
74	let system_path_name = system_path.module_name();
75
76	let doc_string = get_intra_doc_string(
77		"Origin is always created with the base filter configured in",
78		&system_path_name,
79	);
80
81	let doc_string_none_origin =
82		get_intra_doc_string("Create with system none origin and", &system_path_name);
83
84	let doc_string_root_origin =
85		get_intra_doc_string("Create with system root origin and", &system_path_name);
86
87	let doc_string_signed_origin =
88		get_intra_doc_string("Create with system signed origin and", &system_path_name);
89
90	let doc_string_runtime_origin =
91		get_intra_doc_string("Convert to runtime origin, using as filter:", &system_path_name);
92
93	let doc_string_runtime_origin_with_caller = get_intra_doc_string(
94		"Convert to runtime origin with caller being system signed or none and use filter",
95		&system_path_name,
96	);
97
98	Ok(quote! {
99		#( #query_origin_part_macros )*
100
101		/// The runtime origin type representing the origin of a call.
102		///
103		#[doc = #doc_string]
104		#[derive(Clone)]
105		pub struct RuntimeOrigin {
106			pub caller: OriginCaller,
107			filter: #scrate::__private::Rc<#scrate::__private::Box<dyn Fn(&<#runtime as #system_path::Config>::RuntimeCall) -> bool>>,
108		}
109
110		impl core::fmt::Debug for RuntimeOrigin {
111			fn fmt(
112				&self,
113				fmt: &mut core::fmt::Formatter,
114			) -> core::result::Result<(), core::fmt::Error> {
115				fmt.debug_struct("Origin")
116					.field("caller", &self.caller)
117					.field("filter", &"[function ptr]")
118					.finish()
119			}
120		}
121
122		impl #scrate::traits::OriginTrait for RuntimeOrigin {
123			type Call = <#runtime as #system_path::Config>::RuntimeCall;
124			type PalletsOrigin = OriginCaller;
125			type AccountId = <#runtime as #system_path::Config>::AccountId;
126
127			fn add_filter(&mut self, filter: impl Fn(&Self::Call) -> bool + 'static) {
128				let f = self.filter.clone();
129
130				self.filter = #scrate::__private::Rc::new(#scrate::__private::Box::new(move |call| {
131					f(call) && filter(call)
132				}));
133			}
134
135			fn reset_filter(&mut self) {
136				let filter = <
137					<#runtime as #system_path::Config>::BaseCallFilter
138					as #scrate::traits::Contains<<#runtime as #system_path::Config>::RuntimeCall>
139				>::contains;
140
141				self.filter = #scrate::__private::Rc::new(#scrate::__private::Box::new(filter));
142			}
143
144			fn set_caller(&mut self, caller: OriginCaller) {
145				self.caller = caller;
146			}
147
148			fn set_caller_from(&mut self, other: impl Into<Self>) {
149				self.caller = other.into().caller;
150			}
151
152			fn filter_call(&self, call: &Self::Call) -> bool {
153				match self.caller {
154					// Root bypasses all filters
155					OriginCaller::system(#system_path::Origin::<#runtime>::Root) => true,
156					_ => (self.filter)(call),
157				}
158			}
159
160			fn caller(&self) -> &Self::PalletsOrigin {
161				&self.caller
162			}
163
164			fn into_caller(self) -> Self::PalletsOrigin {
165				self.caller
166			}
167
168			fn try_with_caller<R>(
169				mut self,
170				f: impl FnOnce(Self::PalletsOrigin) -> Result<R, Self::PalletsOrigin>,
171			) -> Result<R, Self> {
172				match f(self.caller) {
173					Ok(r) => Ok(r),
174					Err(caller) => { self.caller = caller; Err(self) }
175				}
176			}
177
178			fn none() -> Self {
179				#system_path::RawOrigin::None.into()
180			}
181
182			fn root() -> Self {
183				#system_path::RawOrigin::Root.into()
184			}
185
186			fn signed(by: Self::AccountId) -> Self {
187				#system_path::RawOrigin::Signed(by).into()
188			}
189		}
190
191		#[derive(
192			Clone, PartialEq, Eq,
193			#scrate::__private::Debug,
194			#scrate::__private::codec::Encode,
195			#scrate::__private::codec::Decode,
196			#scrate::__private::codec::DecodeWithMemTracking,
197			#scrate::__private::scale_info::TypeInfo,
198			#scrate::__private::codec::MaxEncodedLen,
199		)]
200		#[allow(non_camel_case_types)]
201		pub enum OriginCaller {
202			#[codec(index = #system_index)]
203			system(#system_path::Origin<#runtime>),
204			#caller_variants
205			#[allow(dead_code)]
206			#[codec(skip)]
207			Void(#scrate::__private::Void)
208		}
209
210		// For backwards compatibility and ease of accessing these functions.
211		#[allow(dead_code)]
212		impl RuntimeOrigin {
213			#[doc = #doc_string_none_origin]
214			pub fn none() -> Self {
215				<RuntimeOrigin as #scrate::traits::OriginTrait>::none()
216			}
217
218			#[doc = #doc_string_root_origin]
219			pub fn root() -> Self {
220				<RuntimeOrigin as #scrate::traits::OriginTrait>::root()
221			}
222
223			#[doc = #doc_string_signed_origin]
224			pub fn signed(by: <#runtime as #system_path::Config>::AccountId) -> Self {
225				<RuntimeOrigin as #scrate::traits::OriginTrait>::signed(by)
226			}
227		}
228
229		impl From<#system_path::Origin<#runtime>> for OriginCaller {
230			fn from(x: #system_path::Origin<#runtime>) -> Self {
231				OriginCaller::system(x)
232			}
233		}
234
235		impl #scrate::traits::CallerTrait<<#runtime as #system_path::Config>::AccountId> for OriginCaller {
236			fn into_system(self) -> Option<#system_path::RawOrigin<<#runtime as #system_path::Config>::AccountId>> {
237				match self {
238					OriginCaller::system(x) => Some(x),
239					_ => None,
240				}
241			}
242			fn as_system_ref(&self) -> Option<&#system_path::RawOrigin<<#runtime as #system_path::Config>::AccountId>> {
243				match &self {
244					OriginCaller::system(o) => Some(o),
245					_ => None,
246				}
247			}
248		}
249
250		impl TryFrom<OriginCaller> for #system_path::Origin<#runtime> {
251			type Error = OriginCaller;
252			fn try_from(x: OriginCaller)
253				-> core::result::Result<#system_path::Origin<#runtime>, OriginCaller>
254			{
255				if let OriginCaller::system(l) = x {
256					Ok(l)
257				} else {
258					Err(x)
259				}
260			}
261		}
262
263		impl From<#system_path::Origin<#runtime>> for RuntimeOrigin {
264
265			#[doc = #doc_string_runtime_origin]
266			fn from(x: #system_path::Origin<#runtime>) -> Self {
267				let o: OriginCaller = x.into();
268				o.into()
269			}
270		}
271
272		impl From<OriginCaller> for RuntimeOrigin {
273			fn from(x: OriginCaller) -> Self {
274				let mut o = RuntimeOrigin {
275					caller: x,
276					filter: #scrate::__private::Rc::new(#scrate::__private::Box::new(|_| true)),
277				};
278
279				#scrate::traits::OriginTrait::reset_filter(&mut o);
280
281				o
282			}
283		}
284
285		impl From<RuntimeOrigin> for core::result::Result<#system_path::Origin<#runtime>, RuntimeOrigin> {
286			/// NOTE: converting to pallet origin loses the origin filter information.
287			fn from(val: RuntimeOrigin) -> Self {
288				if let OriginCaller::system(l) = val.caller {
289					Ok(l)
290				} else {
291					Err(val)
292				}
293			}
294		}
295		impl From<Option<<#runtime as #system_path::Config>::AccountId>> for RuntimeOrigin {
296			#[doc = #doc_string_runtime_origin_with_caller]
297			fn from(x: Option<<#runtime as #system_path::Config>::AccountId>) -> Self {
298				<#system_path::Origin<#runtime>>::from(x).into()
299			}
300		}
301
302		impl #scrate::__private::AsSystemOriginSigner<<#runtime as #system_path::Config>::AccountId> for RuntimeOrigin {
303			fn as_system_origin_signer(&self) -> Option<&<#runtime as #system_path::Config>::AccountId> {
304				if let OriginCaller::system(#system_path::Origin::<#runtime>::Signed(ref signed)) = &self.caller {
305					Some(signed)
306				} else {
307					None
308				}
309			}
310		}
311
312		impl #scrate::__private::AsTransactionAuthorizedOrigin for RuntimeOrigin {
313			fn is_transaction_authorized(&self) -> bool {
314				!matches!(&self.caller, OriginCaller::system(#system_path::Origin::<#runtime>::None))
315			}
316		}
317
318		#pallet_conversions
319	})
320}
321
322fn expand_origin_caller_variant(
323	runtime: &Ident,
324	pallet: &Pallet,
325	index: u8,
326	instance: Option<&Ident>,
327	generics: &Generics,
328) -> TokenStream {
329	let part_is_generic = !generics.params.is_empty();
330	let variant_name = &pallet.name;
331	let path = &pallet.path;
332	let attr = pallet.get_attributes();
333
334	match instance {
335		Some(inst) if part_is_generic => quote! {
336			#attr
337			#[codec(index = #index)]
338			#variant_name(#path::Origin<#runtime, #path::#inst>),
339		},
340		Some(inst) => quote! {
341			#attr
342			#[codec(index = #index)]
343			#variant_name(#path::Origin<#path::#inst>),
344		},
345		None if part_is_generic => quote! {
346			#attr
347			#[codec(index = #index)]
348			#variant_name(#path::Origin<#runtime>),
349		},
350		None => quote! {
351			#attr
352			#[codec(index = #index)]
353			#variant_name(#path::Origin),
354		},
355	}
356}
357
358fn expand_origin_pallet_conversions(
359	_scrate: &TokenStream,
360	runtime: &Ident,
361	pallet: &Pallet,
362	instance: Option<&Ident>,
363	generics: &Generics,
364) -> TokenStream {
365	let path = &pallet.path;
366	let variant_name = &pallet.name;
367
368	let part_is_generic = !generics.params.is_empty();
369	let pallet_origin = match instance {
370		Some(inst) if part_is_generic => quote!(#path::Origin<#runtime, #path::#inst>),
371		Some(inst) => quote!(#path::Origin<#path::#inst>),
372		None if part_is_generic => quote!(#path::Origin<#runtime>),
373		None => quote!(#path::Origin),
374	};
375
376	let doc_string = get_intra_doc_string(" Convert to runtime origin using", &path.module_name());
377	let attr = pallet.get_attributes();
378
379	quote! {
380		#attr
381		impl From<#pallet_origin> for OriginCaller {
382			fn from(x: #pallet_origin) -> Self {
383				OriginCaller::#variant_name(x)
384			}
385		}
386
387		#attr
388		impl From<#pallet_origin> for RuntimeOrigin {
389			#[doc = #doc_string]
390			fn from(x: #pallet_origin) -> Self {
391				let x: OriginCaller = x.into();
392				x.into()
393			}
394		}
395
396		#attr
397		impl From<RuntimeOrigin> for core::result::Result<#pallet_origin, RuntimeOrigin> {
398			/// NOTE: converting to pallet origin loses the origin filter information.
399			fn from(val: RuntimeOrigin) -> Self {
400				if let OriginCaller::#variant_name(l) = val.caller {
401					Ok(l)
402				} else {
403					Err(val)
404				}
405			}
406		}
407
408		#attr
409		impl TryFrom<OriginCaller> for #pallet_origin {
410			type Error = OriginCaller;
411			fn try_from(
412				x: OriginCaller,
413			) -> core::result::Result<#pallet_origin, OriginCaller> {
414				if let OriginCaller::#variant_name(l) = x {
415					Ok(l)
416				} else {
417					Err(x)
418				}
419			}
420		}
421
422		#attr
423		impl<'a> TryFrom<&'a OriginCaller> for &'a #pallet_origin {
424			type Error = ();
425			fn try_from(
426				x: &'a OriginCaller,
427			) -> core::result::Result<&'a #pallet_origin, ()> {
428				if let OriginCaller::#variant_name(l) = x {
429					Ok(&l)
430				} else {
431					Err(())
432				}
433			}
434		}
435
436		#attr
437		impl<'a> TryFrom<&'a RuntimeOrigin> for &'a #pallet_origin {
438			type Error = ();
439			fn try_from(
440				x: &'a RuntimeOrigin,
441			) -> core::result::Result<&'a #pallet_origin, ()> {
442				if let OriginCaller::#variant_name(l) = &x.caller {
443					Ok(&l)
444				} else {
445					Err(())
446				}
447			}
448		}
449	}
450}
451
452// Get the actual documentation using the doc information and system path name
453fn get_intra_doc_string(doc_info: &str, system_path_name: &String) -> String {
454	format!(" {} [`{}::Config::BaseCallFilter`].", doc_info, system_path_name)
455}