frame_support/
dispatch.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//! Dispatch system. Contains a macro for defining runtime modules and
19//! generating values representing lazy module function calls.
20
21use crate::traits::UnfilteredDispatchable;
22use codec::{Codec, Decode, Encode, EncodeLike, MaxEncodedLen};
23use core::fmt;
24use scale_info::TypeInfo;
25#[cfg(feature = "std")]
26use serde::{Deserialize, Serialize};
27use sp_runtime::{
28	generic::{CheckedExtrinsic, UncheckedExtrinsic},
29	traits::SignedExtension,
30	DispatchError, RuntimeDebug,
31};
32use sp_weights::Weight;
33
34/// The return type of a `Dispatchable` in frame. When returned explicitly from
35/// a dispatchable function it allows overriding the default `PostDispatchInfo`
36/// returned from a dispatch.
37pub type DispatchResultWithPostInfo = sp_runtime::DispatchResultWithInfo<PostDispatchInfo>;
38
39#[docify::export]
40/// Un-augmented version of `DispatchResultWithPostInfo` that can be returned from
41/// dispatchable functions and is automatically converted to the augmented type. Should be
42/// used whenever the `PostDispatchInfo` does not need to be overwritten. As this should
43/// be the common case it is the implicit return type when none is specified.
44pub type DispatchResult = Result<(), sp_runtime::DispatchError>;
45
46/// The error type contained in a `DispatchResultWithPostInfo`.
47pub type DispatchErrorWithPostInfo = sp_runtime::DispatchErrorWithPostInfo<PostDispatchInfo>;
48
49/// Serializable version of pallet dispatchable.
50pub trait Callable<T> {
51	type RuntimeCall: UnfilteredDispatchable + Codec + Clone + PartialEq + Eq;
52}
53
54// dirty hack to work around serde_derive issue
55// https://github.com/rust-lang/rust/issues/51331
56pub type CallableCallFor<A, R> = <A as Callable<R>>::RuntimeCall;
57
58/// Means to checks if the dispatchable is feeless.
59///
60/// This is automatically implemented for all dispatchables during pallet expansion.
61/// If a call is marked by [`#[pallet::feeless_if]`](`macro@frame_support_procedural::feeless_if`)
62/// attribute, the corresponding closure is checked.
63pub trait CheckIfFeeless {
64	/// The Origin type of the runtime.
65	type Origin;
66
67	/// Checks if the dispatchable satisfies the feeless condition as defined by
68	/// [`#[pallet::feeless_if]`](`macro@frame_support_procedural::feeless_if`)
69	fn is_feeless(&self, origin: &Self::Origin) -> bool;
70}
71
72/// Origin for the System pallet.
73#[derive(PartialEq, Eq, Clone, RuntimeDebug, Encode, Decode, TypeInfo, MaxEncodedLen)]
74pub enum RawOrigin<AccountId> {
75	/// The system itself ordained this dispatch to happen: this is the highest privilege level.
76	Root,
77	/// It is signed by some public key and we provide the `AccountId`.
78	Signed(AccountId),
79	/// It is signed by nobody, can be either:
80	/// * included and agreed upon by the validators anyway,
81	/// * or unsigned transaction validated by a pallet.
82	None,
83}
84
85impl<AccountId> From<Option<AccountId>> for RawOrigin<AccountId> {
86	fn from(s: Option<AccountId>) -> RawOrigin<AccountId> {
87		match s {
88			Some(who) => RawOrigin::Signed(who),
89			None => RawOrigin::None,
90		}
91	}
92}
93
94impl<AccountId> RawOrigin<AccountId> {
95	/// Returns `Some` with a reference to the `AccountId` if `self` is `Signed`, `None` otherwise.
96	pub fn as_signed(&self) -> Option<&AccountId> {
97		match &self {
98			Self::Signed(x) => Some(x),
99			_ => None,
100		}
101	}
102
103	/// Returns `true` if `self` is `Root`, `None` otherwise.
104	pub fn is_root(&self) -> bool {
105		matches!(&self, Self::Root)
106	}
107
108	/// Returns `true` if `self` is `None`, `None` otherwise.
109	pub fn is_none(&self) -> bool {
110		matches!(&self, Self::None)
111	}
112}
113
114/// A type that can be used as a parameter in a dispatchable function.
115///
116/// When using `decl_module` all arguments for call functions must implement this trait.
117pub trait Parameter: Codec + EncodeLike + Clone + Eq + fmt::Debug + scale_info::TypeInfo {}
118impl<T> Parameter for T where T: Codec + EncodeLike + Clone + Eq + fmt::Debug + scale_info::TypeInfo {}
119
120/// Means of classifying a dispatchable function.
121pub trait ClassifyDispatch<T> {
122	/// Classify the dispatch function based on input data `target` of type `T`. When implementing
123	/// this for a dispatchable, `T` will be a tuple of all arguments given to the function (except
124	/// origin).
125	fn classify_dispatch(&self, target: T) -> DispatchClass;
126}
127
128/// Indicates if dispatch function should pay fees or not.
129///
130/// If set to `Pays::No`, the block resource limits are applied, yet no fee is deducted.
131pub trait PaysFee<T> {
132	fn pays_fee(&self, _target: T) -> Pays;
133}
134
135/// Explicit enum to denote if a transaction pays fee or not.
136#[derive(Clone, Copy, Eq, PartialEq, RuntimeDebug, Encode, Decode, TypeInfo)]
137pub enum Pays {
138	/// Transactor will pay related fees.
139	Yes,
140	/// Transactor will NOT pay related fees.
141	No,
142}
143
144impl Default for Pays {
145	fn default() -> Self {
146		Self::Yes
147	}
148}
149
150impl From<Pays> for PostDispatchInfo {
151	fn from(pays_fee: Pays) -> Self {
152		Self { actual_weight: None, pays_fee }
153	}
154}
155
156impl From<bool> for Pays {
157	fn from(b: bool) -> Self {
158		match b {
159			true => Self::Yes,
160			false => Self::No,
161		}
162	}
163}
164
165/// A generalized group of dispatch types.
166///
167/// NOTE whenever upgrading the enum make sure to also update
168/// [DispatchClass::all] and [DispatchClass::non_mandatory] helper functions.
169#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
170#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))]
171#[derive(PartialEq, Eq, Clone, Copy, Encode, Decode, RuntimeDebug, TypeInfo)]
172pub enum DispatchClass {
173	/// A normal dispatch.
174	Normal,
175	/// An operational dispatch.
176	Operational,
177	/// A mandatory dispatch. These kinds of dispatch are always included regardless of their
178	/// weight, therefore it is critical that they are separately validated to ensure that a
179	/// malicious validator cannot craft a valid but impossibly heavy block. Usually this just
180	/// means ensuring that the extrinsic can only be included once and that it is always very
181	/// light.
182	///
183	/// Do *NOT* use it for extrinsics that can be heavy.
184	///
185	/// The only real use case for this is inherent extrinsics that are required to execute in a
186	/// block for the block to be valid, and it solves the issue in the case that the block
187	/// initialization is sufficiently heavy to mean that those inherents do not fit into the
188	/// block. Essentially, we assume that in these exceptional circumstances, it is better to
189	/// allow an overweight block to be created than to not allow any block at all to be created.
190	Mandatory,
191}
192
193impl Default for DispatchClass {
194	fn default() -> Self {
195		Self::Normal
196	}
197}
198
199impl DispatchClass {
200	/// Returns an array containing all dispatch classes.
201	pub fn all() -> &'static [DispatchClass] {
202		&[DispatchClass::Normal, DispatchClass::Operational, DispatchClass::Mandatory]
203	}
204
205	/// Returns an array of all dispatch classes except `Mandatory`.
206	pub fn non_mandatory() -> &'static [DispatchClass] {
207		&[DispatchClass::Normal, DispatchClass::Operational]
208	}
209}
210
211/// A trait that represents one or many values of given type.
212///
213/// Useful to accept as parameter type to let the caller pass either a single value directly
214/// or an iterator.
215pub trait OneOrMany<T> {
216	/// The iterator type.
217	type Iter: Iterator<Item = T>;
218	/// Convert this item into an iterator.
219	fn into_iter(self) -> Self::Iter;
220}
221
222impl OneOrMany<DispatchClass> for DispatchClass {
223	type Iter = core::iter::Once<DispatchClass>;
224	fn into_iter(self) -> Self::Iter {
225		core::iter::once(self)
226	}
227}
228
229impl<'a> OneOrMany<DispatchClass> for &'a [DispatchClass] {
230	type Iter = core::iter::Cloned<core::slice::Iter<'a, DispatchClass>>;
231	fn into_iter(self) -> Self::Iter {
232		self.iter().cloned()
233	}
234}
235
236/// A bundle of static information collected from the `#[pallet::weight]` attributes.
237#[derive(Clone, Copy, Eq, PartialEq, Default, RuntimeDebug, Encode, Decode, TypeInfo)]
238pub struct DispatchInfo {
239	/// Weight of this transaction.
240	pub weight: Weight,
241	/// Class of this transaction.
242	pub class: DispatchClass,
243	/// Does this transaction pay fees.
244	pub pays_fee: Pays,
245}
246
247/// A `Dispatchable` function (aka transaction) that can carry some static information along with
248/// it, using the `#[pallet::weight]` attribute.
249pub trait GetDispatchInfo {
250	/// Return a `DispatchInfo`, containing relevant information of this dispatch.
251	///
252	/// This is done independently of its encoded size.
253	fn get_dispatch_info(&self) -> DispatchInfo;
254}
255
256impl GetDispatchInfo for () {
257	fn get_dispatch_info(&self) -> DispatchInfo {
258		DispatchInfo::default()
259	}
260}
261
262/// Extract the actual weight from a dispatch result if any or fall back to the default weight.
263pub fn extract_actual_weight(result: &DispatchResultWithPostInfo, info: &DispatchInfo) -> Weight {
264	match result {
265		Ok(post_info) => post_info,
266		Err(err) => &err.post_info,
267	}
268	.calc_actual_weight(info)
269}
270
271/// Extract the actual pays_fee from a dispatch result if any or fall back to the default weight.
272pub fn extract_actual_pays_fee(result: &DispatchResultWithPostInfo, info: &DispatchInfo) -> Pays {
273	match result {
274		Ok(post_info) => post_info,
275		Err(err) => &err.post_info,
276	}
277	.pays_fee(info)
278}
279
280/// Weight information that is only available post dispatch.
281/// NOTE: This can only be used to reduce the weight or fee, not increase it.
282#[derive(Clone, Copy, Eq, PartialEq, Default, RuntimeDebug, Encode, Decode, TypeInfo)]
283pub struct PostDispatchInfo {
284	/// Actual weight consumed by a call or `None` which stands for the worst case static weight.
285	pub actual_weight: Option<Weight>,
286	/// Whether this transaction should pay fees when all is said and done.
287	pub pays_fee: Pays,
288}
289
290impl PostDispatchInfo {
291	/// Calculate how much (if any) weight was not used by the `Dispatchable`.
292	pub fn calc_unspent(&self, info: &DispatchInfo) -> Weight {
293		info.weight - self.calc_actual_weight(info)
294	}
295
296	/// Calculate how much weight was actually spent by the `Dispatchable`.
297	pub fn calc_actual_weight(&self, info: &DispatchInfo) -> Weight {
298		if let Some(actual_weight) = self.actual_weight {
299			actual_weight.min(info.weight)
300		} else {
301			info.weight
302		}
303	}
304
305	/// Determine if user should actually pay fees at the end of the dispatch.
306	pub fn pays_fee(&self, info: &DispatchInfo) -> Pays {
307		// If they originally were not paying fees, or the post dispatch info
308		// says they should not pay fees, then they don't pay fees.
309		// This is because the pre dispatch information must contain the
310		// worst case for weight and fees paid.
311		if info.pays_fee == Pays::No || self.pays_fee == Pays::No {
312			Pays::No
313		} else {
314			// Otherwise they pay.
315			Pays::Yes
316		}
317	}
318}
319
320impl From<()> for PostDispatchInfo {
321	fn from(_: ()) -> Self {
322		Self { actual_weight: None, pays_fee: Default::default() }
323	}
324}
325
326impl sp_runtime::traits::Printable for PostDispatchInfo {
327	fn print(&self) {
328		"actual_weight=".print();
329		match self.actual_weight {
330			Some(weight) => weight.print(),
331			None => "max-weight".print(),
332		};
333		"pays_fee=".print();
334		match self.pays_fee {
335			Pays::Yes => "Yes".print(),
336			Pays::No => "No".print(),
337		}
338	}
339}
340
341/// Allows easy conversion from `DispatchError` to `DispatchErrorWithPostInfo` for dispatchables
342/// that want to return a custom a posterior weight on error.
343pub trait WithPostDispatchInfo {
344	/// Call this on your modules custom errors type in order to return a custom weight on error.
345	///
346	/// # Example
347	///
348	/// ```ignore
349	/// let who = ensure_signed(origin).map_err(|e| e.with_weight(Weight::from_parts(100, 0)))?;
350	/// ensure!(who == me, Error::<T>::NotMe.with_weight(200_000));
351	/// ```
352	fn with_weight(self, actual_weight: Weight) -> DispatchErrorWithPostInfo;
353}
354
355impl<T> WithPostDispatchInfo for T
356where
357	T: Into<DispatchError>,
358{
359	fn with_weight(self, actual_weight: Weight) -> DispatchErrorWithPostInfo {
360		DispatchErrorWithPostInfo {
361			post_info: PostDispatchInfo {
362				actual_weight: Some(actual_weight),
363				pays_fee: Default::default(),
364			},
365			error: self.into(),
366		}
367	}
368}
369
370/// Implementation for unchecked extrinsic.
371impl<Address, Call, Signature, Extra> GetDispatchInfo
372	for UncheckedExtrinsic<Address, Call, Signature, Extra>
373where
374	Call: GetDispatchInfo,
375	Extra: SignedExtension,
376{
377	fn get_dispatch_info(&self) -> DispatchInfo {
378		self.function.get_dispatch_info()
379	}
380}
381
382/// Implementation for checked extrinsic.
383impl<AccountId, Call, Extra> GetDispatchInfo for CheckedExtrinsic<AccountId, Call, Extra>
384where
385	Call: GetDispatchInfo,
386{
387	fn get_dispatch_info(&self) -> DispatchInfo {
388		self.function.get_dispatch_info()
389	}
390}
391
392/// Implementation for test extrinsic.
393#[cfg(feature = "std")]
394impl<Call: Encode + GetDispatchInfo, Extra: Encode> GetDispatchInfo
395	for sp_runtime::testing::TestXt<Call, Extra>
396{
397	fn get_dispatch_info(&self) -> DispatchInfo {
398		// for testing: weight == size.
399		DispatchInfo {
400			weight: Weight::from_parts(self.encode().len() as _, 0),
401			pays_fee: Pays::Yes,
402			class: self.call.get_dispatch_info().class,
403		}
404	}
405}
406
407/// A struct holding value for each `DispatchClass`.
408#[derive(Clone, Eq, PartialEq, Default, Debug, Encode, Decode, TypeInfo, MaxEncodedLen)]
409pub struct PerDispatchClass<T> {
410	/// Value for `Normal` extrinsics.
411	normal: T,
412	/// Value for `Operational` extrinsics.
413	operational: T,
414	/// Value for `Mandatory` extrinsics.
415	mandatory: T,
416}
417
418impl<T> PerDispatchClass<T> {
419	/// Create new `PerDispatchClass` with the same value for every class.
420	pub fn new(val: impl Fn(DispatchClass) -> T) -> Self {
421		Self {
422			normal: val(DispatchClass::Normal),
423			operational: val(DispatchClass::Operational),
424			mandatory: val(DispatchClass::Mandatory),
425		}
426	}
427
428	/// Get a mutable reference to current value of given class.
429	pub fn get_mut(&mut self, class: DispatchClass) -> &mut T {
430		match class {
431			DispatchClass::Operational => &mut self.operational,
432			DispatchClass::Normal => &mut self.normal,
433			DispatchClass::Mandatory => &mut self.mandatory,
434		}
435	}
436
437	/// Get current value for given class.
438	pub fn get(&self, class: DispatchClass) -> &T {
439		match class {
440			DispatchClass::Normal => &self.normal,
441			DispatchClass::Operational => &self.operational,
442			DispatchClass::Mandatory => &self.mandatory,
443		}
444	}
445}
446
447impl<T: Clone> PerDispatchClass<T> {
448	/// Set the value of given class.
449	pub fn set(&mut self, new: T, class: impl OneOrMany<DispatchClass>) {
450		for class in class.into_iter() {
451			*self.get_mut(class) = new.clone();
452		}
453	}
454}
455
456impl PerDispatchClass<Weight> {
457	/// Returns the total weight consumed by all extrinsics in the block.
458	///
459	/// Saturates on overflow.
460	pub fn total(&self) -> Weight {
461		let mut sum = Weight::zero();
462		for class in DispatchClass::all() {
463			sum.saturating_accrue(*self.get(*class));
464		}
465		sum
466	}
467
468	/// Add some weight to the given class. Saturates at the numeric bounds.
469	pub fn add(mut self, weight: Weight, class: DispatchClass) -> Self {
470		self.accrue(weight, class);
471		self
472	}
473
474	/// Increase the weight of the given class. Saturates at the numeric bounds.
475	pub fn accrue(&mut self, weight: Weight, class: DispatchClass) {
476		self.get_mut(class).saturating_accrue(weight);
477	}
478
479	/// Try to increase the weight of the given class. Saturates at the numeric bounds.
480	pub fn checked_accrue(&mut self, weight: Weight, class: DispatchClass) -> Result<(), ()> {
481		self.get_mut(class).checked_accrue(weight).ok_or(())
482	}
483
484	/// Reduce the weight of the given class. Saturates at the numeric bounds.
485	pub fn reduce(&mut self, weight: Weight, class: DispatchClass) {
486		self.get_mut(class).saturating_reduce(weight);
487	}
488}
489
490/// Means of weighing some particular kind of data (`T`).
491pub trait WeighData<T> {
492	/// Weigh the data `T` given by `target`. When implementing this for a dispatchable, `T` will be
493	/// a tuple of all arguments given to the function (except origin).
494	fn weigh_data(&self, target: T) -> Weight;
495}
496
497impl<T> WeighData<T> for Weight {
498	fn weigh_data(&self, _: T) -> Weight {
499		return *self
500	}
501}
502
503impl<T> PaysFee<T> for (Weight, DispatchClass, Pays) {
504	fn pays_fee(&self, _: T) -> Pays {
505		self.2
506	}
507}
508
509impl<T> WeighData<T> for (Weight, DispatchClass) {
510	fn weigh_data(&self, args: T) -> Weight {
511		return self.0.weigh_data(args)
512	}
513}
514
515impl<T> WeighData<T> for (Weight, DispatchClass, Pays) {
516	fn weigh_data(&self, args: T) -> Weight {
517		return self.0.weigh_data(args)
518	}
519}
520
521impl<T> ClassifyDispatch<T> for (Weight, DispatchClass) {
522	fn classify_dispatch(&self, _: T) -> DispatchClass {
523		self.1
524	}
525}
526
527impl<T> PaysFee<T> for (Weight, DispatchClass) {
528	fn pays_fee(&self, _: T) -> Pays {
529		Pays::Yes
530	}
531}
532
533impl<T> WeighData<T> for (Weight, Pays) {
534	fn weigh_data(&self, args: T) -> Weight {
535		return self.0.weigh_data(args)
536	}
537}
538
539impl<T> ClassifyDispatch<T> for (Weight, Pays) {
540	fn classify_dispatch(&self, _: T) -> DispatchClass {
541		DispatchClass::Normal
542	}
543}
544
545impl<T> PaysFee<T> for (Weight, Pays) {
546	fn pays_fee(&self, _: T) -> Pays {
547		self.1
548	}
549}
550
551impl From<(Option<Weight>, Pays)> for PostDispatchInfo {
552	fn from(post_weight_info: (Option<Weight>, Pays)) -> Self {
553		let (actual_weight, pays_fee) = post_weight_info;
554		Self { actual_weight, pays_fee }
555	}
556}
557
558impl From<Option<Weight>> for PostDispatchInfo {
559	fn from(actual_weight: Option<Weight>) -> Self {
560		Self { actual_weight, pays_fee: Default::default() }
561	}
562}
563
564impl<T> ClassifyDispatch<T> for Weight {
565	fn classify_dispatch(&self, _: T) -> DispatchClass {
566		DispatchClass::Normal
567	}
568}
569
570impl<T> PaysFee<T> for Weight {
571	fn pays_fee(&self, _: T) -> Pays {
572		Pays::Yes
573	}
574}
575
576impl<T> ClassifyDispatch<T> for (Weight, DispatchClass, Pays) {
577	fn classify_dispatch(&self, _: T) -> DispatchClass {
578		self.1
579	}
580}
581
582// TODO: Eventually remove these
583
584impl<T> ClassifyDispatch<T> for u64 {
585	fn classify_dispatch(&self, _: T) -> DispatchClass {
586		DispatchClass::Normal
587	}
588}
589
590impl<T> PaysFee<T> for u64 {
591	fn pays_fee(&self, _: T) -> Pays {
592		Pays::Yes
593	}
594}
595
596impl<T> WeighData<T> for u64 {
597	fn weigh_data(&self, _: T) -> Weight {
598		return Weight::from_parts(*self, 0)
599	}
600}
601
602impl<T> WeighData<T> for (u64, DispatchClass, Pays) {
603	fn weigh_data(&self, args: T) -> Weight {
604		return self.0.weigh_data(args)
605	}
606}
607
608impl<T> ClassifyDispatch<T> for (u64, DispatchClass, Pays) {
609	fn classify_dispatch(&self, _: T) -> DispatchClass {
610		self.1
611	}
612}
613
614impl<T> PaysFee<T> for (u64, DispatchClass, Pays) {
615	fn pays_fee(&self, _: T) -> Pays {
616		self.2
617	}
618}
619
620impl<T> WeighData<T> for (u64, DispatchClass) {
621	fn weigh_data(&self, args: T) -> Weight {
622		return self.0.weigh_data(args)
623	}
624}
625
626impl<T> ClassifyDispatch<T> for (u64, DispatchClass) {
627	fn classify_dispatch(&self, _: T) -> DispatchClass {
628		self.1
629	}
630}
631
632impl<T> PaysFee<T> for (u64, DispatchClass) {
633	fn pays_fee(&self, _: T) -> Pays {
634		Pays::Yes
635	}
636}
637
638impl<T> WeighData<T> for (u64, Pays) {
639	fn weigh_data(&self, args: T) -> Weight {
640		return self.0.weigh_data(args)
641	}
642}
643
644impl<T> ClassifyDispatch<T> for (u64, Pays) {
645	fn classify_dispatch(&self, _: T) -> DispatchClass {
646		DispatchClass::Normal
647	}
648}
649
650impl<T> PaysFee<T> for (u64, Pays) {
651	fn pays_fee(&self, _: T) -> Pays {
652		self.1
653	}
654}
655
656// END TODO
657
658#[cfg(test)]
659// Do not complain about unused `dispatch` and `dispatch_aux`.
660#[allow(dead_code)]
661mod weight_tests {
662	use super::*;
663	use sp_core::parameter_types;
664	use sp_runtime::{generic, traits::BlakeTwo256};
665	use sp_weights::RuntimeDbWeight;
666
667	pub use self::frame_system::{Call, Config};
668
669	fn from_actual_ref_time(ref_time: Option<u64>) -> PostDispatchInfo {
670		PostDispatchInfo {
671			actual_weight: ref_time.map(|t| Weight::from_all(t)),
672			pays_fee: Default::default(),
673		}
674	}
675
676	fn from_post_weight_info(ref_time: Option<u64>, pays_fee: Pays) -> PostDispatchInfo {
677		PostDispatchInfo { actual_weight: ref_time.map(|t| Weight::from_all(t)), pays_fee }
678	}
679
680	#[crate::pallet(dev_mode)]
681	pub mod frame_system {
682		use super::{frame_system, frame_system::pallet_prelude::*};
683		pub use crate::dispatch::RawOrigin;
684		use crate::pallet_prelude::*;
685
686		#[pallet::pallet]
687		pub struct Pallet<T>(_);
688
689		#[pallet::config]
690		#[pallet::disable_frame_system_supertrait_check]
691		pub trait Config: 'static {
692			type Block: Parameter + sp_runtime::traits::Block;
693			type AccountId;
694			type Balance;
695			type BaseCallFilter: crate::traits::Contains<Self::RuntimeCall>;
696			type RuntimeOrigin;
697			type RuntimeCall;
698			type RuntimeTask;
699			type PalletInfo: crate::traits::PalletInfo;
700			type DbWeight: Get<crate::weights::RuntimeDbWeight>;
701		}
702
703		#[pallet::error]
704		pub enum Error<T> {
705			/// Required by construct_runtime
706			CallFiltered,
707		}
708
709		#[pallet::origin]
710		pub type Origin<T> = RawOrigin<<T as Config>::AccountId>;
711
712		#[pallet::call]
713		impl<T: Config> Pallet<T> {
714			// no arguments, fixed weight
715			#[pallet::weight(1000)]
716			pub fn f00(_origin: OriginFor<T>) -> DispatchResult {
717				unimplemented!();
718			}
719
720			#[pallet::weight((1000, DispatchClass::Mandatory))]
721			pub fn f01(_origin: OriginFor<T>) -> DispatchResult {
722				unimplemented!();
723			}
724
725			#[pallet::weight((1000, Pays::No))]
726			pub fn f02(_origin: OriginFor<T>) -> DispatchResult {
727				unimplemented!();
728			}
729
730			#[pallet::weight((1000, DispatchClass::Operational, Pays::No))]
731			pub fn f03(_origin: OriginFor<T>) -> DispatchResult {
732				unimplemented!();
733			}
734
735			// weight = a x 10 + b
736			#[pallet::weight(((_a * 10 + _eb * 1) as u64, DispatchClass::Normal, Pays::Yes))]
737			pub fn f11(_origin: OriginFor<T>, _a: u32, _eb: u32) -> DispatchResult {
738				unimplemented!();
739			}
740
741			#[pallet::weight((0, DispatchClass::Operational, Pays::Yes))]
742			pub fn f12(_origin: OriginFor<T>, _a: u32, _eb: u32) -> DispatchResult {
743				unimplemented!();
744			}
745
746			#[pallet::weight(T::DbWeight::get().reads(3) + T::DbWeight::get().writes(2) + Weight::from_all(10_000))]
747			pub fn f20(_origin: OriginFor<T>) -> DispatchResult {
748				unimplemented!();
749			}
750
751			#[pallet::weight(T::DbWeight::get().reads_writes(6, 5) + Weight::from_all(40_000))]
752			pub fn f21(_origin: OriginFor<T>) -> DispatchResult {
753				unimplemented!();
754			}
755		}
756
757		pub mod pallet_prelude {
758			pub type OriginFor<T> = <T as super::Config>::RuntimeOrigin;
759
760			pub type HeaderFor<T> =
761				<<T as super::Config>::Block as sp_runtime::traits::HeaderProvider>::HeaderT;
762
763			pub type BlockNumberFor<T> = <HeaderFor<T> as sp_runtime::traits::Header>::Number;
764		}
765	}
766
767	type BlockNumber = u32;
768	type AccountId = u32;
769	type Balance = u32;
770	type Header = generic::Header<BlockNumber, BlakeTwo256>;
771	type UncheckedExtrinsic = generic::UncheckedExtrinsic<u32, RuntimeCall, (), ()>;
772	type Block = generic::Block<Header, UncheckedExtrinsic>;
773
774	crate::construct_runtime!(
775		pub enum Runtime
776		{
777			System: self::frame_system,
778		}
779	);
780
781	parameter_types! {
782		pub const DbWeight: RuntimeDbWeight = RuntimeDbWeight {
783			read: 100,
784			write: 1000,
785		};
786	}
787
788	impl Config for Runtime {
789		type Block = Block;
790		type AccountId = AccountId;
791		type Balance = Balance;
792		type BaseCallFilter = crate::traits::Everything;
793		type RuntimeOrigin = RuntimeOrigin;
794		type RuntimeCall = RuntimeCall;
795		type RuntimeTask = RuntimeTask;
796		type DbWeight = DbWeight;
797		type PalletInfo = PalletInfo;
798	}
799
800	#[test]
801	fn weights_are_correct() {
802		// #[pallet::weight(1000)]
803		let info = Call::<Runtime>::f00 {}.get_dispatch_info();
804		assert_eq!(info.weight, Weight::from_parts(1000, 0));
805		assert_eq!(info.class, DispatchClass::Normal);
806		assert_eq!(info.pays_fee, Pays::Yes);
807
808		// #[pallet::weight((1000, DispatchClass::Mandatory))]
809		let info = Call::<Runtime>::f01 {}.get_dispatch_info();
810		assert_eq!(info.weight, Weight::from_parts(1000, 0));
811		assert_eq!(info.class, DispatchClass::Mandatory);
812		assert_eq!(info.pays_fee, Pays::Yes);
813
814		// #[pallet::weight((1000, Pays::No))]
815		let info = Call::<Runtime>::f02 {}.get_dispatch_info();
816		assert_eq!(info.weight, Weight::from_parts(1000, 0));
817		assert_eq!(info.class, DispatchClass::Normal);
818		assert_eq!(info.pays_fee, Pays::No);
819
820		// #[pallet::weight((1000, DispatchClass::Operational, Pays::No))]
821		let info = Call::<Runtime>::f03 {}.get_dispatch_info();
822		assert_eq!(info.weight, Weight::from_parts(1000, 0));
823		assert_eq!(info.class, DispatchClass::Operational);
824		assert_eq!(info.pays_fee, Pays::No);
825
826		// #[pallet::weight(((_a * 10 + _eb * 1) as u64, DispatchClass::Normal, Pays::Yes))]
827		let info = Call::<Runtime>::f11 { a: 13, eb: 20 }.get_dispatch_info();
828		assert_eq!(info.weight, Weight::from_parts(150, 0)); // 13*10 + 20
829		assert_eq!(info.class, DispatchClass::Normal);
830		assert_eq!(info.pays_fee, Pays::Yes);
831
832		// #[pallet::weight((0, DispatchClass::Operational, Pays::Yes))]
833		let info = Call::<Runtime>::f12 { a: 10, eb: 20 }.get_dispatch_info();
834		assert_eq!(info.weight, Weight::zero());
835		assert_eq!(info.class, DispatchClass::Operational);
836		assert_eq!(info.pays_fee, Pays::Yes);
837
838		// #[pallet::weight(T::DbWeight::get().reads(3) + T::DbWeight::get().writes(2) +
839		// Weight::from_all(10_000))]
840		let info = Call::<Runtime>::f20 {}.get_dispatch_info();
841		assert_eq!(info.weight, Weight::from_parts(12300, 10000)); // 100*3 + 1000*2 + 10_1000
842		assert_eq!(info.class, DispatchClass::Normal);
843		assert_eq!(info.pays_fee, Pays::Yes);
844
845		// #[pallet::weight(T::DbWeight::get().reads_writes(6, 5) + Weight::from_all(40_000))]
846		let info = Call::<Runtime>::f21 {}.get_dispatch_info();
847		assert_eq!(info.weight, Weight::from_parts(45600, 40000)); // 100*6 + 1000*5 + 40_1000
848		assert_eq!(info.class, DispatchClass::Normal);
849		assert_eq!(info.pays_fee, Pays::Yes);
850	}
851
852	#[test]
853	fn extract_actual_weight_works() {
854		let pre = DispatchInfo { weight: Weight::from_parts(1000, 0), ..Default::default() };
855		assert_eq!(
856			extract_actual_weight(&Ok(from_actual_ref_time(Some(7))), &pre),
857			Weight::from_parts(7, 0)
858		);
859		assert_eq!(
860			extract_actual_weight(&Ok(from_actual_ref_time(Some(1000))), &pre),
861			Weight::from_parts(1000, 0)
862		);
863		assert_eq!(
864			extract_actual_weight(
865				&Err(DispatchError::BadOrigin.with_weight(Weight::from_parts(9, 0))),
866				&pre
867			),
868			Weight::from_parts(9, 0)
869		);
870	}
871
872	#[test]
873	fn extract_actual_weight_caps_at_pre_weight() {
874		let pre = DispatchInfo { weight: Weight::from_parts(1000, 0), ..Default::default() };
875		assert_eq!(
876			extract_actual_weight(&Ok(from_actual_ref_time(Some(1250))), &pre),
877			Weight::from_parts(1000, 0)
878		);
879		assert_eq!(
880			extract_actual_weight(
881				&Err(DispatchError::BadOrigin.with_weight(Weight::from_parts(1300, 0))),
882				&pre
883			),
884			Weight::from_parts(1000, 0),
885		);
886	}
887
888	#[test]
889	fn extract_actual_pays_fee_works() {
890		let pre = DispatchInfo { weight: Weight::from_parts(1000, 0), ..Default::default() };
891		assert_eq!(extract_actual_pays_fee(&Ok(from_actual_ref_time(Some(7))), &pre), Pays::Yes);
892		assert_eq!(
893			extract_actual_pays_fee(&Ok(from_actual_ref_time(Some(1000)).into()), &pre),
894			Pays::Yes
895		);
896		assert_eq!(
897			extract_actual_pays_fee(&Ok(from_post_weight_info(Some(1000), Pays::Yes)), &pre),
898			Pays::Yes
899		);
900		assert_eq!(
901			extract_actual_pays_fee(&Ok(from_post_weight_info(Some(1000), Pays::No)), &pre),
902			Pays::No
903		);
904		assert_eq!(
905			extract_actual_pays_fee(
906				&Err(DispatchError::BadOrigin.with_weight(Weight::from_parts(9, 0))),
907				&pre
908			),
909			Pays::Yes
910		);
911		assert_eq!(
912			extract_actual_pays_fee(
913				&Err(DispatchErrorWithPostInfo {
914					post_info: PostDispatchInfo { actual_weight: None, pays_fee: Pays::No },
915					error: DispatchError::BadOrigin,
916				}),
917				&pre
918			),
919			Pays::No
920		);
921
922		let pre = DispatchInfo {
923			weight: Weight::from_parts(1000, 0),
924			pays_fee: Pays::No,
925			..Default::default()
926		};
927		assert_eq!(extract_actual_pays_fee(&Ok(from_actual_ref_time(Some(7))), &pre), Pays::No);
928		assert_eq!(extract_actual_pays_fee(&Ok(from_actual_ref_time(Some(1000))), &pre), Pays::No);
929		assert_eq!(
930			extract_actual_pays_fee(&Ok(from_post_weight_info(Some(1000), Pays::Yes)), &pre),
931			Pays::No
932		);
933	}
934}
935
936#[cfg(test)]
937mod per_dispatch_class_tests {
938	use super::*;
939	use sp_runtime::traits::Zero;
940	use DispatchClass::*;
941
942	#[test]
943	fn add_works() {
944		let a = PerDispatchClass {
945			normal: (5, 10).into(),
946			operational: (20, 30).into(),
947			mandatory: Weight::MAX,
948		};
949		assert_eq!(
950			a.clone()
951				.add((20, 5).into(), Normal)
952				.add((10, 10).into(), Operational)
953				.add((u64::MAX, 3).into(), Mandatory),
954			PerDispatchClass {
955				normal: (25, 15).into(),
956				operational: (30, 40).into(),
957				mandatory: Weight::MAX
958			}
959		);
960		let b = a
961			.add(Weight::MAX, Normal)
962			.add(Weight::MAX, Operational)
963			.add(Weight::MAX, Mandatory);
964		assert_eq!(
965			b,
966			PerDispatchClass {
967				normal: Weight::MAX,
968				operational: Weight::MAX,
969				mandatory: Weight::MAX
970			}
971		);
972		assert_eq!(b.total(), Weight::MAX);
973	}
974
975	#[test]
976	fn accrue_works() {
977		let mut a = PerDispatchClass::default();
978
979		a.accrue((10, 15).into(), Normal);
980		assert_eq!(a.normal, (10, 15).into());
981		assert_eq!(a.total(), (10, 15).into());
982
983		a.accrue((20, 25).into(), Operational);
984		assert_eq!(a.operational, (20, 25).into());
985		assert_eq!(a.total(), (30, 40).into());
986
987		a.accrue((30, 35).into(), Mandatory);
988		assert_eq!(a.mandatory, (30, 35).into());
989		assert_eq!(a.total(), (60, 75).into());
990
991		a.accrue((u64::MAX, 10).into(), Operational);
992		assert_eq!(a.operational, (u64::MAX, 35).into());
993		assert_eq!(a.total(), (u64::MAX, 85).into());
994
995		a.accrue((10, u64::MAX).into(), Normal);
996		assert_eq!(a.normal, (20, u64::MAX).into());
997		assert_eq!(a.total(), Weight::MAX);
998	}
999
1000	#[test]
1001	fn reduce_works() {
1002		let mut a = PerDispatchClass {
1003			normal: (10, u64::MAX).into(),
1004			mandatory: (u64::MAX, 10).into(),
1005			operational: (20, 20).into(),
1006		};
1007
1008		a.reduce((5, 100).into(), Normal);
1009		assert_eq!(a.normal, (5, u64::MAX - 100).into());
1010		assert_eq!(a.total(), (u64::MAX, u64::MAX - 70).into());
1011
1012		a.reduce((15, 5).into(), Operational);
1013		assert_eq!(a.operational, (5, 15).into());
1014		assert_eq!(a.total(), (u64::MAX, u64::MAX - 75).into());
1015
1016		a.reduce((50, 0).into(), Mandatory);
1017		assert_eq!(a.mandatory, (u64::MAX - 50, 10).into());
1018		assert_eq!(a.total(), (u64::MAX - 40, u64::MAX - 75).into());
1019
1020		a.reduce((u64::MAX, 100).into(), Operational);
1021		assert!(a.operational.is_zero());
1022		assert_eq!(a.total(), (u64::MAX - 45, u64::MAX - 90).into());
1023
1024		a.reduce((5, u64::MAX).into(), Normal);
1025		assert!(a.normal.is_zero());
1026		assert_eq!(a.total(), (u64::MAX - 50, 10).into());
1027	}
1028
1029	#[test]
1030	fn checked_accrue_works() {
1031		let mut a = PerDispatchClass::default();
1032
1033		a.checked_accrue((1, 2).into(), Normal).unwrap();
1034		a.checked_accrue((3, 4).into(), Operational).unwrap();
1035		a.checked_accrue((5, 6).into(), Mandatory).unwrap();
1036		a.checked_accrue((7, 8).into(), Operational).unwrap();
1037		a.checked_accrue((9, 0).into(), Normal).unwrap();
1038
1039		assert_eq!(
1040			a,
1041			PerDispatchClass {
1042				normal: (10, 2).into(),
1043				operational: (10, 12).into(),
1044				mandatory: (5, 6).into(),
1045			}
1046		);
1047
1048		a.checked_accrue((u64::MAX - 10, u64::MAX - 2).into(), Normal).unwrap();
1049		a.checked_accrue((0, 0).into(), Normal).unwrap();
1050		a.checked_accrue((1, 0).into(), Normal).unwrap_err();
1051		a.checked_accrue((0, 1).into(), Normal).unwrap_err();
1052
1053		assert_eq!(
1054			a,
1055			PerDispatchClass {
1056				normal: Weight::MAX,
1057				operational: (10, 12).into(),
1058				mandatory: (5, 6).into(),
1059			}
1060		);
1061	}
1062
1063	#[test]
1064	fn checked_accrue_does_not_modify_on_error() {
1065		let mut a = PerDispatchClass {
1066			normal: 0.into(),
1067			operational: Weight::MAX / 2 + 2.into(),
1068			mandatory: 10.into(),
1069		};
1070
1071		a.checked_accrue(Weight::MAX / 2, Operational).unwrap_err();
1072		a.checked_accrue(Weight::MAX - 9.into(), Mandatory).unwrap_err();
1073		a.checked_accrue(Weight::MAX, Normal).unwrap(); // This one works
1074
1075		assert_eq!(
1076			a,
1077			PerDispatchClass {
1078				normal: Weight::MAX,
1079				operational: Weight::MAX / 2 + 2.into(),
1080				mandatory: 10.into(),
1081			}
1082		);
1083	}
1084
1085	#[test]
1086	fn total_works() {
1087		assert!(PerDispatchClass::default().total().is_zero());
1088
1089		assert_eq!(
1090			PerDispatchClass {
1091				normal: 0.into(),
1092				operational: (10, 20).into(),
1093				mandatory: (20, u64::MAX).into(),
1094			}
1095			.total(),
1096			(30, u64::MAX).into()
1097		);
1098
1099		assert_eq!(
1100			PerDispatchClass {
1101				normal: (u64::MAX - 10, 10).into(),
1102				operational: (3, u64::MAX).into(),
1103				mandatory: (4, u64::MAX).into(),
1104			}
1105			.total(),
1106			(u64::MAX - 3, u64::MAX).into()
1107		);
1108	}
1109}