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