mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-17 10:11:03 +00:00
reschedule (#6860)
* reschedule * add tests * Apply suggestions from code review Co-authored-by: Dan Forbes <dan@danforbes.dev> * add test for reschedule named perodic * update test * handle the case when reschedule does not change time Co-authored-by: Dan Forbes <dan@danforbes.dev> Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com>
This commit is contained in:
@@ -186,10 +186,12 @@ decl_error! {
|
||||
pub enum Error for Module<T: Trait> {
|
||||
/// Failed to schedule a call
|
||||
FailedToSchedule,
|
||||
/// Failed to cancel a scheduled call
|
||||
FailedToCancel,
|
||||
/// Cannot find the scheduled call.
|
||||
NotFound,
|
||||
/// Given target block number is in the past.
|
||||
TargetBlockNumberInPast,
|
||||
/// Reschedule failed because it does not change scheduled time.
|
||||
RescheduleNoChange,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -467,13 +469,7 @@ impl<T: Trait> Module<T> {
|
||||
));
|
||||
}
|
||||
|
||||
fn do_schedule(
|
||||
when: DispatchTime<T::BlockNumber>,
|
||||
maybe_periodic: Option<schedule::Period<T::BlockNumber>>,
|
||||
priority: schedule::Priority,
|
||||
origin: T::PalletsOrigin,
|
||||
call: <T as Trait>::Call
|
||||
) -> Result<TaskAddress<T::BlockNumber>, DispatchError> {
|
||||
fn resolve_time(when: DispatchTime<T::BlockNumber>) -> Result<T::BlockNumber, DispatchError> {
|
||||
let now = frame_system::Module::<T>::block_number();
|
||||
|
||||
let when = match when {
|
||||
@@ -485,6 +481,18 @@ impl<T: Trait> Module<T> {
|
||||
return Err(Error::<T>::TargetBlockNumberInPast.into())
|
||||
}
|
||||
|
||||
Ok(when)
|
||||
}
|
||||
|
||||
fn do_schedule(
|
||||
when: DispatchTime<T::BlockNumber>,
|
||||
maybe_periodic: Option<schedule::Period<T::BlockNumber>>,
|
||||
priority: schedule::Priority,
|
||||
origin: T::PalletsOrigin,
|
||||
call: <T as Trait>::Call
|
||||
) -> Result<TaskAddress<T::BlockNumber>, DispatchError> {
|
||||
let when = Self::resolve_time(when)?;
|
||||
|
||||
// sanitize maybe_periodic
|
||||
let maybe_periodic = maybe_periodic
|
||||
.filter(|p| p.1 > 1 && !p.0.is_zero())
|
||||
@@ -531,10 +539,34 @@ impl<T: Trait> Module<T> {
|
||||
Self::deposit_event(RawEvent::Canceled(when, index));
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::<T>::FailedToCancel)?
|
||||
Err(Error::<T>::NotFound)?
|
||||
}
|
||||
}
|
||||
|
||||
fn do_reschedule(
|
||||
(when, index): TaskAddress<T::BlockNumber>,
|
||||
new_time: DispatchTime<T::BlockNumber>,
|
||||
) -> Result<TaskAddress<T::BlockNumber>, DispatchError> {
|
||||
let new_time = Self::resolve_time(new_time)?;
|
||||
|
||||
if new_time == when {
|
||||
return Err(Error::<T>::RescheduleNoChange.into());
|
||||
}
|
||||
|
||||
Agenda::<T>::try_mutate(when, |agenda| -> DispatchResult {
|
||||
let task = agenda.get_mut(index as usize).ok_or(Error::<T>::NotFound)?;
|
||||
let task = task.take().ok_or(Error::<T>::NotFound)?;
|
||||
Agenda::<T>::append(new_time, Some(task));
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
let new_index = Agenda::<T>::decode_len(new_time).unwrap_or(1) as u32 - 1;
|
||||
Self::deposit_event(RawEvent::Canceled(when, index));
|
||||
Self::deposit_event(RawEvent::Scheduled(new_time, new_index));
|
||||
|
||||
Ok((new_time, new_index))
|
||||
}
|
||||
|
||||
fn do_schedule_named(
|
||||
id: Vec<u8>,
|
||||
when: DispatchTime<T::BlockNumber>,
|
||||
@@ -548,16 +580,7 @@ impl<T: Trait> Module<T> {
|
||||
return Err(Error::<T>::FailedToSchedule)?
|
||||
}
|
||||
|
||||
let now = frame_system::Module::<T>::block_number();
|
||||
|
||||
let when = match when {
|
||||
DispatchTime::At(x) => x,
|
||||
DispatchTime::After(x) => now.saturating_add(x)
|
||||
};
|
||||
|
||||
if when <= now {
|
||||
return Err(Error::<T>::TargetBlockNumberInPast.into())
|
||||
}
|
||||
let when = Self::resolve_time(when)?;
|
||||
|
||||
// sanitize maybe_periodic
|
||||
let maybe_periodic = maybe_periodic
|
||||
@@ -601,10 +624,41 @@ impl<T: Trait> Module<T> {
|
||||
Self::deposit_event(RawEvent::Canceled(when, index));
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::<T>::FailedToCancel)?
|
||||
Err(Error::<T>::NotFound)?
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn do_reschedule_named(
|
||||
id: Vec<u8>,
|
||||
new_time: DispatchTime<T::BlockNumber>,
|
||||
) -> Result<TaskAddress<T::BlockNumber>, DispatchError> {
|
||||
let new_time = Self::resolve_time(new_time)?;
|
||||
|
||||
Lookup::<T>::try_mutate_exists(id, |lookup| -> Result<TaskAddress<T::BlockNumber>, DispatchError> {
|
||||
let (when, index) = lookup.ok_or(Error::<T>::NotFound)?;
|
||||
|
||||
if new_time == when {
|
||||
return Err(Error::<T>::RescheduleNoChange.into());
|
||||
}
|
||||
|
||||
Agenda::<T>::try_mutate(when, |agenda| -> DispatchResult {
|
||||
let task = agenda.get_mut(index as usize).ok_or(Error::<T>::NotFound)?;
|
||||
let task = task.take().ok_or(Error::<T>::NotFound)?;
|
||||
Agenda::<T>::append(new_time, Some(task));
|
||||
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
let new_index = Agenda::<T>::decode_len(new_time).unwrap_or(1) as u32 - 1;
|
||||
Self::deposit_event(RawEvent::Canceled(when, index));
|
||||
Self::deposit_event(RawEvent::Scheduled(new_time, new_index));
|
||||
|
||||
*lookup = Some((new_time, new_index));
|
||||
|
||||
Ok((new_time, new_index))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Trait> schedule::Anon<T::BlockNumber, <T as Trait>::Call, T::PalletsOrigin> for Module<T> {
|
||||
@@ -623,6 +677,17 @@ impl<T: Trait> schedule::Anon<T::BlockNumber, <T as Trait>::Call, T::PalletsOrig
|
||||
fn cancel((when, index): Self::Address) -> Result<(), ()> {
|
||||
Self::do_cancel(None, (when, index)).map_err(|_| ())
|
||||
}
|
||||
|
||||
fn reschedule(
|
||||
address: Self::Address,
|
||||
when: DispatchTime<T::BlockNumber>,
|
||||
) -> Result<Self::Address, DispatchError> {
|
||||
Self::do_reschedule(address, when)
|
||||
}
|
||||
|
||||
fn next_dispatch_time((when, index): Self::Address) -> Result<T::BlockNumber, ()> {
|
||||
Agenda::<T>::get(when).get(index as usize).ok_or(()).map(|_| when)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Trait> schedule::Named<T::BlockNumber, <T as Trait>::Call, T::PalletsOrigin> for Module<T> {
|
||||
@@ -642,6 +707,17 @@ impl<T: Trait> schedule::Named<T::BlockNumber, <T as Trait>::Call, T::PalletsOri
|
||||
fn cancel_named(id: Vec<u8>) -> Result<(), ()> {
|
||||
Self::do_cancel_named(None, id).map_err(|_| ())
|
||||
}
|
||||
|
||||
fn reschedule_named(
|
||||
id: Vec<u8>,
|
||||
when: DispatchTime<T::BlockNumber>,
|
||||
) -> Result<Self::Address, DispatchError> {
|
||||
Self::do_reschedule_named(id, when)
|
||||
}
|
||||
|
||||
fn next_dispatch_time(id: Vec<u8>) -> Result<T::BlockNumber, ()> {
|
||||
Lookup::<T>::get(id).and_then(|(when, index)| Agenda::<T>::get(when).get(index as usize).map(|_| when)).ok_or(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -868,6 +944,95 @@ mod tests {
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reschedule_works() {
|
||||
new_test_ext().execute_with(|| {
|
||||
let call = Call::Logger(logger::Call::log(42, 1000));
|
||||
assert!(!<Test as frame_system::Trait>::BaseCallFilter::filter(&call));
|
||||
assert_eq!(Scheduler::do_schedule(DispatchTime::At(4), None, 127, root(), call).unwrap(), (4, 0));
|
||||
|
||||
run_to_block(3);
|
||||
assert!(logger::log().is_empty());
|
||||
|
||||
assert_eq!(Scheduler::do_reschedule((4, 0), DispatchTime::At(6)).unwrap(), (6, 0));
|
||||
|
||||
assert_noop!(Scheduler::do_reschedule((6, 0), DispatchTime::At(6)), Error::<Test>::RescheduleNoChange);
|
||||
|
||||
run_to_block(4);
|
||||
assert!(logger::log().is_empty());
|
||||
|
||||
run_to_block(6);
|
||||
assert_eq!(logger::log(), vec![(root(), 42u32)]);
|
||||
|
||||
run_to_block(100);
|
||||
assert_eq!(logger::log(), vec![(root(), 42u32)]);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reschedule_named_works() {
|
||||
new_test_ext().execute_with(|| {
|
||||
let call = Call::Logger(logger::Call::log(42, 1000));
|
||||
assert!(!<Test as frame_system::Trait>::BaseCallFilter::filter(&call));
|
||||
assert_eq!(Scheduler::do_schedule_named(
|
||||
1u32.encode(), DispatchTime::At(4), None, 127, root(), call
|
||||
).unwrap(), (4, 0));
|
||||
|
||||
run_to_block(3);
|
||||
assert!(logger::log().is_empty());
|
||||
|
||||
assert_eq!(Scheduler::do_reschedule_named(1u32.encode(), DispatchTime::At(6)).unwrap(), (6, 0));
|
||||
|
||||
assert_noop!(Scheduler::do_reschedule_named(1u32.encode(), DispatchTime::At(6)), Error::<Test>::RescheduleNoChange);
|
||||
|
||||
run_to_block(4);
|
||||
assert!(logger::log().is_empty());
|
||||
|
||||
run_to_block(6);
|
||||
assert_eq!(logger::log(), vec![(root(), 42u32)]);
|
||||
|
||||
run_to_block(100);
|
||||
assert_eq!(logger::log(), vec![(root(), 42u32)]);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reschedule_named_perodic_works() {
|
||||
new_test_ext().execute_with(|| {
|
||||
let call = Call::Logger(logger::Call::log(42, 1000));
|
||||
assert!(!<Test as frame_system::Trait>::BaseCallFilter::filter(&call));
|
||||
assert_eq!(Scheduler::do_schedule_named(
|
||||
1u32.encode(), DispatchTime::At(4), Some((3, 3)), 127, root(), call
|
||||
).unwrap(), (4, 0));
|
||||
|
||||
run_to_block(3);
|
||||
assert!(logger::log().is_empty());
|
||||
|
||||
assert_eq!(Scheduler::do_reschedule_named(1u32.encode(), DispatchTime::At(5)).unwrap(), (5, 0));
|
||||
assert_eq!(Scheduler::do_reschedule_named(1u32.encode(), DispatchTime::At(6)).unwrap(), (6, 0));
|
||||
|
||||
run_to_block(5);
|
||||
assert!(logger::log().is_empty());
|
||||
|
||||
run_to_block(6);
|
||||
assert_eq!(logger::log(), vec![(root(), 42u32)]);
|
||||
|
||||
assert_eq!(Scheduler::do_reschedule_named(1u32.encode(), DispatchTime::At(10)).unwrap(), (10, 0));
|
||||
|
||||
run_to_block(9);
|
||||
assert_eq!(logger::log(), vec![(root(), 42u32)]);
|
||||
|
||||
run_to_block(10);
|
||||
assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32)]);
|
||||
|
||||
run_to_block(13);
|
||||
assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32), (root(), 42u32)]);
|
||||
|
||||
run_to_block(100);
|
||||
assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32), (root(), 42u32)]);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cancel_named_scheduling_works_with_normal_cancel() {
|
||||
new_test_ext().execute_with(|| {
|
||||
|
||||
Reference in New Issue
Block a user