referrerpolicy=no-referrer-when-downgrade

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::*;