Skip to content

Commit

Permalink
Adjust automation time slot (#431)
Browse files Browse the repository at this point in the history
* Adjust automation time slot

* fixup: auto format Rust code

* Fix tests

* Renamed variable name and updated tests

* Updated comments and values of tests

* Removed unused type declaration from runtime files

---------

Co-authored-by: oak-code-formatter <[email protected]>
Co-authored-by: chrisli30 <[email protected]>
  • Loading branch information
3 people authored Sep 22, 2023
1 parent cf4a6ea commit 771c9c1
Show file tree
Hide file tree
Showing 7 changed files with 289 additions and 180 deletions.
44 changes: 24 additions & 20 deletions pallets/automation-time/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,7 @@

//! # Automation time pallet
//!
//! DISCLAIMER: This pallet is still in it's early stages. At this point
//! we only support scheduling two tasks per hour, and sending an on-chain
//! with a custom message.
//!
//! This pallet allows a user to schedule tasks. Tasks can scheduled for any whole hour in the future.
//! This pallet allows a user to schedule tasks. Tasks can scheduled for any whole SlotSizeSeconds in the future.
//! In order to run tasks this pallet consumes up to a certain amount of weight during `on_initialize`.
//!
//! The pallet supports the following tasks:
Expand Down Expand Up @@ -133,6 +129,10 @@ pub mod pallet {
#[pallet::constant]
type MaxWeightPerSlot: Get<u128>;

/// The minimum time interval tasks could schedule for. For example, if the value is 600, then only inputs that are multiples of 600 are allowed. In other words, tasks can only be scheduled at 0, 10, 20 ... minutes of each hour.
#[pallet::constant]
type SlotSizeSeconds: Get<u64>;

/// The maximum percentage of weight per block used for scheduled tasks.
#[pallet::constant]
type UpdateQueueRatio: Get<Perbill>;
Expand Down Expand Up @@ -236,7 +236,7 @@ pub mod pallet {
#[pallet::error]
#[derive(PartialEq)]
pub enum Error<T> {
/// Time must end in a whole hour.
/// Time in seconds must be a multiple of SlotSizeSeconds
InvalidTime,
/// Time must be in the future.
PastTime,
Expand Down Expand Up @@ -365,7 +365,7 @@ pub mod pallet {
/// * `overall_weight`: The overall weight in which fees will be paid for XCM instructions.
///
/// # Errors
/// * `InvalidTime`: Time must end in a whole hour.
/// * `InvalidTime`: Time in seconds must be a multiple of SlotSizeSeconds.
/// * `PastTime`: Time must be in the future.
/// * `DuplicateTask`: There can be no duplicate tasks.
/// * `TimeTooFarOut`: Execution time or frequency are past the max time horizon.
Expand Down Expand Up @@ -422,7 +422,7 @@ pub mod pallet {
/// * `overall_weight`: The overall weight in which fees will be paid for XCM instructions.
///
/// # Errors
/// * `InvalidTime`: Time must end in a whole hour.
/// * `InvalidTime`: Time in seconds must be a multiple of SlotSizeSeconds.
/// * `PastTime`: Time must be in the future.
/// * `DuplicateTask`: There can be no duplicate tasks.
/// * `TimeTooFarOut`: Execution time or frequency are past the max time horizon.
Expand Down Expand Up @@ -478,7 +478,7 @@ pub mod pallet {
/// * `account_minimum`: The minimum amount of funds that should be left in the wallet
///
/// # Errors
/// * `InvalidTime`: Execution time and frequency must end in a whole hour.
/// * `InvalidTime`: Execution time and frequency must be a multiple of SlotSizeSeconds.
/// * `PastTime`: Time must be in the future.
/// * `DuplicateTask`: There can be no duplicate tasks.
/// * `TimeSlotFull`: Time slot is full. No more tasks can be scheduled for this time.
Expand Down Expand Up @@ -520,7 +520,7 @@ pub mod pallet {
/// * `call`: The call that will be dispatched.
///
/// # Errors
/// * `InvalidTime`: Execution time and frequency must end in a whole hour.
/// * `InvalidTime`: Execution time and frequency must be a multiple of SlotSizeSeconds.
/// * `PastTime`: Time must be in the future.
/// * `DuplicateTask`: There can be no duplicate tasks.
/// * `TimeSlotFull`: Time slot is full. No more tasks can be scheduled for this time.
Expand Down Expand Up @@ -594,7 +594,7 @@ pub mod pallet {
/// In order to do this we:
/// * Get the most recent timestamp from the block.
/// * Convert the ms unix timestamp to seconds.
/// * Bring the timestamp down to the last whole hour.
/// * Bring the timestamp down to the last whole SlotSizeSeconds.
pub fn get_current_time_slot() -> Result<UnixTime, DispatchError> {
let now = <timestamp::Pallet<T>>::get()
.checked_into::<UnixTime>()
Expand All @@ -605,14 +605,15 @@ pub mod pallet {
}

let now = now.checked_div(1000).ok_or(ArithmeticError::Overflow)?;
let diff_to_hour = now.checked_rem(3600).ok_or(ArithmeticError::Overflow)?;
Ok(now.checked_sub(diff_to_hour).ok_or(ArithmeticError::Overflow)?)
let diff_to_slot =
now.checked_rem(T::SlotSizeSeconds::get()).ok_or(ArithmeticError::Overflow)?;
Ok(now.checked_sub(diff_to_slot).ok_or(ArithmeticError::Overflow)?)
}

/// Checks to see if the scheduled time is valid.
///
/// In order for a time to be valid it must
/// - End in a whole hour
/// - A multiple of SlotSizeSeconds
/// - Be in the future
/// - Not be more than MaxScheduleSeconds out
pub fn is_valid_time(scheduled_time: UnixTime) -> DispatchResult {
Expand All @@ -621,7 +622,9 @@ pub mod pallet {
return Ok(())
}

let remainder = scheduled_time.checked_rem(3600).ok_or(ArithmeticError::Overflow)?;
let remainder = scheduled_time
.checked_rem(T::SlotSizeSeconds::get())
.ok_or(ArithmeticError::Overflow)?;
if remainder != 0 {
Err(<Error<T>>::InvalidTime)?;
}
Expand Down Expand Up @@ -791,8 +794,8 @@ pub mod pallet {
allotted_weight,
);

let last_missed_slot_tracker =
last_missed_slot.saturating_add(missed_slots_moved.saturating_mul(3600));
let last_missed_slot_tracker = last_missed_slot
.saturating_add(missed_slots_moved.saturating_mul(T::SlotSizeSeconds::get()));
let used_weight = append_weight;
(last_missed_slot_tracker, used_weight)
} else {
Expand All @@ -811,8 +814,9 @@ pub mod pallet {
) -> (Weight, u64) {
// will need to move task queue into missed queue
let mut missed_tasks = vec![];
let mut diff =
(current_time_slot.saturating_sub(last_missed_slot) / 3600).saturating_sub(1);
let mut diff = (current_time_slot.saturating_sub(last_missed_slot) /
T::SlotSizeSeconds::get())
.saturating_sub(1);
for i in 0..diff {
if allotted_weight.ref_time() <
<T as Config>::WeightInfo::shift_missed_tasks().ref_time()
Expand Down Expand Up @@ -843,7 +847,7 @@ pub mod pallet {
number_of_missed_slots: u64,
) -> Vec<MissedTaskV2Of<T>> {
let mut tasks = vec![];
let seconds_in_slot = 3600;
let seconds_in_slot = T::SlotSizeSeconds::get();
let shift = seconds_in_slot.saturating_mul(number_of_missed_slots + 1);
let new_time_slot = last_missed_slot.saturating_add(shift);
if let Some(ScheduledTasksOf::<T> { tasks: account_task_ids, .. }) =
Expand Down
55 changes: 27 additions & 28 deletions pallets/automation-time/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -285,34 +285,6 @@ impl<
}
}

parameter_types! {
pub const MaxTasksPerSlot: u32 = 2;
#[derive(Debug)]
pub const MaxExecutionTimes: u32 = 3;
pub const MaxScheduleSeconds: u64 = 1 * 24 * 60 * 60;
pub const MaxBlockWeight: u64 = 20_000_000;
pub const MaxWeightPercentage: Perbill = Perbill::from_percent(40);
pub const UpdateQueueRatio: Perbill = Perbill::from_percent(50);
pub const ExecutionWeightFee: Balance = NATIVE_EXECUTION_WEIGHT_FEE;

// When unit testing dynamic dispatch, we use the real weight value of the extrinsics call
// This is an external lib that we don't own so we try to not mock, follow the rule don't mock
// what you don't own
// One of test we do is Balances::transfer call, which has its weight define here:
// https://github.com/paritytech/substrate/blob/polkadot-v0.9.38/frame/balances/src/weights.rs#L61-L73
// When logging the final calculated amount, its value is 73_314_000.
//
// in our unit test, we test a few transfers with dynamic dispatch. On top
// of that, there is also weight of our call such as fetching the tasks,
// move from schedule slot to tasks queue,.. so the weight of a schedule
// transfer with dynamic dispatch is even higher.
//
// and because we test run a few of them so I set it to ~10x value of 73_314_000
pub const MaxWeightPerSlot: u128 = 700_000_000;
pub const XmpFee: u128 = 1_000_000;
pub const GetNativeCurrencyId: CurrencyId = NATIVE;
}

pub struct MockPalletBalanceWeight<T>(PhantomData<T>);
impl<Test: frame_system::Config> pallet_balances::WeightInfo for MockPalletBalanceWeight<Test> {
fn transfer() -> Weight {
Expand Down Expand Up @@ -496,6 +468,32 @@ impl TransferCallCreator<MultiAddress<AccountId, ()>, Balance, RuntimeCall>
}

parameter_types! {
pub const MaxTasksPerSlot: u32 = 2;
#[derive(Debug)]
pub const MaxExecutionTimes: u32 = 3;
pub const MaxScheduleSeconds: u64 = 86_400; // 24 hours in seconds
pub const SlotSizeSeconds: u64 = 600; // 10 minutes in seconds;
pub const MaxBlockWeight: u64 = 20_000_000;
pub const MaxWeightPercentage: Perbill = Perbill::from_percent(40);
pub const UpdateQueueRatio: Perbill = Perbill::from_percent(50);
pub const ExecutionWeightFee: Balance = NATIVE_EXECUTION_WEIGHT_FEE;

// When unit testing dynamic dispatch, we use the real weight value of the extrinsics call
// This is an external lib that we don't own so we try to not mock, follow the rule don't mock
// what you don't own
// One of test we do is Balances::transfer call, which has its weight define here:
// https://github.com/paritytech/substrate/blob/polkadot-v0.9.38/frame/balances/src/weights.rs#L61-L73
// When logging the final calculated amount, its value is 73_314_000.
//
// in our unit test, we test a few transfers with dynamic dispatch. On top
// of that, there is also weight of our call such as fetching the tasks,
// move from schedule slot to tasks queue,.. so the weight of a schedule
// transfer with dynamic dispatch is even higher.
//
// and because we test run a few of them so I set it to ~10x value of 73_314_000
pub const MaxWeightPerSlot: u128 = 700_000_000;
pub const XmpFee: u128 = 1_000_000;
pub const GetNativeCurrencyId: CurrencyId = NATIVE;
pub const RelayNetwork: NetworkId = NetworkId::Rococo;
// The universal location within the global consensus system
pub UniversalLocation: InteriorMultiLocation =
Expand All @@ -513,6 +511,7 @@ impl pallet_automation_time::Config for Test {
type WeightInfo = MockWeight<Test>;
type ExecutionWeightFee = ExecutionWeightFee;
type MaxWeightPerSlot = MaxWeightPerSlot;
type SlotSizeSeconds = SlotSizeSeconds;
type Currency = Balances;
type MultiCurrency = Currencies;
type CurrencyId = CurrencyId;
Expand Down
Loading

0 comments on commit 771c9c1

Please sign in to comment.