1234567891011121314151617181920212223242526272829303132333435363738394041424344#![cfg_attr(not(feature = "std"), no_std)]454647484950pub mod weights;5152use sp_core::H160;53use codec::{Codec, Decode, Encode};54use frame_system::{self as system, ensure_signed};55pub use pallet::*;56use scale_info::TypeInfo;57use sp_runtime::{58 traits::{BadOrigin, One, Saturating, Zero},59 RuntimeDebug, DispatchErrorWithPostInfo,60};61use sp_std::{borrow::Borrow, cmp::Ordering, marker::PhantomData, prelude::*};6263use frame_support::{64 dispatch::{DispatchError, DispatchResult, Dispatchable, Parameter},65 traits::{66 schedule::{self, DispatchTime, MaybeHashed},67 NamedReservableCurrency, EnsureOrigin, Get, IsType, OriginTrait, PrivilegeCmp,68 StorageVersion,69 },70 weights::{GetDispatchInfo, Weight},71};7273pub use weights::WeightInfo;747576pub type PeriodicIndex = u32;7778pub type TaskAddress<BlockNumber> = (BlockNumber, u32);79pub const MAX_TASK_ID_LENGTH_IN_BYTES: u8 = 16;8081type ScheduledId = [u8; MAX_TASK_ID_LENGTH_IN_BYTES as usize];82pub type CallOrHashOf<T> = MaybeHashed<<T as Config>::Call, <T as frame_system::Config>::Hash>;838485#[cfg_attr(any(feature = "std", test), derive(PartialEq, Eq))]86#[derive(Clone, RuntimeDebug, Encode, Decode, TypeInfo)]87pub struct ScheduledV3<Call, BlockNumber, PalletsOrigin, AccountId> {88 89 maybe_id: Option<ScheduledId>,90 91 priority: schedule::Priority,92 93 call: Call,94 95 maybe_periodic: Option<schedule::Period<BlockNumber>>,96 97 origin: PalletsOrigin,98 _phantom: PhantomData<AccountId>,99}100101pub type ScheduledV3Of<T> = ScheduledV3<102 CallOrHashOf<T>,103 <T as frame_system::Config>::BlockNumber,104 <T as Config>::PalletsOrigin,105 <T as frame_system::Config>::AccountId,106>;107108pub type ScheduledOf<T> = ScheduledV3Of<T>;109110111pub type Scheduled<Call, BlockNumber, PalletsOrigin, AccountId> =112 ScheduledV3<Call, BlockNumber, PalletsOrigin, AccountId>;113114#[cfg(feature = "runtime-benchmarks")]115mod preimage_provider {116 use frame_support::traits::PreimageRecipient;117 pub trait PreimageProviderAndMaybeRecipient<H>: PreimageRecipient<H> {}118 impl<H, T: PreimageRecipient<H>> PreimageProviderAndMaybeRecipient<H> for T {}119}120121#[cfg(not(feature = "runtime-benchmarks"))]122mod preimage_provider {123 use frame_support::traits::PreimageProvider;124 pub trait PreimageProviderAndMaybeRecipient<H>: PreimageProvider<H> {}125 impl<H, T: PreimageProvider<H>> PreimageProviderAndMaybeRecipient<H> for T {}126}127128pub use preimage_provider::PreimageProviderAndMaybeRecipient;129130pub(crate) trait MarginalWeightInfo: WeightInfo {131 fn item(periodic: bool, named: bool, resolved: Option<bool>) -> Weight {132 match (periodic, named, resolved) {133 (_, false, None) => Self::on_initialize_aborted(2) - Self::on_initialize_aborted(1),134 (_, true, None) => {135 Self::on_initialize_named_aborted(2) - Self::on_initialize_named_aborted(1)136 }137 (false, false, Some(false)) => Self::on_initialize(2) - Self::on_initialize(1),138 (false, true, Some(false)) => {139 Self::on_initialize_named(2) - Self::on_initialize_named(1)140 }141 (true, false, Some(false)) => {142 Self::on_initialize_periodic(2) - Self::on_initialize_periodic(1)143 }144 (true, true, Some(false)) => {145 Self::on_initialize_periodic_named(2) - Self::on_initialize_periodic_named(1)146 }147 (false, false, Some(true)) => {148 Self::on_initialize_resolved(2) - Self::on_initialize_resolved(1)149 }150 (false, true, Some(true)) => {151 Self::on_initialize_named_resolved(2) - Self::on_initialize_named_resolved(1)152 }153 (true, false, Some(true)) => {154 Self::on_initialize_periodic_resolved(2) - Self::on_initialize_periodic_resolved(1)155 }156 (true, true, Some(true)) => {157 Self::on_initialize_periodic_named_resolved(2)158 - Self::on_initialize_periodic_named_resolved(1)159 }160 }161 }162}163impl<T: WeightInfo> MarginalWeightInfo for T {}164165#[frame_support::pallet]166pub mod pallet {167 use super::*;168 use frame_support::{169 dispatch::PostDispatchInfo,170 pallet_prelude::*,171 traits::{schedule::LookupError, PreimageProvider},172 };173 use frame_system::pallet_prelude::*;174175 176 const STORAGE_VERSION: StorageVersion = StorageVersion::new(3);177178 #[pallet::pallet]179 #[pallet::generate_store(pub(super) trait Store)]180 #[pallet::storage_version(STORAGE_VERSION)]181 #[pallet::without_storage_info]182 pub struct Pallet<T>(_);183184 185 #[pallet::config]186 pub trait Config: frame_system::Config {187 188 type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event>;189190 191 type Origin: OriginTrait<PalletsOrigin = Self::PalletsOrigin>192 + From<Self::PalletsOrigin>193 + IsType<<Self as system::Config>::Origin>;194195 196 type PalletsOrigin: From<system::RawOrigin<Self::AccountId>> + Codec + Clone + Eq + TypeInfo;197198 type Currency: NamedReservableCurrency<Self::AccountId, ReserveIdentifier = ScheduledId>;199200 201 type Call: Parameter202 + Dispatchable<Origin = <Self as Config>::Origin, PostInfo = PostDispatchInfo>203 + GetDispatchInfo204 + From<system::Call<Self>>;205206 207 208 #[pallet::constant]209 type MaximumWeight: Get<Weight>;210211 212 type ScheduleOrigin: EnsureOrigin<<Self as system::Config>::Origin>;213214 215 216 217 218 219 220 221 type OriginPrivilegeCmp: PrivilegeCmp<Self::PalletsOrigin>;222223 224 225 #[pallet::constant]226 type MaxScheduledPerBlock: Get<u32>;227228 229 type WeightInfo: WeightInfo;230231 232 type PreimageProvider: PreimageProviderAndMaybeRecipient<Self::Hash>;233234 235 type NoPreimagePostponement: Get<Option<Self::BlockNumber>>;236237 238 239240 241 type CallExecutor: DispatchCall<Self, H160>;242 }243244 245 pub trait DispatchCall<T: frame_system::Config + Config, SelfContainedSignedInfo> {246 fn reserve_balance(247 id: ScheduledId,248 sponsor: <T as frame_system::Config>::AccountId,249 call: <T as Config>::Call,250 count: u32,251 ) -> Result<(), DispatchError>;252253 fn pay_for_call(254 id: ScheduledId,255 sponsor: <T as frame_system::Config>::AccountId,256 call: <T as Config>::Call,257 ) -> Result<u128, DispatchError>;258259 260 fn dispatch_call(261 signer: T::AccountId,262 function: <T as Config>::Call,263 ) -> Result<264 Result<PostDispatchInfo, DispatchErrorWithPostInfo<PostDispatchInfo>>,265 TransactionValidityError,266 >;267268 fn cancel_reserve(269 id: ScheduledId,270 sponsor: <T as frame_system::Config>::AccountId,271 ) -> Result<u128, DispatchError>;272 }273274 275 #[pallet::storage]276 pub type Agenda<T: Config> =277 StorageMap<_, Twox64Concat, T::BlockNumber, Vec<Option<ScheduledV3Of<T>>>, ValueQuery>;278279 280 #[pallet::storage]281 pub(crate) type Lookup<T: Config> =282 StorageMap<_, Twox64Concat, ScheduledId, TaskAddress<T::BlockNumber>>;283284 285 #[pallet::event]286 #[pallet::generate_deposit(pub(super) fn deposit_event)]287 pub enum Event<T: Config> {288 289 Scheduled { when: T::BlockNumber, index: u32 },290 291 Canceled { when: T::BlockNumber, index: u32 },292 293 Dispatched {294 task: TaskAddress<T::BlockNumber>,295 id: Option<ScheduledId>,296 result: DispatchResult,297 },298 299 CallLookupFailed {300 task: TaskAddress<T::BlockNumber>,301 id: Option<ScheduledId>,302 error: LookupError,303 },304 }305306 #[pallet::error]307 pub enum Error<T> {308 309 FailedToSchedule,310 311 NotFound,312 313 TargetBlockNumberInPast,314 315 RescheduleNoChange,316 }317318 #[pallet::hooks]319 impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {320 321 fn on_initialize(now: T::BlockNumber) -> Weight {322 let limit = T::MaximumWeight::get();323324 let mut queued = Agenda::<T>::take(now)325 .into_iter()326 .enumerate()327 .filter_map(|(index, s)| Some((index as u32, s?)))328 .collect::<Vec<_>>();329330 if queued.len() as u32 > T::MaxScheduledPerBlock::get() {331 log::warn!(332 target: "runtime::scheduler",333 "Warning: This block has more items queued in Scheduler than \334 expected from the runtime configuration. An update might be needed."335 );336 }337338 queued.sort_by_key(|(_, s)| s.priority);339340 let next = now + One::one();341342 let mut total_weight: Weight = T::WeightInfo::on_initialize(0);343 for (order, (index, mut s)) in queued.into_iter().enumerate() {344 let named = if let Some(ref id) = s.maybe_id {345 Lookup::<T>::remove(id);346 true347 } else {348 false349 };350351 let (call, maybe_completed) = s.call.resolved::<T::PreimageProvider>();352 s.call = call;353354 let resolved = if let Some(completed) = maybe_completed {355 T::PreimageProvider::unrequest_preimage(&completed);356 true357 } else {358 false359 };360 let call = match s.call.as_value().cloned() {361 Some(c) => c,362 None => {363 364 total_weight.saturating_accrue(T::WeightInfo::item(false, named, None));365 if let Some(delay) = T::NoPreimagePostponement::get() {366 let until = now.saturating_add(delay);367 if let Some(ref id) = s.maybe_id {368 let index = Agenda::<T>::decode_len(until).unwrap_or(0);369 Lookup::<T>::insert(id, (until, index as u32));370 }371 Agenda::<T>::append(until, Some(s));372 }373 continue;374 }375 };376377 let periodic = s.maybe_periodic.is_some();378 let call_weight = call.get_dispatch_info().weight;379 let mut item_weight = T::WeightInfo::item(periodic, named, Some(resolved));380 let origin =381 <<T as Config>::Origin as From<T::PalletsOrigin>>::from(s.origin.clone())382 .into();383 if ensure_signed(origin).is_ok() {384 385 item_weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1));386 }387388 389 390 391 392 let hard_deadline = s.priority <= schedule::HARD_DEADLINE;393 let test_weight = total_weight394 .saturating_add(call_weight)395 .saturating_add(item_weight);396 if !hard_deadline && order > 0 && test_weight > limit {397 398 total_weight.saturating_accrue(T::WeightInfo::item(false, named, None));399 if let Some(ref id) = s.maybe_id {400 401 402 403 404 let index = Agenda::<T>::decode_len(next).unwrap_or(0);405 Lookup::<T>::insert(id, (next, index as u32));406 }407 Agenda::<T>::append(next, Some(s));408 continue;409 }410411 let sender = ensure_signed(412 <<T as Config>::Origin as From<T::PalletsOrigin>>::from(s.origin.clone())413 .into(),414 )415 .unwrap();416417 418 419 420 421 422 423 424 425426 let r = T::CallExecutor::dispatch_call(sender, call.clone());427428 let mut actual_call_weight: Weight = item_weight;429 let result: Result<_, DispatchError> = match r {430 Ok(o) => match o {431 Ok(di) => {432 actual_call_weight = di.actual_weight.unwrap_or(item_weight);433 Ok(())434 }435 Err(err) => Err(err.error),436 },437 Err(_) => {438 log::error!(439 target: "runtime::scheduler",440 "Warning: Scheduler has failed to execute a post-dispatch transaction. \441 This block might have become invalid.");442 Err(DispatchError::CannotLookup)443 } 444 };445446 total_weight.saturating_accrue(item_weight);447 total_weight.saturating_accrue(actual_call_weight);448449 Self::deposit_event(Event::Dispatched {450 task: (now, index),451 id: s.maybe_id.clone(),452 result,453 });454455 if let &Some((period, count)) = &s.maybe_periodic {456 if count > 1 {457 s.maybe_periodic = Some((period, count - 1));458 } else {459 s.maybe_periodic = None;460 }461 let wake = now + period;462 463 if let Some(ref id) = s.maybe_id {464 let wake_index = Agenda::<T>::decode_len(wake).unwrap_or(0);465 Lookup::<T>::insert(id, (wake, wake_index as u32));466 }467 Agenda::<T>::append(wake, Some(s));468 }469 }470 0471 472 }473 }474475 #[pallet::call]476 impl<T: Config> Pallet<T> {477 478 #[pallet::weight(<T as Config>::WeightInfo::schedule_named(T::MaxScheduledPerBlock::get()))]479 pub fn schedule_named(480 origin: OriginFor<T>,481 id: ScheduledId,482 when: T::BlockNumber,483 maybe_periodic: Option<schedule::Period<T::BlockNumber>>,484 priority: schedule::Priority,485 call: Box<CallOrHashOf<T>>,486 ) -> DispatchResult {487 T::ScheduleOrigin::ensure_origin(origin.clone())?;488 let origin = <T as Config>::Origin::from(origin);489 Self::do_schedule_named(490 id,491 DispatchTime::At(when),492 maybe_periodic,493 priority,494 origin.caller().clone(),495 *call,496 )?;497 Ok(())498 }499500 501 #[pallet::weight(<T as Config>::WeightInfo::cancel_named(T::MaxScheduledPerBlock::get()))]502 pub fn cancel_named(origin: OriginFor<T>, id: ScheduledId) -> DispatchResult {503 T::ScheduleOrigin::ensure_origin(origin.clone())?;504 let origin = <T as Config>::Origin::from(origin);505 Self::do_cancel_named(Some(origin.caller().clone()), id)?;506 Ok(())507 }508509 510 511 512 513 514 #[pallet::weight(<T as Config>::WeightInfo::schedule_named(T::MaxScheduledPerBlock::get()))]515 pub fn schedule_named_after(516 origin: OriginFor<T>,517 id: ScheduledId,518 after: T::BlockNumber,519 maybe_periodic: Option<schedule::Period<T::BlockNumber>>,520 priority: schedule::Priority,521 call: Box<CallOrHashOf<T>>,522 ) -> DispatchResult {523 T::ScheduleOrigin::ensure_origin(origin.clone())?;524 let origin = <T as Config>::Origin::from(origin);525 Self::do_schedule_named(526 id,527 DispatchTime::After(after),528 maybe_periodic,529 priority,530 origin.caller().clone(),531 *call,532 )?;533 Ok(())534 }535 }536}537538impl<T: Config> Pallet<T> {539 #[cfg(feature = "try-runtime")]540 pub fn pre_migrate_to_v3() -> Result<(), &'static str> {541 Ok(())542 }543544 #[cfg(feature = "try-runtime")]545 pub fn post_migrate_to_v3() -> Result<(), &'static str> {546 use frame_support::dispatch::GetStorageVersion;547548 assert!(Self::current_storage_version() == 3);549 for k in Agenda::<T>::iter_keys() {550 let _ = Agenda::<T>::try_get(k).map_err(|()| "Invalid item in Agenda")?;551 }552 Ok(())553 }554555 556 pub fn migrate_origin<OldOrigin: Into<T::PalletsOrigin> + codec::Decode>() {557 Agenda::<T>::translate::<558 Vec<Option<Scheduled<CallOrHashOf<T>, T::BlockNumber, OldOrigin, T::AccountId>>>,559 _,560 >(|_, agenda| {561 Some(562 agenda563 .into_iter()564 .map(|schedule| {565 schedule.map(|schedule| Scheduled {566 maybe_id: schedule.maybe_id,567 priority: schedule.priority,568 call: schedule.call,569 maybe_periodic: schedule.maybe_periodic,570 origin: schedule.origin.into(),571 _phantom: Default::default(),572 })573 })574 .collect::<Vec<_>>(),575 )576 });577 }578579 fn resolve_time(when: DispatchTime<T::BlockNumber>) -> Result<T::BlockNumber, DispatchError> {580 let now = frame_system::Pallet::<T>::block_number();581582 let when = match when {583 DispatchTime::At(x) => x,584 585 586 DispatchTime::After(x) => now.saturating_add(x).saturating_add(One::one()),587 };588589 if when <= now {590 return Err(Error::<T>::TargetBlockNumberInPast.into());591 }592593 Ok(when)594 }595596 fn do_schedule(597 when: DispatchTime<T::BlockNumber>,598 maybe_periodic: Option<schedule::Period<T::BlockNumber>>,599 priority: schedule::Priority,600 origin: T::PalletsOrigin,601 call: CallOrHashOf<T>,602 ) -> Result<TaskAddress<T::BlockNumber>, DispatchError> {603 let when = Self::resolve_time(when)?;604 call.ensure_requested::<T::PreimageProvider>();605606 607 let maybe_periodic = maybe_periodic608 .filter(|p| p.1 > 1 && !p.0.is_zero())609 610 .map(|(p, c)| (p, c - 1));611 let s = Some(Scheduled {612 maybe_id: None,613 priority,614 call,615 maybe_periodic,616 origin,617 _phantom: PhantomData::<T::AccountId>::default(),618 });619 Agenda::<T>::append(when, s);620 let index = Agenda::<T>::decode_len(when).unwrap_or(1) as u32 - 1;621 Self::deposit_event(Event::Scheduled { when, index });622623 Ok((when, index))624 }625626 fn do_cancel(627 origin: Option<T::PalletsOrigin>,628 (when, index): TaskAddress<T::BlockNumber>,629 ) -> Result<(), DispatchError> {630 let scheduled = Agenda::<T>::try_mutate(when, |agenda| {631 agenda.get_mut(index as usize).map_or(632 Ok(None),633 |s| -> Result<Option<Scheduled<_, _, _, _>>, DispatchError> {634 if let (Some(ref o), Some(ref s)) = (origin, s.borrow()) {635 if matches!(636 T::OriginPrivilegeCmp::cmp_privilege(o, &s.origin),637 Some(Ordering::Less) | None638 ) {639 return Err(BadOrigin.into());640 }641 };642 Ok(s.take())643 },644 )645 })?;646 if let Some(s) = scheduled {647 s.call.ensure_unrequested::<T::PreimageProvider>();648 if let Some(id) = s.maybe_id {649 Lookup::<T>::remove(id);650 }651 Self::deposit_event(Event::Canceled { when, index });652 Ok(())653 } else {654 Err(Error::<T>::NotFound)?655 }656 }657658 fn do_reschedule(659 (when, index): TaskAddress<T::BlockNumber>,660 new_time: DispatchTime<T::BlockNumber>,661 ) -> Result<TaskAddress<T::BlockNumber>, DispatchError> {662 let new_time = Self::resolve_time(new_time)?;663664 if new_time == when {665 return Err(Error::<T>::RescheduleNoChange.into());666 }667668 Agenda::<T>::try_mutate(when, |agenda| -> DispatchResult {669 let task = agenda.get_mut(index as usize).ok_or(Error::<T>::NotFound)?;670 let task = task.take().ok_or(Error::<T>::NotFound)?;671 Agenda::<T>::append(new_time, Some(task));672 Ok(())673 })?;674675 let new_index = Agenda::<T>::decode_len(new_time).unwrap_or(1) as u32 - 1;676 Self::deposit_event(Event::Canceled { when, index });677 Self::deposit_event(Event::Scheduled {678 when: new_time,679 index: new_index,680 });681682 Ok((new_time, new_index))683 }684685 fn do_schedule_named(686 id: ScheduledId,687 when: DispatchTime<T::BlockNumber>,688 maybe_periodic: Option<schedule::Period<T::BlockNumber>>,689 priority: schedule::Priority,690 origin: T::PalletsOrigin,691 call: CallOrHashOf<T>,692 ) -> Result<TaskAddress<T::BlockNumber>, DispatchError> {693 694 if Lookup::<T>::contains_key(&id) {695 return Err(Error::<T>::FailedToSchedule)?;696 }697698 let when = Self::resolve_time(when)?;699700 call.ensure_requested::<T::PreimageProvider>();701702 703 let maybe_periodic = maybe_periodic704 .filter(|p| p.1 > 1 && !p.0.is_zero())705 706 .map(|(p, c)| (p, c - 1));707708 let s = Scheduled {709 maybe_id: Some(id.clone()),710 priority,711 call: call.clone(),712 maybe_periodic,713 origin: origin.clone(),714 _phantom: Default::default(),715 };716717 718 719 720 721 722 723 724 725 726 727 728 729 730731 Agenda::<T>::append(when, Some(s));732 let index = Agenda::<T>::decode_len(when).unwrap_or(1) as u32 - 1;733 let address = (when, index);734 Lookup::<T>::insert(&id, &address);735 Self::deposit_event(Event::Scheduled { when, index });736737 Ok(address)738 }739740 fn do_cancel_named(origin: Option<T::PalletsOrigin>, id: ScheduledId) -> DispatchResult {741 Lookup::<T>::try_mutate_exists(id, |lookup| -> DispatchResult {742 if let Some((when, index)) = lookup.take() {743 let i = index as usize;744 Agenda::<T>::try_mutate(when, |agenda| -> DispatchResult {745 if let Some(s) = agenda.get_mut(i) {746 if let (Some(ref o), Some(ref s)) = (origin.clone(), s.borrow()) {747 if matches!(748 T::OriginPrivilegeCmp::cmp_privilege(o, &s.origin),749 Some(Ordering::Less) | None750 ) {751 return Err(BadOrigin.into());752 }753 754 755 756 757 758 759 760 761762 s.call.ensure_unrequested::<T::PreimageProvider>();763 }764 *s = None;765 }766 Ok(())767 })?;768769 Self::deposit_event(Event::Canceled { when, index });770 Ok(())771 } else {772 Err(Error::<T>::NotFound)?773 }774 })775 }776777 fn do_reschedule_named(778 id: ScheduledId,779 new_time: DispatchTime<T::BlockNumber>,780 ) -> Result<TaskAddress<T::BlockNumber>, DispatchError> {781 let new_time = Self::resolve_time(new_time)?;782783 Lookup::<T>::try_mutate_exists(784 id,785 |lookup| -> Result<TaskAddress<T::BlockNumber>, DispatchError> {786 let (when, index) = lookup.ok_or(Error::<T>::NotFound)?;787788 if new_time == when {789 return Err(Error::<T>::RescheduleNoChange.into());790 }791792 Agenda::<T>::try_mutate(when, |agenda| -> DispatchResult {793 let task = agenda.get_mut(index as usize).ok_or(Error::<T>::NotFound)?;794 let task = task.take().ok_or(Error::<T>::NotFound)?;795 Agenda::<T>::append(new_time, Some(task));796797 Ok(())798 })?;799800 let new_index = Agenda::<T>::decode_len(new_time).unwrap_or(1) as u32 - 1;801 Self::deposit_event(Event::Canceled { when, index });802 Self::deposit_event(Event::Scheduled {803 when: new_time,804 index: new_index,805 });806807 *lookup = Some((new_time, new_index));808809 Ok((new_time, new_index))810 },811 )812 }813}814815impl<T: Config> schedule::v2::Anon<T::BlockNumber, <T as Config>::Call, T::PalletsOrigin>816 for Pallet<T>817{818 type Address = TaskAddress<T::BlockNumber>;819 type Hash = T::Hash;820821 fn schedule(822 when: DispatchTime<T::BlockNumber>,823 maybe_periodic: Option<schedule::Period<T::BlockNumber>>,824 priority: schedule::Priority,825 origin: T::PalletsOrigin,826 call: CallOrHashOf<T>,827 ) -> Result<Self::Address, DispatchError> {828 Self::do_schedule(when, maybe_periodic, priority, origin, call)829 }830831 fn cancel((when, index): Self::Address) -> Result<(), ()> {832 Self::do_cancel(None, (when, index)).map_err(|_| ())833 }834835 fn reschedule(836 address: Self::Address,837 when: DispatchTime<T::BlockNumber>,838 ) -> Result<Self::Address, DispatchError> {839 Self::do_reschedule(address, when)840 }841842 fn next_dispatch_time((when, index): Self::Address) -> Result<T::BlockNumber, ()> {843 Agenda::<T>::get(when)844 .get(index as usize)845 .ok_or(())846 .map(|_| when)847 }848}849850impl<T: Config> schedule::v2::Named<T::BlockNumber, <T as Config>::Call, T::PalletsOrigin>851 for Pallet<T>852{853 type Address = TaskAddress<T::BlockNumber>;854 type Hash = T::Hash;855856 fn schedule_named(857 id: Vec<u8>,858 when: DispatchTime<T::BlockNumber>,859 maybe_periodic: Option<schedule::Period<T::BlockNumber>>,860 priority: schedule::Priority,861 origin: T::PalletsOrigin,862 call: CallOrHashOf<T>,863 ) -> Result<Self::Address, ()> {864 let inner_id: ScheduledId = id865 .try_into()866 .unwrap_or([0; MAX_TASK_ID_LENGTH_IN_BYTES as usize]);867 Self::do_schedule_named(inner_id, when, maybe_periodic, priority, origin, call)868 .map_err(|_| ())869 }870871 fn cancel_named(id: Vec<u8>) -> Result<(), ()> {872 let inner_id: ScheduledId = id873 .try_into()874 .unwrap_or([0; MAX_TASK_ID_LENGTH_IN_BYTES as usize]);875 Self::do_cancel_named(None, inner_id).map_err(|_| ())876 }877878 fn reschedule_named(879 id: Vec<u8>,880 when: DispatchTime<T::BlockNumber>,881 ) -> Result<Self::Address, DispatchError> {882 let inner_id: ScheduledId = id883 .try_into()884 .unwrap_or([0; MAX_TASK_ID_LENGTH_IN_BYTES as usize]);885 Self::do_reschedule_named(inner_id, when)886 }887888 fn next_dispatch_time(id: Vec<u8>) -> Result<T::BlockNumber, ()> {889 let inner_id: ScheduledId = id890 .try_into()891 .unwrap_or([0; MAX_TASK_ID_LENGTH_IN_BYTES as usize]);892 Lookup::<T>::get(inner_id)893 .and_then(|(when, index)| Agenda::<T>::get(when).get(index as usize).map(|_| when))894 .ok_or(())895 }896}