diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 766bc9515b8ab..4391fe88ead31 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -372,6 +372,7 @@ impl pallet_scheduler::Config for Runtime { type WeightInfo = pallet_scheduler::weights::SubstrateWeight; type OriginPrivilegeCmp = EqualPrivilegeOnly; type Preimages = Preimage; + type CallFilter = Everything; } impl pallet_glutton::Config for Runtime { diff --git a/frame/democracy/src/tests.rs b/frame/democracy/src/tests.rs index 06fde5129c6d0..db7ddc243b8a5 100644 --- a/frame/democracy/src/tests.rs +++ b/frame/democracy/src/tests.rs @@ -22,7 +22,7 @@ use crate as pallet_democracy; use frame_support::{ assert_noop, assert_ok, ord_parameter_types, parameter_types, traits::{ - ConstU32, ConstU64, Contains, EqualPrivilegeOnly, GenesisBuild, OnInitialize, + ConstU32, ConstU64, Contains, EqualPrivilegeOnly, Everything, GenesisBuild, OnInitialize, SortedMembers, StorePreimage, }, weights::Weight, @@ -132,6 +132,7 @@ impl pallet_scheduler::Config for Test { type WeightInfo = (); type OriginPrivilegeCmp = EqualPrivilegeOnly; type Preimages = (); + type CallFilter = Everything; } impl pallet_balances::Config for Test { diff --git a/frame/referenda/src/mock.rs b/frame/referenda/src/mock.rs index cdedb79556f35..0ae6c4e692686 100644 --- a/frame/referenda/src/mock.rs +++ b/frame/referenda/src/mock.rs @@ -23,8 +23,8 @@ use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ assert_ok, ord_parameter_types, parameter_types, traits::{ - ConstU32, ConstU64, Contains, EqualPrivilegeOnly, OnInitialize, OriginTrait, Polling, - SortedMembers, + ConstU32, ConstU64, Contains, EqualPrivilegeOnly, Everything, OnInitialize, OriginTrait, + Polling, SortedMembers, }, weights::Weight, }; @@ -109,6 +109,7 @@ impl pallet_scheduler::Config for Test { type WeightInfo = (); type OriginPrivilegeCmp = EqualPrivilegeOnly; type Preimages = Preimage; + type CallFilter = Everything; } impl pallet_balances::Config for Test { type MaxReserves = (); diff --git a/frame/scheduler/src/lib.rs b/frame/scheduler/src/lib.rs index 8194f286c8323..e819b0ce72b4a 100644 --- a/frame/scheduler/src/lib.rs +++ b/frame/scheduler/src/lib.rs @@ -67,8 +67,8 @@ use frame_support::{ ensure, traits::{ schedule::{self, DispatchTime, MaybeHashed}, - Bounded, CallerTrait, EnsureOrigin, Get, Hash as PreimageHash, IsType, OriginTrait, - PalletInfoAccess, PrivilegeCmp, QueryPreimage, StorageVersion, StorePreimage, + Bounded, CallerTrait, Contains, EnsureOrigin, Get, Hash as PreimageHash, IsType, + OriginTrait, PalletInfoAccess, PrivilegeCmp, QueryPreimage, StorageVersion, StorePreimage, }, weights::{Weight, WeightMeter}, }; @@ -165,7 +165,7 @@ impl MarginalWeightInfo for T {} #[frame_support::pallet] pub mod pallet { use super::*; - use frame_support::{dispatch::PostDispatchInfo, pallet_prelude::*}; + use frame_support::{dispatch::PostDispatchInfo, pallet_prelude::*, traits::Contains}; use frame_system::pallet_prelude::*; /// The current storage version. @@ -228,6 +228,9 @@ pub mod pallet { /// The preimage provider with which we look up call hashes to get the call. type Preimages: QueryPreimage + StorePreimage; + + /// Filtering calls. + type CallFilter: Contains<::RuntimeCall>; } #[pallet::storage] @@ -311,6 +314,7 @@ pub mod pallet { ) -> DispatchResult { T::ScheduleOrigin::ensure_origin(origin.clone())?; let origin = ::RuntimeOrigin::from(origin); + Self::check_call_filter(&call)?; Self::do_schedule( DispatchTime::At(when), maybe_periodic, @@ -344,6 +348,7 @@ pub mod pallet { ) -> DispatchResult { T::ScheduleOrigin::ensure_origin(origin.clone())?; let origin = ::RuntimeOrigin::from(origin); + Self::check_call_filter(&call)?; Self::do_schedule_named( id, DispatchTime::At(when), @@ -377,6 +382,7 @@ pub mod pallet { ) -> DispatchResult { T::ScheduleOrigin::ensure_origin(origin.clone())?; let origin = ::RuntimeOrigin::from(origin); + Self::check_call_filter(&call)?; Self::do_schedule( DispatchTime::After(after), maybe_periodic, @@ -400,6 +406,7 @@ pub mod pallet { ) -> DispatchResult { T::ScheduleOrigin::ensure_origin(origin.clone())?; let origin = ::RuntimeOrigin::from(origin); + Self::check_call_filter(&call)?; Self::do_schedule_named( id, DispatchTime::After(after), @@ -941,6 +948,14 @@ impl Pallet { Self::deposit_event(Event::Canceled { when, index }); Self::place_task(new_time, task).map_err(|x| x.0) } + + fn check_call_filter(call: &::RuntimeCall) -> DispatchResult { + if !::CallFilter::contains(call) { + return Err(>::CallFiltered.into()) + } + + Ok(()) + } } enum ServiceTaskError { diff --git a/frame/scheduler/src/mock.rs b/frame/scheduler/src/mock.rs index adb54fd78b181..aa2f756b635d2 100644 --- a/frame/scheduler/src/mock.rs +++ b/frame/scheduler/src/mock.rs @@ -90,6 +90,16 @@ pub mod logger { }); Ok(()) } + + #[pallet::call_index(2)] + #[pallet::weight(*weight)] + pub fn log_not_sheduled(origin: OriginFor, i: u32, weight: Weight) -> DispatchResult { + Self::deposit_event(Event::Logged(i, weight)); + Log::mutate(|log| { + log.push((origin.caller().clone(), i)); + }); + Ok(()) + } } } @@ -117,6 +127,13 @@ impl Contains for BaseFilter { } } +pub struct CallFilter; +impl Contains for CallFilter { + fn contains(call: &RuntimeCall) -> bool { + !matches!(call, RuntimeCall::Logger(LoggerCall::log_not_sheduled { .. })) + } +} + parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights::simple_max( @@ -220,6 +237,7 @@ impl Config for Test { type WeightInfo = TestWeightInfo; type OriginPrivilegeCmp = EqualPrivilegeOnly; type Preimages = Preimage; + type CallFilter = CallFilter; } pub type LoggerCall = logger::Call; diff --git a/frame/scheduler/src/tests.rs b/frame/scheduler/src/tests.rs index a0cac897d43df..f9c9868dfdda1 100644 --- a/frame/scheduler/src/tests.rs +++ b/frame/scheduler/src/tests.rs @@ -712,6 +712,39 @@ fn root_calls_works() { }); } +#[test] +fn fails_to_schedule_filtered_task() { + new_test_ext().execute_with(|| { + let call = Box::new(RuntimeCall::Logger(LoggerCall::log_not_sheduled { + i: 42, + weight: Weight::from_ref_time(10), + })); + assert_err!( + Scheduler::schedule(RuntimeOrigin::root(), 4, None, 127, call.clone(),), + frame_system::Error::::CallFiltered + ); + assert_err!( + Scheduler::schedule_named(RuntimeOrigin::root(), [1u8; 32], 4, None, 127, call.clone(),), + frame_system::Error::::CallFiltered + ); + assert_err!( + Scheduler::schedule_after(RuntimeOrigin::root(), 4, None, 127, call.clone(),), + frame_system::Error::::CallFiltered + ); + assert_err!( + Scheduler::schedule_named_after( + RuntimeOrigin::root(), + [1u8; 32], + 4, + None, + 127, + call.clone(), + ), + frame_system::Error::::CallFiltered + ); + }); +} + #[test] fn fails_to_schedule_task_in_the_past() { new_test_ext().execute_with(|| {