12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152#![cfg_attr(not(feature = "std"), no_std)]5354mod benchmarking;55pub mod weights;5657use sp_std::{prelude::*, marker::PhantomData, borrow::Borrow};58use codec::{Encode, Decode, Codec};59use sp_runtime::{RuntimeDebug, traits::{Zero, One, BadOrigin, Saturating}};60use frame_support::{61 decl_module, decl_storage, decl_event, decl_error, IterableStorageMap,62 dispatch::{Dispatchable, DispatchError, DispatchResult, Parameter},63 traits::{Get, schedule::{self, DispatchTime}, OriginTrait, EnsureOrigin, IsType},64 weights::{GetDispatchInfo, Weight},65};66use frame_system::{self as system, ensure_signed};67use pallet_nft::*;6869use nft_data_structs::*;70pub use weights::WeightInfo;7172737475767778pub trait Config: system::Config79{ 8081 82 type Event: From<Event<Self>> + Into<<Self as system::Config>::Event>;8384 85 type Origin: OriginTrait<PalletsOrigin = Self::PalletsOrigin>86 + From<Self::PalletsOrigin> + IsType<<Self as system::Config>::Origin>;8788 89 type PalletsOrigin: From<system::RawOrigin<Self::AccountId>> + Codec + Clone + Eq;9091 92 type Call: Parameter + Dispatchable<Origin=<Self as Config>::Origin> + GetDispatchInfo + From<system::Call<Self>>;9394 95 96 type MaximumWeight: Get<Weight>;9798 99 type ScheduleOrigin: EnsureOrigin<<Self as system::Config>::Origin>;100101 102 103 type MaxScheduledPerBlock: Get<u32>;104105 106 type Sponsoring: SponsoringResolve<Self::AccountId, <Self as Config>::Call>;107108 109 type WeightInfo: WeightInfo;110}111112113114115pub type PeriodicIndex = u32;116117pub type TaskAddress<BlockNumber> = (BlockNumber, u32);118119#[cfg_attr(any(feature = "std", test), derive(PartialEq, Eq))]120#[derive(Clone, RuntimeDebug, Encode, Decode)]121struct ScheduledV1<Call, BlockNumber> {122 maybe_id: Option<Vec<u8>>,123 priority: schedule::Priority,124 call: Call,125 maybe_periodic: Option<schedule::Period<BlockNumber>>,126}127128129#[cfg_attr(any(feature = "std", test), derive(PartialEq, Eq))]130#[derive(Clone, RuntimeDebug, Encode, Decode)]131pub struct ScheduledV2<Call, BlockNumber, PalletsOrigin, AccountId> {132 133 maybe_id: Option<Vec<u8>>,134 135 priority: schedule::Priority,136 137 call: Call,138 139 maybe_periodic: Option<schedule::Period<BlockNumber>>,140 141 origin: PalletsOrigin,142 _phantom: PhantomData<AccountId>,143}144145146pub type Scheduled<Call, BlockNumber, PalletsOrigin, AccountId> = ScheduledV2<Call, BlockNumber, PalletsOrigin, AccountId>;147148149150151#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug)]152enum Releases {153 V1,154 V2,155}156157impl Default for Releases {158 fn default() -> Self {159 Releases::V1160 }161}162163#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug)]164pub struct CallSpec {165166 module: u32,167 method: u32,168}169170decl_storage! {171 trait Store for Module<T: Config> as Scheduler {172 173 pub Agenda: map hasher(twox_64_concat) T::BlockNumber174 => Vec<Option<Scheduled<<T as Config>::Call, T::BlockNumber, T::PalletsOrigin, T::AccountId>>>;175176 pub SpecAgenda: map hasher(twox_64_concat) T::BlockNumber177 => Vec<Option<CallSpec>>; 178179 180 Lookup: map hasher(twox_64_concat) Vec<u8> => Option<TaskAddress<T::BlockNumber>>;181182 183 184 185 StorageVersion build(|_| Releases::V2): Releases;186 }187}188189decl_event!(190 pub enum Event<T> where <T as system::Config>::BlockNumber {191 192 Scheduled(BlockNumber, u32),193 194 Canceled(BlockNumber, u32),195 196 Dispatched(TaskAddress<BlockNumber>, Option<Vec<u8>>, DispatchResult),197 }198);199200decl_error! {201 pub enum Error for Module<T: Config> {202 203 FailedToSchedule,204 205 NotFound,206 207 TargetBlockNumberInPast,208 209 RescheduleNoChange,210 }211}212213decl_module! {214 215 pub struct Module<T: Config> for enum Call 216 where 217 origin: <T as system::Config>::Origin218 {219 type Error = Error<T>;220 fn deposit_event() = default;221222223 224 225 226 227 228 229 230 231 232 233 234 #[weight = 0]235 fn schedule(origin,236 when: T::BlockNumber,237 maybe_periodic: Option<schedule::Period<T::BlockNumber>>,238 priority: schedule::Priority,239 call: Box<<T as Config>::Call>,240 ) 241 {242 let origin = <T as Config>::Origin::from(origin);243 Self::do_schedule(DispatchTime::At(when), maybe_periodic, priority, origin.caller().clone(), *call)?;244 }245246 247 248 249 250 251 252 253 254 255 256 #[weight = <T as Config>::WeightInfo::cancel(T::MaxScheduledPerBlock::get())]257 fn cancel(origin, when: T::BlockNumber, index: u32) {258 T::ScheduleOrigin::ensure_origin(origin.clone())?;259 let origin = <T as Config>::Origin::from(origin);260 Self::do_cancel(Some(origin.caller().clone()), (when, index))?;261 }262263 264 265 266 267 268 269 270 271 272 273 #[weight = <T as Config>::WeightInfo::schedule_named(T::MaxScheduledPerBlock::get())]274 fn schedule_named(origin,275 id: Vec<u8>,276 when: T::BlockNumber,277 maybe_periodic: Option<schedule::Period<T::BlockNumber>>,278 priority: schedule::Priority,279 call: Box<<T as Config>::Call>,280 ) {281 T::ScheduleOrigin::ensure_origin(origin.clone())?;282 let origin = <T as Config>::Origin::from(origin);283 Self::do_schedule_named(284 id, DispatchTime::At(when), maybe_periodic, priority, origin.caller().clone(), *call285 )?;286 }287288 289 290 291 292 293 294 295 296 297 298 #[weight = <T as Config>::WeightInfo::cancel_named(T::MaxScheduledPerBlock::get())]299 fn cancel_named(origin, id: Vec<u8>) {300 T::ScheduleOrigin::ensure_origin(origin.clone())?;301 let origin = <T as Config>::Origin::from(origin);302 Self::do_cancel_named(Some(origin.caller().clone()), id)?;303 }304305 306 307 308 309 310 #[weight = <T as Config>::WeightInfo::schedule(T::MaxScheduledPerBlock::get())]311 fn schedule_after(origin,312 after: T::BlockNumber,313 maybe_periodic: Option<schedule::Period<T::BlockNumber>>,314 priority: schedule::Priority,315 call: Box<<T as Config>::Call>,316 ) {317 T::ScheduleOrigin::ensure_origin(origin.clone())?;318 let origin = <T as Config>::Origin::from(origin);319 Self::do_schedule(320 DispatchTime::After(after), maybe_periodic, priority, origin.caller().clone(), *call321 )?;322 }323324 325 326 327 328 329 #[weight = <T as Config>::WeightInfo::schedule_named(T::MaxScheduledPerBlock::get())]330 fn schedule_named_after(origin,331 id: Vec<u8>,332 after: T::BlockNumber,333 maybe_periodic: Option<schedule::Period<T::BlockNumber>>,334 priority: schedule::Priority,335 call: Box<<T as Config>::Call>,336 ) {337 T::ScheduleOrigin::ensure_origin(origin.clone())?;338 let origin = <T as Config>::Origin::from(origin);339 Self::do_schedule_named(340 id, DispatchTime::After(after), maybe_periodic, priority, origin.caller().clone(), *call341 )?;342 }343344 345 346 347 348 349 350 351 352 353 354 355 fn on_initialize(now: T::BlockNumber) -> Weight {356 let limit = T::MaximumWeight::get();357 let mut queued = Agenda::<T>::take(now).into_iter()358 .enumerate()359 .filter_map(|(index, s)| s.map(|inner| (index as u32, inner)))360 .collect::<Vec<_>>();361 if queued.len() as u32 > T::MaxScheduledPerBlock::get() {362 log::warn!(363 target: "runtime::scheduler",364 "Warning: This block has more items queued in Scheduler than \365 expected from the runtime configuration. An update might be needed."366 );367 }368 queued.sort_by_key(|(_, s)| s.priority);369 let base_weight: Weight = T::DbWeight::get().reads_writes(1, 2); 370 let mut total_weight: Weight = <T as Config>::WeightInfo::schedule(T::MaxScheduledPerBlock::get());371 queued.into_iter()372 .enumerate()373 .scan(base_weight, |cumulative_weight, (order, (index, s))| {374 *cumulative_weight = cumulative_weight375 .saturating_add(s.call.get_dispatch_info().weight);376377 let origin = <<T as Config>::Origin as From<T::PalletsOrigin>>::from(378 s.origin.clone()379 ).into();380381 if ensure_signed(origin).is_ok() {382 383 *cumulative_weight = cumulative_weight384 .saturating_add(T::DbWeight::get().reads_writes(1, 1));385 }386387 if s.maybe_id.is_some() {388 389 *cumulative_weight = cumulative_weight.saturating_add(T::DbWeight::get().writes(1));390 }391 if s.maybe_periodic.is_some() {392 393 *cumulative_weight = cumulative_weight.saturating_add(T::DbWeight::get().reads_writes(1, 1));394 }395396 Some((order, index, *cumulative_weight, s))397 })398 .filter_map(|(order, index, cumulative_weight, mut s)| {399 400 401 402 403 if s.priority <= schedule::HARD_DEADLINE || cumulative_weight <= limit || order == 0 {404405 let origin = <<T as Config>::Origin as From<T::PalletsOrigin>>::from(406 s.origin.clone()407 ).into();408 let sender = ensure_signed(origin).unwrap_or(T::AccountId::default());409 let who_will_pay = T::Sponsoring::resolve(&sender, &s.call.clone()).unwrap_or(410 T::AccountId::default());411 let sponsor = T::PalletsOrigin::from(system::RawOrigin::Signed(who_will_pay));412 let r = s.call.clone().dispatch(sponsor.into());413 let maybe_id = s.maybe_id.clone();414 if let &Some((period, count)) = &s.maybe_periodic {415 if count > 1 {416 s.maybe_periodic = Some((period, count - 1));417 } else {418 s.maybe_periodic = None;419 }420 let next = now + period;421 422 if let Some(ref id) = s.maybe_id {423 let next_index = Agenda::<T>::decode_len(now + period).unwrap_or(0);424 Lookup::<T>::insert(id, (next, next_index as u32));425 }426 Agenda::<T>::append(next, Some(s));427 } else {428 if let Some(ref id) = s.maybe_id {429 Lookup::<T>::remove(id);430 }431 }432 Self::deposit_event(RawEvent::Dispatched(433 (now, index),434 maybe_id,435 r.map(|_| ()).map_err(|e| e.error)436 ));437 total_weight = cumulative_weight;438 None439 } else {440 Some(Some(s))441 }442 })443 .for_each(|unused| {444 let next = now + One::one();445 Agenda::<T>::append(next, unused);446 });447448 total_weight449 }450 }451}452453impl<T: Config> Module<T> {454 455 456 pub fn migrate_v1_to_t2() -> bool {457 if StorageVersion::get() == Releases::V1 {458 StorageVersion::put(Releases::V2);459460 Agenda::<T>::translate::<461 Vec<Option<ScheduledV1<<T as Config>::Call, T::BlockNumber>>>, _462 >(|_, agenda| Some(463 agenda464 .into_iter()465 .map(|schedule| schedule.map(|schedule| ScheduledV2 {466 maybe_id: schedule.maybe_id,467 priority: schedule.priority,468 call: schedule.call,469 maybe_periodic: schedule.maybe_periodic,470 origin: system::RawOrigin::Root.into(),471 _phantom: Default::default(),472 }))473 .collect::<Vec<_>>()474 ));475476 true477 } else {478 false479 }480 }481482 483 pub fn migrate_origin<OldOrigin: Into<T::PalletsOrigin> + codec::Decode>() {484 Agenda::<T>::translate::<485 Vec<Option<Scheduled<<T as Config>::Call, T::BlockNumber, OldOrigin, T::AccountId>>>, _486 >(|_, agenda| Some(487 agenda488 .into_iter()489 .map(|schedule| schedule.map(|schedule| Scheduled {490 maybe_id: schedule.maybe_id,491 priority: schedule.priority,492 call: schedule.call,493 maybe_periodic: schedule.maybe_periodic,494 origin: schedule.origin.into(),495 _phantom: Default::default(),496 }))497 .collect::<Vec<_>>()498 ));499 }500501 fn resolve_time(when: DispatchTime<T::BlockNumber>) -> Result<T::BlockNumber, DispatchError> {502 let now = frame_system::Pallet::<T>::block_number();503504 let when = match when {505 DispatchTime::At(x) => x,506 507 508 DispatchTime::After(x) => now.saturating_add(x).saturating_add(One::one())509 };510511 if when <= now {512 return Err(Error::<T>::TargetBlockNumberInPast.into())513 }514515 Ok(when)516 }517518 fn do_schedule(519 when: DispatchTime<T::BlockNumber>,520 maybe_periodic: Option<schedule::Period<T::BlockNumber>>,521 priority: schedule::Priority,522 origin: T::PalletsOrigin,523 call: <T as Config>::Call524 ) -> Result<TaskAddress<T::BlockNumber>, DispatchError> {525 let when = Self::resolve_time(when)?;526527 528 let maybe_periodic = maybe_periodic529 .filter(|p| p.1 > 1 && !p.0.is_zero())530 531 .map(|(p, c)| (p, c - 1));532 let s = Some(Scheduled {533 maybe_id: None, priority, call, maybe_periodic, origin, _phantom: PhantomData::<T::AccountId>::default(),534 });535 Agenda::<T>::append(when, s);536 let index = Agenda::<T>::decode_len(when).unwrap_or(1) as u32 - 1;537 if index > T::MaxScheduledPerBlock::get() {538 log::warn!(539 target: "runtime::scheduler",540 "Warning: There are more items queued in the Scheduler than \541 expected from the runtime configuration. An update might be needed.",542 );543 }544 Self::deposit_event(RawEvent::Scheduled(when, index));545546 Ok((when, index))547 }548549 fn do_cancel(550 origin: Option<T::PalletsOrigin>,551 (when, index): TaskAddress<T::BlockNumber>552 ) -> Result<(), DispatchError> {553 let scheduled = Agenda::<T>::try_mutate(554 when,555 |agenda| {556 agenda.get_mut(index as usize)557 .map_or(Ok(None), |s| -> Result<Option<Scheduled<_, _, _, _>>, DispatchError> {558 if let (Some(ref o), Some(ref s)) = (origin, s.borrow()) {559 if *o != s.origin {560 return Err(BadOrigin.into());561 }562 };563 Ok(s.take())564 })565 },566 )?;567 if let Some(s) = scheduled {568 if let Some(id) = s.maybe_id {569 Lookup::<T>::remove(id);570 }571 Self::deposit_event(RawEvent::Canceled(when, index));572 Ok(())573 } else {574 Err(Error::<T>::NotFound)?575 }576 }577578 fn do_reschedule(579 (when, index): TaskAddress<T::BlockNumber>,580 new_time: DispatchTime<T::BlockNumber>,581 ) -> Result<TaskAddress<T::BlockNumber>, DispatchError> {582 let new_time = Self::resolve_time(new_time)?;583584 if new_time == when {585 return Err(Error::<T>::RescheduleNoChange.into());586 }587588 Agenda::<T>::try_mutate(when, |agenda| -> DispatchResult {589 let task = agenda.get_mut(index as usize).ok_or(Error::<T>::NotFound)?;590 let task = task.take().ok_or(Error::<T>::NotFound)?;591 Agenda::<T>::append(new_time, Some(task));592 Ok(())593 })?;594595 let new_index = Agenda::<T>::decode_len(new_time).unwrap_or(1) as u32 - 1;596 Self::deposit_event(RawEvent::Canceled(when, index));597 Self::deposit_event(RawEvent::Scheduled(new_time, new_index));598599 Ok((new_time, new_index))600 }601602 fn do_schedule_named(603 id: Vec<u8>,604 when: DispatchTime<T::BlockNumber>,605 maybe_periodic: Option<schedule::Period<T::BlockNumber>>,606 priority: schedule::Priority,607 origin: T::PalletsOrigin,608 call: <T as Config>::Call,609 ) -> Result<TaskAddress<T::BlockNumber>, DispatchError> {610 611 if Lookup::<T>::contains_key(&id) {612 return Err(Error::<T>::FailedToSchedule)?613 }614615 let when = Self::resolve_time(when)?;616617 618 let maybe_periodic = maybe_periodic619 .filter(|p| p.1 > 1 && !p.0.is_zero())620 621 .map(|(p, c)| (p, c - 1));622623 let s = Scheduled {624 maybe_id: Some(id.clone()), priority, call, maybe_periodic, origin, _phantom: Default::default()625 };626 Agenda::<T>::append(when, Some(s));627 let index = Agenda::<T>::decode_len(when).unwrap_or(1) as u32 - 1;628 if index > T::MaxScheduledPerBlock::get() {629 log::warn!(630 target: "runtime::scheduler",631 "Warning: There are more items queued in the Scheduler than \632 expected from the runtime configuration. An update might be needed.",633 );634 }635 let address = (when, index);636 Lookup::<T>::insert(&id, &address);637 Self::deposit_event(RawEvent::Scheduled(when, index));638639 Ok(address)640 }641642 fn do_cancel_named(origin: Option<T::PalletsOrigin>, id: Vec<u8>) -> DispatchResult {643 Lookup::<T>::try_mutate_exists(id, |lookup| -> DispatchResult {644 if let Some((when, index)) = lookup.take() {645 let i = index as usize;646 Agenda::<T>::try_mutate(when, |agenda| -> DispatchResult {647 if let Some(s) = agenda.get_mut(i) {648 if let (Some(ref o), Some(ref s)) = (origin, s.borrow()) {649 if *o != s.origin {650 return Err(BadOrigin.into());651 }652 }653 *s = None;654 }655 Ok(())656 })?;657 Self::deposit_event(RawEvent::Canceled(when, index));658 Ok(())659 } else {660 Err(Error::<T>::NotFound)?661 }662 })663 }664665 fn do_reschedule_named(666 id: Vec<u8>,667 new_time: DispatchTime<T::BlockNumber>,668 ) -> Result<TaskAddress<T::BlockNumber>, DispatchError> {669 let new_time = Self::resolve_time(new_time)?;670671 Lookup::<T>::try_mutate_exists(id, |lookup| -> Result<TaskAddress<T::BlockNumber>, DispatchError> {672 let (when, index) = lookup.ok_or(Error::<T>::NotFound)?;673674 if new_time == when {675 return Err(Error::<T>::RescheduleNoChange.into());676 }677678 Agenda::<T>::try_mutate(when, |agenda| -> DispatchResult {679 let task = agenda.get_mut(index as usize).ok_or(Error::<T>::NotFound)?;680 let task = task.take().ok_or(Error::<T>::NotFound)?;681 Agenda::<T>::append(new_time, Some(task));682683 Ok(())684 })?;685686 let new_index = Agenda::<T>::decode_len(new_time).unwrap_or(1) as u32 - 1;687 Self::deposit_event(RawEvent::Canceled(when, index));688 Self::deposit_event(RawEvent::Scheduled(new_time, new_index));689690 *lookup = Some((new_time, new_index));691692 Ok((new_time, new_index))693 })694 }695}696697impl<T: Config> schedule::Anon<T::BlockNumber, <T as Config>::Call, T::PalletsOrigin> for Module<T> {698 type Address = TaskAddress<T::BlockNumber>;699700 fn schedule(701 when: DispatchTime<T::BlockNumber>,702 maybe_periodic: Option<schedule::Period<T::BlockNumber>>,703 priority: schedule::Priority,704 origin: T::PalletsOrigin,705 call: <T as Config>::Call706 ) -> Result<Self::Address, DispatchError> {707 Self::do_schedule(when, maybe_periodic, priority, origin, call)708 }709710 fn cancel((when, index): Self::Address) -> Result<(), ()> {711 Self::do_cancel(None, (when, index)).map_err(|_| ())712 }713714 fn reschedule(715 address: Self::Address,716 when: DispatchTime<T::BlockNumber>,717 ) -> Result<Self::Address, DispatchError> {718 Self::do_reschedule(address, when)719 }720721 fn next_dispatch_time((when, index): Self::Address) -> Result<T::BlockNumber, ()> {722 Agenda::<T>::get(when).get(index as usize).ok_or(()).map(|_| when)723 }724}725726impl<T: Config> schedule::Named<T::BlockNumber, <T as Config>::Call, T::PalletsOrigin> for Module<T> {727 type Address = TaskAddress<T::BlockNumber>;728729 fn schedule_named(730 id: Vec<u8>,731 when: DispatchTime<T::BlockNumber>,732 maybe_periodic: Option<schedule::Period<T::BlockNumber>>,733 priority: schedule::Priority,734 origin: T::PalletsOrigin,735 call: <T as Config>::Call,736 ) -> Result<Self::Address, ()> {737 Self::do_schedule_named(id, when, maybe_periodic, priority, origin, call).map_err(|_| ())738 }739740 fn cancel_named(id: Vec<u8>) -> Result<(), ()> {741 Self::do_cancel_named(None, id).map_err(|_| ())742 }743744 fn reschedule_named(745 id: Vec<u8>,746 when: DispatchTime<T::BlockNumber>,747 ) -> Result<Self::Address, DispatchError> {748 Self::do_reschedule_named(id, when)749 }750751 fn next_dispatch_time(id: Vec<u8>) -> Result<T::BlockNumber, ()> {752 Lookup::<T>::get(id).and_then(|(when, index)| Agenda::<T>::get(when).get(index as usize).map(|_| when)).ok_or(())753 }754}755756#[cfg(test)]757mod tests {758 use super::*;759760 use frame_support::{761 parameter_types, assert_ok, ord_parameter_types,762 assert_noop, assert_err, Hashable,763 traits::{OnInitialize, OnFinalize, Filter},764 weights::constants::RocksDbWeight,765 };766 use sp_core::H256;767 use sp_runtime::{768 Perbill,769 testing::Header,770 traits::{BlakeTwo256, IdentityLookup},771 };772 use frame_system::{EnsureOneOf, EnsureRoot, EnsureSignedBy};773 use substrate_test_utils::assert_eq_uvec;774 use crate as scheduler;775776 mod logger {777 use super::*;778 use std::cell::RefCell;779780 thread_local! {781 static LOG: RefCell<Vec<(OriginCaller, u32)>> = RefCell::new(Vec::new());782 }783 pub fn log() -> Vec<(OriginCaller, u32)> {784 LOG.with(|log| log.borrow().clone())785 }786 pub trait Config: system::Config {787 type Event: From<Event> + Into<<Self as system::Config>::Event>;788 }789 decl_event! {790 pub enum Event {791 Logged(u32, Weight),792 }793 }794 decl_module! {795 pub struct Module<T: Config> for enum Call796 where797 origin: <T as system::Config>::Origin,798 <T as system::Config>::Origin: OriginTrait<PalletsOrigin = OriginCaller>799 {800 fn deposit_event() = default;801802 #[weight = *weight]803 fn log(origin, i: u32, weight: Weight) {804 Self::deposit_event(Event::Logged(i, weight));805 LOG.with(|log| {806 log.borrow_mut().push((origin.caller().clone(), i));807 })808 }809810 #[weight = *weight]811 fn log_without_filter(origin, i: u32, weight: Weight) {812 Self::deposit_event(Event::Logged(i, weight));813 LOG.with(|log| {814 log.borrow_mut().push((origin.caller().clone(), i));815 })816 }817 }818 }819 }820821 type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Test>;822 type Block = frame_system::mocking::MockBlock<Test>;823824 frame_support::construct_runtime!(825 pub enum Test where826 Block = Block,827 NodeBlock = Block,828 UncheckedExtrinsic = UncheckedExtrinsic,829 {830 System: frame_system::{Pallet, Call, Config, Storage, Event<T>},831 Logger: logger::{Pallet, Call, Event},832 Scheduler: scheduler::{Pallet, Call, Storage, Event<T>},833 }834 );835836 837 pub struct BaseFilter;838 impl Filter<Call> for BaseFilter {839 fn filter(call: &Call) -> bool {840 !matches!(call, Call::Logger(logger::Call::log(_, _)))841 }842 }843844 parameter_types! {845 pub const BlockHashCount: u64 = 250;846 pub BlockWeights: frame_system::limits::BlockWeights =847 frame_system::limits::BlockWeights::simple_max(2_000_000_000_000);848 }849 impl system::Config for Test {850 type BaseCallFilter = BaseFilter;851 type BlockWeights = ();852 type BlockLength = ();853 type DbWeight = RocksDbWeight;854 type Origin = Origin;855 type Call = Call;856 type Index = u64;857 type BlockNumber = u64;858 type Hash = H256;859 type Hashing = BlakeTwo256;860 type AccountId = u64;861 type Lookup = IdentityLookup<Self::AccountId>;862 type Header = Header;863 type Event = Event;864 type BlockHashCount = BlockHashCount;865 type Version = ();866 type PalletInfo = PalletInfo;867 type AccountData = ();868 type OnNewAccount = ();869 type OnKilledAccount = ();870 type SystemWeightInfo = ();871 type SS58Prefix = ();872 type OnSetCode = ();873 }874 impl logger::Config for Test {875 type Event = Event;876 }877 parameter_types! {878 pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) * BlockWeights::get().max_block;879 pub const MaxScheduledPerBlock: u32 = 10;880 }881 ord_parameter_types! {882 pub const One: u64 = 1;883 }884885 impl Config for Test {886 type Event = Event;887 type Origin = Origin;888 type PalletsOrigin = OriginCaller;889 type Call = Call;890 type MaximumWeight = MaximumSchedulerWeight;891 type ScheduleOrigin = EnsureOneOf<u64, EnsureRoot<u64>, EnsureSignedBy<One, u64>>;892 type MaxScheduledPerBlock = MaxScheduledPerBlock;893 type WeightInfo = ();894 }895896 pub fn new_test_ext() -> sp_io::TestExternalities {897 let t = system::GenesisConfig::default().build_storage::<Test>().unwrap();898 t.into()899 }900901 fn run_to_block(n: u64) {902 while System::block_number() < n {903 Scheduler::on_finalize(System::block_number());904 System::set_block_number(System::block_number() + 1);905 Scheduler::on_initialize(System::block_number());906 }907 }908909 fn root() -> OriginCaller {910 system::RawOrigin::Root.into()911 }912913 #[test]914 fn basic_scheduling_works() {915 new_test_ext().execute_with(|| {916 let call = Call::Logger(logger::Call::log(42, 1000));917 assert!(!<Test as frame_system::Config>::BaseCallFilter::filter(&call));918 assert_ok!(Scheduler::do_schedule(DispatchTime::At(4), None, 127, root(), call));919 run_to_block(3);920 assert!(logger::log().is_empty());921 run_to_block(4);922 assert_eq!(logger::log(), vec![(root(), 42u32)]);923 run_to_block(100);924 assert_eq!(logger::log(), vec![(root(), 42u32)]);925 });926 }927928 #[test]929 fn schedule_after_works() {930 new_test_ext().execute_with(|| {931 run_to_block(2);932 let call = Call::Logger(logger::Call::log(42, 1000));933 assert!(!<Test as frame_system::Config>::BaseCallFilter::filter(&call));934 935 assert_ok!(Scheduler::do_schedule(DispatchTime::After(3), None, 127, root(), call));936 run_to_block(5);937 assert!(logger::log().is_empty());938 run_to_block(6);939 assert_eq!(logger::log(), vec![(root(), 42u32)]);940 run_to_block(100);941 assert_eq!(logger::log(), vec![(root(), 42u32)]);942 });943 }944945 #[test]946 fn schedule_after_zero_works() {947 new_test_ext().execute_with(|| {948 run_to_block(2);949 let call = Call::Logger(logger::Call::log(42, 1000));950 assert!(!<Test as frame_system::Config>::BaseCallFilter::filter(&call));951 assert_ok!(Scheduler::do_schedule(DispatchTime::After(0), None, 127, root(), call));952 953 run_to_block(3);954 assert_eq!(logger::log(), vec![(root(), 42u32)]);955 run_to_block(100);956 assert_eq!(logger::log(), vec![(root(), 42u32)]);957 });958 }959960 #[test]961 fn periodic_scheduling_works() {962 new_test_ext().execute_with(|| {963 964 assert_ok!(Scheduler::do_schedule(965 DispatchTime::At(4), Some((3, 3)), 127, root(), Call::Logger(logger::Call::log(42, 1000))966 ));967 run_to_block(3);968 assert!(logger::log().is_empty());969 run_to_block(4);970 assert_eq!(logger::log(), vec![(root(), 42u32)]);971 run_to_block(6);972 assert_eq!(logger::log(), vec![(root(), 42u32)]);973 run_to_block(7);974 assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32)]);975 run_to_block(9);976 assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32)]);977 run_to_block(10);978 assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32), (root(), 42u32)]);979 run_to_block(100);980 assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32), (root(), 42u32)]);981 });982 }983984 #[test]985 fn reschedule_works() {986 new_test_ext().execute_with(|| {987 let call = Call::Logger(logger::Call::log(42, 1000));988 assert!(!<Test as frame_system::Config>::BaseCallFilter::filter(&call));989 assert_eq!(Scheduler::do_schedule(DispatchTime::At(4), None, 127, root(), call).unwrap(), (4, 0));990991 run_to_block(3);992 assert!(logger::log().is_empty());993994 assert_eq!(Scheduler::do_reschedule((4, 0), DispatchTime::At(6)).unwrap(), (6, 0));995996 assert_noop!(Scheduler::do_reschedule((6, 0), DispatchTime::At(6)), Error::<Test>::RescheduleNoChange);997998 run_to_block(4);999 assert!(logger::log().is_empty());10001001 run_to_block(6);1002 assert_eq!(logger::log(), vec![(root(), 42u32)]);10031004 run_to_block(100);1005 assert_eq!(logger::log(), vec![(root(), 42u32)]);1006 });1007 }10081009 #[test]1010 fn reschedule_named_works() {1011 new_test_ext().execute_with(|| {1012 let call = Call::Logger(logger::Call::log(42, 1000));1013 assert!(!<Test as frame_system::Config>::BaseCallFilter::filter(&call));1014 assert_eq!(Scheduler::do_schedule_named(1015 1u32.encode(), DispatchTime::At(4), None, 127, root(), call1016 ).unwrap(), (4, 0));10171018 run_to_block(3);1019 assert!(logger::log().is_empty());10201021 assert_eq!(Scheduler::do_reschedule_named(1u32.encode(), DispatchTime::At(6)).unwrap(), (6, 0));10221023 assert_noop!(Scheduler::do_reschedule_named(1u32.encode(), DispatchTime::At(6)), Error::<Test>::RescheduleNoChange);10241025 run_to_block(4);1026 assert!(logger::log().is_empty());10271028 run_to_block(6);1029 assert_eq!(logger::log(), vec![(root(), 42u32)]);10301031 run_to_block(100);1032 assert_eq!(logger::log(), vec![(root(), 42u32)]);1033 });1034 }10351036 #[test]1037 fn reschedule_named_perodic_works() {1038 new_test_ext().execute_with(|| {1039 let call = Call::Logger(logger::Call::log(42, 1000));1040 assert!(!<Test as frame_system::Config>::BaseCallFilter::filter(&call));1041 assert_eq!(Scheduler::do_schedule_named(1042 1u32.encode(), DispatchTime::At(4), Some((3, 3)), 127, root(), call1043 ).unwrap(), (4, 0));10441045 run_to_block(3);1046 assert!(logger::log().is_empty());10471048 assert_eq!(Scheduler::do_reschedule_named(1u32.encode(), DispatchTime::At(5)).unwrap(), (5, 0));1049 assert_eq!(Scheduler::do_reschedule_named(1u32.encode(), DispatchTime::At(6)).unwrap(), (6, 0));10501051 run_to_block(5);1052 assert!(logger::log().is_empty());10531054 run_to_block(6);1055 assert_eq!(logger::log(), vec![(root(), 42u32)]);10561057 assert_eq!(Scheduler::do_reschedule_named(1u32.encode(), DispatchTime::At(10)).unwrap(), (10, 0));10581059 run_to_block(9);1060 assert_eq!(logger::log(), vec![(root(), 42u32)]);10611062 run_to_block(10);1063 assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32)]);10641065 run_to_block(13);1066 assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32), (root(), 42u32)]);10671068 run_to_block(100);1069 assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32), (root(), 42u32)]);1070 });1071 }10721073 #[test]1074 fn cancel_named_scheduling_works_with_normal_cancel() {1075 new_test_ext().execute_with(|| {1076 1077 Scheduler::do_schedule_named(1078 1u32.encode(), DispatchTime::At(4), None, 127, root(), Call::Logger(logger::Call::log(69, 1000))1079 ).unwrap();1080 let i = Scheduler::do_schedule(1081 DispatchTime::At(4), None, 127, root(), Call::Logger(logger::Call::log(42, 1000))1082 ).unwrap();1083 run_to_block(3);1084 assert!(logger::log().is_empty());1085 assert_ok!(Scheduler::do_cancel_named(None, 1u32.encode()));1086 assert_ok!(Scheduler::do_cancel(None, i));1087 run_to_block(100);1088 assert!(logger::log().is_empty());1089 });1090 }10911092 #[test]1093 fn cancel_named_periodic_scheduling_works() {1094 new_test_ext().execute_with(|| {1095 1096 Scheduler::do_schedule_named(1097 1u32.encode(),1098 DispatchTime::At(4),1099 Some((3, 3)),1100 127,1101 root(),1102 Call::Logger(logger::Call::log(42, 1000))1103 ).unwrap();1104 1105 assert!(Scheduler::do_schedule_named(1106 1u32.encode(),1107 DispatchTime::At(4),1108 None,1109 127,1110 root(),1111 Call::Logger(logger::Call::log(69, 1000))1112 ).is_err());1113 1114 Scheduler::do_schedule_named(1115 2u32.encode(), DispatchTime::At(8), None, 127, root(), Call::Logger(logger::Call::log(69, 1000))1116 ).unwrap();1117 run_to_block(3);1118 assert!(logger::log().is_empty());1119 run_to_block(4);1120 assert_eq!(logger::log(), vec![(root(), 42u32)]);1121 run_to_block(6);1122 assert_ok!(Scheduler::do_cancel_named(None, 1u32.encode()));1123 run_to_block(100);1124 assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 69u32)]);1125 });1126 }11271128 #[test]1129 fn scheduler_respects_weight_limits() {1130 new_test_ext().execute_with(|| {1131 assert_ok!(Scheduler::do_schedule(1132 DispatchTime::At(4),1133 None,1134 127,1135 root(),1136 Call::Logger(logger::Call::log(42, MaximumSchedulerWeight::get() / 2))1137 ));1138 assert_ok!(Scheduler::do_schedule(1139 DispatchTime::At(4),1140 None,1141 127,1142 root(), Call::Logger(logger::Call::log(69, MaximumSchedulerWeight::get() / 2))1143 ));1144 1145 run_to_block(4);1146 assert_eq!(logger::log(), vec![(root(), 42u32)]);1147 run_to_block(5);1148 assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 69u32)]);1149 });1150 }11511152 #[test]1153 fn scheduler_respects_hard_deadlines_more() {1154 new_test_ext().execute_with(|| {1155 assert_ok!(Scheduler::do_schedule(1156 DispatchTime::At(4),1157 None,1158 0,1159 root(),1160 Call::Logger(logger::Call::log(42, MaximumSchedulerWeight::get() / 2))1161 ));1162 assert_ok!(Scheduler::do_schedule(1163 DispatchTime::At(4),1164 None,1165 0,1166 root(),1167 Call::Logger(logger::Call::log(69, MaximumSchedulerWeight::get() / 2))1168 ));1169 1170 run_to_block(4);1171 assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 69u32)]);1172 });1173 }11741175 #[test]1176 fn scheduler_respects_priority_ordering() {1177 new_test_ext().execute_with(|| {1178 assert_ok!(Scheduler::do_schedule(1179 DispatchTime::At(4),1180 None,1181 1,1182 root(),1183 Call::Logger(logger::Call::log(42, MaximumSchedulerWeight::get() / 2))1184 ));1185 assert_ok!(Scheduler::do_schedule(1186 DispatchTime::At(4),1187 None,1188 0,1189 root(),1190 Call::Logger(logger::Call::log(69, MaximumSchedulerWeight::get() / 2))1191 ));1192 run_to_block(4);1193 assert_eq!(logger::log(), vec![(root(), 69u32), (root(), 42u32)]);1194 });1195 }11961197 #[test]1198 fn scheduler_respects_priority_ordering_with_soft_deadlines() {1199 new_test_ext().execute_with(|| {1200 assert_ok!(Scheduler::do_schedule(1201 DispatchTime::At(4),1202 None,1203 255,1204 root(), Call::Logger(logger::Call::log(42, MaximumSchedulerWeight::get() / 3))1205 ));1206 assert_ok!(Scheduler::do_schedule(1207 DispatchTime::At(4),1208 None,1209 127,1210 root(), Call::Logger(logger::Call::log(69, MaximumSchedulerWeight::get() / 2))1211 ));1212 assert_ok!(Scheduler::do_schedule(1213 DispatchTime::At(4),1214 None,1215 126,1216 root(), Call::Logger(logger::Call::log(2600, MaximumSchedulerWeight::get() / 2))1217 ));12181219 1220 run_to_block(4);1221 assert_eq!(logger::log(), vec![(root(), 2600u32)]);1222 1223 run_to_block(5);1224 assert_eq!(logger::log(), vec![(root(), 2600u32), (root(), 69u32), (root(), 42u32)]);1225 });1226 }12271228 #[test]1229 fn on_initialize_weight_is_correct() {1230 new_test_ext().execute_with(|| {1231 let base_weight: Weight = <Test as frame_system::Config>::DbWeight::get().reads_writes(1, 2);1232 let base_multiplier = 0;1233 let named_multiplier = <Test as frame_system::Config>::DbWeight::get().writes(1);1234 let periodic_multiplier = <Test as frame_system::Config>::DbWeight::get().reads_writes(1, 1);12351236 1237 assert_ok!(1238 Scheduler::do_schedule_named(1239 1u32.encode(), DispatchTime::At(1), None, 255, root(),1240 Call::Logger(logger::Call::log(3, MaximumSchedulerWeight::get() / 3))1241 )1242 );1243 1244 assert_ok!(Scheduler::do_schedule(1245 DispatchTime::At(1),1246 Some((1000, 3)),1247 128,1248 root(),1249 Call::Logger(logger::Call::log(42, MaximumSchedulerWeight::get() / 3))1250 ));1251 1252 assert_ok!(Scheduler::do_schedule(1253 DispatchTime::At(1),1254 None,1255 127,1256 root(),1257 Call::Logger(logger::Call::log(69, MaximumSchedulerWeight::get() / 2))1258 ));1259 1260 assert_ok!(Scheduler::do_schedule_named(1261 2u32.encode(), DispatchTime::At(1), Some((1000, 3)), 126, root(),1262 Call::Logger(logger::Call::log(2600, MaximumSchedulerWeight::get() / 2)))1263 );12641265 1266 let actual_weight = Scheduler::on_initialize(1);1267 let call_weight = MaximumSchedulerWeight::get() / 2;1268 assert_eq!(1269 actual_weight, call_weight + base_weight + base_multiplier + named_multiplier + periodic_multiplier1270 );1271 assert_eq!(logger::log(), vec![(root(), 2600u32)]);12721273 1274 let actual_weight = Scheduler::on_initialize(2);1275 let call_weight = MaximumSchedulerWeight::get() / 2 + MaximumSchedulerWeight::get() / 3;1276 assert_eq!(actual_weight, call_weight + base_weight + base_multiplier * 2 + periodic_multiplier);1277 assert_eq!(logger::log(), vec![(root(), 2600u32), (root(), 69u32), (root(), 42u32)]);12781279 1280 let actual_weight = Scheduler::on_initialize(3);1281 let call_weight = MaximumSchedulerWeight::get() / 3;1282 assert_eq!(actual_weight, call_weight + base_weight + base_multiplier + named_multiplier);1283 assert_eq!(logger::log(), vec![(root(), 2600u32), (root(), 69u32), (root(), 42u32), (root(), 3u32)]);12841285 1286 let actual_weight = Scheduler::on_initialize(4);1287 assert_eq!(actual_weight, 0);1288 });1289 }12901291 #[test]1292 fn root_calls_works() {1293 new_test_ext().execute_with(|| {1294 let call = Box::new(Call::Logger(logger::Call::log(69, 1000)));1295 let call2 = Box::new(Call::Logger(logger::Call::log(42, 1000)));1296 assert_ok!(Scheduler::schedule_named(Origin::root(), 1u32.encode(), 4, None, 127, call));1297 assert_ok!(Scheduler::schedule(Origin::root(), 4, None, 127, call2));1298 run_to_block(3);1299 1300 assert_eq!(Agenda::<Test>::get(4).len(), 2);1301 assert!(logger::log().is_empty());1302 assert_ok!(Scheduler::cancel_named(Origin::root(), 1u32.encode()));1303 assert_ok!(Scheduler::cancel(Origin::root(), 4, 1));1304 1305 run_to_block(100);1306 assert!(logger::log().is_empty());1307 });1308 }13091310 #[test]1311 fn fails_to_schedule_task_in_the_past() {1312 new_test_ext().execute_with(|| {1313 run_to_block(3);13141315 let call = Box::new(Call::Logger(logger::Call::log(69, 1000)));1316 let call2 = Box::new(Call::Logger(logger::Call::log(42, 1000)));13171318 assert_err!(1319 Scheduler::schedule_named(Origin::root(), 1u32.encode(), 2, None, 127, call),1320 Error::<Test>::TargetBlockNumberInPast,1321 );13221323 assert_err!(1324 Scheduler::schedule(Origin::root(), 2, None, 127, call2.clone()),1325 Error::<Test>::TargetBlockNumberInPast,1326 );13271328 assert_err!(1329 Scheduler::schedule(Origin::root(), 3, None, 127, call2),1330 Error::<Test>::TargetBlockNumberInPast,1331 );1332 });1333 }13341335 #[test]1336 fn should_use_orign() {1337 new_test_ext().execute_with(|| {1338 let call = Box::new(Call::Logger(logger::Call::log(69, 1000)));1339 let call2 = Box::new(Call::Logger(logger::Call::log(42, 1000)));1340 assert_ok!(1341 Scheduler::schedule_named(system::RawOrigin::Signed(1).into(), 1u32.encode(), 4, None, 127, call)1342 );1343 assert_ok!(Scheduler::schedule(system::RawOrigin::Signed(1).into(), 4, None, 127, call2));1344 run_to_block(3);1345 1346 assert_eq!(Agenda::<Test>::get(4).len(), 2);1347 assert!(logger::log().is_empty());1348 assert_ok!(Scheduler::cancel_named(system::RawOrigin::Signed(1).into(), 1u32.encode()));1349 assert_ok!(Scheduler::cancel(system::RawOrigin::Signed(1).into(), 4, 1));1350 1351 run_to_block(100);1352 assert!(logger::log().is_empty());1353 });1354 }13551356 #[test]1357 fn should_check_orign() {1358 new_test_ext().execute_with(|| {1359 let call = Box::new(Call::Logger(logger::Call::log(69, 1000)));1360 let call2 = Box::new(Call::Logger(logger::Call::log(42, 1000)));1361 assert_noop!(1362 Scheduler::schedule_named(system::RawOrigin::Signed(2).into(), 1u32.encode(), 4, None, 127, call),1363 BadOrigin1364 );1365 assert_noop!(Scheduler::schedule(system::RawOrigin::Signed(2).into(), 4, None, 127, call2), BadOrigin);1366 });1367 }13681369 #[test]1370 fn should_check_orign_for_cancel() {1371 new_test_ext().execute_with(|| {1372 let call = Box::new(Call::Logger(logger::Call::log_without_filter(69, 1000)));1373 let call2 = Box::new(Call::Logger(logger::Call::log_without_filter(42, 1000)));1374 assert_ok!(1375 Scheduler::schedule_named(system::RawOrigin::Signed(1).into(), 1u32.encode(), 4, None, 127, call)1376 );1377 assert_ok!(Scheduler::schedule(system::RawOrigin::Signed(1).into(), 4, None, 127, call2));1378 run_to_block(3);1379 1380 assert_eq!(Agenda::<Test>::get(4).len(), 2);1381 assert!(logger::log().is_empty());1382 assert_noop!(Scheduler::cancel_named(system::RawOrigin::Signed(2).into(), 1u32.encode()), BadOrigin);1383 assert_noop!(Scheduler::cancel(system::RawOrigin::Signed(2).into(), 4, 1), BadOrigin);1384 assert_noop!(Scheduler::cancel_named(system::RawOrigin::Root.into(), 1u32.encode()), BadOrigin);1385 assert_noop!(Scheduler::cancel(system::RawOrigin::Root.into(), 4, 1), BadOrigin);1386 run_to_block(5);1387 assert_eq!(1388 logger::log(),1389 vec![(system::RawOrigin::Signed(1).into(), 69u32), (system::RawOrigin::Signed(1).into(), 42u32)]1390 );1391 });1392 }13931394 #[test]1395 fn migration_to_v2_works() {1396 new_test_ext().execute_with(|| {1397 for i in 0..3u64 {1398 let k = i.twox_64_concat();1399 let old = vec![1400 Some(ScheduledV1 {1401 maybe_id: None,1402 priority: i as u8 + 10,1403 call: Call::Logger(logger::Call::log(96, 100)),1404 maybe_periodic: None,1405 }),1406 None,1407 Some(ScheduledV1 {1408 maybe_id: Some(b"test".to_vec()),1409 priority: 123,1410 call: Call::Logger(logger::Call::log(69, 1000)),1411 maybe_periodic: Some((456u64, 10)),1412 }),1413 ];1414 frame_support::migration::put_storage_value(1415 b"Scheduler",1416 b"Agenda",1417 &k,1418 old,1419 );1420 }14211422 assert_eq!(StorageVersion::get(), Releases::V1);14231424 assert!(Scheduler::migrate_v1_to_t2());14251426 assert_eq_uvec!(Agenda::<Test>::iter().collect::<Vec<_>>(), vec![1427 (1428 0,1429 vec![1430 Some(ScheduledV2 {1431 maybe_id: None,1432 priority: 10,1433 call: Call::Logger(logger::Call::log(96, 100)),1434 maybe_periodic: None,1435 origin: root(),1436 _phantom: PhantomData::<u64>::default(),1437 }),1438 None,1439 Some(ScheduledV2 {1440 maybe_id: Some(b"test".to_vec()),1441 priority: 123,1442 call: Call::Logger(logger::Call::log(69, 1000)),1443 maybe_periodic: Some((456u64, 10)),1444 origin: root(),1445 _phantom: PhantomData::<u64>::default(),1446 }),1447 ]),1448 (1449 1,1450 vec![1451 Some(ScheduledV2 {1452 maybe_id: None,1453 priority: 11,1454 call: Call::Logger(logger::Call::log(96, 100)),1455 maybe_periodic: None,1456 origin: root(),1457 _phantom: PhantomData::<u64>::default(),1458 }),1459 None,1460 Some(ScheduledV2 {1461 maybe_id: Some(b"test".to_vec()),1462 priority: 123,1463 call: Call::Logger(logger::Call::log(69, 1000)),1464 maybe_periodic: Some((456u64, 10)),1465 origin: root(),1466 _phantom: PhantomData::<u64>::default(),1467 }),1468 ]1469 ),1470 (1471 2,1472 vec![1473 Some(ScheduledV2 {1474 maybe_id: None,1475 priority: 12,1476 call: Call::Logger(logger::Call::log(96, 100)),1477 maybe_periodic: None,1478 origin: root(),1479 _phantom: PhantomData::<u64>::default(),1480 }),1481 None,1482 Some(ScheduledV2 {1483 maybe_id: Some(b"test".to_vec()),1484 priority: 123,1485 call: Call::Logger(logger::Call::log(69, 1000)),1486 maybe_periodic: Some((456u64, 10)),1487 origin: root(),1488 _phantom: PhantomData::<u64>::default(),1489 }),1490 ]1491 )1492 ]);14931494 assert_eq!(StorageVersion::get(), Releases::V2);1495 });1496 }14971498 #[test]1499 fn test_migrate_origin() {1500 new_test_ext().execute_with(|| {1501 for i in 0..3u64 {1502 let k = i.twox_64_concat();1503 let old: Vec<Option<Scheduled<_, _, u32, u64>>> = vec![1504 Some(Scheduled {1505 maybe_id: None,1506 priority: i as u8 + 10,1507 call: Call::Logger(logger::Call::log(96, 100)),1508 origin: 3u32,1509 maybe_periodic: None,1510 _phantom: Default::default(),1511 }),1512 None,1513 Some(Scheduled {1514 maybe_id: Some(b"test".to_vec()),1515 priority: 123,1516 origin: 2u32,1517 call: Call::Logger(logger::Call::log(69, 1000)),1518 maybe_periodic: Some((456u64, 10)),1519 _phantom: Default::default(),1520 }),1521 ];1522 frame_support::migration::put_storage_value(1523 b"Scheduler",1524 b"Agenda",1525 &k,1526 old,1527 );1528 }15291530 impl Into<OriginCaller> for u32 {1531 fn into(self) -> OriginCaller {1532 match self {1533 3u32 => system::RawOrigin::Root.into(),1534 2u32 => system::RawOrigin::None.into(),1535 _ => unreachable!("test make no use of it"),1536 }1537 }1538 }15391540 Scheduler::migrate_origin::<u32>();15411542 assert_eq_uvec!(Agenda::<Test>::iter().collect::<Vec<_>>(), vec![1543 (1544 0,1545 vec![1546 Some(ScheduledV2::<_, _, OriginCaller, u64> {1547 maybe_id: None,1548 priority: 10,1549 call: Call::Logger(logger::Call::log(96, 100)),1550 maybe_periodic: None,1551 origin: system::RawOrigin::Root.into(),1552 _phantom: PhantomData::<u64>::default(),1553 }),1554 None,1555 Some(ScheduledV2 {1556 maybe_id: Some(b"test".to_vec()),1557 priority: 123,1558 call: Call::Logger(logger::Call::log(69, 1000)),1559 maybe_periodic: Some((456u64, 10)),1560 origin: system::RawOrigin::None.into(),1561 _phantom: PhantomData::<u64>::default(),1562 }),1563 ]),1564 (1565 1,1566 vec![1567 Some(ScheduledV2 {1568 maybe_id: None,1569 priority: 11,1570 call: Call::Logger(logger::Call::log(96, 100)),1571 maybe_periodic: None,1572 origin: system::RawOrigin::Root.into(),1573 _phantom: PhantomData::<u64>::default(),1574 }),1575 None,1576 Some(ScheduledV2 {1577 maybe_id: Some(b"test".to_vec()),1578 priority: 123,1579 call: Call::Logger(logger::Call::log(69, 1000)),1580 maybe_periodic: Some((456u64, 10)),1581 origin: system::RawOrigin::None.into(),1582 _phantom: PhantomData::<u64>::default(),1583 }),1584 ]1585 ),1586 (1587 2,1588 vec![1589 Some(ScheduledV2 {1590 maybe_id: None,1591 priority: 12,1592 call: Call::Logger(logger::Call::log(96, 100)),1593 maybe_periodic: None,1594 origin: system::RawOrigin::Root.into(),1595 _phantom: PhantomData::<u64>::default(),1596 }),1597 None,1598 Some(ScheduledV2 {1599 maybe_id: Some(b"test".to_vec()),1600 priority: 123,1601 call: Call::Logger(logger::Call::log(69, 1000)),1602 maybe_periodic: Some((456u64, 10)),1603 origin: system::RawOrigin::None.into(),1604 _phantom: PhantomData::<u64>::default(),1605 }),1606 ]1607 )1608 ]);1609 });1610 }1611}