// This file is part of Substrate. // Copyright (C) 2018-2021 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //! Macros that define an Origin type. Every function call to your runtime has an origin which //! specifies where the extrinsic was generated from. /// Constructs an Origin type for a runtime. This is usually called automatically by the /// construct_runtime macro. See also __create_decl_macro. #[macro_export] macro_rules! impl_outer_origin { // Macro transformations (to convert invocations with incomplete parameters to the canonical // form) ( $(#[$attr:meta])* pub enum $name:ident for $runtime:ident { $( $rest_without_system:tt )* } ) => { $crate::impl_outer_origin! { $(#[$attr])* pub enum $name for $runtime where system = frame_system { $( $rest_without_system )* } } }; ( $(#[$attr:meta])* pub enum $name:ident for $runtime:ident where system = $system:ident $(, system_index = $system_index:tt)? { $( $rest_with_system:tt )* } ) => { $crate::paste::item! { $crate::impl_outer_origin!( $( #[$attr] )*; $name; [< $name Caller >]; $runtime; $system; system_index { $( $system_index )? }; Modules { $( $rest_with_system )* }; ); } }; // Generic + Instance ( $(#[$attr:meta])*; $name:ident; $caller_name:ident; $runtime:ident; $system:ident; system_index { $( $system_index:tt )? }; Modules { $( #[codec(index = $index:tt)] )? $module:ident $instance:ident $(, $( $rest_module:tt )* )? }; $( $parsed:tt )* ) => { $crate::impl_outer_origin!( $( #[$attr] )*; $name; $caller_name; $runtime; $system; system_index { $( $system_index )? }; Modules { $( $( $rest_module )* )? }; $( $parsed )* $module <$runtime> { $instance } index { $( $index )? }, ); }; // Instance ( $(#[$attr:meta])*; $name:ident; $caller_name:ident; $runtime:ident; $system:ident; system_index { $( $system_index:tt )? }; Modules { $( #[codec(index = $index:tt )] )? $module:ident $instance:ident $(, $rest_module:tt )* }; $( $parsed:tt )* ) => { $crate::impl_outer_origin!( $( #[$attr] )*; $name; $caller_name; $runtime; $system; system_index { $( $system_index )? }; Modules { $( $rest_module )* }; $( $parsed )* $module { $instance } index { $( $index )? }, ); }; // Generic ( $(#[$attr:meta])*; $name:ident; $caller_name:ident; $runtime:ident; $system:ident; system_index { $( $system_index:tt )? }; Modules { $( #[codec(index = $index:tt )] )? $module:ident $(, $( $rest_module:tt )* )? }; $( $parsed:tt )* ) => { $crate::impl_outer_origin!( $( #[$attr] )*; $name; $caller_name; $runtime; $system; system_index { $( $system_index )? }; Modules { $( $( $rest_module )* )? }; $( $parsed )* $module <$runtime> index { $( $index )? }, ); }; // No Generic and no Instance ( $(#[$attr:meta])*; $name:ident; $caller_name:ident; $runtime:ident; $system:ident; system_index { $( $system_index:tt )? }; Modules { $( #[codec(index = $index:tt )] )? $module:ident $(, $( $rest_module:tt )* )? }; $( $parsed:tt )* ) => { $crate::impl_outer_origin!( $( #[$attr] )*; $name; $caller_name; $runtime; $system; system_index { $( $system_index )? }; Modules { $( $( $rest_module )* )? }; $( $parsed )* $module index { $( $index )? }, ); }; // The main macro expansion that actually renders the Origin enum code. ( $(#[$attr:meta])*; $name:ident; $caller_name:ident; $runtime:ident; $system:ident; system_index { $( $system_index:tt )? }; Modules { }; $( $module:ident $( < $generic:ident > )? $( { $generic_instance:ident } )? index { $( $index:tt )? }, )* ) => { // WARNING: All instance must hold the filter `frame_system::Config::BaseCallFilter`, except // when caller is system Root. One can use `OriginTrait::reset_filter` to do so. #[derive(Clone)] pub struct $name { caller: $caller_name, filter: $crate::sp_std::rc::Rc::Call) -> bool>>, } #[cfg(not(feature = "std"))] impl $crate::sp_std::fmt::Debug for $name { fn fmt( &self, fmt: &mut $crate::sp_std::fmt::Formatter ) -> $crate::sp_std::result::Result<(), $crate::sp_std::fmt::Error> { fmt.write_str("") } } #[cfg(feature = "std")] impl $crate::sp_std::fmt::Debug for $name { fn fmt( &self, fmt: &mut $crate::sp_std::fmt::Formatter ) -> $crate::sp_std::result::Result<(), $crate::sp_std::fmt::Error> { fmt.debug_struct(stringify!($name)) .field("caller", &self.caller) .field("filter", &"[function ptr]") .finish() } } impl $crate::traits::OriginTrait for $name { type Call = <$runtime as $system::Config>::Call; type PalletsOrigin = $caller_name; type AccountId = <$runtime as $system::Config>::AccountId; fn add_filter(&mut self, filter: impl Fn(&Self::Call) -> bool + 'static) { let f = self.filter.clone(); self.filter = $crate::sp_std::rc::Rc::new(Box::new(move |call| { f(call) && filter(call) })); } fn reset_filter(&mut self) { let filter = < <$runtime as $system::Config>::BaseCallFilter as $crate::traits::Filter<<$runtime as $system::Config>::Call> >::filter; self.filter = $crate::sp_std::rc::Rc::new(Box::new(filter)); } fn set_caller_from(&mut self, other: impl Into) { self.caller = other.into().caller } fn filter_call(&self, call: &Self::Call) -> bool { (self.filter)(call) } fn caller(&self) -> &Self::PalletsOrigin { &self.caller } fn try_with_caller( mut self, f: impl FnOnce(Self::PalletsOrigin) -> Result, ) -> Result { match f(self.caller) { Ok(r) => Ok(r), Err(caller) => { self.caller = caller; Err(self) } } } /// Create with system none origin and `frame-system::Config::BaseCallFilter`. fn none() -> Self { $system::RawOrigin::None.into() } /// Create with system root origin and no filter. fn root() -> Self { $system::RawOrigin::Root.into() } /// Create with system signed origin and `frame-system::Config::BaseCallFilter`. fn signed(by: <$runtime as $system::Config>::AccountId) -> Self { $system::RawOrigin::Signed(by).into() } } $crate::paste::item! { #[derive(Clone, PartialEq, Eq, $crate::RuntimeDebug, $crate::codec::Encode, $crate::codec::Decode)] $(#[$attr])* #[allow(non_camel_case_types)] pub enum $caller_name { $( #[codec(index = $system_index)] )? system($system::Origin<$runtime>), $( $( #[codec(index = $index)] )? [< $module $( _ $generic_instance )? >] ($module::Origin < $( $generic, )? $( $module::$generic_instance )? > ), )* #[allow(dead_code)] Void($crate::Void) } } // For backwards compatibility and ease of accessing these functions. #[allow(dead_code)] impl $name { /// Create with system none origin and `frame-system::Config::BaseCallFilter`. pub fn none() -> Self { <$name as $crate::traits::OriginTrait>::none() } /// Create with system root origin and no filter. pub fn root() -> Self { <$name as $crate::traits::OriginTrait>::root() } /// Create with system signed origin and `frame-system::Config::BaseCallFilter`. pub fn signed(by: <$runtime as $system::Config>::AccountId) -> Self { <$name as $crate::traits::OriginTrait>::signed(by) } } impl From<$system::Origin<$runtime>> for $caller_name { fn from(x: $system::Origin<$runtime>) -> Self { $caller_name::system(x) } } impl $crate::sp_std::convert::TryFrom<$caller_name> for $system::Origin<$runtime> { type Error = $caller_name; fn try_from(x: $caller_name) -> $crate::sp_std::result::Result<$system::Origin<$runtime>, $caller_name> { if let $caller_name::system(l) = x { Ok(l) } else { Err(x) } } } impl From<$system::Origin<$runtime>> for $name { /// Convert to runtime origin: /// * root origin is built with no filter /// * others use `frame-system::Config::BaseCallFilter` fn from(x: $system::Origin<$runtime>) -> Self { let o: $caller_name = x.into(); o.into() } } impl From<$caller_name> for $name { fn from(x: $caller_name) -> Self { let mut o = $name { caller: x, filter: $crate::sp_std::rc::Rc::new(Box::new(|_| true)), }; // Root has no filter if !matches!(o.caller, $caller_name::system($system::Origin::<$runtime>::Root)) { $crate::traits::OriginTrait::reset_filter(&mut o); } o } } impl Into<$crate::sp_std::result::Result<$system::Origin<$runtime>, $name>> for $name { /// NOTE: converting to pallet origin loses the origin filter information. fn into(self) -> $crate::sp_std::result::Result<$system::Origin<$runtime>, Self> { if let $caller_name::system(l) = self.caller { Ok(l) } else { Err(self) } } } impl From::AccountId>> for $name { /// Convert to runtime origin with caller being system signed or none and use filter /// `frame-system::Config::BaseCallFilter`. fn from(x: Option<<$runtime as $system::Config>::AccountId>) -> Self { <$system::Origin<$runtime>>::from(x).into() } } $( $crate::paste::item! { impl From<$module::Origin < $( $generic )? $(, $module::$generic_instance )? > > for $caller_name { fn from(x: $module::Origin < $( $generic )? $(, $module::$generic_instance )? >) -> Self { $caller_name::[< $module $( _ $generic_instance )? >](x) } } impl From<$module::Origin < $( $generic )? $(, $module::$generic_instance )? > > for $name { /// Convert to runtime origin using `frame-system::Config::BaseCallFilter`. fn from(x: $module::Origin < $( $generic )? $(, $module::$generic_instance )? >) -> Self { let x: $caller_name = x.into(); x.into() } } impl Into< $crate::sp_std::result::Result< $module::Origin < $( $generic )? $(, $module::$generic_instance )? >, $name, >> for $name { /// NOTE: converting to pallet origin loses the origin filter information. fn into(self) -> $crate::sp_std::result::Result< $module::Origin < $( $generic )? $(, $module::$generic_instance )? >, Self, > { if let $caller_name::[< $module $( _ $generic_instance )? >](l) = self.caller { Ok(l) } else { Err(self) } } } impl $crate::sp_std::convert::TryFrom< $caller_name > for $module::Origin < $( $generic )? $(, $module::$generic_instance )? > { type Error = $caller_name; fn try_from(x: $caller_name) -> $crate::sp_std::result::Result< $module::Origin < $( $generic )? $(, $module::$generic_instance )? >, $caller_name, > { if let $caller_name::[< $module $( _ $generic_instance )? >](l) = x { Ok(l) } else { Err(x) } } } } )* } } #[cfg(test)] mod tests { use codec::{Encode, Decode}; use crate::traits::{Filter, OriginTrait}; mod frame_system { use super::*; pub trait Config { type AccountId; type Call; type BaseCallFilter; } #[derive(Clone, PartialEq, Eq, Debug, Encode, Decode)] pub enum RawOrigin { Root, Signed(AccountId), None, } impl From> for RawOrigin { fn from(s: Option) -> RawOrigin { match s { Some(who) => RawOrigin::Signed(who), None => RawOrigin::None, } } } pub type Origin = RawOrigin<::AccountId>; } mod origin_without_generic { use super::*; #[derive(Clone, PartialEq, Eq, Debug, Encode, Decode)] pub struct Origin; } mod origin_with_generic { use super::*; #[derive(Clone, PartialEq, Eq, Debug, Encode, Decode)] pub struct Origin { t: T } } #[derive(Clone, PartialEq, Eq, Debug, Encode, Decode)] pub struct TestRuntime; pub struct BaseCallFilter; impl Filter for BaseCallFilter { fn filter(c: &u32) -> bool { *c % 2 == 0 } } impl frame_system::Config for TestRuntime { type AccountId = u32; type Call = u32; type BaseCallFilter = BaseCallFilter; } impl_outer_origin!( pub enum OriginWithoutSystem for TestRuntime { origin_without_generic, origin_with_generic, } ); impl_outer_origin!( pub enum OriginWithoutSystem2 for TestRuntime { origin_with_generic, origin_without_generic } ); impl_outer_origin!( pub enum OriginWithSystem for TestRuntime where system = frame_system { origin_without_generic, origin_with_generic } ); impl_outer_origin!( pub enum OriginWithSystem2 for TestRuntime where system = frame_system { origin_with_generic, origin_without_generic, } ); impl_outer_origin!( pub enum OriginEmpty for TestRuntime where system = frame_system {} ); impl_outer_origin!( pub enum OriginIndices for TestRuntime where system = frame_system, system_index = 11 { origin_with_generic, #[codec(index = 10)] origin_without_generic, } ); #[test] fn test_default_filter() { assert_eq!(OriginWithSystem::root().filter_call(&0), true); assert_eq!(OriginWithSystem::root().filter_call(&1), true); assert_eq!(OriginWithSystem::none().filter_call(&0), true); assert_eq!(OriginWithSystem::none().filter_call(&1), false); assert_eq!(OriginWithSystem::signed(0).filter_call(&0), true); assert_eq!(OriginWithSystem::signed(0).filter_call(&1), false); assert_eq!(OriginWithSystem::from(Some(0)).filter_call(&0), true); assert_eq!(OriginWithSystem::from(Some(0)).filter_call(&1), false); assert_eq!(OriginWithSystem::from(None).filter_call(&0), true); assert_eq!(OriginWithSystem::from(None).filter_call(&1), false); assert_eq!(OriginWithSystem::from(origin_without_generic::Origin).filter_call(&0), true); assert_eq!(OriginWithSystem::from(origin_without_generic::Origin).filter_call(&1), false); let mut origin = OriginWithSystem::from(Some(0)); origin.add_filter(|c| *c % 2 == 1); assert_eq!(origin.filter_call(&0), false); assert_eq!(origin.filter_call(&1), false); origin.set_caller_from(OriginWithSystem::root()); assert!(matches!(origin.caller, OriginWithSystemCaller::system(frame_system::RawOrigin::Root))); assert_eq!(origin.filter_call(&0), false); assert_eq!(origin.filter_call(&1), false); origin.reset_filter(); assert_eq!(origin.filter_call(&0), true); assert_eq!(origin.filter_call(&1), false); } #[test] fn test_codec() { use codec::Encode; assert_eq!(OriginIndices::root().caller.encode()[0], 11); let without_generic_variant = OriginIndicesCaller::origin_without_generic( origin_without_generic::Origin ); assert_eq!(without_generic_variant.encode()[0], 10); assert_eq!(OriginWithoutSystem::root().caller.encode()[0], 0); let without_generic_variant = OriginWithoutSystemCaller::origin_without_generic( origin_without_generic::Origin ); assert_eq!(without_generic_variant.encode()[0], 1); } }