frame_support/traits/schedule.rs
1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18//! Traits and associated utilities for scheduling dispatchables in FRAME.
19
20#[allow(deprecated)]
21use super::PreimageProvider;
22use alloc::vec::Vec;
23use codec::{Codec, Decode, DecodeWithMemTracking, Encode, EncodeLike, MaxEncodedLen};
24use core::{fmt::Debug, result::Result};
25use scale_info::TypeInfo;
26use sp_runtime::{traits::Saturating, DispatchError, RuntimeDebug};
27
28/// Information relating to the period of a scheduled task. First item is the length of the
29/// period and the second is the number of times it should be executed in total before the task
30/// is considered finished and removed.
31pub type Period<BlockNumber> = (BlockNumber, u32);
32
33/// Priority with which a call is scheduled. It's just a linear amount with lowest values meaning
34/// higher priority.
35pub type Priority = u8;
36
37/// The dispatch time of a scheduled task.
38#[derive(
39 Encode,
40 Decode,
41 DecodeWithMemTracking,
42 Copy,
43 Clone,
44 PartialEq,
45 Eq,
46 RuntimeDebug,
47 TypeInfo,
48 MaxEncodedLen,
49)]
50pub enum DispatchTime<BlockNumber> {
51 /// At specified block.
52 At(BlockNumber),
53 /// After specified number of blocks.
54 After(BlockNumber),
55}
56
57impl<BlockNumber: Saturating + Copy> DispatchTime<BlockNumber> {
58 pub fn evaluate(&self, since: BlockNumber) -> BlockNumber {
59 match &self {
60 Self::At(m) => *m,
61 Self::After(m) => m.saturating_add(since),
62 }
63 }
64}
65
66/// The highest priority. We invert the value so that normal sorting will place the highest
67/// priority at the beginning of the list.
68pub const HIGHEST_PRIORITY: Priority = 0;
69/// Anything of this value or lower will definitely be scheduled on the block that they ask for,
70/// even if it breaches the `MaximumWeight` limitation.
71pub const HARD_DEADLINE: Priority = 63;
72/// The lowest priority. Most stuff should be around here.
73pub const LOWEST_PRIORITY: Priority = 255;
74
75/// Type representing an encodable value or the hash of the encoding of such a value.
76#[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)]
77pub enum MaybeHashed<T, Hash> {
78 /// The value itself.
79 Value(T),
80 /// The hash of the encoded value which this value represents.
81 Hash(Hash),
82}
83
84impl<T, H> From<T> for MaybeHashed<T, H> {
85 fn from(t: T) -> Self {
86 MaybeHashed::Value(t)
87 }
88}
89
90/// Error type for `MaybeHashed::lookup`.
91#[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)]
92pub enum LookupError {
93 /// A call of this hash was not known.
94 Unknown,
95 /// The preimage for this hash was known but could not be decoded into a `Call`.
96 BadFormat,
97}
98
99impl<T: Decode, H> MaybeHashed<T, H> {
100 pub fn as_value(&self) -> Option<&T> {
101 match &self {
102 Self::Value(c) => Some(c),
103 Self::Hash(_) => None,
104 }
105 }
106
107 pub fn as_hash(&self) -> Option<&H> {
108 match &self {
109 Self::Value(_) => None,
110 Self::Hash(h) => Some(h),
111 }
112 }
113
114 pub fn ensure_requested<P: PreimageProvider<H>>(&self) {
115 match &self {
116 Self::Value(_) => (),
117 Self::Hash(hash) => P::request_preimage(hash),
118 }
119 }
120
121 pub fn ensure_unrequested<P: PreimageProvider<H>>(&self) {
122 match &self {
123 Self::Value(_) => (),
124 Self::Hash(hash) => P::unrequest_preimage(hash),
125 }
126 }
127
128 pub fn resolved<P: PreimageProvider<H>>(self) -> (Self, Option<H>) {
129 match self {
130 Self::Value(c) => (Self::Value(c), None),
131 Self::Hash(h) => {
132 let data = match P::get_preimage(&h) {
133 Some(p) => p,
134 None => return (Self::Hash(h), None),
135 };
136 match T::decode(&mut &data[..]) {
137 Ok(c) => (Self::Value(c), Some(h)),
138 Err(_) => (Self::Hash(h), None),
139 }
140 },
141 }
142 }
143}
144
145#[deprecated(note = "Use `v3` instead. Will be removed after September 2024.")]
146pub mod v1 {
147 use super::*;
148
149 /// A type that can be used as a scheduler.
150 pub trait Anon<BlockNumber, Call, RuntimeOrigin> {
151 /// An address which can be used for removing a scheduled task.
152 type Address: Codec + Clone + Eq + EncodeLike + Debug + TypeInfo + MaxEncodedLen;
153
154 /// Schedule a dispatch to happen at the beginning of some block in the future.
155 ///
156 /// This is not named.
157 fn schedule(
158 when: DispatchTime<BlockNumber>,
159 maybe_periodic: Option<Period<BlockNumber>>,
160 priority: Priority,
161 origin: RuntimeOrigin,
162 call: Call,
163 ) -> Result<Self::Address, DispatchError>;
164
165 /// Cancel a scheduled task. If periodic, then it will cancel all further instances of that,
166 /// also.
167 ///
168 /// Will return an error if the `address` is invalid.
169 ///
170 /// NOTE: This guaranteed to work only *before* the point that it is due to be executed.
171 /// If it ends up being delayed beyond the point of execution, then it cannot be cancelled.
172 ///
173 /// NOTE2: This will not work to cancel periodic tasks after their initial execution. For
174 /// that, you must name the task explicitly using the `Named` trait.
175 fn cancel(address: Self::Address) -> Result<(), ()>;
176
177 /// Reschedule a task. For one-off tasks, this dispatch is guaranteed to succeed
178 /// only if it is executed *before* the currently scheduled block. For periodic tasks,
179 /// this dispatch is guaranteed to succeed only before the *initial* execution; for
180 /// others, use `reschedule_named`.
181 ///
182 /// Will return an error if the `address` is invalid.
183 fn reschedule(
184 address: Self::Address,
185 when: DispatchTime<BlockNumber>,
186 ) -> Result<Self::Address, DispatchError>;
187
188 /// Return the next dispatch time for a given task.
189 ///
190 /// Will return an error if the `address` is invalid.
191 fn next_dispatch_time(address: Self::Address) -> Result<BlockNumber, ()>;
192 }
193
194 /// A type that can be used as a scheduler.
195 pub trait Named<BlockNumber, Call, RuntimeOrigin> {
196 /// An address which can be used for removing a scheduled task.
197 type Address: Codec + Clone + Eq + EncodeLike + core::fmt::Debug + MaxEncodedLen;
198
199 /// Schedule a dispatch to happen at the beginning of some block in the future.
200 ///
201 /// - `id`: The identity of the task. This must be unique and will return an error if not.
202 fn schedule_named(
203 id: Vec<u8>,
204 when: DispatchTime<BlockNumber>,
205 maybe_periodic: Option<Period<BlockNumber>>,
206 priority: Priority,
207 origin: RuntimeOrigin,
208 call: Call,
209 ) -> Result<Self::Address, ()>;
210
211 /// Cancel a scheduled, named task. If periodic, then it will cancel all further instances
212 /// of that, also.
213 ///
214 /// Will return an error if the `id` is invalid.
215 ///
216 /// NOTE: This guaranteed to work only *before* the point that it is due to be executed.
217 /// If it ends up being delayed beyond the point of execution, then it cannot be cancelled.
218 fn cancel_named(id: Vec<u8>) -> Result<(), ()>;
219
220 /// Reschedule a task. For one-off tasks, this dispatch is guaranteed to succeed
221 /// only if it is executed *before* the currently scheduled block.
222 fn reschedule_named(
223 id: Vec<u8>,
224 when: DispatchTime<BlockNumber>,
225 ) -> Result<Self::Address, DispatchError>;
226
227 /// Return the next dispatch time for a given task.
228 ///
229 /// Will return an error if the `id` is invalid.
230 fn next_dispatch_time(id: Vec<u8>) -> Result<BlockNumber, ()>;
231 }
232
233 #[allow(deprecated)]
234 impl<T, BlockNumber, Call, RuntimeOrigin> Anon<BlockNumber, Call, RuntimeOrigin> for T
235 where
236 T: v2::Anon<BlockNumber, Call, RuntimeOrigin>,
237 {
238 #[allow(deprecated)]
239 type Address = T::Address;
240
241 fn schedule(
242 when: DispatchTime<BlockNumber>,
243 maybe_periodic: Option<Period<BlockNumber>>,
244 priority: Priority,
245 origin: RuntimeOrigin,
246 call: Call,
247 ) -> Result<Self::Address, DispatchError> {
248 let c = MaybeHashed::<Call, T::Hash>::Value(call);
249
250 #[allow(deprecated)]
251 T::schedule(when, maybe_periodic, priority, origin, c)
252 }
253
254 fn cancel(address: Self::Address) -> Result<(), ()> {
255 #[allow(deprecated)]
256 T::cancel(address)
257 }
258
259 fn reschedule(
260 address: Self::Address,
261 when: DispatchTime<BlockNumber>,
262 ) -> Result<Self::Address, DispatchError> {
263 #[allow(deprecated)]
264 T::reschedule(address, when)
265 }
266
267 fn next_dispatch_time(address: Self::Address) -> Result<BlockNumber, ()> {
268 #[allow(deprecated)]
269 T::next_dispatch_time(address)
270 }
271 }
272
273 #[allow(deprecated)]
274 impl<T, BlockNumber, Call, RuntimeOrigin> Named<BlockNumber, Call, RuntimeOrigin> for T
275 where
276 T: v2::Named<BlockNumber, Call, RuntimeOrigin>,
277 {
278 #[allow(deprecated)]
279 type Address = T::Address;
280
281 fn schedule_named(
282 id: Vec<u8>,
283 when: DispatchTime<BlockNumber>,
284 maybe_periodic: Option<Period<BlockNumber>>,
285 priority: Priority,
286 origin: RuntimeOrigin,
287 call: Call,
288 ) -> Result<Self::Address, ()> {
289 let c = MaybeHashed::<Call, T::Hash>::Value(call);
290 #[allow(deprecated)]
291 T::schedule_named(id, when, maybe_periodic, priority, origin, c)
292 }
293
294 fn cancel_named(id: Vec<u8>) -> Result<(), ()> {
295 #[allow(deprecated)]
296 T::cancel_named(id)
297 }
298
299 fn reschedule_named(
300 id: Vec<u8>,
301 when: DispatchTime<BlockNumber>,
302 ) -> Result<Self::Address, DispatchError> {
303 #[allow(deprecated)]
304 T::reschedule_named(id, when)
305 }
306
307 fn next_dispatch_time(id: Vec<u8>) -> Result<BlockNumber, ()> {
308 #[allow(deprecated)]
309 T::next_dispatch_time(id)
310 }
311 }
312}
313
314#[deprecated(note = "Use `v3` instead. Will be removed after September 2024.")]
315pub mod v2 {
316 use super::*;
317
318 /// A type that can be used as a scheduler.
319 pub trait Anon<BlockNumber, Call, RuntimeOrigin> {
320 /// An address which can be used for removing a scheduled task.
321 type Address: Codec + Clone + Eq + EncodeLike + Debug + TypeInfo + MaxEncodedLen;
322 /// A means of expressing a call by the hash of its encoded data.
323 type Hash;
324
325 /// Schedule a dispatch to happen at the beginning of some block in the future.
326 ///
327 /// This is not named.
328 fn schedule(
329 when: DispatchTime<BlockNumber>,
330 maybe_periodic: Option<Period<BlockNumber>>,
331 priority: Priority,
332 origin: RuntimeOrigin,
333 call: MaybeHashed<Call, Self::Hash>,
334 ) -> Result<Self::Address, DispatchError>;
335
336 /// Cancel a scheduled task. If periodic, then it will cancel all further instances of that,
337 /// also.
338 ///
339 /// Will return an error if the `address` is invalid.
340 ///
341 /// NOTE: This guaranteed to work only *before* the point that it is due to be executed.
342 /// If it ends up being delayed beyond the point of execution, then it cannot be cancelled.
343 ///
344 /// NOTE2: This will not work to cancel periodic tasks after their initial execution. For
345 /// that, you must name the task explicitly using the `Named` trait.
346 fn cancel(address: Self::Address) -> Result<(), ()>;
347
348 /// Reschedule a task. For one-off tasks, this dispatch is guaranteed to succeed
349 /// only if it is executed *before* the currently scheduled block. For periodic tasks,
350 /// this dispatch is guaranteed to succeed only before the *initial* execution; for
351 /// others, use `reschedule_named`.
352 ///
353 /// Will return an error if the `address` is invalid.
354 fn reschedule(
355 address: Self::Address,
356 when: DispatchTime<BlockNumber>,
357 ) -> Result<Self::Address, DispatchError>;
358
359 /// Return the next dispatch time for a given task.
360 ///
361 /// Will return an error if the `address` is invalid.
362 fn next_dispatch_time(address: Self::Address) -> Result<BlockNumber, ()>;
363 }
364
365 /// A type that can be used as a scheduler.
366 pub trait Named<BlockNumber, Call, RuntimeOrigin> {
367 /// An address which can be used for removing a scheduled task.
368 type Address: Codec + Clone + Eq + EncodeLike + core::fmt::Debug + MaxEncodedLen;
369 /// A means of expressing a call by the hash of its encoded data.
370 type Hash;
371
372 /// Schedule a dispatch to happen at the beginning of some block in the future.
373 ///
374 /// - `id`: The identity of the task. This must be unique and will return an error if not.
375 fn schedule_named(
376 id: Vec<u8>,
377 when: DispatchTime<BlockNumber>,
378 maybe_periodic: Option<Period<BlockNumber>>,
379 priority: Priority,
380 origin: RuntimeOrigin,
381 call: MaybeHashed<Call, Self::Hash>,
382 ) -> Result<Self::Address, ()>;
383
384 /// Cancel a scheduled, named task. If periodic, then it will cancel all further instances
385 /// of that, also.
386 ///
387 /// Will return an error if the `id` is invalid.
388 ///
389 /// NOTE: This guaranteed to work only *before* the point that it is due to be executed.
390 /// If it ends up being delayed beyond the point of execution, then it cannot be cancelled.
391 fn cancel_named(id: Vec<u8>) -> Result<(), ()>;
392
393 /// Reschedule a task. For one-off tasks, this dispatch is guaranteed to succeed
394 /// only if it is executed *before* the currently scheduled block.
395 fn reschedule_named(
396 id: Vec<u8>,
397 when: DispatchTime<BlockNumber>,
398 ) -> Result<Self::Address, DispatchError>;
399
400 /// Return the next dispatch time for a given task.
401 ///
402 /// Will return an error if the `id` is invalid.
403 fn next_dispatch_time(id: Vec<u8>) -> Result<BlockNumber, ()>;
404 }
405}
406
407pub mod v3 {
408 use super::*;
409 use crate::traits::Bounded;
410
411 /// A type that can be used as a scheduler.
412 pub trait Anon<BlockNumber, Call, Origin> {
413 /// An address which can be used for removing a scheduled task.
414 type Address: Codec + MaxEncodedLen + Clone + Eq + EncodeLike + Debug + TypeInfo;
415 /// The hasher used in the runtime.
416 type Hasher: sp_runtime::traits::Hash;
417
418 /// Schedule a dispatch to happen at the beginning of some block in the future.
419 ///
420 /// This is not named.
421 fn schedule(
422 when: DispatchTime<BlockNumber>,
423 maybe_periodic: Option<Period<BlockNumber>>,
424 priority: Priority,
425 origin: Origin,
426 call: Bounded<Call, Self::Hasher>,
427 ) -> Result<Self::Address, DispatchError>;
428
429 /// Cancel a scheduled task. If periodic, then it will cancel all further instances of that,
430 /// also.
431 ///
432 /// Will return an `Unavailable` error if the `address` is invalid.
433 ///
434 /// NOTE: This guaranteed to work only *before* the point that it is due to be executed.
435 /// If it ends up being delayed beyond the point of execution, then it cannot be cancelled.
436 ///
437 /// NOTE2: This will not work to cancel periodic tasks after their initial execution. For
438 /// that, you must name the task explicitly using the `Named` trait.
439 fn cancel(address: Self::Address) -> Result<(), DispatchError>;
440
441 /// Reschedule a task. For one-off tasks, this dispatch is guaranteed to succeed
442 /// only if it is executed *before* the currently scheduled block. For periodic tasks,
443 /// this dispatch is guaranteed to succeed only before the *initial* execution; for
444 /// others, use `reschedule_named`.
445 ///
446 /// Will return an `Unavailable` error if the `address` is invalid.
447 fn reschedule(
448 address: Self::Address,
449 when: DispatchTime<BlockNumber>,
450 ) -> Result<Self::Address, DispatchError>;
451
452 /// Return the next dispatch time for a given task.
453 ///
454 /// Will return an `Unavailable` error if the `address` is invalid.
455 fn next_dispatch_time(address: Self::Address) -> Result<BlockNumber, DispatchError>;
456 }
457
458 pub type TaskName = [u8; 32];
459
460 /// A type that can be used as a scheduler.
461 pub trait Named<BlockNumber, Call, Origin> {
462 /// An address which can be used for removing a scheduled task.
463 type Address: Codec + MaxEncodedLen + Clone + Eq + EncodeLike + core::fmt::Debug;
464 /// The hasher used in the runtime.
465 type Hasher: sp_runtime::traits::Hash;
466
467 /// Schedule a dispatch to happen at the beginning of some block in the future.
468 ///
469 /// - `id`: The identity of the task. This must be unique and will return an error if not.
470 ///
471 /// NOTE: This will request `call` to be made available.
472 fn schedule_named(
473 id: TaskName,
474 when: DispatchTime<BlockNumber>,
475 maybe_periodic: Option<Period<BlockNumber>>,
476 priority: Priority,
477 origin: Origin,
478 call: Bounded<Call, Self::Hasher>,
479 ) -> Result<Self::Address, DispatchError>;
480
481 /// Cancel a scheduled, named task. If periodic, then it will cancel all further instances
482 /// of that, also.
483 ///
484 /// Will return an `Unavailable` error if the `id` is invalid.
485 ///
486 /// NOTE: This guaranteed to work only *before* the point that it is due to be executed.
487 /// If it ends up being delayed beyond the point of execution, then it cannot be cancelled.
488 fn cancel_named(id: TaskName) -> Result<(), DispatchError>;
489
490 /// Reschedule a task. For one-off tasks, this dispatch is guaranteed to succeed
491 /// only if it is executed *before* the currently scheduled block.
492 ///
493 /// Will return an `Unavailable` error if the `id` is invalid.
494 fn reschedule_named(
495 id: TaskName,
496 when: DispatchTime<BlockNumber>,
497 ) -> Result<Self::Address, DispatchError>;
498
499 /// Return the next dispatch time for a given task.
500 ///
501 /// Will return an `Unavailable` error if the `id` is invalid.
502 fn next_dispatch_time(id: TaskName) -> Result<BlockNumber, DispatchError>;
503 }
504}
505
506#[allow(deprecated)]
507pub use v1::*;