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, DecodeWithMemTracking, 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::{
30		Dispatchable, ExtensionPostDispatchWeightHandler, RefundWeight, TransactionExtension,
31	},
32	DispatchError, RuntimeDebug,
33};
34use sp_weights::Weight;
35
36/// The return type of a `Dispatchable` in frame. When returned explicitly from
37/// a dispatchable function it allows overriding the default `PostDispatchInfo`
38/// returned from a dispatch.
39pub type DispatchResultWithPostInfo = sp_runtime::DispatchResultWithInfo<PostDispatchInfo>;
40
41#[docify::export]
42/// Un-augmented version of `DispatchResultWithPostInfo` that can be returned from
43/// dispatchable functions and is automatically converted to the augmented type. Should be
44/// used whenever the `PostDispatchInfo` does not need to be overwritten. As this should
45/// be the common case it is the implicit return type when none is specified.
46pub type DispatchResult = Result<(), sp_runtime::DispatchError>;
47
48/// The error type contained in a `DispatchResultWithPostInfo`.
49pub type DispatchErrorWithPostInfo = sp_runtime::DispatchErrorWithPostInfo<PostDispatchInfo>;
50
51/// Serializable version of pallet dispatchable.
52pub trait Callable<T> {
53	type RuntimeCall: UnfilteredDispatchable + Codec + Clone + PartialEq + Eq;
54}
55
56// dirty hack to work around serde_derive issue
57// https://github.com/rust-lang/rust/issues/51331
58pub type CallableCallFor<A, R> = <A as Callable<R>>::RuntimeCall;
59
60/// Means to checks if the dispatchable is feeless.
61///
62/// This is automatically implemented for all dispatchables during pallet expansion.
63/// If a call is marked by [`#[pallet::feeless_if]`](`macro@frame_support_procedural::feeless_if`)
64/// attribute, the corresponding closure is checked.
65pub trait CheckIfFeeless {
66	/// The Origin type of the runtime.
67	type Origin;
68
69	/// Checks if the dispatchable satisfies the feeless condition as defined by
70	/// [`#[pallet::feeless_if]`](`macro@frame_support_procedural::feeless_if`)
71	fn is_feeless(&self, origin: &Self::Origin) -> bool;
72}
73
74/// Origin for the System pallet.
75#[derive(
76	PartialEq,
77	Eq,
78	Clone,
79	RuntimeDebug,
80	Encode,
81	Decode,
82	DecodeWithMemTracking,
83	TypeInfo,
84	MaxEncodedLen,
85)]
86pub enum RawOrigin<AccountId> {
87	/// The system itself ordained this dispatch to happen: this is the highest privilege level.
88	Root,
89	/// It is signed by some public key and we provide the `AccountId`.
90	Signed(AccountId),
91	/// It is signed by nobody, can be either:
92	/// * included and agreed upon by the validators anyway,
93	/// * or unsigned transaction validated by a pallet.
94	None,
95}
96
97impl<AccountId> From<Option<AccountId>> for RawOrigin<AccountId> {
98	fn from(s: Option<AccountId>) -> RawOrigin<AccountId> {
99		match s {
100			Some(who) => RawOrigin::Signed(who),
101			None => RawOrigin::None,
102		}
103	}
104}
105
106impl<AccountId> RawOrigin<AccountId> {
107	/// Returns `Some` with a reference to the `AccountId` if `self` is `Signed`, `None` otherwise.
108	pub fn as_signed(&self) -> Option<&AccountId> {
109		match &self {
110			Self::Signed(x) => Some(x),
111			_ => None,
112		}
113	}
114
115	/// Returns `true` if `self` is `Root`, `None` otherwise.
116	pub fn is_root(&self) -> bool {
117		matches!(&self, Self::Root)
118	}
119
120	/// Returns `true` if `self` is `None`, `None` otherwise.
121	pub fn is_none(&self) -> bool {
122		matches!(&self, Self::None)
123	}
124}
125
126/// A type that can be used as a parameter in a dispatchable function.
127///
128/// When using `decl_module` all arguments for call functions must implement this trait.
129pub trait Parameter:
130	Codec + DecodeWithMemTracking + EncodeLike + Clone + Eq + fmt::Debug + scale_info::TypeInfo
131{
132}
133impl<T> Parameter for T where
134	T: Codec + DecodeWithMemTracking + EncodeLike + Clone + Eq + fmt::Debug + scale_info::TypeInfo
135{
136}
137
138/// Means of classifying a dispatchable function.
139pub trait ClassifyDispatch<T> {
140	/// Classify the dispatch function based on input data `target` of type `T`. When implementing
141	/// this for a dispatchable, `T` will be a tuple of all arguments given to the function (except
142	/// origin).
143	fn classify_dispatch(&self, target: T) -> DispatchClass;
144}
145
146/// Indicates if dispatch function should pay fees or not.
147///
148/// If set to `Pays::No`, the block resource limits are applied, yet no fee is deducted.
149pub trait PaysFee<T> {
150	fn pays_fee(&self, _target: T) -> Pays;
151}
152
153/// Explicit enum to denote if a transaction pays fee or not.
154#[derive(
155	Clone, Copy, Eq, PartialEq, RuntimeDebug, Encode, Decode, DecodeWithMemTracking, TypeInfo,
156)]
157pub enum Pays {
158	/// Transactor will pay related fees.
159	Yes,
160	/// Transactor will NOT pay related fees.
161	No,
162}
163
164impl Default for Pays {
165	fn default() -> Self {
166		Self::Yes
167	}
168}
169
170impl From<Pays> for PostDispatchInfo {
171	fn from(pays_fee: Pays) -> Self {
172		Self { actual_weight: None, pays_fee }
173	}
174}
175
176impl From<bool> for Pays {
177	fn from(b: bool) -> Self {
178		match b {
179			true => Self::Yes,
180			false => Self::No,
181		}
182	}
183}
184
185/// A generalized group of dispatch types.
186///
187/// NOTE whenever upgrading the enum make sure to also update
188/// [DispatchClass::all] and [DispatchClass::non_mandatory] helper functions.
189#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
190#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))]
191#[derive(
192	PartialEq, Eq, Clone, Copy, Encode, Decode, DecodeWithMemTracking, RuntimeDebug, TypeInfo,
193)]
194pub enum DispatchClass {
195	/// A normal dispatch.
196	Normal,
197	/// An operational dispatch.
198	Operational,
199	/// A mandatory dispatch. These kinds of dispatch are always included regardless of their
200	/// weight, therefore it is critical that they are separately validated to ensure that a
201	/// malicious validator cannot craft a valid but impossibly heavy block. Usually this just
202	/// means ensuring that the extrinsic can only be included once and that it is always very
203	/// light.
204	///
205	/// Do *NOT* use it for extrinsics that can be heavy.
206	///
207	/// The only real use case for this is inherent extrinsics that are required to execute in a
208	/// block for the block to be valid, and it solves the issue in the case that the block
209	/// initialization is sufficiently heavy to mean that those inherents do not fit into the
210	/// block. Essentially, we assume that in these exceptional circumstances, it is better to
211	/// allow an overweight block to be created than to not allow any block at all to be created.
212	Mandatory,
213}
214
215impl Default for DispatchClass {
216	fn default() -> Self {
217		Self::Normal
218	}
219}
220
221impl DispatchClass {
222	/// Returns an array containing all dispatch classes.
223	pub fn all() -> &'static [DispatchClass] {
224		&[DispatchClass::Normal, DispatchClass::Operational, DispatchClass::Mandatory]
225	}
226
227	/// Returns an array of all dispatch classes except `Mandatory`.
228	pub fn non_mandatory() -> &'static [DispatchClass] {
229		&[DispatchClass::Normal, DispatchClass::Operational]
230	}
231}
232
233/// A trait that represents one or many values of given type.
234///
235/// Useful to accept as parameter type to let the caller pass either a single value directly
236/// or an iterator.
237pub trait OneOrMany<T> {
238	/// The iterator type.
239	type Iter: Iterator<Item = T>;
240	/// Convert this item into an iterator.
241	fn into_iter(self) -> Self::Iter;
242}
243
244impl OneOrMany<DispatchClass> for DispatchClass {
245	type Iter = core::iter::Once<DispatchClass>;
246	fn into_iter(self) -> Self::Iter {
247		core::iter::once(self)
248	}
249}
250
251impl<'a> OneOrMany<DispatchClass> for &'a [DispatchClass] {
252	type Iter = core::iter::Cloned<core::slice::Iter<'a, DispatchClass>>;
253	fn into_iter(self) -> Self::Iter {
254		self.iter().cloned()
255	}
256}
257
258/// A bundle of static information collected from the `#[pallet::weight]` attributes.
259#[derive(Clone, Copy, Eq, PartialEq, Default, RuntimeDebug, Encode, Decode, TypeInfo)]
260pub struct DispatchInfo {
261	/// Weight of this transaction's call.
262	pub call_weight: Weight,
263	/// Weight of this transaction's extension.
264	pub extension_weight: Weight,
265	/// Class of this transaction.
266	pub class: DispatchClass,
267	/// Does this transaction pay fees.
268	pub pays_fee: Pays,
269}
270
271impl DispatchInfo {
272	/// Returns the weight used by this extrinsic's extension and call when applied.
273	pub fn total_weight(&self) -> Weight {
274		self.call_weight.saturating_add(self.extension_weight)
275	}
276}
277
278/// A `Dispatchable` function (aka transaction) that can carry some static information along with
279/// it, using the `#[pallet::weight]` attribute.
280pub trait GetDispatchInfo {
281	/// Return a `DispatchInfo`, containing relevant information of this dispatch.
282	///
283	/// This is done independently of its encoded size.
284	fn get_dispatch_info(&self) -> DispatchInfo;
285}
286
287impl GetDispatchInfo for () {
288	fn get_dispatch_info(&self) -> DispatchInfo {
289		DispatchInfo::default()
290	}
291}
292
293/// Extract the actual weight from a dispatch result if any or fall back to the default weight.
294pub fn extract_actual_weight(result: &DispatchResultWithPostInfo, info: &DispatchInfo) -> Weight {
295	match result {
296		Ok(post_info) => post_info,
297		Err(err) => &err.post_info,
298	}
299	.calc_actual_weight(info)
300}
301
302/// Extract the actual pays_fee from a dispatch result if any or fall back to the default
303/// weight.
304pub fn extract_actual_pays_fee(result: &DispatchResultWithPostInfo, info: &DispatchInfo) -> Pays {
305	match result {
306		Ok(post_info) => post_info,
307		Err(err) => &err.post_info,
308	}
309	.pays_fee(info)
310}
311
312/// Weight information that is only available post dispatch.
313/// NOTE: This can only be used to reduce the weight or fee, not increase it.
314#[derive(
315	Clone,
316	Copy,
317	Eq,
318	PartialEq,
319	Default,
320	RuntimeDebug,
321	Encode,
322	Decode,
323	DecodeWithMemTracking,
324	TypeInfo,
325)]
326pub struct PostDispatchInfo {
327	/// Actual weight consumed by a call or `None` which stands for the worst case static weight.
328	pub actual_weight: Option<Weight>,
329	/// Whether this transaction should pay fees when all is said and done.
330	pub pays_fee: Pays,
331}
332
333impl PostDispatchInfo {
334	/// Calculate how much (if any) weight was not used by the `Dispatchable`.
335	pub fn calc_unspent(&self, info: &DispatchInfo) -> Weight {
336		info.total_weight() - self.calc_actual_weight(info)
337	}
338
339	/// Calculate how much weight was actually spent by the `Dispatchable`.
340	pub fn calc_actual_weight(&self, info: &DispatchInfo) -> Weight {
341		if let Some(actual_weight) = self.actual_weight {
342			let info_total_weight = info.total_weight();
343			if actual_weight.any_gt(info_total_weight) {
344				log::error!(
345					target: crate::LOG_TARGET,
346					"Post dispatch weight is greater than pre dispatch weight. \
347					Pre dispatch weight may underestimating the actual weight. \
348					Greater post dispatch weight components are ignored.
349					Pre dispatch weight: {info_total_weight:?},
350					Post dispatch weight: {actual_weight:?}",
351				);
352			}
353			actual_weight.min(info.total_weight())
354		} else {
355			info.total_weight()
356		}
357	}
358
359	/// Determine if user should actually pay fees at the end of the dispatch.
360	pub fn pays_fee(&self, info: &DispatchInfo) -> Pays {
361		// If they originally were not paying fees, or the post dispatch info
362		// says they should not pay fees, then they don't pay fees.
363		// This is because the pre dispatch information must contain the
364		// worst case for weight and fees paid.
365		if info.pays_fee == Pays::No || self.pays_fee == Pays::No {
366			Pays::No
367		} else {
368			// Otherwise they pay.
369			Pays::Yes
370		}
371	}
372}
373
374impl From<()> for PostDispatchInfo {
375	fn from(_: ()) -> Self {
376		Self { actual_weight: None, pays_fee: Default::default() }
377	}
378}
379
380impl sp_runtime::traits::Printable for PostDispatchInfo {
381	fn print(&self) {
382		"actual_weight=".print();
383		match self.actual_weight {
384			Some(weight) => weight.print(),
385			None => "max-weight".print(),
386		};
387		"pays_fee=".print();
388		match self.pays_fee {
389			Pays::Yes => "Yes".print(),
390			Pays::No => "No".print(),
391		}
392	}
393}
394
395/// Allows easy conversion from `DispatchError` to `DispatchErrorWithPostInfo` for dispatchables
396/// that want to return a custom a posterior weight on error.
397pub trait WithPostDispatchInfo {
398	/// Call this on your modules custom errors type in order to return a custom weight on error.
399	///
400	/// # Example
401	///
402	/// ```ignore
403	/// let who = ensure_signed(origin).map_err(|e| e.with_weight(Weight::from_parts(100, 0)))?;
404	/// ensure!(who == me, Error::<T>::NotMe.with_weight(200_000));
405	/// ```
406	fn with_weight(self, actual_weight: Weight) -> DispatchErrorWithPostInfo;
407}
408
409impl<T> WithPostDispatchInfo for T
410where
411	T: Into<DispatchError>,
412{
413	fn with_weight(self, actual_weight: Weight) -> DispatchErrorWithPostInfo {
414		DispatchErrorWithPostInfo {
415			post_info: PostDispatchInfo {
416				actual_weight: Some(actual_weight),
417				pays_fee: Default::default(),
418			},
419			error: self.into(),
420		}
421	}
422}
423
424/// Implementation for unchecked extrinsic.
425impl<Address, Call: Dispatchable, Signature, Extension: TransactionExtension<Call>> GetDispatchInfo
426	for UncheckedExtrinsic<Address, Call, Signature, Extension>
427where
428	Call: GetDispatchInfo + Dispatchable,
429{
430	fn get_dispatch_info(&self) -> DispatchInfo {
431		let mut info = self.function.get_dispatch_info();
432		info.extension_weight = self.extension_weight();
433		info
434	}
435}
436
437/// Implementation for checked extrinsic.
438impl<AccountId, Call: Dispatchable, Extension: TransactionExtension<Call>> GetDispatchInfo
439	for CheckedExtrinsic<AccountId, Call, Extension>
440where
441	Call: GetDispatchInfo,
442{
443	fn get_dispatch_info(&self) -> DispatchInfo {
444		let mut info = self.function.get_dispatch_info();
445		info.extension_weight = self.extension_weight();
446		info
447	}
448}
449
450/// A struct holding value for each `DispatchClass`.
451#[derive(Clone, Eq, PartialEq, Default, Debug, Encode, Decode, TypeInfo, MaxEncodedLen)]
452pub struct PerDispatchClass<T> {
453	/// Value for `Normal` extrinsics.
454	normal: T,
455	/// Value for `Operational` extrinsics.
456	operational: T,
457	/// Value for `Mandatory` extrinsics.
458	mandatory: T,
459}
460
461impl<T> PerDispatchClass<T> {
462	/// Create new `PerDispatchClass` with the same value for every class.
463	pub fn new(val: impl Fn(DispatchClass) -> T) -> Self {
464		Self {
465			normal: val(DispatchClass::Normal),
466			operational: val(DispatchClass::Operational),
467			mandatory: val(DispatchClass::Mandatory),
468		}
469	}
470
471	/// Get a mutable reference to current value of given class.
472	pub fn get_mut(&mut self, class: DispatchClass) -> &mut T {
473		match class {
474			DispatchClass::Operational => &mut self.operational,
475			DispatchClass::Normal => &mut self.normal,
476			DispatchClass::Mandatory => &mut self.mandatory,
477		}
478	}
479
480	/// Get current value for given class.
481	pub fn get(&self, class: DispatchClass) -> &T {
482		match class {
483			DispatchClass::Normal => &self.normal,
484			DispatchClass::Operational => &self.operational,
485			DispatchClass::Mandatory => &self.mandatory,
486		}
487	}
488}
489
490impl<T: Clone> PerDispatchClass<T> {
491	/// Set the value of given class.
492	pub fn set(&mut self, new: T, class: impl OneOrMany<DispatchClass>) {
493		for class in class.into_iter() {
494			*self.get_mut(class) = new.clone();
495		}
496	}
497}
498
499impl PerDispatchClass<Weight> {
500	/// Returns the total weight consumed by all extrinsics in the block.
501	///
502	/// Saturates on overflow.
503	pub fn total(&self) -> Weight {
504		let mut sum = Weight::zero();
505		for class in DispatchClass::all() {
506			sum.saturating_accrue(*self.get(*class));
507		}
508		sum
509	}
510
511	/// Add some weight to the given class. Saturates at the numeric bounds.
512	pub fn add(mut self, weight: Weight, class: DispatchClass) -> Self {
513		self.accrue(weight, class);
514		self
515	}
516
517	/// Increase the weight of the given class. Saturates at the numeric bounds.
518	pub fn accrue(&mut self, weight: Weight, class: DispatchClass) {
519		self.get_mut(class).saturating_accrue(weight);
520	}
521
522	/// Try to increase the weight of the given class. Saturates at the numeric bounds.
523	pub fn checked_accrue(&mut self, weight: Weight, class: DispatchClass) -> Result<(), ()> {
524		self.get_mut(class).checked_accrue(weight).ok_or(())
525	}
526
527	/// Reduce the weight of the given class. Saturates at the numeric bounds.
528	pub fn reduce(&mut self, weight: Weight, class: DispatchClass) {
529		self.get_mut(class).saturating_reduce(weight);
530	}
531}
532
533/// Means of weighing some particular kind of data (`T`).
534pub trait WeighData<T> {
535	/// Weigh the data `T` given by `target`. When implementing this for a dispatchable, `T` will be
536	/// a tuple of all arguments given to the function (except origin).
537	fn weigh_data(&self, target: T) -> Weight;
538}
539
540impl<T> WeighData<T> for Weight {
541	fn weigh_data(&self, _: T) -> Weight {
542		return *self
543	}
544}
545
546impl<T> PaysFee<T> for (Weight, DispatchClass, Pays) {
547	fn pays_fee(&self, _: T) -> Pays {
548		self.2
549	}
550}
551
552impl<T> WeighData<T> for (Weight, DispatchClass) {
553	fn weigh_data(&self, args: T) -> Weight {
554		return self.0.weigh_data(args)
555	}
556}
557
558impl<T> WeighData<T> for (Weight, DispatchClass, Pays) {
559	fn weigh_data(&self, args: T) -> Weight {
560		return self.0.weigh_data(args)
561	}
562}
563
564impl<T> ClassifyDispatch<T> for (Weight, DispatchClass) {
565	fn classify_dispatch(&self, _: T) -> DispatchClass {
566		self.1
567	}
568}
569
570impl<T> PaysFee<T> for (Weight, DispatchClass) {
571	fn pays_fee(&self, _: T) -> Pays {
572		Pays::Yes
573	}
574}
575
576impl<T> WeighData<T> for (Weight, Pays) {
577	fn weigh_data(&self, args: T) -> Weight {
578		return self.0.weigh_data(args)
579	}
580}
581
582impl<T> ClassifyDispatch<T> for (Weight, Pays) {
583	fn classify_dispatch(&self, _: T) -> DispatchClass {
584		DispatchClass::Normal
585	}
586}
587
588impl<T> PaysFee<T> for (Weight, Pays) {
589	fn pays_fee(&self, _: T) -> Pays {
590		self.1
591	}
592}
593
594impl From<(Option<Weight>, Pays)> for PostDispatchInfo {
595	fn from(post_weight_info: (Option<Weight>, Pays)) -> Self {
596		let (actual_weight, pays_fee) = post_weight_info;
597		Self { actual_weight, pays_fee }
598	}
599}
600
601impl From<Option<Weight>> for PostDispatchInfo {
602	fn from(actual_weight: Option<Weight>) -> Self {
603		Self { actual_weight, pays_fee: Default::default() }
604	}
605}
606
607impl<T> ClassifyDispatch<T> for Weight {
608	fn classify_dispatch(&self, _: T) -> DispatchClass {
609		DispatchClass::Normal
610	}
611}
612
613impl<T> PaysFee<T> for Weight {
614	fn pays_fee(&self, _: T) -> Pays {
615		Pays::Yes
616	}
617}
618
619impl<T> ClassifyDispatch<T> for (Weight, DispatchClass, Pays) {
620	fn classify_dispatch(&self, _: T) -> DispatchClass {
621		self.1
622	}
623}
624
625impl RefundWeight for PostDispatchInfo {
626	fn refund(&mut self, weight: Weight) {
627		if let Some(actual_weight) = self.actual_weight.as_mut() {
628			actual_weight.saturating_reduce(weight);
629		}
630	}
631}
632
633impl ExtensionPostDispatchWeightHandler<DispatchInfo> for PostDispatchInfo {
634	fn set_extension_weight(&mut self, info: &DispatchInfo) {
635		let actual_weight = self
636			.actual_weight
637			.unwrap_or(info.call_weight)
638			.saturating_add(info.extension_weight);
639		self.actual_weight = Some(actual_weight);
640	}
641}
642
643impl ExtensionPostDispatchWeightHandler<()> for PostDispatchInfo {
644	fn set_extension_weight(&mut self, _: &()) {}
645}
646
647// TODO: Eventually remove these
648
649impl<T> ClassifyDispatch<T> for u64 {
650	fn classify_dispatch(&self, _: T) -> DispatchClass {
651		DispatchClass::Normal
652	}
653}
654
655impl<T> PaysFee<T> for u64 {
656	fn pays_fee(&self, _: T) -> Pays {
657		Pays::Yes
658	}
659}
660
661impl<T> WeighData<T> for u64 {
662	fn weigh_data(&self, _: T) -> Weight {
663		return Weight::from_parts(*self, 0)
664	}
665}
666
667impl<T> WeighData<T> for (u64, DispatchClass, Pays) {
668	fn weigh_data(&self, args: T) -> Weight {
669		return self.0.weigh_data(args)
670	}
671}
672
673impl<T> ClassifyDispatch<T> for (u64, DispatchClass, Pays) {
674	fn classify_dispatch(&self, _: T) -> DispatchClass {
675		self.1
676	}
677}
678
679impl<T> PaysFee<T> for (u64, DispatchClass, Pays) {
680	fn pays_fee(&self, _: T) -> Pays {
681		self.2
682	}
683}
684
685impl<T> WeighData<T> for (u64, DispatchClass) {
686	fn weigh_data(&self, args: T) -> Weight {
687		return self.0.weigh_data(args)
688	}
689}
690
691impl<T> ClassifyDispatch<T> for (u64, DispatchClass) {
692	fn classify_dispatch(&self, _: T) -> DispatchClass {
693		self.1
694	}
695}
696
697impl<T> PaysFee<T> for (u64, DispatchClass) {
698	fn pays_fee(&self, _: T) -> Pays {
699		Pays::Yes
700	}
701}
702
703impl<T> WeighData<T> for (u64, Pays) {
704	fn weigh_data(&self, args: T) -> Weight {
705		return self.0.weigh_data(args)
706	}
707}
708
709impl<T> ClassifyDispatch<T> for (u64, Pays) {
710	fn classify_dispatch(&self, _: T) -> DispatchClass {
711		DispatchClass::Normal
712	}
713}
714
715impl<T> PaysFee<T> for (u64, Pays) {
716	fn pays_fee(&self, _: T) -> Pays {
717		self.1
718	}
719}
720
721// END TODO
722
723#[cfg(test)]
724// Do not complain about unused `dispatch` and `dispatch_aux`.
725#[allow(dead_code)]
726mod weight_tests {
727	use super::*;
728	use sp_core::parameter_types;
729	use sp_runtime::{generic, traits::BlakeTwo256};
730	use sp_weights::RuntimeDbWeight;
731
732	pub use self::frame_system::{Call, Config};
733
734	fn from_actual_ref_time(ref_time: Option<u64>) -> PostDispatchInfo {
735		PostDispatchInfo {
736			actual_weight: ref_time.map(|t| Weight::from_all(t)),
737			pays_fee: Default::default(),
738		}
739	}
740
741	fn from_post_weight_info(ref_time: Option<u64>, pays_fee: Pays) -> PostDispatchInfo {
742		PostDispatchInfo { actual_weight: ref_time.map(|t| Weight::from_all(t)), pays_fee }
743	}
744
745	#[crate::pallet(dev_mode)]
746	pub mod frame_system {
747		use super::{frame_system, frame_system::pallet_prelude::*};
748		pub use crate::dispatch::RawOrigin;
749		use crate::pallet_prelude::*;
750
751		#[pallet::pallet]
752		pub struct Pallet<T>(_);
753
754		#[pallet::config]
755		#[pallet::disable_frame_system_supertrait_check]
756		pub trait Config: 'static {
757			type Block: Parameter + sp_runtime::traits::Block;
758			type AccountId;
759			type Balance;
760			type BaseCallFilter: crate::traits::Contains<Self::RuntimeCall>;
761			type RuntimeOrigin;
762			type RuntimeCall;
763			type RuntimeTask;
764			type PalletInfo: crate::traits::PalletInfo;
765			type DbWeight: Get<crate::weights::RuntimeDbWeight>;
766		}
767
768		#[pallet::error]
769		pub enum Error<T> {
770			/// Required by construct_runtime
771			CallFiltered,
772		}
773
774		#[pallet::origin]
775		pub type Origin<T> = RawOrigin<<T as Config>::AccountId>;
776
777		#[pallet::call]
778		impl<T: Config> Pallet<T> {
779			// no arguments, fixed weight
780			#[pallet::weight(1000)]
781			pub fn f00(_origin: OriginFor<T>) -> DispatchResult {
782				unimplemented!();
783			}
784
785			#[pallet::weight((1000, DispatchClass::Mandatory))]
786			pub fn f01(_origin: OriginFor<T>) -> DispatchResult {
787				unimplemented!();
788			}
789
790			#[pallet::weight((1000, Pays::No))]
791			pub fn f02(_origin: OriginFor<T>) -> DispatchResult {
792				unimplemented!();
793			}
794
795			#[pallet::weight((1000, DispatchClass::Operational, Pays::No))]
796			pub fn f03(_origin: OriginFor<T>) -> DispatchResult {
797				unimplemented!();
798			}
799
800			// weight = a x 10 + b
801			#[pallet::weight(((_a * 10 + _eb * 1) as u64, DispatchClass::Normal, Pays::Yes))]
802			pub fn f11(_origin: OriginFor<T>, _a: u32, _eb: u32) -> DispatchResult {
803				unimplemented!();
804			}
805
806			#[pallet::weight((0, DispatchClass::Operational, Pays::Yes))]
807			pub fn f12(_origin: OriginFor<T>, _a: u32, _eb: u32) -> DispatchResult {
808				unimplemented!();
809			}
810
811			#[pallet::weight(T::DbWeight::get().reads(3) + T::DbWeight::get().writes(2) + Weight::from_all(10_000))]
812			pub fn f20(_origin: OriginFor<T>) -> DispatchResult {
813				unimplemented!();
814			}
815
816			#[pallet::weight(T::DbWeight::get().reads_writes(6, 5) + Weight::from_all(40_000))]
817			pub fn f21(_origin: OriginFor<T>) -> DispatchResult {
818				unimplemented!();
819			}
820
821			#[pallet::weight(1000)]
822			pub fn f99(_origin: OriginFor<T>) -> DispatchResult {
823				Ok(())
824			}
825
826			#[pallet::weight(1000)]
827			pub fn f100(_origin: OriginFor<T>) -> DispatchResultWithPostInfo {
828				Ok(crate::dispatch::PostDispatchInfo {
829					actual_weight: Some(Weight::from_parts(500, 0)),
830					pays_fee: Pays::Yes,
831				})
832			}
833		}
834
835		pub mod pallet_prelude {
836			pub type OriginFor<T> = <T as super::Config>::RuntimeOrigin;
837
838			pub type HeaderFor<T> =
839				<<T as super::Config>::Block as sp_runtime::traits::HeaderProvider>::HeaderT;
840
841			pub type BlockNumberFor<T> = <HeaderFor<T> as sp_runtime::traits::Header>::Number;
842		}
843	}
844
845	type BlockNumber = u32;
846	type AccountId = u32;
847	type Balance = u32;
848	type Header = generic::Header<BlockNumber, BlakeTwo256>;
849	type UncheckedExtrinsic = generic::UncheckedExtrinsic<u32, RuntimeCall, (), ()>;
850	type Block = generic::Block<Header, UncheckedExtrinsic>;
851
852	crate::construct_runtime!(
853		pub enum Runtime
854		{
855			System: self::frame_system,
856		}
857	);
858
859	parameter_types! {
860		pub const DbWeight: RuntimeDbWeight = RuntimeDbWeight {
861			read: 100,
862			write: 1000,
863		};
864	}
865
866	impl Config for Runtime {
867		type Block = Block;
868		type AccountId = AccountId;
869		type Balance = Balance;
870		type BaseCallFilter = crate::traits::Everything;
871		type RuntimeOrigin = RuntimeOrigin;
872		type RuntimeCall = RuntimeCall;
873		type RuntimeTask = RuntimeTask;
874		type DbWeight = DbWeight;
875		type PalletInfo = PalletInfo;
876	}
877
878	#[test]
879	fn weights_are_correct() {
880		// #[pallet::weight(1000)]
881		let info = Call::<Runtime>::f00 {}.get_dispatch_info();
882		assert_eq!(info.total_weight(), Weight::from_parts(1000, 0));
883		assert_eq!(info.class, DispatchClass::Normal);
884		assert_eq!(info.pays_fee, Pays::Yes);
885
886		// #[pallet::weight((1000, DispatchClass::Mandatory))]
887		let info = Call::<Runtime>::f01 {}.get_dispatch_info();
888		assert_eq!(info.total_weight(), Weight::from_parts(1000, 0));
889		assert_eq!(info.class, DispatchClass::Mandatory);
890		assert_eq!(info.pays_fee, Pays::Yes);
891
892		// #[pallet::weight((1000, Pays::No))]
893		let info = Call::<Runtime>::f02 {}.get_dispatch_info();
894		assert_eq!(info.total_weight(), Weight::from_parts(1000, 0));
895		assert_eq!(info.class, DispatchClass::Normal);
896		assert_eq!(info.pays_fee, Pays::No);
897
898		// #[pallet::weight((1000, DispatchClass::Operational, Pays::No))]
899		let info = Call::<Runtime>::f03 {}.get_dispatch_info();
900		assert_eq!(info.total_weight(), Weight::from_parts(1000, 0));
901		assert_eq!(info.class, DispatchClass::Operational);
902		assert_eq!(info.pays_fee, Pays::No);
903
904		// #[pallet::weight(((_a * 10 + _eb * 1) as u64, DispatchClass::Normal, Pays::Yes))]
905		let info = Call::<Runtime>::f11 { a: 13, eb: 20 }.get_dispatch_info();
906		assert_eq!(info.total_weight(), Weight::from_parts(150, 0)); // 13*10 + 20
907		assert_eq!(info.class, DispatchClass::Normal);
908		assert_eq!(info.pays_fee, Pays::Yes);
909
910		// #[pallet::weight((0, DispatchClass::Operational, Pays::Yes))]
911		let info = Call::<Runtime>::f12 { a: 10, eb: 20 }.get_dispatch_info();
912		assert_eq!(info.total_weight(), Weight::zero());
913		assert_eq!(info.class, DispatchClass::Operational);
914		assert_eq!(info.pays_fee, Pays::Yes);
915
916		// #[pallet::weight(T::DbWeight::get().reads(3) + T::DbWeight::get().writes(2) +
917		// Weight::from_all(10_000))]
918		let info = Call::<Runtime>::f20 {}.get_dispatch_info();
919		assert_eq!(info.total_weight(), Weight::from_parts(12300, 10000)); // 100*3 + 1000*2 + 10_1000
920		assert_eq!(info.class, DispatchClass::Normal);
921		assert_eq!(info.pays_fee, Pays::Yes);
922
923		// #[pallet::weight(T::DbWeight::get().reads_writes(6, 5) + Weight::from_all(40_000))]
924		let info = Call::<Runtime>::f21 {}.get_dispatch_info();
925		assert_eq!(info.total_weight(), Weight::from_parts(45600, 40000)); // 100*6 + 1000*5 + 40_1000
926		assert_eq!(info.class, DispatchClass::Normal);
927		assert_eq!(info.pays_fee, Pays::Yes);
928	}
929
930	#[test]
931	fn extract_actual_weight_works() {
932		let pre = DispatchInfo {
933			call_weight: Weight::from_parts(1000, 0),
934			extension_weight: Weight::zero(),
935			..Default::default()
936		};
937		assert_eq!(
938			extract_actual_weight(&Ok(from_actual_ref_time(Some(7))), &pre),
939			Weight::from_parts(7, 0)
940		);
941		assert_eq!(
942			extract_actual_weight(&Ok(from_actual_ref_time(Some(1000))), &pre),
943			Weight::from_parts(1000, 0)
944		);
945		assert_eq!(
946			extract_actual_weight(
947				&Err(DispatchError::BadOrigin.with_weight(Weight::from_parts(9, 0))),
948				&pre
949			),
950			Weight::from_parts(9, 0)
951		);
952	}
953
954	#[test]
955	fn extract_actual_weight_caps_at_pre_weight() {
956		let pre = DispatchInfo {
957			call_weight: Weight::from_parts(1000, 0),
958			extension_weight: Weight::zero(),
959			..Default::default()
960		};
961		assert_eq!(
962			extract_actual_weight(&Ok(from_actual_ref_time(Some(1250))), &pre),
963			Weight::from_parts(1000, 0)
964		);
965		assert_eq!(
966			extract_actual_weight(
967				&Err(DispatchError::BadOrigin.with_weight(Weight::from_parts(1300, 0))),
968				&pre
969			),
970			Weight::from_parts(1000, 0),
971		);
972	}
973
974	#[test]
975	fn extract_actual_pays_fee_works() {
976		let pre = DispatchInfo {
977			call_weight: Weight::from_parts(1000, 0),
978			extension_weight: Weight::zero(),
979			..Default::default()
980		};
981		assert_eq!(extract_actual_pays_fee(&Ok(from_actual_ref_time(Some(7))), &pre), Pays::Yes);
982		assert_eq!(
983			extract_actual_pays_fee(&Ok(from_actual_ref_time(Some(1000)).into()), &pre),
984			Pays::Yes
985		);
986		assert_eq!(
987			extract_actual_pays_fee(&Ok(from_post_weight_info(Some(1000), Pays::Yes)), &pre),
988			Pays::Yes
989		);
990		assert_eq!(
991			extract_actual_pays_fee(&Ok(from_post_weight_info(Some(1000), Pays::No)), &pre),
992			Pays::No
993		);
994		assert_eq!(
995			extract_actual_pays_fee(
996				&Err(DispatchError::BadOrigin.with_weight(Weight::from_parts(9, 0))),
997				&pre
998			),
999			Pays::Yes
1000		);
1001		assert_eq!(
1002			extract_actual_pays_fee(
1003				&Err(DispatchErrorWithPostInfo {
1004					post_info: PostDispatchInfo { actual_weight: None, pays_fee: Pays::No },
1005					error: DispatchError::BadOrigin,
1006				}),
1007				&pre
1008			),
1009			Pays::No
1010		);
1011
1012		let pre = DispatchInfo {
1013			call_weight: Weight::from_parts(1000, 0),
1014			extension_weight: Weight::zero(),
1015			pays_fee: Pays::No,
1016			..Default::default()
1017		};
1018		assert_eq!(extract_actual_pays_fee(&Ok(from_actual_ref_time(Some(7))), &pre), Pays::No);
1019		assert_eq!(extract_actual_pays_fee(&Ok(from_actual_ref_time(Some(1000))), &pre), Pays::No);
1020		assert_eq!(
1021			extract_actual_pays_fee(&Ok(from_post_weight_info(Some(1000), Pays::Yes)), &pre),
1022			Pays::No
1023		);
1024	}
1025
1026	#[test]
1027	fn weight_accrue_works() {
1028		let mut post_dispatch = PostDispatchInfo {
1029			actual_weight: Some(Weight::from_parts(1100, 25)),
1030			pays_fee: Pays::Yes,
1031		};
1032		post_dispatch.refund(Weight::from_parts(100, 15));
1033		assert_eq!(
1034			post_dispatch,
1035			PostDispatchInfo {
1036				actual_weight: Some(Weight::from_parts(1000, 10)),
1037				pays_fee: Pays::Yes
1038			}
1039		);
1040
1041		let mut post_dispatch = PostDispatchInfo { actual_weight: None, pays_fee: Pays::Yes };
1042		post_dispatch.refund(Weight::from_parts(100, 15));
1043		assert_eq!(post_dispatch, PostDispatchInfo { actual_weight: None, pays_fee: Pays::Yes });
1044	}
1045}
1046
1047#[cfg(test)]
1048mod per_dispatch_class_tests {
1049	use super::*;
1050	use sp_runtime::traits::Zero;
1051	use DispatchClass::*;
1052
1053	#[test]
1054	fn add_works() {
1055		let a = PerDispatchClass {
1056			normal: (5, 10).into(),
1057			operational: (20, 30).into(),
1058			mandatory: Weight::MAX,
1059		};
1060		assert_eq!(
1061			a.clone()
1062				.add((20, 5).into(), Normal)
1063				.add((10, 10).into(), Operational)
1064				.add((u64::MAX, 3).into(), Mandatory),
1065			PerDispatchClass {
1066				normal: (25, 15).into(),
1067				operational: (30, 40).into(),
1068				mandatory: Weight::MAX
1069			}
1070		);
1071		let b = a
1072			.add(Weight::MAX, Normal)
1073			.add(Weight::MAX, Operational)
1074			.add(Weight::MAX, Mandatory);
1075		assert_eq!(
1076			b,
1077			PerDispatchClass {
1078				normal: Weight::MAX,
1079				operational: Weight::MAX,
1080				mandatory: Weight::MAX
1081			}
1082		);
1083		assert_eq!(b.total(), Weight::MAX);
1084	}
1085
1086	#[test]
1087	fn accrue_works() {
1088		let mut a = PerDispatchClass::default();
1089
1090		a.accrue((10, 15).into(), Normal);
1091		assert_eq!(a.normal, (10, 15).into());
1092		assert_eq!(a.total(), (10, 15).into());
1093
1094		a.accrue((20, 25).into(), Operational);
1095		assert_eq!(a.operational, (20, 25).into());
1096		assert_eq!(a.total(), (30, 40).into());
1097
1098		a.accrue((30, 35).into(), Mandatory);
1099		assert_eq!(a.mandatory, (30, 35).into());
1100		assert_eq!(a.total(), (60, 75).into());
1101
1102		a.accrue((u64::MAX, 10).into(), Operational);
1103		assert_eq!(a.operational, (u64::MAX, 35).into());
1104		assert_eq!(a.total(), (u64::MAX, 85).into());
1105
1106		a.accrue((10, u64::MAX).into(), Normal);
1107		assert_eq!(a.normal, (20, u64::MAX).into());
1108		assert_eq!(a.total(), Weight::MAX);
1109	}
1110
1111	#[test]
1112	fn reduce_works() {
1113		let mut a = PerDispatchClass {
1114			normal: (10, u64::MAX).into(),
1115			mandatory: (u64::MAX, 10).into(),
1116			operational: (20, 20).into(),
1117		};
1118
1119		a.reduce((5, 100).into(), Normal);
1120		assert_eq!(a.normal, (5, u64::MAX - 100).into());
1121		assert_eq!(a.total(), (u64::MAX, u64::MAX - 70).into());
1122
1123		a.reduce((15, 5).into(), Operational);
1124		assert_eq!(a.operational, (5, 15).into());
1125		assert_eq!(a.total(), (u64::MAX, u64::MAX - 75).into());
1126
1127		a.reduce((50, 0).into(), Mandatory);
1128		assert_eq!(a.mandatory, (u64::MAX - 50, 10).into());
1129		assert_eq!(a.total(), (u64::MAX - 40, u64::MAX - 75).into());
1130
1131		a.reduce((u64::MAX, 100).into(), Operational);
1132		assert!(a.operational.is_zero());
1133		assert_eq!(a.total(), (u64::MAX - 45, u64::MAX - 90).into());
1134
1135		a.reduce((5, u64::MAX).into(), Normal);
1136		assert!(a.normal.is_zero());
1137		assert_eq!(a.total(), (u64::MAX - 50, 10).into());
1138	}
1139
1140	#[test]
1141	fn checked_accrue_works() {
1142		let mut a = PerDispatchClass::default();
1143
1144		a.checked_accrue((1, 2).into(), Normal).unwrap();
1145		a.checked_accrue((3, 4).into(), Operational).unwrap();
1146		a.checked_accrue((5, 6).into(), Mandatory).unwrap();
1147		a.checked_accrue((7, 8).into(), Operational).unwrap();
1148		a.checked_accrue((9, 0).into(), Normal).unwrap();
1149
1150		assert_eq!(
1151			a,
1152			PerDispatchClass {
1153				normal: (10, 2).into(),
1154				operational: (10, 12).into(),
1155				mandatory: (5, 6).into(),
1156			}
1157		);
1158
1159		a.checked_accrue((u64::MAX - 10, u64::MAX - 2).into(), Normal).unwrap();
1160		a.checked_accrue((0, 0).into(), Normal).unwrap();
1161		a.checked_accrue((1, 0).into(), Normal).unwrap_err();
1162		a.checked_accrue((0, 1).into(), Normal).unwrap_err();
1163
1164		assert_eq!(
1165			a,
1166			PerDispatchClass {
1167				normal: Weight::MAX,
1168				operational: (10, 12).into(),
1169				mandatory: (5, 6).into(),
1170			}
1171		);
1172	}
1173
1174	#[test]
1175	fn checked_accrue_does_not_modify_on_error() {
1176		let mut a = PerDispatchClass {
1177			normal: 0.into(),
1178			operational: Weight::MAX / 2 + 2.into(),
1179			mandatory: 10.into(),
1180		};
1181
1182		a.checked_accrue(Weight::MAX / 2, Operational).unwrap_err();
1183		a.checked_accrue(Weight::MAX - 9.into(), Mandatory).unwrap_err();
1184		a.checked_accrue(Weight::MAX, Normal).unwrap(); // This one works
1185
1186		assert_eq!(
1187			a,
1188			PerDispatchClass {
1189				normal: Weight::MAX,
1190				operational: Weight::MAX / 2 + 2.into(),
1191				mandatory: 10.into(),
1192			}
1193		);
1194	}
1195
1196	#[test]
1197	fn total_works() {
1198		assert!(PerDispatchClass::default().total().is_zero());
1199
1200		assert_eq!(
1201			PerDispatchClass {
1202				normal: 0.into(),
1203				operational: (10, 20).into(),
1204				mandatory: (20, u64::MAX).into(),
1205			}
1206			.total(),
1207			(30, u64::MAX).into()
1208		);
1209
1210		assert_eq!(
1211			PerDispatchClass {
1212				normal: (u64::MAX - 10, 10).into(),
1213				operational: (3, u64::MAX).into(),
1214				mandatory: (4, u64::MAX).into(),
1215			}
1216			.total(),
1217			(u64::MAX - 3, u64::MAX).into()
1218		);
1219	}
1220}
1221
1222#[cfg(test)]
1223mod test_extensions {
1224	use codec::{Decode, DecodeWithMemTracking, Encode};
1225	use scale_info::TypeInfo;
1226	use sp_runtime::{
1227		impl_tx_ext_default,
1228		traits::{
1229			DispatchInfoOf, DispatchOriginOf, Dispatchable, PostDispatchInfoOf,
1230			TransactionExtension,
1231		},
1232		transaction_validity::TransactionValidityError,
1233	};
1234	use sp_weights::Weight;
1235
1236	use super::{DispatchResult, PostDispatchInfo};
1237
1238	/// Test extension that refunds half its cost if the preset inner flag is set.
1239	#[derive(Clone, Eq, PartialEq, Debug, Encode, Decode, DecodeWithMemTracking, TypeInfo)]
1240	pub struct HalfCostIf(pub bool);
1241
1242	impl<RuntimeCall: Dispatchable> TransactionExtension<RuntimeCall> for HalfCostIf {
1243		const IDENTIFIER: &'static str = "HalfCostIf";
1244		type Implicit = ();
1245		type Val = ();
1246		type Pre = bool;
1247
1248		fn weight(&self, _: &RuntimeCall) -> sp_weights::Weight {
1249			Weight::from_parts(100, 0)
1250		}
1251
1252		fn prepare(
1253			self,
1254			_val: Self::Val,
1255			_origin: &DispatchOriginOf<RuntimeCall>,
1256			_call: &RuntimeCall,
1257			_info: &DispatchInfoOf<RuntimeCall>,
1258			_len: usize,
1259		) -> Result<Self::Pre, TransactionValidityError> {
1260			Ok(self.0)
1261		}
1262
1263		fn post_dispatch_details(
1264			pre: Self::Pre,
1265			_info: &DispatchInfoOf<RuntimeCall>,
1266			_post_info: &PostDispatchInfoOf<RuntimeCall>,
1267			_len: usize,
1268			_result: &DispatchResult,
1269		) -> Result<Weight, TransactionValidityError> {
1270			if pre {
1271				Ok(Weight::from_parts(50, 0))
1272			} else {
1273				Ok(Weight::zero())
1274			}
1275		}
1276		impl_tx_ext_default!(RuntimeCall; validate);
1277	}
1278
1279	/// Test extension that refunds its cost if the actual post dispatch weight up until this point
1280	/// in the extension pipeline is less than the preset inner `ref_time` amount.
1281	#[derive(Clone, Eq, PartialEq, Debug, Encode, Decode, DecodeWithMemTracking, TypeInfo)]
1282	pub struct FreeIfUnder(pub u64);
1283
1284	impl<RuntimeCall: Dispatchable> TransactionExtension<RuntimeCall> for FreeIfUnder
1285	where
1286		RuntimeCall: Dispatchable<PostInfo = PostDispatchInfo>,
1287	{
1288		const IDENTIFIER: &'static str = "FreeIfUnder";
1289		type Implicit = ();
1290		type Val = ();
1291		type Pre = u64;
1292
1293		fn weight(&self, _: &RuntimeCall) -> sp_weights::Weight {
1294			Weight::from_parts(200, 0)
1295		}
1296
1297		fn prepare(
1298			self,
1299			_val: Self::Val,
1300			_origin: &DispatchOriginOf<RuntimeCall>,
1301			_call: &RuntimeCall,
1302			_info: &DispatchInfoOf<RuntimeCall>,
1303			_len: usize,
1304		) -> Result<Self::Pre, TransactionValidityError> {
1305			Ok(self.0)
1306		}
1307
1308		fn post_dispatch_details(
1309			pre: Self::Pre,
1310			_info: &DispatchInfoOf<RuntimeCall>,
1311			post_info: &PostDispatchInfoOf<RuntimeCall>,
1312			_len: usize,
1313			_result: &DispatchResult,
1314		) -> Result<Weight, TransactionValidityError> {
1315			if let Some(actual) = post_info.actual_weight {
1316				if pre > actual.ref_time() {
1317					return Ok(Weight::from_parts(200, 0));
1318				}
1319			}
1320			Ok(Weight::zero())
1321		}
1322		impl_tx_ext_default!(RuntimeCall; validate);
1323	}
1324
1325	/// Test extension that sets its actual post dispatch `ref_time` weight to the preset inner
1326	/// amount.
1327	#[derive(Clone, Eq, PartialEq, Debug, Encode, Decode, DecodeWithMemTracking, TypeInfo)]
1328	pub struct ActualWeightIs(pub u64);
1329
1330	impl<RuntimeCall: Dispatchable> TransactionExtension<RuntimeCall> for ActualWeightIs {
1331		const IDENTIFIER: &'static str = "ActualWeightIs";
1332		type Implicit = ();
1333		type Val = ();
1334		type Pre = u64;
1335
1336		fn weight(&self, _: &RuntimeCall) -> sp_weights::Weight {
1337			Weight::from_parts(300, 0)
1338		}
1339
1340		fn prepare(
1341			self,
1342			_val: Self::Val,
1343			_origin: &DispatchOriginOf<RuntimeCall>,
1344			_call: &RuntimeCall,
1345			_info: &DispatchInfoOf<RuntimeCall>,
1346			_len: usize,
1347		) -> Result<Self::Pre, TransactionValidityError> {
1348			Ok(self.0)
1349		}
1350
1351		fn post_dispatch_details(
1352			pre: Self::Pre,
1353			_info: &DispatchInfoOf<RuntimeCall>,
1354			_post_info: &PostDispatchInfoOf<RuntimeCall>,
1355			_len: usize,
1356			_result: &DispatchResult,
1357		) -> Result<Weight, TransactionValidityError> {
1358			Ok(Weight::from_parts(300u64.saturating_sub(pre), 0))
1359		}
1360		impl_tx_ext_default!(RuntimeCall; validate);
1361	}
1362}
1363
1364#[cfg(test)]
1365// Do not complain about unused `dispatch` and `dispatch_aux`.
1366#[allow(dead_code)]
1367mod extension_weight_tests {
1368	use crate::assert_ok;
1369
1370	use super::*;
1371	use sp_core::parameter_types;
1372	use sp_runtime::{
1373		generic::{self, ExtrinsicFormat},
1374		traits::{Applyable, BlakeTwo256, DispatchTransaction, TransactionExtension},
1375	};
1376	use sp_weights::RuntimeDbWeight;
1377	use test_extensions::{ActualWeightIs, FreeIfUnder, HalfCostIf};
1378
1379	use super::weight_tests::frame_system;
1380	use frame_support::construct_runtime;
1381
1382	pub type TxExtension = (HalfCostIf, FreeIfUnder, ActualWeightIs);
1383	pub type UncheckedExtrinsic = generic::UncheckedExtrinsic<u64, RuntimeCall, (), TxExtension>;
1384	pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
1385	pub type Block = generic::Block<Header, UncheckedExtrinsic>;
1386	pub type AccountId = u64;
1387	pub type Balance = u32;
1388	pub type BlockNumber = u32;
1389
1390	construct_runtime!(
1391		pub enum ExtRuntime {
1392			System: frame_system,
1393		}
1394	);
1395
1396	impl frame_system::Config for ExtRuntime {
1397		type Block = Block;
1398		type AccountId = AccountId;
1399		type Balance = Balance;
1400		type BaseCallFilter = crate::traits::Everything;
1401		type RuntimeOrigin = RuntimeOrigin;
1402		type RuntimeCall = RuntimeCall;
1403		type RuntimeTask = RuntimeTask;
1404		type DbWeight = DbWeight;
1405		type PalletInfo = PalletInfo;
1406	}
1407
1408	parameter_types! {
1409		pub const DbWeight: RuntimeDbWeight = RuntimeDbWeight {
1410			read: 100,
1411			write: 1000,
1412		};
1413	}
1414
1415	pub struct ExtBuilder {}
1416
1417	impl Default for ExtBuilder {
1418		fn default() -> Self {
1419			Self {}
1420		}
1421	}
1422
1423	impl ExtBuilder {
1424		pub fn build(self) -> sp_io::TestExternalities {
1425			let mut ext = sp_io::TestExternalities::new(Default::default());
1426			ext.execute_with(|| {});
1427			ext
1428		}
1429
1430		pub fn build_and_execute(self, test: impl FnOnce() -> ()) {
1431			self.build().execute_with(|| {
1432				test();
1433			})
1434		}
1435	}
1436
1437	#[test]
1438	fn no_post_dispatch_with_no_refund() {
1439		ExtBuilder::default().build_and_execute(|| {
1440			let call = RuntimeCall::System(frame_system::Call::<ExtRuntime>::f99 {});
1441			let ext: TxExtension = (HalfCostIf(false), FreeIfUnder(1500), ActualWeightIs(0));
1442			let uxt = UncheckedExtrinsic::new_signed(call.clone(), 0, (), ext.clone());
1443			assert_eq!(uxt.extension_weight(), Weight::from_parts(600, 0));
1444
1445			let mut info = call.get_dispatch_info();
1446			assert_eq!(info.total_weight(), Weight::from_parts(1000, 0));
1447			info.extension_weight = ext.weight(&call);
1448			let (pre, _) = ext.validate_and_prepare(Some(0).into(), &call, &info, 0, 0).unwrap();
1449			let res = call.dispatch(Some(0).into());
1450			let mut post_info = res.unwrap();
1451			assert!(post_info.actual_weight.is_none());
1452			assert_ok!(<TxExtension as TransactionExtension<RuntimeCall>>::post_dispatch(
1453				pre,
1454				&info,
1455				&mut post_info,
1456				0,
1457				&Ok(()),
1458			));
1459			assert!(post_info.actual_weight.is_none());
1460		});
1461	}
1462
1463	#[test]
1464	fn no_post_dispatch_refunds_when_dispatched() {
1465		ExtBuilder::default().build_and_execute(|| {
1466			let call = RuntimeCall::System(frame_system::Call::<ExtRuntime>::f99 {});
1467			let ext: TxExtension = (HalfCostIf(true), FreeIfUnder(100), ActualWeightIs(0));
1468			let uxt = UncheckedExtrinsic::new_signed(call.clone(), 0, (), ext.clone());
1469			assert_eq!(uxt.extension_weight(), Weight::from_parts(600, 0));
1470
1471			let mut info = call.get_dispatch_info();
1472			assert_eq!(info.total_weight(), Weight::from_parts(1000, 0));
1473			info.extension_weight = ext.weight(&call);
1474			let post_info =
1475				ext.dispatch_transaction(Some(0).into(), call, &info, 0, 0).unwrap().unwrap();
1476			// 1000 call weight + 50 + 200 + 0
1477			assert_eq!(post_info.actual_weight, Some(Weight::from_parts(1250, 0)));
1478		});
1479	}
1480
1481	#[test]
1482	fn post_dispatch_with_refunds() {
1483		ExtBuilder::default().build_and_execute(|| {
1484			let call = RuntimeCall::System(frame_system::Call::<ExtRuntime>::f100 {});
1485			// First testcase
1486			let ext: TxExtension = (HalfCostIf(false), FreeIfUnder(2000), ActualWeightIs(0));
1487			let uxt = UncheckedExtrinsic::new_signed(call.clone(), 0, (), ext.clone());
1488			assert_eq!(uxt.extension_weight(), Weight::from_parts(600, 0));
1489
1490			let mut info = call.get_dispatch_info();
1491			assert_eq!(info.call_weight, Weight::from_parts(1000, 0));
1492			info.extension_weight = ext.weight(&call);
1493			assert_eq!(info.total_weight(), Weight::from_parts(1600, 0));
1494			let (pre, _) = ext.validate_and_prepare(Some(0).into(), &call, &info, 0, 0).unwrap();
1495			let res = call.clone().dispatch(Some(0).into());
1496			let mut post_info = res.unwrap();
1497			// 500 actual call weight
1498			assert_eq!(post_info.actual_weight, Some(Weight::from_parts(500, 0)));
1499			// add the 600 worst case extension weight
1500			post_info.set_extension_weight(&info);
1501			// extension weight should be refunded
1502			assert_ok!(<TxExtension as TransactionExtension<RuntimeCall>>::post_dispatch(
1503				pre,
1504				&info,
1505				&mut post_info,
1506				0,
1507				&Ok(()),
1508			));
1509			// 500 actual call weight + 100 + 0 + 0
1510			assert_eq!(post_info.actual_weight, Some(Weight::from_parts(600, 0)));
1511
1512			// Second testcase
1513			let ext: TxExtension = (HalfCostIf(false), FreeIfUnder(1100), ActualWeightIs(200));
1514			let (pre, _) = ext.validate_and_prepare(Some(0).into(), &call, &info, 0, 0).unwrap();
1515			let res = call.clone().dispatch(Some(0).into());
1516			let mut post_info = res.unwrap();
1517			// 500 actual call weight
1518			assert_eq!(post_info.actual_weight, Some(Weight::from_parts(500, 0)));
1519			// add the 600 worst case extension weight
1520			post_info.set_extension_weight(&info);
1521			// extension weight should be refunded
1522			assert_ok!(<TxExtension as TransactionExtension<RuntimeCall>>::post_dispatch(
1523				pre,
1524				&info,
1525				&mut post_info,
1526				0,
1527				&Ok(()),
1528			));
1529			// 500 actual call weight + 100 + 200 + 200
1530			assert_eq!(post_info.actual_weight, Some(Weight::from_parts(1000, 0)));
1531
1532			// Third testcase
1533			let ext: TxExtension = (HalfCostIf(true), FreeIfUnder(1060), ActualWeightIs(200));
1534			let (pre, _) = ext.validate_and_prepare(Some(0).into(), &call, &info, 0, 0).unwrap();
1535			let res = call.clone().dispatch(Some(0).into());
1536			let mut post_info = res.unwrap();
1537			// 500 actual call weight
1538			assert_eq!(post_info.actual_weight, Some(Weight::from_parts(500, 0)));
1539			// add the 600 worst case extension weight
1540			post_info.set_extension_weight(&info);
1541			// extension weight should be refunded
1542			assert_ok!(<TxExtension as TransactionExtension<RuntimeCall>>::post_dispatch(
1543				pre,
1544				&info,
1545				&mut post_info,
1546				0,
1547				&Ok(()),
1548			));
1549			// 500 actual call weight + 50 + 0 + 200
1550			assert_eq!(post_info.actual_weight, Some(Weight::from_parts(750, 0)));
1551
1552			// Fourth testcase
1553			let ext: TxExtension = (HalfCostIf(false), FreeIfUnder(100), ActualWeightIs(300));
1554			let (pre, _) = ext.validate_and_prepare(Some(0).into(), &call, &info, 0, 0).unwrap();
1555			let res = call.clone().dispatch(Some(0).into());
1556			let mut post_info = res.unwrap();
1557			// 500 actual call weight
1558			assert_eq!(post_info.actual_weight, Some(Weight::from_parts(500, 0)));
1559			// add the 600 worst case extension weight
1560			post_info.set_extension_weight(&info);
1561			// extension weight should be refunded
1562			assert_ok!(<TxExtension as TransactionExtension<RuntimeCall>>::post_dispatch(
1563				pre,
1564				&info,
1565				&mut post_info,
1566				0,
1567				&Ok(()),
1568			));
1569			// 500 actual call weight + 100 + 200 + 300
1570			assert_eq!(post_info.actual_weight, Some(Weight::from_parts(1100, 0)));
1571		});
1572	}
1573
1574	#[test]
1575	fn checked_extrinsic_apply() {
1576		ExtBuilder::default().build_and_execute(|| {
1577			let call = RuntimeCall::System(frame_system::Call::<ExtRuntime>::f100 {});
1578			// First testcase
1579			let ext: TxExtension = (HalfCostIf(false), FreeIfUnder(2000), ActualWeightIs(0));
1580			let xt = CheckedExtrinsic {
1581				format: ExtrinsicFormat::Signed(0, ext.clone()),
1582				function: call.clone(),
1583			};
1584			assert_eq!(xt.extension_weight(), Weight::from_parts(600, 0));
1585			let mut info = call.get_dispatch_info();
1586			assert_eq!(info.call_weight, Weight::from_parts(1000, 0));
1587			info.extension_weight = ext.weight(&call);
1588			assert_eq!(info.total_weight(), Weight::from_parts(1600, 0));
1589			let post_info = xt.apply::<ExtRuntime>(&info, 0).unwrap().unwrap();
1590			// 500 actual call weight + 100 + 0 + 0
1591			assert_eq!(post_info.actual_weight, Some(Weight::from_parts(600, 0)));
1592
1593			// Second testcase
1594			let ext: TxExtension = (HalfCostIf(false), FreeIfUnder(1100), ActualWeightIs(200));
1595			let xt = CheckedExtrinsic {
1596				format: ExtrinsicFormat::Signed(0, ext),
1597				function: call.clone(),
1598			};
1599			let post_info = xt.apply::<ExtRuntime>(&info, 0).unwrap().unwrap();
1600			// 500 actual call weight + 100 + 200 + 200
1601			assert_eq!(post_info.actual_weight, Some(Weight::from_parts(1000, 0)));
1602
1603			// Third testcase
1604			let ext: TxExtension = (HalfCostIf(true), FreeIfUnder(1060), ActualWeightIs(200));
1605			let xt = CheckedExtrinsic {
1606				format: ExtrinsicFormat::Signed(0, ext),
1607				function: call.clone(),
1608			};
1609			let post_info = xt.apply::<ExtRuntime>(&info, 0).unwrap().unwrap();
1610			// 500 actual call weight + 50 + 0 + 200
1611			assert_eq!(post_info.actual_weight, Some(Weight::from_parts(750, 0)));
1612
1613			// Fourth testcase
1614			let ext: TxExtension = (HalfCostIf(false), FreeIfUnder(100), ActualWeightIs(300));
1615			let xt = CheckedExtrinsic {
1616				format: ExtrinsicFormat::Signed(0, ext),
1617				function: call.clone(),
1618			};
1619			let post_info = xt.apply::<ExtRuntime>(&info, 0).unwrap().unwrap();
1620			// 500 actual call weight + 100 + 200 + 300
1621			assert_eq!(post_info.actual_weight, Some(Weight::from_parts(1100, 0)));
1622		});
1623	}
1624}