1234567891011121314151617181920212223242526272829303132333435363738394041424344#![cfg_attr(not(feature = "std"), no_std)]4546#[cfg(feature = "runtime-benchmarks")]47mod benchmarking;4849pub mod weights;5051use sp_core::H160;52use codec::{Codec, Decode, Encode};53use frame_system::{self as system, ensure_signed};54pub use pallet::*;55use scale_info::TypeInfo;56use sp_runtime::{57 traits::{BadOrigin, One, Saturating, Zero},58 RuntimeDebug, DispatchErrorWithPostInfo,59};60use sp_std::{borrow::Borrow, cmp::Ordering, marker::PhantomData, prelude::*};6162use frame_support::{63 dispatch::{DispatchError, DispatchResult, Dispatchable, Parameter},64 traits::{65 schedule::{self, DispatchTime, MaybeHashed},66 NamedReservableCurrency, EnsureOrigin, Get, IsType, OriginTrait, PrivilegeCmp,67 StorageVersion,68 },69 weights::{GetDispatchInfo, Weight},70};7172pub use weights::WeightInfo;737475pub type PeriodicIndex = u32;7677pub type TaskAddress<BlockNumber> = (BlockNumber, u32);78pub const MAX_TASK_ID_LENGTH_IN_BYTES: u8 = 16;7980type ScheduledId = [u8; MAX_TASK_ID_LENGTH_IN_BYTES as usize];81pub type CallOrHashOf<T> = MaybeHashed<<T as Config>::Call, <T as frame_system::Config>::Hash>;828384#[cfg_attr(any(feature = "std", test), derive(PartialEq, Eq))]85#[derive(Clone, RuntimeDebug, Encode, Decode, TypeInfo)]86pub struct ScheduledV3<Call, BlockNumber, PalletsOrigin, AccountId> {87 88 maybe_id: Option<ScheduledId>,89 90 priority: schedule::Priority,91 92 call: Call,93 94 maybe_periodic: Option<schedule::Period<BlockNumber>>,95 96 origin: PalletsOrigin,97 _phantom: PhantomData<AccountId>,98}99100pub type ScheduledV3Of<T> = ScheduledV3<101 CallOrHashOf<T>,102 <T as frame_system::Config>::BlockNumber,103 <T as Config>::PalletsOrigin,104 <T as frame_system::Config>::AccountId,105>;106107pub type ScheduledOf<T> = ScheduledV3Of<T>;108109110pub type Scheduled<Call, BlockNumber, PalletsOrigin, AccountId> =111 ScheduledV3<Call, BlockNumber, PalletsOrigin, AccountId>;112113#[cfg(feature = "runtime-benchmarks")]114mod preimage_provider {115 use frame_support::traits::PreimageRecipient;116 pub trait PreimageProviderAndMaybeRecipient<H>: PreimageRecipient<H> {}117 impl<H, T: PreimageRecipient<H>> PreimageProviderAndMaybeRecipient<H> for T {}118}119120#[cfg(not(feature = "runtime-benchmarks"))]121mod preimage_provider {122 use frame_support::traits::PreimageProvider;123 pub trait PreimageProviderAndMaybeRecipient<H>: PreimageProvider<H> {}124 impl<H, T: PreimageProvider<H>> PreimageProviderAndMaybeRecipient<H> for T {}125}126127pub use preimage_provider::PreimageProviderAndMaybeRecipient;128129pub(crate) trait MarginalWeightInfo: WeightInfo {130 fn item(periodic: bool, named: bool, resolved: Option<bool>) -> Weight {131 match (periodic, named, resolved) {132 (_, false, None) => Self::on_initialize_aborted(2) - Self::on_initialize_aborted(1),133 (_, true, None) => {134 Self::on_initialize_named_aborted(2) - Self::on_initialize_named_aborted(1)135 }136 (false, false, Some(false)) => Self::on_initialize(2) - Self::on_initialize(1),137 (false, true, Some(false)) => {138 Self::on_initialize_named(2) - Self::on_initialize_named(1)139 }140 (true, false, Some(false)) => {141 Self::on_initialize_periodic(2) - Self::on_initialize_periodic(1)142 }143 (true, true, Some(false)) => {144 Self::on_initialize_periodic_named(2) - Self::on_initialize_periodic_named(1)145 }146 (false, false, Some(true)) => {147 Self::on_initialize_resolved(2) - Self::on_initialize_resolved(1)148 }149 (false, true, Some(true)) => {150 Self::on_initialize_named_resolved(2) - Self::on_initialize_named_resolved(1)151 }152 (true, false, Some(true)) => {153 Self::on_initialize_periodic_resolved(2) - Self::on_initialize_periodic_resolved(1)154 }155 (true, true, Some(true)) => {156 Self::on_initialize_periodic_named_resolved(2)157 - Self::on_initialize_periodic_named_resolved(1)158 }159 }160 }161}162impl<T: WeightInfo> MarginalWeightInfo for T {}163164#[frame_support::pallet]165pub mod pallet {166 use super::*;167 use frame_support::{168 dispatch::PostDispatchInfo,169 pallet_prelude::*,170 traits::{schedule::LookupError, PreimageProvider},171 };172 use frame_system::pallet_prelude::*;173174 175 const STORAGE_VERSION: StorageVersion = StorageVersion::new(3);176177 #[pallet::pallet]178 #[pallet::generate_store(pub(super) trait Store)]179 #[pallet::storage_version(STORAGE_VERSION)]180 #[pallet::without_storage_info]181 pub struct Pallet<T>(_);182183 184 #[pallet::config]185 pub trait Config: frame_system::Config {186 187 type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event>;188189 190 type Origin: OriginTrait<PalletsOrigin = Self::PalletsOrigin>191 + From<Self::PalletsOrigin>192 + IsType<<Self as system::Config>::Origin>;193194 195 type PalletsOrigin: From<system::RawOrigin<Self::AccountId>> + Codec + Clone + Eq + TypeInfo;196197 type Currency: NamedReservableCurrency<Self::AccountId, ReserveIdentifier = ScheduledId>;198199 200 type Call: Parameter201 + Dispatchable<Origin = <Self as Config>::Origin, PostInfo = PostDispatchInfo>202 + GetDispatchInfo203 + From<system::Call<Self>>;204205 206 207 #[pallet::constant]208 type MaximumWeight: Get<Weight>;209210 211 type ScheduleOrigin: EnsureOrigin<<Self as system::Config>::Origin>;212213 214 215 216 217 218 219 220 type OriginPrivilegeCmp: PrivilegeCmp<Self::PalletsOrigin>;221222 223 224 #[pallet::constant]225 type MaxScheduledPerBlock: Get<u32>;226227 228 type WeightInfo: WeightInfo;229230 231 type PreimageProvider: PreimageProviderAndMaybeRecipient<Self::Hash>;232233 234 type NoPreimagePostponement: Get<Option<Self::BlockNumber>>;235236 237 238239 240 type CallExecutor: DispatchCall<Self, H160>;241 }242243 244 pub trait DispatchCall<T: frame_system::Config + Config, SelfContainedSignedInfo> {245 fn reserve_balance(246 id: ScheduledId,247 sponsor: <T as frame_system::Config>::AccountId,248 call: <T as Config>::Call,249 count: u32,250 ) -> Result<(), DispatchError>;251252 fn pay_for_call(253 id: ScheduledId,254 sponsor: <T as frame_system::Config>::AccountId,255 call: <T as Config>::Call,256 ) -> Result<u128, DispatchError>;257258 259 fn dispatch_call(260 signer: T::AccountId,261 function: <T as Config>::Call,262 ) -> Result<263 Result<PostDispatchInfo, DispatchErrorWithPostInfo<PostDispatchInfo>>,264 TransactionValidityError,265 >;266267 fn cancel_reserve(268 id: ScheduledId,269 sponsor: <T as frame_system::Config>::AccountId,270 ) -> Result<u128, DispatchError>;271 }272273 274 #[pallet::storage]275 pub type Agenda<T: Config> =276 StorageMap<_, Twox64Concat, T::BlockNumber, Vec<Option<ScheduledV3Of<T>>>, ValueQuery>;277278 279 #[pallet::storage]280 pub(crate) type Lookup<T: Config> =281 StorageMap<_, Twox64Concat, ScheduledId, TaskAddress<T::BlockNumber>>;282283 284 #[pallet::event]285 #[pallet::generate_deposit(pub(super) fn deposit_event)]286 pub enum Event<T: Config> {287 288 Scheduled { when: T::BlockNumber, index: u32 },289 290 Canceled { when: T::BlockNumber, index: u32 },291 292 Dispatched {293 task: TaskAddress<T::BlockNumber>,294 id: Option<ScheduledId>,295 result: DispatchResult,296 },297 298 CallLookupFailed {299 task: TaskAddress<T::BlockNumber>,300 id: Option<ScheduledId>,301 error: LookupError,302 },303 }304305 #[pallet::error]306 pub enum Error<T> {307 308 FailedToSchedule,309 310 NotFound,311 312 TargetBlockNumberInPast,313 314 RescheduleNoChange,315 }316317 #[pallet::hooks]318 impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {319 320 fn on_initialize(now: T::BlockNumber) -> Weight {321 let limit = T::MaximumWeight::get();322323 let mut queued = Agenda::<T>::take(now)324 .into_iter()325 .enumerate()326 .filter_map(|(index, s)| Some((index as u32, s?)))327 .collect::<Vec<_>>();328329 if queued.len() as u32 > T::MaxScheduledPerBlock::get() {330 log::warn!(331 target: "runtime::scheduler",332 "Warning: This block has more items queued in Scheduler than \333 expected from the runtime configuration. An update might be needed."334 );335 }336337 queued.sort_by_key(|(_, s)| s.priority);338339 let next = now + One::one();340341 let mut total_weight: Weight = T::WeightInfo::on_initialize(0);342 for (order, (index, mut s)) in queued.into_iter().enumerate() {343 let named = if let Some(ref id) = s.maybe_id {344 Lookup::<T>::remove(id);345 true346 } else {347 false348 };349350 let (call, maybe_completed) = s.call.resolved::<T::PreimageProvider>();351 s.call = call;352353 let resolved = if let Some(completed) = maybe_completed {354 T::PreimageProvider::unrequest_preimage(&completed);355 true356 } else {357 false358 };359 let call = match s.call.as_value().cloned() {360 Some(c) => c,361 None => {362 363 total_weight.saturating_accrue(T::WeightInfo::item(false, named, None));364 if let Some(delay) = T::NoPreimagePostponement::get() {365 let until = now.saturating_add(delay);366 if let Some(ref id) = s.maybe_id {367 let index = Agenda::<T>::decode_len(until).unwrap_or(0);368 Lookup::<T>::insert(id, (until, index as u32));369 }370 Agenda::<T>::append(until, Some(s));371 }372 continue;373 }374 };375376 let periodic = s.maybe_periodic.is_some();377 let call_weight = call.get_dispatch_info().weight;378 let mut item_weight = T::WeightInfo::item(periodic, named, Some(resolved));379 let origin =380 <<T as Config>::Origin as From<T::PalletsOrigin>>::from(s.origin.clone())381 .into();382 if ensure_signed(origin).is_ok() {383 384 item_weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1));385 }386387 388 389 390 391 let hard_deadline = s.priority <= schedule::HARD_DEADLINE;392 let test_weight = total_weight393 .saturating_add(call_weight)394 .saturating_add(item_weight);395 if !hard_deadline && order > 0 && test_weight > limit {396 397 total_weight.saturating_accrue(T::WeightInfo::item(false, named, None));398 if let Some(ref id) = s.maybe_id {399 400 401 402 403 let index = Agenda::<T>::decode_len(next).unwrap_or(0);404 Lookup::<T>::insert(id, (next, index as u32));405 }406 Agenda::<T>::append(next, Some(s));407 continue;408 }409410 let sender = ensure_signed(411 <<T as Config>::Origin as From<T::PalletsOrigin>>::from(s.origin.clone())412 .into(),413 )414 .unwrap();415416 417 418 419 420 421 422 423 424425 let r = T::CallExecutor::dispatch_call(sender, call.clone());426427 let mut actual_call_weight: Weight = item_weight;428 let result: Result<_, DispatchError> = match r {429 Ok(o) => match o {430 Ok(di) => {431 actual_call_weight = di.actual_weight.unwrap_or(item_weight);432 Ok(())433 }434 Err(err) => Err(err.error),435 },436 Err(_) => {437 log::error!(438 target: "runtime::scheduler",439 "Warning: Scheduler has failed to execute a post-dispatch transaction. \440 This block might have become invalid.");441 Err(DispatchError::CannotLookup)442 } 443 };444445 total_weight.saturating_accrue(item_weight);446 total_weight.saturating_accrue(actual_call_weight);447448 Self::deposit_event(Event::Dispatched {449 task: (now, index),450 id: s.maybe_id.clone(),451 result,452 });453454 if let &Some((period, count)) = &s.maybe_periodic {455 if count > 1 {456 s.maybe_periodic = Some((period, count - 1));457 } else {458 s.maybe_periodic = None;459 }460 let wake = now + period;461 462 if let Some(ref id) = s.maybe_id {463 let wake_index = Agenda::<T>::decode_len(wake).unwrap_or(0);464 Lookup::<T>::insert(id, (wake, wake_index as u32));465 }466 Agenda::<T>::append(wake, Some(s));467 }468 }469 0470 471 }472 }473474 #[pallet::call]475 impl<T: Config> Pallet<T> {476 477 #[pallet::weight(<T as Config>::WeightInfo::schedule_named(T::MaxScheduledPerBlock::get()))]478 pub fn schedule_named(479 origin: OriginFor<T>,480 id: ScheduledId,481 when: T::BlockNumber,482 maybe_periodic: Option<schedule::Period<T::BlockNumber>>,483 priority: schedule::Priority,484 call: Box<CallOrHashOf<T>>,485 ) -> DispatchResult {486 T::ScheduleOrigin::ensure_origin(origin.clone())?;487 let origin = <T as Config>::Origin::from(origin);488 Self::do_schedule_named(489 id,490 DispatchTime::At(when),491 maybe_periodic,492 priority,493 origin.caller().clone(),494 *call,495 )?;496 Ok(())497 }498499 500 #[pallet::weight(<T as Config>::WeightInfo::cancel_named(T::MaxScheduledPerBlock::get()))]501 pub fn cancel_named(origin: OriginFor<T>, id: ScheduledId) -> DispatchResult {502 T::ScheduleOrigin::ensure_origin(origin.clone())?;503 let origin = <T as Config>::Origin::from(origin);504 Self::do_cancel_named(Some(origin.caller().clone()), id)?;505 Ok(())506 }507508 509 510 511 512 513 #[pallet::weight(<T as Config>::WeightInfo::schedule_named(T::MaxScheduledPerBlock::get()))]514 pub fn schedule_named_after(515 origin: OriginFor<T>,516 id: ScheduledId,517 after: T::BlockNumber,518 maybe_periodic: Option<schedule::Period<T::BlockNumber>>,519 priority: schedule::Priority,520 call: Box<CallOrHashOf<T>>,521 ) -> DispatchResult {522 T::ScheduleOrigin::ensure_origin(origin.clone())?;523 let origin = <T as Config>::Origin::from(origin);524 Self::do_schedule_named(525 id,526 DispatchTime::After(after),527 maybe_periodic,528 priority,529 origin.caller().clone(),530 *call,531 )?;532 Ok(())533 }534 }535}536537impl<T: Config> Pallet<T> {538 #[cfg(feature = "try-runtime")]539 pub fn pre_migrate_to_v3() -> Result<(), &'static str> {540 Ok(())541 }542543 #[cfg(feature = "try-runtime")]544 pub fn post_migrate_to_v3() -> Result<(), &'static str> {545 use frame_support::dispatch::GetStorageVersion;546547 assert!(Self::current_storage_version() == 3);548 for k in Agenda::<T>::iter_keys() {549 let _ = Agenda::<T>::try_get(k).map_err(|()| "Invalid item in Agenda")?;550 }551 Ok(())552 }553554 555 pub fn migrate_origin<OldOrigin: Into<T::PalletsOrigin> + codec::Decode>() {556 Agenda::<T>::translate::<557 Vec<Option<Scheduled<CallOrHashOf<T>, T::BlockNumber, OldOrigin, T::AccountId>>>,558 _,559 >(|_, agenda| {560 Some(561 agenda562 .into_iter()563 .map(|schedule| {564 schedule.map(|schedule| Scheduled {565 maybe_id: schedule.maybe_id,566 priority: schedule.priority,567 call: schedule.call,568 maybe_periodic: schedule.maybe_periodic,569 origin: schedule.origin.into(),570 _phantom: Default::default(),571 })572 })573 .collect::<Vec<_>>(),574 )575 });576 }577578 fn resolve_time(when: DispatchTime<T::BlockNumber>) -> Result<T::BlockNumber, DispatchError> {579 let now = frame_system::Pallet::<T>::block_number();580581 let when = match when {582 DispatchTime::At(x) => x,583 584 585 DispatchTime::After(x) => now.saturating_add(x).saturating_add(One::one()),586 };587588 if when <= now {589 return Err(Error::<T>::TargetBlockNumberInPast.into());590 }591592 Ok(when)593 }594595 fn do_schedule(596 when: DispatchTime<T::BlockNumber>,597 maybe_periodic: Option<schedule::Period<T::BlockNumber>>,598 priority: schedule::Priority,599 origin: T::PalletsOrigin,600 call: CallOrHashOf<T>,601 ) -> Result<TaskAddress<T::BlockNumber>, DispatchError> {602 let when = Self::resolve_time(when)?;603 call.ensure_requested::<T::PreimageProvider>();604605 606 let maybe_periodic = maybe_periodic607 .filter(|p| p.1 > 1 && !p.0.is_zero())608 609 .map(|(p, c)| (p, c - 1));610 let s = Some(Scheduled {611 maybe_id: None,612 priority,613 call,614 maybe_periodic,615 origin,616 _phantom: PhantomData::<T::AccountId>::default(),617 });618 Agenda::<T>::append(when, s);619 let index = Agenda::<T>::decode_len(when).unwrap_or(1) as u32 - 1;620 Self::deposit_event(Event::Scheduled { when, index });621622 Ok((when, index))623 }624625 fn do_cancel(626 origin: Option<T::PalletsOrigin>,627 (when, index): TaskAddress<T::BlockNumber>,628 ) -> Result<(), DispatchError> {629 let scheduled = Agenda::<T>::try_mutate(when, |agenda| {630 agenda.get_mut(index as usize).map_or(631 Ok(None),632 |s| -> Result<Option<Scheduled<_, _, _, _>>, DispatchError> {633 if let (Some(ref o), Some(ref s)) = (origin, s.borrow()) {634 if matches!(635 T::OriginPrivilegeCmp::cmp_privilege(o, &s.origin),636 Some(Ordering::Less) | None637 ) {638 return Err(BadOrigin.into());639 }640 };641 Ok(s.take())642 },643 )644 })?;645 if let Some(s) = scheduled {646 s.call.ensure_unrequested::<T::PreimageProvider>();647 if let Some(id) = s.maybe_id {648 Lookup::<T>::remove(id);649 }650 Self::deposit_event(Event::Canceled { when, index });651 Ok(())652 } else {653 Err(Error::<T>::NotFound)?654 }655 }656657 fn do_reschedule(658 (when, index): TaskAddress<T::BlockNumber>,659 new_time: DispatchTime<T::BlockNumber>,660 ) -> Result<TaskAddress<T::BlockNumber>, DispatchError> {661 let new_time = Self::resolve_time(new_time)?;662663 if new_time == when {664 return Err(Error::<T>::RescheduleNoChange.into());665 }666667 Agenda::<T>::try_mutate(when, |agenda| -> DispatchResult {668 let task = agenda.get_mut(index as usize).ok_or(Error::<T>::NotFound)?;669 let task = task.take().ok_or(Error::<T>::NotFound)?;670 Agenda::<T>::append(new_time, Some(task));671 Ok(())672 })?;673674 let new_index = Agenda::<T>::decode_len(new_time).unwrap_or(1) as u32 - 1;675 Self::deposit_event(Event::Canceled { when, index });676 Self::deposit_event(Event::Scheduled {677 when: new_time,678 index: new_index,679 });680681 Ok((new_time, new_index))682 }683684 fn do_schedule_named(685 id: ScheduledId,686 when: DispatchTime<T::BlockNumber>,687 maybe_periodic: Option<schedule::Period<T::BlockNumber>>,688 priority: schedule::Priority,689 origin: T::PalletsOrigin,690 call: CallOrHashOf<T>,691 ) -> Result<TaskAddress<T::BlockNumber>, DispatchError> {692 693 if Lookup::<T>::contains_key(&id) {694 return Err(Error::<T>::FailedToSchedule)?;695 }696697 let when = Self::resolve_time(when)?;698699 call.ensure_requested::<T::PreimageProvider>();700701 702 let maybe_periodic = maybe_periodic703 .filter(|p| p.1 > 1 && !p.0.is_zero())704 705 .map(|(p, c)| (p, c - 1));706707 let s = Scheduled {708 maybe_id: Some(id.clone()),709 priority,710 call: call.clone(),711 maybe_periodic,712 origin: origin.clone(),713 _phantom: Default::default(),714 };715716 717 718 719 720 721 722 723 724 725 726 727 728 729730 Agenda::<T>::append(when, Some(s));731 let index = Agenda::<T>::decode_len(when).unwrap_or(1) as u32 - 1;732 let address = (when, index);733 Lookup::<T>::insert(&id, &address);734 Self::deposit_event(Event::Scheduled { when, index });735736 Ok(address)737 }738739 fn do_cancel_named(origin: Option<T::PalletsOrigin>, id: ScheduledId) -> DispatchResult {740 Lookup::<T>::try_mutate_exists(id, |lookup| -> DispatchResult {741 if let Some((when, index)) = lookup.take() {742 let i = index as usize;743 Agenda::<T>::try_mutate(when, |agenda| -> DispatchResult {744 if let Some(s) = agenda.get_mut(i) {745 if let (Some(ref o), Some(ref s)) = (origin.clone(), s.borrow()) {746 if matches!(747 T::OriginPrivilegeCmp::cmp_privilege(o, &s.origin),748 Some(Ordering::Less) | None749 ) {750 return Err(BadOrigin.into());751 }752 753 754 755 756 757 758 759 760761 s.call.ensure_unrequested::<T::PreimageProvider>();762 }763 *s = None;764 }765 Ok(())766 })?;767768 Self::deposit_event(Event::Canceled { when, index });769 Ok(())770 } else {771 Err(Error::<T>::NotFound)?772 }773 })774 }775776 fn do_reschedule_named(777 id: ScheduledId,778 new_time: DispatchTime<T::BlockNumber>,779 ) -> Result<TaskAddress<T::BlockNumber>, DispatchError> {780 let new_time = Self::resolve_time(new_time)?;781782 Lookup::<T>::try_mutate_exists(783 id,784 |lookup| -> Result<TaskAddress<T::BlockNumber>, DispatchError> {785 let (when, index) = lookup.ok_or(Error::<T>::NotFound)?;786787 if new_time == when {788 return Err(Error::<T>::RescheduleNoChange.into());789 }790791 Agenda::<T>::try_mutate(when, |agenda| -> DispatchResult {792 let task = agenda.get_mut(index as usize).ok_or(Error::<T>::NotFound)?;793 let task = task.take().ok_or(Error::<T>::NotFound)?;794 Agenda::<T>::append(new_time, Some(task));795796 Ok(())797 })?;798799 let new_index = Agenda::<T>::decode_len(new_time).unwrap_or(1) as u32 - 1;800 Self::deposit_event(Event::Canceled { when, index });801 Self::deposit_event(Event::Scheduled {802 when: new_time,803 index: new_index,804 });805806 *lookup = Some((new_time, new_index));807808 Ok((new_time, new_index))809 },810 )811 }812}813814impl<T: Config> schedule::v2::Anon<T::BlockNumber, <T as Config>::Call, T::PalletsOrigin>815 for Pallet<T>816{817 type Address = TaskAddress<T::BlockNumber>;818 type Hash = T::Hash;819820 fn schedule(821 when: DispatchTime<T::BlockNumber>,822 maybe_periodic: Option<schedule::Period<T::BlockNumber>>,823 priority: schedule::Priority,824 origin: T::PalletsOrigin,825 call: CallOrHashOf<T>,826 ) -> Result<Self::Address, DispatchError> {827 Self::do_schedule(when, maybe_periodic, priority, origin, call)828 }829830 fn cancel((when, index): Self::Address) -> Result<(), ()> {831 Self::do_cancel(None, (when, index)).map_err(|_| ())832 }833834 fn reschedule(835 address: Self::Address,836 when: DispatchTime<T::BlockNumber>,837 ) -> Result<Self::Address, DispatchError> {838 Self::do_reschedule(address, when)839 }840841 fn next_dispatch_time((when, index): Self::Address) -> Result<T::BlockNumber, ()> {842 Agenda::<T>::get(when)843 .get(index as usize)844 .ok_or(())845 .map(|_| when)846 }847}848849impl<T: Config> schedule::v2::Named<T::BlockNumber, <T as Config>::Call, T::PalletsOrigin>850 for Pallet<T>851{852 type Address = TaskAddress<T::BlockNumber>;853 type Hash = T::Hash;854855 fn schedule_named(856 id: Vec<u8>,857 when: DispatchTime<T::BlockNumber>,858 maybe_periodic: Option<schedule::Period<T::BlockNumber>>,859 priority: schedule::Priority,860 origin: T::PalletsOrigin,861 call: CallOrHashOf<T>,862 ) -> Result<Self::Address, ()> {863 let inner_id: ScheduledId = id864 .try_into()865 .unwrap_or([0; MAX_TASK_ID_LENGTH_IN_BYTES as usize]);866 Self::do_schedule_named(inner_id, when, maybe_periodic, priority, origin, call)867 .map_err(|_| ())868 }869870 fn cancel_named(id: Vec<u8>) -> Result<(), ()> {871 let inner_id: ScheduledId = id872 .try_into()873 .unwrap_or([0; MAX_TASK_ID_LENGTH_IN_BYTES as usize]);874 Self::do_cancel_named(None, inner_id).map_err(|_| ())875 }876877 fn reschedule_named(878 id: Vec<u8>,879 when: DispatchTime<T::BlockNumber>,880 ) -> Result<Self::Address, DispatchError> {881 let inner_id: ScheduledId = id882 .try_into()883 .unwrap_or([0; MAX_TASK_ID_LENGTH_IN_BYTES as usize]);884 Self::do_reschedule_named(inner_id, when)885 }886887 fn next_dispatch_time(id: Vec<u8>) -> Result<T::BlockNumber, ()> {888 let inner_id: ScheduledId = id889 .try_into()890 .unwrap_or([0; MAX_TASK_ID_LENGTH_IN_BYTES as usize]);891 Lookup::<T>::get(inner_id)892 .and_then(|(when, index)| Agenda::<T>::get(when).get(index as usize).map(|_| when))893 .ok_or(())894 }895}