Skip to content

Commit ffd4ebb

Browse files
committed
refactor delay-tasks
1 parent 8523a1b commit ffd4ebb

File tree

6 files changed

+357
-488
lines changed

6 files changed

+357
-488
lines changed

delay-tasks/Cargo.toml

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "orml-delay-tasks"
3-
description = "Delayed xtokens transfer assets executor."
3+
description = "Scheduler delay task and execute."
44
repository = "https://github.com/open-web3-stack/open-runtime-module-library/tree/master/auction"
55
license = "Apache-2.0"
66
version = "0.7.0"
@@ -21,17 +21,21 @@ sp-std = { workspace = true }
2121
xcm = { workspace = true }
2222

2323
orml-traits = { path = "../traits", version = "0.7.0", default-features = false }
24+
orml-xtokens = { path = "../xtokens", version = "0.7.0", default-features = false }
2425

2526
[dev-dependencies]
2627
sp-core = { workspace = true, features = ["std"] }
2728
sp-io = { workspace = true, features = ["std"] }
29+
pallet-preimage = { workspace = true, features = ["std"] }
30+
pallet-scheduler = { workspace = true, features = ["std"] }
2831

2932
[features]
3033
default = [ "std" ]
3134
std = [
3235
"frame-support/std",
3336
"frame-system/std",
3437
"orml-traits/std",
38+
"orml-xtokens/std",
3539
"parity-scale-codec/std",
3640
"scale-info/std",
3741
"serde",

delay-tasks/src/lib.rs

+141-58
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,103 @@
11
#![cfg_attr(not(feature = "std"), no_std)]
22

3-
use frame_support::{pallet_prelude::*, traits::schedule::DispatchTime, transactional, weights::Weight};
3+
use frame_support::{
4+
pallet_prelude::*,
5+
traits::{
6+
schedule::{v1::Named as ScheduleNamed, DispatchTime},
7+
OriginTrait,
8+
},
9+
weights::Weight,
10+
};
411
use frame_system::pallet_prelude::*;
5-
use orml_traits::delay_tasks::{DelayTasksManager, DelayedTask};
12+
use orml_traits::{
13+
task::{DelayTaskHooks, DelayTasksManager, DispatchableTask, TaskResult},
14+
MultiCurrency, NamedMultiReservableCurrency,
15+
};
616
use parity_scale_codec::FullCodec;
717
use scale_info::TypeInfo;
818
use sp_runtime::{
9-
traits::{CheckedAdd, Zero},
19+
traits::{CheckedAdd, Convert, Zero},
1020
ArithmeticError,
1121
};
1222
use sp_std::fmt::Debug;
23+
use sp_std::marker::PhantomData;
24+
use xcm::v4::prelude::*;
1325

1426
pub use module::*;
1527

1628
mod mock;
1729
mod tests;
1830

31+
pub const DELAY_TASK_ID: [u8; 8] = *b"orml/dts";
32+
33+
/// A delayed origin. Can only be dispatched via `dispatch_as` with a delay.
34+
#[derive(PartialEq, Eq, Clone, RuntimeDebug, Encode, Decode, TypeInfo, MaxEncodedLen)]
35+
pub struct DelayedExecuteOrigin;
36+
37+
pub struct EnsureDelayed;
38+
impl<O: Into<Result<DelayedExecuteOrigin, O>> + From<DelayedExecuteOrigin>> EnsureOrigin<O> for EnsureDelayed {
39+
type Success = ();
40+
fn try_origin(o: O) -> Result<Self::Success, O> {
41+
o.into().and_then(|_| Ok(()))
42+
}
43+
44+
#[cfg(feature = "runtime-benchmarks")]
45+
fn try_successful_origin() -> Result<O, ()> {
46+
Ok(O::from(DelayedExecuteOrigin))
47+
}
48+
}
49+
1950
#[frame_support::pallet]
2051
pub mod module {
2152
use super::*;
2253

2354
type Nonce = u64;
2455

56+
/// Origin for the delay tasks module.
57+
#[pallet::origin]
58+
pub type Origin = DelayedExecuteOrigin;
59+
2560
#[pallet::config]
2661
pub trait Config: frame_system::Config {
2762
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
2863

64+
type RuntimeCall: Parameter + From<Call<Self>>;
65+
66+
/// The outer origin type.
67+
type RuntimeOrigin: From<DelayedExecuteOrigin>
68+
+ From<<Self as frame_system::Config>::RuntimeOrigin>
69+
+ OriginTrait<PalletsOrigin = Self::PalletsOrigin>;
70+
71+
/// The caller origin, overarching type of all pallets origins.
72+
type PalletsOrigin: Parameter + Into<<Self as frame_system::Config>::RuntimeOrigin>;
73+
74+
type DelayOrigin: EnsureOrigin<<Self as frame_system::Config>::RuntimeOrigin>;
75+
2976
type GovernanceOrigin: EnsureOrigin<<Self as frame_system::Config>::RuntimeOrigin>;
3077

31-
type Task: DelayedTask + FullCodec + Debug + Clone + PartialEq + TypeInfo;
78+
type Task: DispatchableTask + FullCodec + Debug + Clone + PartialEq + TypeInfo;
79+
80+
/// The Scheduler.
81+
type Scheduler: ScheduleNamed<BlockNumberFor<Self>, <Self as Config>::RuntimeCall, Self::PalletsOrigin>;
82+
83+
type DelayTaskHooks: DelayTaskHooks<Self::Task>;
84+
85+
/// Convert `Location` to `CurrencyId`.
86+
type CurrencyIdConvert: Convert<
87+
Location,
88+
Option<<Self::Currency as MultiCurrency<Self::AccountId>>::CurrencyId>,
89+
>;
90+
91+
type Currency: NamedMultiReservableCurrency<Self::AccountId>;
92+
93+
type ReserveId: Get<<Self::Currency as NamedMultiReservableCurrency<Self::AccountId>>::ReserveIdentifier>;
3294
}
3395

3496
#[pallet::error]
3597
pub enum Error<T> {
3698
InvalidDelayBlock,
3799
InvalidId,
100+
FailedToSchedule,
38101
}
39102

40103
#[pallet::event]
@@ -53,10 +116,6 @@ pub mod module {
53116
id: Nonce,
54117
execute_block: BlockNumberFor<T>,
55118
},
56-
DelayedTaskTryExecuteFailed {
57-
id: Nonce,
58-
error: DispatchError,
59-
},
60119
DelayedTaskCanceled {
61120
id: Nonce,
62121
},
@@ -67,16 +126,7 @@ pub mod module {
67126
pub struct Pallet<T>(_);
68127

69128
#[pallet::hooks]
70-
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
71-
/// `on_initialize` to return the weight used in `on_finalize`.
72-
fn on_initialize(now: BlockNumberFor<T>) -> Weight {
73-
Weight::zero()
74-
}
75-
76-
fn on_finalize(now: BlockNumberFor<T>) {
77-
Self::_on_finalize(now);
78-
}
79-
}
129+
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {}
80130

81131
#[pallet::storage]
82132
#[pallet::getter(fn next_delayed_task_id)]
@@ -86,16 +136,25 @@ pub mod module {
86136
#[pallet::getter(fn delayed_tasks)]
87137
pub type DelayedTasks<T: Config> = StorageMap<_, Twox64Concat, Nonce, (T::Task, BlockNumberFor<T>), OptionQuery>;
88138

89-
#[pallet::storage]
90-
#[pallet::getter(fn delayed_task_queue)]
91-
pub type DelayedTaskQueue<T: Config> =
92-
StorageDoubleMap<_, Twox64Concat, BlockNumberFor<T>, Twox64Concat, Nonce, (), OptionQuery>;
93-
94139
#[pallet::call]
95140
impl<T: Config> Pallet<T> {
96141
#[pallet::call_index(0)]
97142
#[pallet::weight(Weight::zero())]
98-
pub fn reset_execute_block(
143+
pub fn delayed_execute(origin: OriginFor<T>, id: Nonce) -> DispatchResult {
144+
T::DelayOrigin::ensure_origin(origin)?;
145+
146+
let execute_result = Self::do_delayed_execute(id)?;
147+
148+
Self::deposit_event(Event::<T>::DelayedTaskExecuted {
149+
id,
150+
result: execute_result.result,
151+
});
152+
Ok(())
153+
}
154+
155+
#[pallet::call_index(1)]
156+
#[pallet::weight(Weight::zero())]
157+
pub fn reschedule_delay_task(
99158
origin: OriginFor<T>,
100159
id: Nonce,
101160
when: DispatchTime<BlockNumberFor<T>>,
@@ -112,10 +171,11 @@ pub mod module {
112171
};
113172
ensure!(new_execute_block > now, Error::<T>::InvalidDelayBlock);
114173

115-
DelayedTaskQueue::<T>::remove(*execute_block, id);
116-
DelayedTaskQueue::<T>::insert(new_execute_block, id, ());
117174
*execute_block = new_execute_block;
118175

176+
T::Scheduler::reschedule_named((&DELAY_TASK_ID, id).encode(), DispatchTime::At(new_execute_block))
177+
.map_err(|_| Error::<T>::FailedToSchedule)?;
178+
119179
Self::deposit_event(Event::<T>::DelayedTaskReDelayed {
120180
id,
121181
execute_block: new_execute_block,
@@ -126,47 +186,31 @@ pub mod module {
126186
Ok(())
127187
}
128188

129-
#[pallet::call_index(1)]
189+
#[pallet::call_index(2)]
130190
#[pallet::weight(Weight::zero())]
131191
pub fn cancel_delayed_task(origin: OriginFor<T>, id: Nonce) -> DispatchResult {
132192
T::GovernanceOrigin::ensure_origin(origin)?;
133193

134-
let (delay_task, execute_block) = DelayedTasks::<T>::take(id).ok_or(Error::<T>::InvalidId)?;
135-
delay_task.on_cancel()?;
136-
DelayedTaskQueue::<T>::remove(execute_block, id);
194+
let (task, _) = DelayedTasks::<T>::take(id).ok_or(Error::<T>::InvalidId)?;
195+
196+
// pre cancel
197+
T::DelayTaskHooks::on_cancel(&task)?;
198+
199+
T::Scheduler::cancel_named((&DELAY_TASK_ID, id).encode()).map_err(|_| Error::<T>::FailedToSchedule)?;
137200

138201
Self::deposit_event(Event::<T>::DelayedTaskCanceled { id });
139202
Ok(())
140203
}
141204
}
142205

143206
impl<T: Config> Pallet<T> {
144-
fn _on_finalize(now: BlockNumberFor<T>) {
145-
for (id, _) in DelayedTaskQueue::<T>::drain_prefix(now) {
146-
match Self::do_execute_delayed_task(id) {
147-
Ok(result) => {
148-
Self::deposit_event(Event::<T>::DelayedTaskExecuted { id, result });
149-
}
150-
Err(e) => {
151-
log::debug!(
152-
target: "delay-tasks",
153-
"try executing delayed task {:?} failed for: {:?}. The delayed task still exists, but needs to be canceled or reset delay block.",
154-
id,
155-
e
156-
);
157-
Self::deposit_event(Event::<T>::DelayedTaskTryExecuteFailed { id, error: e });
158-
}
159-
}
160-
}
161-
}
162-
163-
#[transactional]
164-
pub(crate) fn do_execute_delayed_task(id: Nonce) -> sp_std::result::Result<DispatchResult, DispatchError> {
207+
pub(crate) fn do_delayed_execute(id: Nonce) -> sp_std::result::Result<TaskResult, DispatchError> {
165208
let (delayed_task, _) = DelayedTasks::<T>::take(id).ok_or(Error::<T>::InvalidId)?;
166209

167-
delayed_task.pre_delayed_execute()?;
210+
// pre delayed dispatch
211+
T::DelayTaskHooks::pre_delayed_execute(&delayed_task)?;
168212

169-
Ok(delayed_task.delayed_execute())
213+
Ok(delayed_task.dispatch(Weight::zero()))
170214
}
171215

172216
/// Retrieves the next delayed task ID from storage, and increment it by
@@ -184,16 +228,28 @@ pub mod module {
184228
impl<T: Config> DelayTasksManager<T::Task, BlockNumberFor<T>> for Pallet<T> {
185229
fn add_delay_task(task: T::Task, delay_blocks: BlockNumberFor<T>) -> DispatchResult {
186230
ensure!(!delay_blocks.is_zero(), Error::<T>::InvalidDelayBlock);
187-
188-
task.pre_delay()?;
189-
190-
let id = Self::get_next_delayed_task_id()?;
191231
let execute_block = frame_system::Pallet::<T>::block_number()
192232
.checked_add(&delay_blocks)
193233
.ok_or(ArithmeticError::Overflow)?;
194234

235+
// pre schedule delay task
236+
T::DelayTaskHooks::pre_delay(&task)?;
237+
238+
let id = Self::get_next_delayed_task_id()?;
239+
let delayed_origin: <T as Config>::RuntimeOrigin = From::from(DelayedExecuteOrigin);
240+
let pallets_origin = delayed_origin.caller().clone();
241+
242+
T::Scheduler::schedule_named(
243+
(&DELAY_TASK_ID, id).encode(),
244+
DispatchTime::At(execute_block),
245+
None,
246+
Zero::zero(),
247+
pallets_origin,
248+
<T as Config>::RuntimeCall::from(Call::<T>::delayed_execute { id }),
249+
)
250+
.map_err(|_| Error::<T>::FailedToSchedule)?;
251+
195252
DelayedTasks::<T>::insert(id, (&task, execute_block));
196-
DelayedTaskQueue::<T>::insert(execute_block, id, ());
197253

198254
Self::deposit_event(Event::<T>::DelayedTaskAdded {
199255
id,
@@ -203,4 +259,31 @@ pub mod module {
203259
Ok(())
204260
}
205261
}
262+
263+
pub struct DelayedXtokensTaskHooks<T>(PhantomData<T>);
264+
impl<T: Config + orml_xtokens::Config> DelayTaskHooks<orml_xtokens::XtokensTask<T>> for DelayedXtokensTaskHooks<T> {
265+
fn pre_delay(task: &orml_xtokens::XtokensTask<T>) -> DispatchResult {
266+
match task {
267+
orml_xtokens::XtokensTask::<T>::TransferAssets { who, assets, fee, .. } => {}
268+
}
269+
270+
Ok(())
271+
}
272+
273+
fn pre_delayed_execute(task: &orml_xtokens::XtokensTask<T>) -> DispatchResult {
274+
match task {
275+
orml_xtokens::XtokensTask::<T>::TransferAssets { who, assets, fee, .. } => {}
276+
}
277+
278+
Ok(())
279+
}
280+
281+
fn on_cancel(task: &orml_xtokens::XtokensTask<T>) -> DispatchResult {
282+
match task {
283+
orml_xtokens::XtokensTask::<T>::TransferAssets { who, assets, fee, .. } => {}
284+
}
285+
286+
Ok(())
287+
}
288+
}
206289
}

0 commit comments

Comments
 (0)