1
1
#![ cfg_attr( not( feature = "std" ) , no_std) ]
2
2
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
+ } ;
4
11
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
+ } ;
6
16
use parity_scale_codec:: FullCodec ;
7
17
use scale_info:: TypeInfo ;
8
18
use sp_runtime:: {
9
- traits:: { CheckedAdd , Zero } ,
19
+ traits:: { CheckedAdd , Convert , Zero } ,
10
20
ArithmeticError ,
11
21
} ;
12
22
use sp_std:: fmt:: Debug ;
23
+ use sp_std:: marker:: PhantomData ;
24
+ use xcm:: v4:: prelude:: * ;
13
25
14
26
pub use module:: * ;
15
27
16
28
mod mock;
17
29
mod tests;
18
30
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
+
19
50
#[ frame_support:: pallet]
20
51
pub mod module {
21
52
use super :: * ;
22
53
23
54
type Nonce = u64 ;
24
55
56
+ /// Origin for the delay tasks module.
57
+ #[ pallet:: origin]
58
+ pub type Origin = DelayedExecuteOrigin ;
59
+
25
60
#[ pallet:: config]
26
61
pub trait Config : frame_system:: Config {
27
62
type RuntimeEvent : From < Event < Self > > + IsType < <Self as frame_system:: Config >:: RuntimeEvent > ;
28
63
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
+
29
76
type GovernanceOrigin : EnsureOrigin < <Self as frame_system:: Config >:: RuntimeOrigin > ;
30
77
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 > ;
32
94
}
33
95
34
96
#[ pallet:: error]
35
97
pub enum Error < T > {
36
98
InvalidDelayBlock ,
37
99
InvalidId ,
100
+ FailedToSchedule ,
38
101
}
39
102
40
103
#[ pallet:: event]
@@ -53,10 +116,6 @@ pub mod module {
53
116
id : Nonce ,
54
117
execute_block : BlockNumberFor < T > ,
55
118
} ,
56
- DelayedTaskTryExecuteFailed {
57
- id : Nonce ,
58
- error : DispatchError ,
59
- } ,
60
119
DelayedTaskCanceled {
61
120
id : Nonce ,
62
121
} ,
@@ -67,16 +126,7 @@ pub mod module {
67
126
pub struct Pallet < T > ( _ ) ;
68
127
69
128
#[ 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 > { }
80
130
81
131
#[ pallet:: storage]
82
132
#[ pallet:: getter( fn next_delayed_task_id) ]
@@ -86,16 +136,25 @@ pub mod module {
86
136
#[ pallet:: getter( fn delayed_tasks) ]
87
137
pub type DelayedTasks < T : Config > = StorageMap < _ , Twox64Concat , Nonce , ( T :: Task , BlockNumberFor < T > ) , OptionQuery > ;
88
138
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
-
94
139
#[ pallet:: call]
95
140
impl < T : Config > Pallet < T > {
96
141
#[ pallet:: call_index( 0 ) ]
97
142
#[ 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 (
99
158
origin : OriginFor < T > ,
100
159
id : Nonce ,
101
160
when : DispatchTime < BlockNumberFor < T > > ,
@@ -112,10 +171,11 @@ pub mod module {
112
171
} ;
113
172
ensure ! ( new_execute_block > now, Error :: <T >:: InvalidDelayBlock ) ;
114
173
115
- DelayedTaskQueue :: < T > :: remove ( * execute_block, id) ;
116
- DelayedTaskQueue :: < T > :: insert ( new_execute_block, id, ( ) ) ;
117
174
* execute_block = new_execute_block;
118
175
176
+ T :: Scheduler :: reschedule_named ( ( & DELAY_TASK_ID , id) . encode ( ) , DispatchTime :: At ( new_execute_block) )
177
+ . map_err ( |_| Error :: < T > :: FailedToSchedule ) ?;
178
+
119
179
Self :: deposit_event ( Event :: < T > :: DelayedTaskReDelayed {
120
180
id,
121
181
execute_block : new_execute_block,
@@ -126,47 +186,31 @@ pub mod module {
126
186
Ok ( ( ) )
127
187
}
128
188
129
- #[ pallet:: call_index( 1 ) ]
189
+ #[ pallet:: call_index( 2 ) ]
130
190
#[ pallet:: weight( Weight :: zero( ) ) ]
131
191
pub fn cancel_delayed_task ( origin : OriginFor < T > , id : Nonce ) -> DispatchResult {
132
192
T :: GovernanceOrigin :: ensure_origin ( origin) ?;
133
193
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 ) ?;
137
200
138
201
Self :: deposit_event ( Event :: < T > :: DelayedTaskCanceled { id } ) ;
139
202
Ok ( ( ) )
140
203
}
141
204
}
142
205
143
206
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 > {
165
208
let ( delayed_task, _) = DelayedTasks :: < T > :: take ( id) . ok_or ( Error :: < T > :: InvalidId ) ?;
166
209
167
- delayed_task. pre_delayed_execute ( ) ?;
210
+ // pre delayed dispatch
211
+ T :: DelayTaskHooks :: pre_delayed_execute ( & delayed_task) ?;
168
212
169
- Ok ( delayed_task. delayed_execute ( ) )
213
+ Ok ( delayed_task. dispatch ( Weight :: zero ( ) ) )
170
214
}
171
215
172
216
/// Retrieves the next delayed task ID from storage, and increment it by
@@ -184,16 +228,28 @@ pub mod module {
184
228
impl < T : Config > DelayTasksManager < T :: Task , BlockNumberFor < T > > for Pallet < T > {
185
229
fn add_delay_task ( task : T :: Task , delay_blocks : BlockNumberFor < T > ) -> DispatchResult {
186
230
ensure ! ( !delay_blocks. is_zero( ) , Error :: <T >:: InvalidDelayBlock ) ;
187
-
188
- task. pre_delay ( ) ?;
189
-
190
- let id = Self :: get_next_delayed_task_id ( ) ?;
191
231
let execute_block = frame_system:: Pallet :: < T > :: block_number ( )
192
232
. checked_add ( & delay_blocks)
193
233
. ok_or ( ArithmeticError :: Overflow ) ?;
194
234
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
+
195
252
DelayedTasks :: < T > :: insert ( id, ( & task, execute_block) ) ;
196
- DelayedTaskQueue :: < T > :: insert ( execute_block, id, ( ) ) ;
197
253
198
254
Self :: deposit_event ( Event :: < T > :: DelayedTaskAdded {
199
255
id,
@@ -203,4 +259,31 @@ pub mod module {
203
259
Ok ( ( ) )
204
260
}
205
261
}
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
+ }
206
289
}
0 commit comments