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

Root origin use no filter by default. Scheduler and Democracy dispatch without asserting BaseCallFilter #6408

Merged
merged 2 commits into from
Jun 19, 2020
Merged
Show file tree
Hide file tree
Changes from all 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
21 changes: 19 additions & 2 deletions frame/democracy/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ use std::cell::RefCell;
use codec::Encode;
use frame_support::{
impl_outer_origin, impl_outer_dispatch, assert_noop, assert_ok, parameter_types,
impl_outer_event, ord_parameter_types, traits::{Contains, OnInitialize}, weights::Weight,
impl_outer_event, ord_parameter_types, traits::{Contains, OnInitialize, Filter},
weights::Weight,
};
use sp_core::H256;
use sp_runtime::{
Expand Down Expand Up @@ -74,6 +75,14 @@ impl_outer_event! {
}
}

// Test that a fitlered call can be dispatched.
pub struct BaseFilter;
impl Filter<Call> for BaseFilter {
fn filter(call: &Call) -> bool {
!matches!(call, &Call::Balances(pallet_balances::Call::set_balance(..)))
}
}

// Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted.
#[derive(Clone, Eq, PartialEq, Debug)]
pub struct Test;
Expand All @@ -84,7 +93,7 @@ parameter_types! {
pub const AvailableBlockRatio: Perbill = Perbill::one();
}
impl frame_system::Trait for Test {
type BaseCallFilter = ();
type BaseCallFilter = BaseFilter;
type Origin = Origin;
type Index = u64;
type BlockNumber = u64;
Expand Down Expand Up @@ -225,6 +234,14 @@ fn set_balance_proposal(value: u64) -> Vec<u8> {
Call::Balances(pallet_balances::Call::set_balance(42, value, 0)).encode()
}

#[test]
fn set_balance_proposal_is_correctly_filtered_out() {
for i in 0..10 {
let call = Call::decode(&mut &set_balance_proposal(i)[..]).unwrap();
assert!(!<Test as frame_system::Trait>::BaseCallFilter::filter(&call));
}
}

fn set_balance_proposal_hash(value: u64) -> H256 {
BlakeTwo256::hash(&set_balance_proposal(value)[..])
}
Expand Down
17 changes: 14 additions & 3 deletions frame/scheduler/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,7 @@ mod tests {

use frame_support::{
impl_outer_event, impl_outer_origin, impl_outer_dispatch, parameter_types, assert_ok,
traits::{OnInitialize, OnFinalize},
traits::{OnInitialize, OnFinalize, Filter},
weights::constants::RocksDbWeight,
};
use sp_core::H256;
Expand Down Expand Up @@ -469,6 +469,15 @@ mod tests {
scheduler<T>,
}
}

// Scheduler must dispatch with root and no filter, this tests base filter is indeed not used.
pub struct BaseFilter;
impl Filter<Call> for BaseFilter {
fn filter(call: &Call) -> bool {
!matches!(call, Call::Logger(_))
}
}

// For testing the pallet, we construct most of a mock runtime. This means
// first constructing a configuration type (`Test`) which `impl`s each of the
// configuration traits of pallets we want to use.
Expand All @@ -481,7 +490,7 @@ mod tests {
pub const AvailableBlockRatio: Perbill = Perbill::one();
}
impl system::Trait for Test {
type BaseCallFilter = ();
type BaseCallFilter = BaseFilter;
type Origin = Origin;
type Call = Call;
type Index = u64;
Expand Down Expand Up @@ -540,7 +549,9 @@ mod tests {
#[test]
fn basic_scheduling_works() {
new_test_ext().execute_with(|| {
Scheduler::do_schedule(4, None, 127, Call::Logger(logger::Call::log(42, 1000)));
let call = Call::Logger(logger::Call::log(42, 1000));
assert!(!<Test as frame_system::Trait>::BaseCallFilter::filter(&call));
Scheduler::do_schedule(4, None, 127, call);
run_to_block(3);
assert!(logger::log().is_empty());
run_to_block(4);
Expand Down
24 changes: 20 additions & 4 deletions frame/support/src/origin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,8 +163,8 @@ macro_rules! impl_outer_origin {
Modules { };
$( $module:ident $( < $generic:ident > )? $( { $generic_instance:ident } )? ,)*
) => {
// WARNING: All instance must hold the filter `frame_system::Trait::BaseCallFilter`.
// One can use `OriginTrait::reset_filter` to do so.
// WARNING: All instance must hold the filter `frame_system::Trait::BaseCallFilter`, except
// when caller is system Root. One can use `OriginTrait::reset_filter` to do so.
#[derive(Clone)]
pub struct $name {
caller: $caller_name,
Expand Down Expand Up @@ -241,28 +241,40 @@ macro_rules! impl_outer_origin {

#[allow(dead_code)]
impl $name {
/// Create with system none origin and `frame-system::Trait::BaseCallFilter`.
pub fn none() -> Self {
$system::RawOrigin::None.into()
}
/// Create with system root origin and no filter.
pub fn root() -> Self {
$system::RawOrigin::Root.into()
}
/// Create with system signed origin and `frame-system::Trait::BaseCallFilter`.
pub fn signed(by: <$runtime as $system::Trait>::AccountId) -> Self {
$system::RawOrigin::Signed(by).into()
}
}

impl From<$system::Origin<$runtime>> for $name {
/// Convert to runtime origin:
/// * root origin is built with no filter
/// * others use `frame-system::Trait::BaseCallFilter`
fn from(x: $system::Origin<$runtime>) -> Self {
let mut o = $name {
caller: $caller_name::system(x),
filter: $crate::sp_std::rc::Rc::new(Box::new(|_| true)),
};
$crate::traits::OriginTrait::reset_filter(&mut o);

// 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)
Expand All @@ -272,13 +284,16 @@ macro_rules! impl_outer_origin {
}
}
impl From<Option<<$runtime as $system::Trait>::AccountId>> for $name {
/// Convert to runtime origin with caller being system signed or none and use filter
/// `frame-system::Trait::BaseCallFilter`.
fn from(x: Option<<$runtime as $system::Trait>::AccountId>) -> Self {
<$system::Origin<$runtime>>::from(x).into()
}
}
$(
$crate::paste::item! {
impl From<$module::Origin < $( $generic )? $(, $module::$generic_instance )? > > for $name {
/// Convert to runtime origin using `frame-system::Trait::BaseCallFilter`.
fn from(x: $module::Origin < $( $generic )? $(, $module::$generic_instance )? >) -> Self {
let mut o = $name {
caller: $caller_name::[< $module $( _ $generic_instance )? >](x),
Expand All @@ -294,6 +309,7 @@ macro_rules! impl_outer_origin {
$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,
Expand Down Expand Up @@ -402,7 +418,7 @@ mod tests {
#[test]
fn test_default_filter() {
assert_eq!(OriginWithSystem::root().filter_call(&0), true);
assert_eq!(OriginWithSystem::root().filter_call(&1), false);
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);
Expand Down
3 changes: 2 additions & 1 deletion frame/system/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,8 @@ pub fn extrinsics_data_root<H: Hash>(xts: Vec<Vec<u8>>) -> H::Output {
}

pub trait Trait: 'static + Eq + Clone {
/// The basic call filter to use in Origin.
/// The basic call filter to use in Origin. All origins are built with this filter as base,
/// except Root.
type BaseCallFilter: Filter<Self::Call>;

/// The `Origin` type used by dispatchable calls.
Expand Down