difftreelog
fix enable scheduler v2
in: master
6 files changed
pallets/scheduler-v2/src/benchmarking.rsdiffbeforeafterboth--- a/pallets/scheduler-v2/src/benchmarking.rs
+++ b/pallets/scheduler-v2/src/benchmarking.rs
@@ -68,7 +68,10 @@
let name = u32_to_name(i);
Scheduler::<T>::do_schedule_named(name, t, period, 0, origin.clone(), call)?;
}
- ensure!(Agenda::<T>::get(when).len() == n as usize, "didn't fill schedule");
+ ensure!(
+ Agenda::<T>::get(when).len() == n as usize,
+ "didn't fill schedule"
+ );
Ok(())
}
@@ -93,19 +96,30 @@
false => None,
};
let origin = make_origin::<T>(signed);
- Scheduled { maybe_id, priority, call, maybe_periodic, origin, _phantom: PhantomData }
+ Scheduled {
+ maybe_id,
+ priority,
+ call,
+ maybe_periodic,
+ origin,
+ _phantom: PhantomData,
+ }
}
fn bounded<T: Config>(len: u32) -> Option<ScheduledCall<T>> {
- let call =
- <<T as Config>::Call>::from(SystemCall::remark { remark: vec![0; len as usize] });
- ScheduledCall::new(call).ok()
+ let call = <<T as Config>::Call>::from(SystemCall::remark {
+ remark: vec![0; len as usize],
+ });
+ ScheduledCall::new(call).ok()
}
fn make_call<T: Config>(maybe_lookup_len: Option<u32>) -> ScheduledCall<T> {
let bound = EncodedCall::bound() as u32;
let mut len = match maybe_lookup_len {
- Some(len) => len.min(<T::Preimages as PreimageRecipient<T::Hash>>::MaxSize::get() - 2).max(bound) - 3,
+ Some(len) => {
+ len.min(<T::Preimages as PreimageRecipient<T::Hash>>::MaxSize::get() - 2)
+ .max(bound) - 3
+ }
None => bound.saturating_sub(4),
};
@@ -114,11 +128,11 @@
Some(x) => x,
None => {
len -= 1;
- continue
- },
+ continue;
+ }
};
if c.lookup_needed() == maybe_lookup_len.is_some() {
- break c
+ break c;
}
if maybe_lookup_len.is_some() {
len += 1;
@@ -126,7 +140,7 @@
if len > 0 {
len -= 1;
} else {
- break c
+ break c;
}
}
}
@@ -140,11 +154,14 @@
}
fn dummy_counter() -> WeightCounter {
- WeightCounter { used: Weight::zero(), limit: Weight::MAX }
+ WeightCounter {
+ used: Weight::zero(),
+ limit: Weight::MAX,
+ }
}
benchmarks! {
- // `service_agendas` when no work is done.
+ // `service_agendas` when no work is done.
service_agendas_base {
let now = T::BlockNumber::from(BLOCK_NUMBER);
IncompleteSince::<T>::put(now - One::one());
@@ -154,7 +171,7 @@
assert_eq!(IncompleteSince::<T>::get(), Some(now - One::one()));
}
- // `service_agenda` when no work is done.
+ // `service_agenda` when no work is done.
service_agenda_base {
let now = BLOCK_NUMBER.into();
let s in 0 .. T::MaxScheduledPerBlock::get();
@@ -166,7 +183,7 @@
assert_eq!(executed, 0);
}
- // `service_task` when the task is a non-periodic, non-named, non-fetched call which is not
+ // `service_task` when the task is a non-periodic, non-named, non-fetched call which is not
// dispatched (e.g. due to being overweight).
service_task_base {
let now = BLOCK_NUMBER.into();
@@ -179,7 +196,7 @@
//assert_eq!(result, Ok(()));
}
- // `service_task` when the task is a non-periodic, non-named, fetched call (with a known
+ // `service_task` when the task is a non-periodic, non-named, fetched call (with a known
// preimage length) and which is not dispatched (e.g. due to being overweight).
service_task_fetched {
let s in (EncodedCall::bound() as u32) .. (<T::Preimages as PreimageRecipient<T::Hash>>::MaxSize::get());
@@ -192,7 +209,7 @@
} verify {
}
- // `service_task` when the task is a non-periodic, named, non-fetched call which is not
+ // `service_task` when the task is a non-periodic, named, non-fetched call which is not
// dispatched (e.g. due to being overweight).
service_task_named {
let now = BLOCK_NUMBER.into();
@@ -204,7 +221,7 @@
} verify {
}
- // `service_task` when the task is a periodic, non-named, non-fetched call which is not
+ // `service_task` when the task is a periodic, non-named, non-fetched call which is not
// dispatched (e.g. due to being overweight).
service_task_periodic {
let now = BLOCK_NUMBER.into();
@@ -216,7 +233,7 @@
} verify {
}
- // `execute_dispatch` when the origin is `Signed`, not counting the dispatable's weight.
+ // `execute_dispatch` when the origin is `Signed`, not counting the dispatable's weight.
execute_dispatch_signed {
let mut counter = WeightCounter { used: Weight::zero(), limit: Weight::MAX };
let origin = make_origin::<T>(true);
@@ -227,7 +244,7 @@
verify {
}
- // `execute_dispatch` when the origin is not `Signed`, not counting the dispatable's weight.
+ // `execute_dispatch` when the origin is not `Signed`, not counting the dispatable's weight.
execute_dispatch_unsigned {
let mut counter = WeightCounter { used: Weight::zero(), limit: Weight::MAX };
let origin = make_origin::<T>(false);
@@ -238,7 +255,7 @@
verify {
}
- schedule {
+ schedule {
let s in 0 .. (T::MaxScheduledPerBlock::get() - 1);
let when = BLOCK_NUMBER.into();
let periodic = Some((T::BlockNumber::one(), 100));
@@ -255,7 +272,7 @@
);
}
- cancel {
+ cancel {
let s in 1 .. T::MaxScheduledPerBlock::get();
let when = BLOCK_NUMBER.into();
@@ -275,7 +292,7 @@
);
}
- schedule_named {
+ schedule_named {
let s in 0 .. (T::MaxScheduledPerBlock::get() - 1);
let id = u32_to_name(s);
let when = BLOCK_NUMBER.into();
@@ -293,7 +310,7 @@
);
}
- cancel_named {
+ cancel_named {
let s in 1 .. T::MaxScheduledPerBlock::get();
let when = BLOCK_NUMBER.into();
@@ -311,5 +328,5 @@
);
}
- // impl_benchmark_test_suite!(Scheduler, crate::mock::new_test_ext(), crate::mock::Test);
+ // impl_benchmark_test_suite!(Scheduler, crate::mock::new_test_ext(), crate::mock::Test);
}
pallets/scheduler-v2/src/lib.rsdiffbeforeafterboth1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617// Original license:18// This file is part of Substrate.1920// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd.21// SPDX-License-Identifier: Apache-2.02223// Licensed under the Apache License, Version 2.0 (the "License");24// you may not use this file except in compliance with the License.25// You may obtain a copy of the License at26//27// http://www.apache.org/licenses/LICENSE-2.028//29// Unless required by applicable law or agreed to in writing, software30// distributed under the License is distributed on an "AS IS" BASIS,31// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.32// See the License for the specific language governing permissions and33// limitations under the License.3435//! # Scheduler36//! A Pallet for scheduling dispatches.37//!38//! - [`Config`]39//! - [`Call`]40//! - [`Pallet`]41//!42//! ## Overview43//!44//! This Pallet exposes capabilities for scheduling dispatches to occur at a45//! specified block number or at a specified period. These scheduled dispatches46//! may be named or anonymous and may be canceled.47//!48//! **NOTE:** The scheduled calls will be dispatched with the default filter49//! for the origin: namely `frame_system::Config::BaseCallFilter` for all origin50//! except root which will get no filter. And not the filter contained in origin51//! use to call `fn schedule`.52//!53//! If a call is scheduled using proxy or whatever mecanism which adds filter,54//! then those filter will not be used when dispatching the schedule call.55//!56//! ## Interface57//!58//! ### Dispatchable Functions59//!60//! * `schedule` - schedule a dispatch, which may be periodic, to occur at a specified block and61//! with a specified priority.62//! * `cancel` - cancel a scheduled dispatch, specified by block number and index.63//! * `schedule_named` - augments the `schedule` interface with an additional `Vec<u8>` parameter64//! that can be used for identification.65//! * `cancel_named` - the named complement to the cancel function.6667// Ensure we're `no_std` when compiling for Wasm.68#![cfg_attr(not(feature = "std"), no_std)]6970#[cfg(feature = "runtime-benchmarks")]71mod benchmarking;72#[cfg(test)]73mod mock;74#[cfg(test)]75mod tests;76pub mod weights;7778use codec::{Codec, Decode, Encode, MaxEncodedLen};79use frame_support::{80 dispatch::{81 DispatchError, DispatchResult, Dispatchable, GetDispatchInfo, Parameter, RawOrigin,82 },83 ensure,84 traits::{85 schedule::{self, DispatchTime},86 EnsureOrigin, Get, IsType, OriginTrait,87 PalletInfoAccess, PrivilegeCmp, StorageVersion,88 PreimageProvider, PreimageRecipient, ConstU32,89 },90 weights::Weight,91};9293use frame_system::{self as system};94use scale_info::TypeInfo;95use sp_io::hashing::blake2_256;96use sp_runtime::{97 traits::{BadOrigin, One, Saturating, Zero, Hash},98 BoundedVec, RuntimeDebug,99};100use sp_std::{borrow::Borrow, cmp::Ordering, marker::PhantomData, prelude::*};101pub use weights::WeightInfo;102103pub use pallet::*;104105/// Just a simple index for naming period tasks.106pub type PeriodicIndex = u32;107/// The location of a scheduled task that can be used to remove it.108pub type TaskAddress<BlockNumber> = (BlockNumber, u32);109110pub type EncodedCall = BoundedVec<u8, ConstU32<128>>;111112#[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)]113#[scale_info(skip_type_params(T))]114pub enum ScheduledCall<T: Config> {115 Inline(EncodedCall),116 PreimageLookup {117 hash: T::Hash,118 unbounded_len: u32,119 },120}121122impl<T: Config> ScheduledCall<T> {123 pub fn new(call: <T as Config>::Call) -> Result<Self, DispatchError> {124 let encoded = call.encode();125 let len = encoded.len();126127 match EncodedCall::try_from(encoded.clone()) {128 Ok(bounded) => Ok(Self::Inline(bounded)),129 Err(_) => {130 let hash = <T as system::Config>::Hashing::hash_of(&encoded);131 <T as Config>::Preimages::note_preimage(encoded.try_into().map_err(|_| <Error<T>>::TooBigScheduledCall)?);132133 Ok(Self::PreimageLookup { hash, unbounded_len: len as u32 })134 }135 }136 }137138 /// The maximum length of the lookup that is needed to peek `Self`.139 pub fn lookup_len(&self) -> Option<u32> {140 match self {141 Self::Inline(..) => None,142 Self::PreimageLookup { unbounded_len, .. } => Some(*unbounded_len),143 }144 }145146 /// Returns whether the image will require a lookup to be peeked.147 pub fn lookup_needed(&self) -> bool {148 match self {149 Self::Inline(_) => false,150 Self::PreimageLookup { .. } => true,151 }152 }153154 fn decode(mut data: &[u8]) -> Result<<T as Config>::Call, DispatchError> {155 <T as Config>::Call::decode(&mut data)156 .map_err(|_| <Error<T>>::ScheduledCallCorrupted.into())157 }158}159160pub trait SchedulerPreimages<T: Config>: PreimageRecipient<T::Hash> {161 fn drop(call: &ScheduledCall<T>);162163 fn peek(call: &ScheduledCall<T>) -> Result<(<T as pallet::Config>::Call, Option<u32>), DispatchError>;164165 /// Convert the given scheduled `call` value back into its original instance. If successful,166 /// `drop` any data backing it. This will not break the realisability of independently167 /// created instances of `ScheduledCall` which happen to have identical data.168 fn realize(call: &ScheduledCall<T>) -> Result<(<T as pallet::Config>::Call, Option<u32>), DispatchError>;169}170171impl<T: Config, PP: PreimageRecipient<T::Hash>> SchedulerPreimages<T> for PP {172 fn drop(call: &ScheduledCall<T>) {173 match call {174 ScheduledCall::Inline(_) => {},175 ScheduledCall::PreimageLookup { hash, .. } => Self::unrequest_preimage(hash),176 }177 }178179 fn peek(call: &ScheduledCall<T>) -> Result<(<T as pallet::Config>::Call, Option<u32>), DispatchError> {180 match call {181 ScheduledCall::Inline(data) => Ok((ScheduledCall::<T>::decode(data)?, None)),182 ScheduledCall::PreimageLookup { hash, unbounded_len } => {183 let (preimage, len) = Self::get_preimage(hash)184 .ok_or(<Error<T>>::PreimageNotFound)185 .map(|preimage| (preimage, *unbounded_len))?;186187 Ok((ScheduledCall::<T>::decode(preimage.as_slice())?, Some(len)))188 },189 }190 }191192 fn realize(call: &ScheduledCall<T>) -> Result<(<T as pallet::Config>::Call, Option<u32>), DispatchError> {193 let r = Self::peek(call)?;194 Self::drop(call);195 Ok(r)196 }197}198199pub type TaskName = [u8; 32];200201/// Information regarding an item to be executed in the future.202#[cfg_attr(any(feature = "std", test), derive(PartialEq, Eq))]203#[derive(Clone, RuntimeDebug, Encode, Decode, MaxEncodedLen, TypeInfo)]204pub struct Scheduled<Name, Call, BlockNumber, PalletsOrigin, AccountId> {205 /// The unique identity for this task, if there is one.206 maybe_id: Option<Name>,207208 /// This task's priority.209 priority: schedule::Priority,210211 /// The call to be dispatched.212 call: Call,213214 /// If the call is periodic, then this points to the information concerning that.215 maybe_periodic: Option<schedule::Period<BlockNumber>>,216217 /// The origin with which to dispatch the call.218 origin: PalletsOrigin,219 _phantom: PhantomData<AccountId>,220}221222pub type ScheduledOf<T> = Scheduled<223 TaskName,224 ScheduledCall<T>,225 <T as frame_system::Config>::BlockNumber,226 <T as Config>::PalletsOrigin,227 <T as frame_system::Config>::AccountId,228>;229230struct WeightCounter {231 used: Weight,232 limit: Weight,233}234235impl WeightCounter {236 fn check_accrue(&mut self, w: Weight) -> bool {237 let test = self.used.saturating_add(w);238 if test > self.limit {239 false240 } else {241 self.used = test;242 true243 }244 }245246 fn can_accrue(&mut self, w: Weight) -> bool {247 self.used.saturating_add(w) <= self.limit248 }249}250251pub(crate) trait MarginalWeightInfo: WeightInfo {252 fn service_task(maybe_lookup_len: Option<usize>, named: bool, periodic: bool) -> Weight {253 let base = Self::service_task_base();254 let mut total = match maybe_lookup_len {255 None => base,256 Some(l) => Self::service_task_fetched(l as u32),257 };258 if named {259 total.saturating_accrue(Self::service_task_named().saturating_sub(base));260 }261 if periodic {262 total.saturating_accrue(Self::service_task_periodic().saturating_sub(base));263 }264 total265 }266}267268impl<T: WeightInfo> MarginalWeightInfo for T {}269270#[frame_support::pallet]271pub mod pallet {272 use super::*;273 use frame_support::{dispatch::PostDispatchInfo, pallet_prelude::*};274 use system::pallet_prelude::*;275276 /// The current storage version.277 const STORAGE_VERSION: StorageVersion = StorageVersion::new(0);278279 #[pallet::pallet]280 #[pallet::generate_store(pub(super) trait Store)]281 #[pallet::storage_version(STORAGE_VERSION)]282 pub struct Pallet<T>(_);283284 #[pallet::config]285 pub trait Config: frame_system::Config {286 type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event>;287288 /// The aggregated origin which the dispatch will take.289 type Origin: OriginTrait<PalletsOrigin = Self::PalletsOrigin>290 + From<Self::PalletsOrigin>291 + IsType<<Self as system::Config>::Origin>292 + Clone;293294 /// The caller origin, overarching type of all pallets origins.295 type PalletsOrigin: From<system::RawOrigin<Self::AccountId>>296 + Codec297 + Clone298 + Eq299 + TypeInfo300 + MaxEncodedLen;301302 /// The aggregated call type.303 type Call: Parameter304 + Dispatchable<305 Origin = <Self as Config>::Origin,306 PostInfo = PostDispatchInfo,307 > + GetDispatchInfo308 + From<system::Call<Self>>;309310 /// The maximum weight that may be scheduled per block for any dispatchables.311 #[pallet::constant]312 type MaximumWeight: Get<Weight>;313314 /// Required origin to schedule or cancel calls.315 type ScheduleOrigin: EnsureOrigin<<Self as system::Config>::Origin>;316317 /// Compare the privileges of origins.318 ///319 /// This will be used when canceling a task, to ensure that the origin that tries320 /// to cancel has greater or equal privileges as the origin that created the scheduled task.321 ///322 /// For simplicity the [`EqualPrivilegeOnly`](frame_support::traits::EqualPrivilegeOnly) can323 /// be used. This will only check if two given origins are equal.324 type OriginPrivilegeCmp: PrivilegeCmp<Self::PalletsOrigin>;325326 /// The maximum number of scheduled calls in the queue for a single block.327 #[pallet::constant]328 type MaxScheduledPerBlock: Get<u32>;329330 /// Weight information for extrinsics in this pallet.331 type WeightInfo: WeightInfo;332333 /// The preimage provider with which we look up call hashes to get the call.334 type Preimages: SchedulerPreimages<Self>;335 }336337 #[pallet::storage]338 pub type IncompleteSince<T: Config> = StorageValue<_, T::BlockNumber>;339340 /// Items to be executed, indexed by the block number that they should be executed on.341 #[pallet::storage]342 pub type Agenda<T: Config> = StorageMap<343 _,344 Twox64Concat,345 T::BlockNumber,346 BoundedVec<Option<ScheduledOf<T>>, T::MaxScheduledPerBlock>,347 ValueQuery,348 >;349350 /// Lookup from a name to the block number and index of the task.351 #[pallet::storage]352 pub(crate) type Lookup<T: Config> =353 StorageMap<_, Twox64Concat, TaskName, TaskAddress<T::BlockNumber>>;354355 /// Events type.356 #[pallet::event]357 #[pallet::generate_deposit(pub(super) fn deposit_event)]358 pub enum Event<T: Config> {359 /// Scheduled some task.360 Scheduled { when: T::BlockNumber, index: u32 },361 /// Canceled some task.362 Canceled { when: T::BlockNumber, index: u32 },363 /// Dispatched some task.364 Dispatched {365 task: TaskAddress<T::BlockNumber>,366 id: Option<[u8; 32]>,367 result: DispatchResult,368 },369 /// The call for the provided hash was not found so the task has been aborted.370 CallUnavailable { task: TaskAddress<T::BlockNumber>, id: Option<[u8; 32]> },371 /// The given task was unable to be renewed since the agenda is full at that block.372 PeriodicFailed { task: TaskAddress<T::BlockNumber>, id: Option<[u8; 32]> },373 /// The given task can never be executed since it is overweight.374 PermanentlyOverweight { task: TaskAddress<T::BlockNumber>, id: Option<[u8; 32]> },375 }376377 #[pallet::error]378 pub enum Error<T> {379 /// Failed to schedule a call380 FailedToSchedule,381 /// There is no place for a new task in the agenda382 AgendaIsExhausted,383 /// Scheduled call is corrupted384 ScheduledCallCorrupted,385 /// Scheduled call preimage is not found386 PreimageNotFound,387 /// Scheduled call is too big388 TooBigScheduledCall,389 /// Cannot find the scheduled call.390 NotFound,391 /// Given target block number is in the past.392 TargetBlockNumberInPast,393 /// Reschedule failed because it does not change scheduled time.394 RescheduleNoChange,395 /// Attempt to use a non-named function on a named task.396 Named,397 }398399 #[pallet::hooks]400 impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {401 /// Execute the scheduled calls402 fn on_initialize(now: T::BlockNumber) -> Weight {403 let mut weight_counter =404 WeightCounter { used: Weight::zero(), limit: T::MaximumWeight::get() };405 Self::service_agendas(&mut weight_counter, now, u32::max_value());406 weight_counter.used407 }408 }409410 #[pallet::call]411 impl<T: Config> Pallet<T> {412 /// Anonymously schedule a task.413 #[pallet::weight(<T as Config>::WeightInfo::schedule(T::MaxScheduledPerBlock::get()))]414 pub fn schedule(415 origin: OriginFor<T>,416 when: T::BlockNumber,417 maybe_periodic: Option<schedule::Period<T::BlockNumber>>,418 priority: schedule::Priority,419 call: Box<<T as Config>::Call>,420 ) -> DispatchResult {421 T::ScheduleOrigin::ensure_origin(origin.clone())?;422 let origin = <T as Config>::Origin::from(origin);423 Self::do_schedule(424 DispatchTime::At(when),425 maybe_periodic,426 priority,427 origin.caller().clone(),428 <ScheduledCall<T>>::new(*call)?,429 )?;430 Ok(())431 }432433 /// Cancel an anonymously scheduled task.434 #[pallet::weight(<T as Config>::WeightInfo::cancel(T::MaxScheduledPerBlock::get()))]435 pub fn cancel(origin: OriginFor<T>, when: T::BlockNumber, index: u32) -> DispatchResult {436 T::ScheduleOrigin::ensure_origin(origin.clone())?;437 let origin = <T as Config>::Origin::from(origin);438 Self::do_cancel(Some(origin.caller().clone()), (when, index))?;439 Ok(())440 }441442 /// Schedule a named task.443 #[pallet::weight(<T as Config>::WeightInfo::schedule_named(T::MaxScheduledPerBlock::get()))]444 pub fn schedule_named(445 origin: OriginFor<T>,446 id: TaskName,447 when: T::BlockNumber,448 maybe_periodic: Option<schedule::Period<T::BlockNumber>>,449 priority: schedule::Priority,450 call: Box<<T as Config>::Call>,451 ) -> DispatchResult {452 T::ScheduleOrigin::ensure_origin(origin.clone())?;453 let origin = <T as Config>::Origin::from(origin);454 Self::do_schedule_named(455 id,456 DispatchTime::At(when),457 maybe_periodic,458 priority,459 origin.caller().clone(),460 <ScheduledCall<T>>::new(*call)?,461 )?;462 Ok(())463 }464465 /// Cancel a named scheduled task.466 #[pallet::weight(<T as Config>::WeightInfo::cancel_named(T::MaxScheduledPerBlock::get()))]467 pub fn cancel_named(origin: OriginFor<T>, id: TaskName) -> DispatchResult {468 T::ScheduleOrigin::ensure_origin(origin.clone())?;469 let origin = <T as Config>::Origin::from(origin);470 Self::do_cancel_named(Some(origin.caller().clone()), id)?;471 Ok(())472 }473474 /// Anonymously schedule a task after a delay.475 ///476 /// # <weight>477 /// Same as [`schedule`].478 /// # </weight>479 #[pallet::weight(<T as Config>::WeightInfo::schedule(T::MaxScheduledPerBlock::get()))]480 pub fn schedule_after(481 origin: OriginFor<T>,482 after: T::BlockNumber,483 maybe_periodic: Option<schedule::Period<T::BlockNumber>>,484 priority: schedule::Priority,485 call: Box<<T as Config>::Call>,486 ) -> DispatchResult {487 T::ScheduleOrigin::ensure_origin(origin.clone())?;488 let origin = <T as Config>::Origin::from(origin);489 Self::do_schedule(490 DispatchTime::After(after),491 maybe_periodic,492 priority,493 origin.caller().clone(),494 <ScheduledCall<T>>::new(*call)?,495 )?;496 Ok(())497 }498499 /// Schedule a named task after a delay.500 ///501 /// # <weight>502 /// Same as [`schedule_named`](Self::schedule_named).503 /// # </weight>504 #[pallet::weight(<T as Config>::WeightInfo::schedule_named(T::MaxScheduledPerBlock::get()))]505 pub fn schedule_named_after(506 origin: OriginFor<T>,507 id: TaskName,508 after: T::BlockNumber,509 maybe_periodic: Option<schedule::Period<T::BlockNumber>>,510 priority: schedule::Priority,511 call: Box<<T as Config>::Call>,512 ) -> DispatchResult {513 T::ScheduleOrigin::ensure_origin(origin.clone())?;514 let origin = <T as Config>::Origin::from(origin);515 Self::do_schedule_named(516 id,517 DispatchTime::After(after),518 maybe_periodic,519 priority,520 origin.caller().clone(),521 <ScheduledCall<T>>::new(*call)?,522 )?;523 Ok(())524 }525 }526}527528impl<T: Config> Pallet<T> {529 fn resolve_time(when: DispatchTime<T::BlockNumber>) -> Result<T::BlockNumber, DispatchError> {530 let now = frame_system::Pallet::<T>::block_number();531532 let when = match when {533 DispatchTime::At(x) => x,534 // The current block has already completed it's scheduled tasks, so535 // Schedule the task at lest one block after this current block.536 DispatchTime::After(x) => now.saturating_add(x).saturating_add(One::one()),537 };538539 if when <= now {540 return Err(Error::<T>::TargetBlockNumberInPast.into())541 }542543 Ok(when)544 }545546 fn place_task(547 when: T::BlockNumber,548 what: ScheduledOf<T>,549 ) -> Result<TaskAddress<T::BlockNumber>, (DispatchError, ScheduledOf<T>)> {550 let maybe_name = what.maybe_id;551 let index = Self::push_to_agenda(when, what)?;552 let address = (when, index);553 if let Some(name) = maybe_name {554 Lookup::<T>::insert(name, address)555 }556 Self::deposit_event(Event::Scheduled { when: address.0, index: address.1 });557 Ok(address)558 }559560 fn push_to_agenda(561 when: T::BlockNumber,562 what: ScheduledOf<T>,563 ) -> Result<u32, (DispatchError, ScheduledOf<T>)> {564 let mut agenda = Agenda::<T>::get(when);565 let index = if (agenda.len() as u32) < T::MaxScheduledPerBlock::get() {566 // will always succeed due to the above check.567 let _ = agenda.try_push(Some(what));568 agenda.len() as u32 - 1569 } else {570 if let Some(hole_index) = agenda.iter().position(|i| i.is_none()) {571 agenda[hole_index] = Some(what);572 hole_index as u32573 } else {574 return Err((<Error<T>>::AgendaIsExhausted.into(), what))575 }576 };577 Agenda::<T>::insert(when, agenda);578 Ok(index)579 }580581 fn do_schedule(582 when: DispatchTime<T::BlockNumber>,583 maybe_periodic: Option<schedule::Period<T::BlockNumber>>,584 priority: schedule::Priority,585 origin: T::PalletsOrigin,586 call: ScheduledCall<T>,587 ) -> Result<TaskAddress<T::BlockNumber>, DispatchError> {588 let when = Self::resolve_time(when)?;589590 // sanitize maybe_periodic591 let maybe_periodic = maybe_periodic592 .filter(|p| p.1 > 1 && !p.0.is_zero())593 // Remove one from the number of repetitions since we will schedule one now.594 .map(|(p, c)| (p, c - 1));595 let task = Scheduled {596 maybe_id: None,597 priority,598 call,599 maybe_periodic,600 origin,601 _phantom: PhantomData,602 };603 Self::place_task(when, task).map_err(|x| x.0)604 }605606 fn do_cancel(607 origin: Option<T::PalletsOrigin>,608 (when, index): TaskAddress<T::BlockNumber>,609 ) -> Result<(), DispatchError> {610 let scheduled = Agenda::<T>::try_mutate(when, |agenda| {611 agenda.get_mut(index as usize).map_or(612 Ok(None),613 |s| -> Result<Option<Scheduled<_, _, _, _, _>>, DispatchError> {614 if let (Some(ref o), Some(ref s)) = (origin, s.borrow()) {615 if matches!(616 T::OriginPrivilegeCmp::cmp_privilege(o, &s.origin),617 Some(Ordering::Less) | None618 ) {619 return Err(BadOrigin.into())620 }621 };622 Ok(s.take())623 },624 )625 })?;626 if let Some(s) = scheduled {627 T::Preimages::drop(&s.call);628629 if let Some(id) = s.maybe_id {630 Lookup::<T>::remove(id);631 }632 Self::deposit_event(Event::Canceled { when, index });633 Ok(())634 } else {635 return Err(Error::<T>::NotFound.into())636 }637 }638639 fn do_schedule_named(640 id: TaskName,641 when: DispatchTime<T::BlockNumber>,642 maybe_periodic: Option<schedule::Period<T::BlockNumber>>,643 priority: schedule::Priority,644 origin: T::PalletsOrigin,645 call: ScheduledCall<T>,646 ) -> Result<TaskAddress<T::BlockNumber>, DispatchError> {647 // ensure id it is unique648 if Lookup::<T>::contains_key(&id) {649 return Err(Error::<T>::FailedToSchedule.into())650 }651652 let when = Self::resolve_time(when)?;653654 // sanitize maybe_periodic655 let maybe_periodic = maybe_periodic656 .filter(|p| p.1 > 1 && !p.0.is_zero())657 // Remove one from the number of repetitions since we will schedule one now.658 .map(|(p, c)| (p, c - 1));659660 let task = Scheduled {661 maybe_id: Some(id),662 priority,663 call,664 maybe_periodic,665 origin,666 _phantom: Default::default(),667 };668 Self::place_task(when, task).map_err(|x| x.0)669 }670671 fn do_cancel_named(origin: Option<T::PalletsOrigin>, id: TaskName) -> DispatchResult {672 Lookup::<T>::try_mutate_exists(id, |lookup| -> DispatchResult {673 if let Some((when, index)) = lookup.take() {674 let i = index as usize;675 Agenda::<T>::try_mutate(when, |agenda| -> DispatchResult {676 if let Some(s) = agenda.get_mut(i) {677 if let (Some(ref o), Some(ref s)) = (origin, s.borrow()) {678 if matches!(679 T::OriginPrivilegeCmp::cmp_privilege(o, &s.origin),680 Some(Ordering::Less) | None681 ) {682 return Err(BadOrigin.into())683 }684 T::Preimages::drop(&s.call);685 }686 *s = None;687 }688 Ok(())689 })?;690 Self::deposit_event(Event::Canceled { when, index });691 Ok(())692 } else {693 return Err(Error::<T>::NotFound.into())694 }695 })696 }697}698699enum ServiceTaskError {700 /// Could not be executed due to missing preimage.701 Unavailable,702 /// Could not be executed due to weight limitations.703 Overweight,704}705use ServiceTaskError::*;706707impl<T: Config> Pallet<T> {708 /// Service up to `max` agendas queue starting from earliest incompletely executed agenda.709 fn service_agendas(weight: &mut WeightCounter, now: T::BlockNumber, max: u32) {710 if !weight.check_accrue(T::WeightInfo::service_agendas_base()) {711 return712 }713714 let mut incomplete_since = now + One::one();715 let mut when = IncompleteSince::<T>::take().unwrap_or(now);716 let mut executed = 0;717718 let max_items = T::MaxScheduledPerBlock::get();719 let mut count_down = max;720 let service_agenda_base_weight = T::WeightInfo::service_agenda_base(max_items);721 while count_down > 0 && when <= now && weight.can_accrue(service_agenda_base_weight) {722 if !Self::service_agenda(weight, &mut executed, now, when, u32::max_value()) {723 incomplete_since = incomplete_since.min(when);724 }725 when.saturating_inc();726 count_down.saturating_dec();727 }728 incomplete_since = incomplete_since.min(when);729 if incomplete_since <= now {730 IncompleteSince::<T>::put(incomplete_since);731 }732 }733734 /// Returns `true` if the agenda was fully completed, `false` if it should be revisited at a735 /// later block.736 fn service_agenda(737 weight: &mut WeightCounter,738 executed: &mut u32,739 now: T::BlockNumber,740 when: T::BlockNumber,741 max: u32,742 ) -> bool {743 let mut agenda = Agenda::<T>::get(when);744 let mut ordered = agenda745 .iter()746 .enumerate()747 .filter_map(|(index, maybe_item)| {748 maybe_item.as_ref().map(|item| (index as u32, item.priority))749 })750 .collect::<Vec<_>>();751 ordered.sort_by_key(|k| k.1);752 let within_limit =753 weight.check_accrue(T::WeightInfo::service_agenda_base(ordered.len() as u32));754 debug_assert!(within_limit, "weight limit should have been checked in advance");755756 // Items which we know can be executed and have postponed for execution in a later block.757 let mut postponed = (ordered.len() as u32).saturating_sub(max);758 // Items which we don't know can ever be executed.759 let mut dropped = 0;760761 for (agenda_index, _) in ordered.into_iter().take(max as usize) {762 let task = match agenda[agenda_index as usize].take() {763 None => continue,764 Some(t) => t,765 };766 let base_weight = T::WeightInfo::service_task(767 task.call.lookup_len().map(|x| x as usize),768 task.maybe_id.is_some(),769 task.maybe_periodic.is_some(),770 );771 if !weight.can_accrue(base_weight) {772 postponed += 1;773 break774 }775 let result = Self::service_task(weight, now, when, agenda_index, *executed == 0, task);776 agenda[agenda_index as usize] = match result {777 Err((Unavailable, slot)) => {778 dropped += 1;779 slot780 },781 Err((Overweight, slot)) => {782 postponed += 1;783 slot784 },785 Ok(()) => {786 *executed += 1;787 None788 },789 };790 }791 if postponed > 0 || dropped > 0 {792 Agenda::<T>::insert(when, agenda);793 } else {794 Agenda::<T>::remove(when);795 }796 postponed == 0797 }798799 /// Service (i.e. execute) the given task, being careful not to overflow the `weight` counter.800 ///801 /// This involves:802 /// - removing and potentially replacing the `Lookup` entry for the task.803 /// - realizing the task's call which can include a preimage lookup.804 /// - Rescheduling the task for execution in a later agenda if periodic.805 fn service_task(806 weight: &mut WeightCounter,807 now: T::BlockNumber,808 when: T::BlockNumber,809 agenda_index: u32,810 is_first: bool,811 mut task: ScheduledOf<T>,812 ) -> Result<(), (ServiceTaskError, Option<ScheduledOf<T>>)> {813 if let Some(ref id) = task.maybe_id {814 Lookup::<T>::remove(id);815 }816817 let (call, lookup_len) = match T::Preimages::peek(&task.call) {818 Ok(c) => c,819 Err(_) => return Err((Unavailable, Some(task))),820 };821822 weight.check_accrue(T::WeightInfo::service_task(823 lookup_len.map(|x| x as usize),824 task.maybe_id.is_some(),825 task.maybe_periodic.is_some(),826 ));827828 match Self::execute_dispatch(weight, task.origin.clone(), call) {829 Err(Unavailable) => {830 debug_assert!(false, "Checked to exist with `peek`");831 Self::deposit_event(Event::CallUnavailable {832 task: (when, agenda_index),833 id: task.maybe_id,834 });835 Err((Unavailable, Some(task)))836 },837 Err(Overweight) if is_first => {838 T::Preimages::drop(&task.call);839 Self::deposit_event(Event::PermanentlyOverweight {840 task: (when, agenda_index),841 id: task.maybe_id,842 });843 Err((Unavailable, Some(task)))844 },845 Err(Overweight) => Err((Overweight, Some(task))),846 Ok(result) => {847 Self::deposit_event(Event::Dispatched {848 task: (when, agenda_index),849 id: task.maybe_id,850 result,851 });852 if let &Some((period, count)) = &task.maybe_periodic {853 if count > 1 {854 task.maybe_periodic = Some((period, count - 1));855 } else {856 task.maybe_periodic = None;857 }858 let wake = now.saturating_add(period);859 match Self::place_task(wake, task) {860 Ok(_) => {},861 Err((_, task)) => {862 // TODO: Leave task in storage somewhere for it to be rescheduled863 // manually.864 T::Preimages::drop(&task.call);865 Self::deposit_event(Event::PeriodicFailed {866 task: (when, agenda_index),867 id: task.maybe_id,868 });869 },870 }871 } else {872 T::Preimages::drop(&task.call);873 }874 Ok(())875 },876 }877 }878879 /// Make a dispatch to the given `call` from the given `origin`, ensuring that the `weight`880 /// counter does not exceed its limit and that it is counted accurately (e.g. accounted using881 /// post info if available).882 ///883 /// NOTE: Only the weight for this function will be counted (origin lookup, dispatch and the884 /// call itself).885 fn execute_dispatch(886 weight: &mut WeightCounter,887 origin: T::PalletsOrigin,888 call: <T as Config>::Call,889 ) -> Result<DispatchResult, ServiceTaskError> {890 let dispatch_origin: <T as Config>::Origin = origin.into();891 let base_weight = match dispatch_origin.clone().as_signed() {892 Some(_) => T::WeightInfo::execute_dispatch_signed(),893 _ => T::WeightInfo::execute_dispatch_unsigned(),894 };895 let call_weight = call.get_dispatch_info().weight;896 // We only allow a scheduled call if it cannot push the weight past the limit.897 let max_weight = base_weight.saturating_add(call_weight);898899 if !weight.can_accrue(max_weight) {900 return Err(Overweight)901 }902903 let (maybe_actual_call_weight, result) = match call.dispatch(dispatch_origin) {904 Ok(post_info) => (post_info.actual_weight, Ok(())),905 Err(error_and_info) =>906 (error_and_info.post_info.actual_weight, Err(error_and_info.error)),907 };908 let call_weight = maybe_actual_call_weight.unwrap_or(call_weight);909 weight.check_accrue(base_weight);910 weight.check_accrue(call_weight);911 Ok(result)912 }913}runtime/common/config/pallets/scheduler.rsdiffbeforeafterboth--- a/runtime/common/config/pallets/scheduler.rs
+++ b/runtime/common/config/pallets/scheduler.rs
@@ -70,22 +70,22 @@
}
}
-impl pallet_unique_scheduler::Config for Runtime {
- type RuntimeEvent = RuntimeEvent;
- type RuntimeOrigin = RuntimeOrigin;
- type Currency = Balances;
- type PalletsOrigin = OriginCaller;
- type RuntimeCall = RuntimeCall;
- type MaximumWeight = MaximumSchedulerWeight;
- type ScheduleOrigin = EnsureSignedOrRoot<AccountId>;
- type PrioritySetOrigin = EnsureRoot<AccountId>;
- type MaxScheduledPerBlock = MaxScheduledPerBlock;
- type WeightInfo = ();
- type CallExecutor = SchedulerPaymentExecutor;
- type OriginPrivilegeCmp = EqualOrRootOnly;
- type PreimageProvider = ();
- type NoPreimagePostponement = NoPreimagePostponement;
-}
+// impl pallet_unique_scheduler::Config for Runtime {
+// type RuntimeEvent = RuntimeEvent;
+// type RuntimeOrigin = RuntimeOrigin;
+// type Currency = Balances;
+// type PalletsOrigin = OriginCaller;
+// type RuntimeCall = RuntimeCall;
+// type MaximumWeight = MaximumSchedulerWeight;
+// type ScheduleOrigin = EnsureSignedOrRoot<AccountId>;
+// type PrioritySetOrigin = EnsureRoot<AccountId>;
+// type MaxScheduledPerBlock = MaxScheduledPerBlock;
+// type WeightInfo = ();
+// type CallExecutor = SchedulerPaymentExecutor;
+// type OriginPrivilegeCmp = EqualOrRootOnly;
+// type PreimageProvider = ();
+// type NoPreimagePostponement = NoPreimagePostponement;
+// }
impl pallet_unique_scheduler_v2::Config for Runtime {
type Event = Event;
runtime/common/construct_runtime/mod.rsdiffbeforeafterboth--- a/runtime/common/construct_runtime/mod.rs
+++ b/runtime/common/construct_runtime/mod.rs
@@ -57,8 +57,8 @@
Inflation: pallet_inflation::{Pallet, Call, Storage} = 60,
Unique: pallet_unique::{Pallet, Call, Storage, Event<T>} = 61,
- #[runtimes(opal)]
- Scheduler: pallet_unique_scheduler::{Pallet, Call, Storage, Event<T>} = 62,
+ // #[runtimes(opal)]
+ // Scheduler: pallet_unique_scheduler::{Pallet, Call, Storage, Event<T>} = 62,
Configuration: pallet_configuration::{Pallet, Call, Storage} = 63,
@@ -97,7 +97,7 @@
Maintenance: pallet_maintenance::{Pallet, Call, Storage, Event<T>} = 154,
#[runtimes(opal)]
- SchedulerV2: pallet_unique_scheduler_v2::{Pallet, Call, Storage, Event<T>} = 154,
+ Scheduler: pallet_unique_scheduler_v2::{Pallet, Call, Storage, Event<T>} = 154,
#[runtimes(opal)]
TestUtils: pallet_test_utils = 255,
test-pallets/utils/Cargo.tomldiffbeforeafterboth--- a/test-pallets/utils/Cargo.toml
+++ b/test-pallets/utils/Cargo.toml
@@ -10,7 +10,8 @@
scale-info = { version = "2.1.1", default-features = false, features = ["derive"] }
frame-support = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }
frame-system = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }
-pallet-unique-scheduler = { path = '../../pallets/scheduler', default-features = false }
+# pallet-unique-scheduler = { path = '../../pallets/scheduler', default-features = false }
+pallet-unique-scheduler-v2 = { path = '../../pallets/scheduler-v2', default-features = false }
[features]
default = ["std"]
@@ -19,6 +20,6 @@
"scale-info/std",
"frame-support/std",
"frame-system/std",
- "pallet-unique-scheduler/std",
+ "pallet-unique-scheduler-v2/std",
]
try-runtime = ["frame-support/try-runtime", "pallet-unique-scheduler/try-runtime"]
test-pallets/utils/src/lib.rsdiffbeforeafterboth--- a/test-pallets/utils/src/lib.rs
+++ b/test-pallets/utils/src/lib.rs
@@ -24,7 +24,7 @@
pub mod pallet {
use frame_support::pallet_prelude::*;
use frame_system::pallet_prelude::*;
- use pallet_unique_scheduler::{ScheduledId, Pallet as SchedulerPallet};
+ use pallet_unique_scheduler_v2::{TaskName, Pallet as SchedulerPallet};
#[pallet::config]
pub trait Config: frame_system::Config + pallet_unique_scheduler::Config {
@@ -94,7 +94,7 @@
#[pallet::weight(10_000)]
pub fn self_canceling_inc(
origin: OriginFor<T>,
- id: ScheduledId,
+ id: TaskName,
max_test_value: u32,
) -> DispatchResult {
Self::ensure_origin_and_enabled(origin.clone())?;