Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Root origin always bypass all filter, other origin cannot bypass BaseCallFilter even when constructed from Root origin #9948

Merged
7 commits merged into from
Oct 7, 2021
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 11 additions & 14 deletions frame/support/procedural/src/construct_runtime/expand/origin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,9 @@ pub fn expand_outer_origin(
Ok(quote! {
#( #query_origin_part_macros )*

// 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.
/// The runtime origin type represanting the origin of a call.
///
/// Origin is always created with the base filter configured in `frame_system::Config::BaseCallFilter`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using proper intra doc links here would be nice.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll do in a follow up when I get more time #9962

#[derive(Clone)]
pub struct Origin {
caller: OriginCaller,
Expand Down Expand Up @@ -140,7 +141,9 @@ pub fn expand_outer_origin(
}

fn filter_call(&self, call: &Self::Call) -> bool {
(self.filter)(call)
// Root bypass all filters
thiolliere marked this conversation as resolved.
Show resolved Hide resolved
matches!(self.caller, OriginCaller::system(#system_path::Origin::<#runtime>::Root))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
matches!(self.caller, OriginCaller::system(#system_path::Origin::<#runtime>::Root))
match self.caller { OriginCaller::system(#system_path::Origin::<#runtime>::Root) => true, _ => false }

Or use an absolute path to matches! here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indeed, done in 84a9ac0

|| (self.filter)(call)
}

fn caller(&self) -> &Self::PalletsOrigin {
Expand All @@ -157,15 +160,14 @@ pub fn expand_outer_origin(
}
}

/// Create with system none origin and `frame-system::Config::BaseCallFilter`.
fn none() -> Self {
#system_path::RawOrigin::None.into()
}
/// Create with system root origin and no filter.

fn root() -> Self {
#system_path::RawOrigin::Root.into()
}
/// Create with system signed origin and `frame-system::Config::BaseCallFilter`.

fn signed(by: <#runtime as #system_path::Config>::AccountId) -> Self {
#system_path::RawOrigin::Signed(by).into()
}
Expand All @@ -191,7 +193,7 @@ pub fn expand_outer_origin(
pub fn none() -> Self {
<Origin as #scrate::traits::OriginTrait>::none()
}
/// Create with system root origin and no filter.
/// Create with system root origin and `frame-system::Config::BaseCallFilter`.
pub fn root() -> Self {
<Origin as #scrate::traits::OriginTrait>::root()
}
Expand Down Expand Up @@ -221,9 +223,7 @@ pub fn expand_outer_origin(
}

impl From<#system_path::Origin<#runtime>> for Origin {
/// Convert to runtime origin:
/// * root origin is built with no filter
/// * others use `frame-system::Config::BaseCallFilter`
/// Convert to runtime origin, using as filter: `frame-system::Config::BaseCallFilter`.
fn from(x: #system_path::Origin<#runtime>) -> Self {
let o: OriginCaller = x.into();
o.into()
Expand All @@ -237,10 +237,7 @@ pub fn expand_outer_origin(
filter: #scrate::sp_std::rc::Rc::new(Box::new(|_| true)),
};

// Root has no filter
if !matches!(o.caller, OriginCaller::system(#system_path::Origin::<#runtime>::Root)) {
#scrate::traits::OriginTrait::reset_filter(&mut o);
}
#scrate::traits::OriginTrait::reset_filter(&mut o);

o
}
Expand Down
11 changes: 7 additions & 4 deletions frame/support/src/traits/dispatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,10 @@ pub trait OriginTrait: Sized {
/// Replace the caller with caller from the other origin
fn set_caller_from(&mut self, other: impl Into<Self>);

/// Filter the call, if false then call is filtered out.
/// Filter the call if caller is not root, if false is returned then the call must be filtered
/// out.
///
/// For root origin caller, the filters are bypassed and true is returned.
fn filter_call(&self, call: &Self::Call) -> bool;

/// Get the caller.
Expand All @@ -82,12 +85,12 @@ pub trait OriginTrait: Sized {
f: impl FnOnce(Self::PalletsOrigin) -> Result<R, Self::PalletsOrigin>,
) -> Result<R, Self>;

/// Create with system none origin and `frame-system::Config::BaseCallFilter`.
/// Create with system none origin and `frame_system::Config::BaseCallFilter`.
fn none() -> Self;

/// Create with system root origin and no filter.
/// Create with system root origin and `frame_system::Config::BaseCallFilter`.
fn root() -> Self;

/// Create with system signed origin and `frame-system::Config::BaseCallFilter`.
/// Create with system signed origin and `frame_system::Config::BaseCallFilter`.
fn signed(by: Self::AccountId) -> Self;
}
18 changes: 15 additions & 3 deletions frame/support/test/tests/construct_runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -327,19 +327,31 @@ mod origin_test {
assert_eq!(Origin::from(super::nested::module3::Origin).filter_call(&rejected_call), false);

let mut origin = Origin::from(Some(0));

origin.add_filter(|c| matches!(c, Call::Module3(_)));
assert_eq!(origin.filter_call(&accepted_call), false);
assert_eq!(origin.filter_call(&rejected_call), false);

// Now test for root origin and filters:
let mut origin = Origin::from(Some(0));
origin.set_caller_from(Origin::root());
assert!(matches!(origin.caller, OriginCaller::system(super::system::RawOrigin::Root)));
assert_eq!(origin.filter_call(&accepted_call), false);

// Root origin bypass all filter.
assert_eq!(origin.filter_call(&accepted_call), true);
assert_eq!(origin.filter_call(&rejected_call), true);

origin.set_caller_from(Origin::from(Some(0)));

// Back to another signed origin, the filtered are now effective again
assert_eq!(origin.filter_call(&accepted_call), true);
assert_eq!(origin.filter_call(&rejected_call), false);

origin.set_caller_from(Origin::root());
origin.reset_filter();

// Root origin bypass all filter, even when they are reset.
assert_eq!(origin.filter_call(&accepted_call), true);
assert_eq!(origin.filter_call(&rejected_call), false);
assert_eq!(origin.filter_call(&rejected_call), true);
}
}

Expand Down