12345678910111213141516171819202122232425262728293031323334353637use super::*;38use frame_benchmarking::{account, benchmarks};39use frame_support::{40 ensure,41 traits::{schedule::Priority, PreimageRecipient},42};43use frame_system::RawOrigin;44use sp_std::{prelude::*, vec};4546use crate::{Pallet as Scheduler, ScheduledCall, EncodedCall};47use frame_system::Call as SystemCall;4849const SEED: u32 = 0;5051const BLOCK_NUMBER: u32 = 2;5253type SystemOrigin<T> = <T as frame_system::Config>::Origin;545556575859606162fn fill_schedule<T: Config>(when: T::BlockNumber, n: u32) -> Result<(), &'static str> {63 let t = DispatchTime::At(when);64 let origin: <T as Config>::PalletsOrigin = frame_system::RawOrigin::Root.into();65 for i in 0..n {66 let call = make_call::<T>(None);67 let period = Some(((i + 100).into(), 100));68 let name = u32_to_name(i);69 Scheduler::<T>::do_schedule_named(name, t, period, 0, origin.clone(), call)?;70 }71 ensure!(Agenda::<T>::get(when).len() == n as usize, "didn't fill schedule");72 Ok(())73}7475fn u32_to_name(i: u32) -> TaskName {76 i.using_encoded(blake2_256)77}7879fn make_task<T: Config>(80 periodic: bool,81 named: bool,82 signed: bool,83 maybe_lookup_len: Option<u32>,84 priority: Priority,85) -> ScheduledOf<T> {86 let call = make_call::<T>(maybe_lookup_len);87 let maybe_periodic = match periodic {88 true => Some((100u32.into(), 100)),89 false => None,90 };91 let maybe_id = match named {92 true => Some(u32_to_name(0)),93 false => None,94 };95 let origin = make_origin::<T>(signed);96 Scheduled { maybe_id, priority, call, maybe_periodic, origin, _phantom: PhantomData }97}9899fn bounded<T: Config>(len: u32) -> Option<ScheduledCall<T>> {100 let call =101 <<T as Config>::Call>::from(SystemCall::remark { remark: vec![0; len as usize] });102 ScheduledCall::new(call).ok()103}104105fn make_call<T: Config>(maybe_lookup_len: Option<u32>) -> ScheduledCall<T> {106 let bound = EncodedCall::bound() as u32;107 let mut len = match maybe_lookup_len {108 Some(len) => len.min(<T::Preimages as PreimageRecipient<T::Hash>>::MaxSize::get() - 2).max(bound) - 3,109 None => bound.saturating_sub(4),110 };111112 loop {113 let c = match bounded::<T>(len) {114 Some(x) => x,115 None => {116 len -= 1;117 continue118 },119 };120 if c.lookup_needed() == maybe_lookup_len.is_some() {121 break c122 }123 if maybe_lookup_len.is_some() {124 len += 1;125 } else {126 if len > 0 {127 len -= 1;128 } else {129 break c130 }131 }132 }133}134135fn make_origin<T: Config>(signed: bool) -> <T as Config>::PalletsOrigin {136 match signed {137 true => frame_system::RawOrigin::Signed(account("origin", 0, SEED)).into(),138 false => frame_system::RawOrigin::Root.into(),139 }140}141142fn dummy_counter() -> WeightCounter {143 WeightCounter { used: Weight::zero(), limit: Weight::MAX }144}145146benchmarks! {147 148 service_agendas_base {149 let now = T::BlockNumber::from(BLOCK_NUMBER);150 IncompleteSince::<T>::put(now - One::one());151 }: {152 Scheduler::<T>::service_agendas(&mut dummy_counter(), now, 0);153 } verify {154 assert_eq!(IncompleteSince::<T>::get(), Some(now - One::one()));155 }156157 158 service_agenda_base {159 let now = BLOCK_NUMBER.into();160 let s in 0 .. T::MaxScheduledPerBlock::get();161 fill_schedule::<T>(now, s)?;162 let mut executed = 0;163 }: {164 Scheduler::<T>::service_agenda(&mut dummy_counter(), &mut executed, now, now, 0);165 } verify {166 assert_eq!(executed, 0);167 }168169 170 171 service_task_base {172 let now = BLOCK_NUMBER.into();173 let task = make_task::<T>(false, false, false, None, 0);174 175 let mut counter = WeightCounter { used: Weight::zero(), limit: Weight::zero() };176 }: {177 let result = Scheduler::<T>::service_task(&mut counter, now, now, 0, true, task);178 } verify {179 180 }181182 183 184 service_task_fetched {185 let s in (EncodedCall::bound() as u32) .. (<T::Preimages as PreimageRecipient<T::Hash>>::MaxSize::get());186 let now = BLOCK_NUMBER.into();187 let task = make_task::<T>(false, false, false, Some(s), 0);188 189 let mut counter = WeightCounter { used: Weight::zero(), limit: Weight::zero() };190 }: {191 let result = Scheduler::<T>::service_task(&mut counter, now, now, 0, true, task);192 } verify {193 }194195 196 197 service_task_named {198 let now = BLOCK_NUMBER.into();199 let task = make_task::<T>(false, true, false, None, 0);200 201 let mut counter = WeightCounter { used: Weight::zero(), limit: Weight::zero() };202 }: {203 let result = Scheduler::<T>::service_task(&mut counter, now, now, 0, true, task);204 } verify {205 }206207 208 209 service_task_periodic {210 let now = BLOCK_NUMBER.into();211 let task = make_task::<T>(true, false, false, None, 0);212 213 let mut counter = WeightCounter { used: Weight::zero(), limit: Weight::zero() };214 }: {215 let result = Scheduler::<T>::service_task(&mut counter, now, now, 0, true, task);216 } verify {217 }218219 220 execute_dispatch_signed {221 let mut counter = WeightCounter { used: Weight::zero(), limit: Weight::MAX };222 let origin = make_origin::<T>(true);223 let call = T::Preimages::realize(&make_call::<T>(None)).unwrap().0;224 }: {225 assert!(Scheduler::<T>::execute_dispatch(&mut counter, origin, call).is_ok());226 }227 verify {228 }229230 231 execute_dispatch_unsigned {232 let mut counter = WeightCounter { used: Weight::zero(), limit: Weight::MAX };233 let origin = make_origin::<T>(false);234 let call = T::Preimages::realize(&make_call::<T>(None)).unwrap().0;235 }: {236 assert!(Scheduler::<T>::execute_dispatch(&mut counter, origin, call).is_ok());237 }238 verify {239 }240241 schedule {242 let s in 0 .. (T::MaxScheduledPerBlock::get() - 1);243 let when = BLOCK_NUMBER.into();244 let periodic = Some((T::BlockNumber::one(), 100));245 let priority = 0;246 247 let call = Box::new(SystemCall::set_storage { items: vec![] }.into());248249 fill_schedule::<T>(when, s)?;250 }: _(RawOrigin::Root, when, periodic, priority, call)251 verify {252 ensure!(253 Agenda::<T>::get(when).len() == (s + 1) as usize,254 "didn't add to schedule"255 );256 }257258 cancel {259 let s in 1 .. T::MaxScheduledPerBlock::get();260 let when = BLOCK_NUMBER.into();261262 fill_schedule::<T>(when, s)?;263 assert_eq!(Agenda::<T>::get(when).len(), s as usize);264 let schedule_origin = T::ScheduleOrigin::successful_origin();265 }: _<SystemOrigin<T>>(schedule_origin, when, 0)266 verify {267 ensure!(268 Lookup::<T>::get(u32_to_name(0)).is_none(),269 "didn't remove from lookup"270 );271 272 ensure!(273 Agenda::<T>::get(when)[0].is_none(),274 "didn't remove from schedule"275 );276 }277278 schedule_named {279 let s in 0 .. (T::MaxScheduledPerBlock::get() - 1);280 let id = u32_to_name(s);281 let when = BLOCK_NUMBER.into();282 let periodic = Some((T::BlockNumber::one(), 100));283 let priority = 0;284 285 let call = Box::new(SystemCall::set_storage { items: vec![] }.into());286287 fill_schedule::<T>(when, s)?;288 }: _(RawOrigin::Root, id, when, periodic, priority, call)289 verify {290 ensure!(291 Agenda::<T>::get(when).len() == (s + 1) as usize,292 "didn't add to schedule"293 );294 }295296 cancel_named {297 let s in 1 .. T::MaxScheduledPerBlock::get();298 let when = BLOCK_NUMBER.into();299300 fill_schedule::<T>(when, s)?;301 }: _(RawOrigin::Root, u32_to_name(0))302 verify {303 ensure!(304 Lookup::<T>::get(u32_to_name(0)).is_none(),305 "didn't remove from lookup"306 );307 308 ensure!(309 Agenda::<T>::get(when)[0].is_none(),310 "didn't remove from schedule"311 );312 }313314 315}