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