Skip to main content

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, Signature, ExtensionV0, ExtensionOtherVersions> GetDispatchInfo
411	for UncheckedExtrinsic<Address, Call, Signature, ExtensionV0, ExtensionOtherVersions>
412where
413	Call: GetDispatchInfo + Dispatchable + Encode,
414	ExtensionV0: TransactionExtension<Call>,
415	ExtensionOtherVersions: sp_runtime::traits::Pipeline<Call>,
416	<Call as Dispatchable>::RuntimeOrigin: sp_runtime::traits::AsTransactionAuthorizedOrigin,
417{
418	fn get_dispatch_info(&self) -> DispatchInfo {
419		let mut info = self.function.get_dispatch_info();
420		info.extension_weight = self.extension_weight();
421		info
422	}
423}
424
425/// Implementation for checked extrinsic.
426impl<AccountId, Call, ExtensionV0, ExtensionOtherVersions> GetDispatchInfo
427	for CheckedExtrinsic<AccountId, Call, ExtensionV0, ExtensionOtherVersions>
428where
429	Call: GetDispatchInfo + Dispatchable + Encode,
430	ExtensionV0: TransactionExtension<Call>,
431	ExtensionOtherVersions: sp_runtime::traits::Pipeline<Call>,
432	<Call as Dispatchable>::RuntimeOrigin: sp_runtime::traits::AsTransactionAuthorizedOrigin,
433{
434	fn get_dispatch_info(&self) -> DispatchInfo {
435		let mut info = self.function.get_dispatch_info();
436		info.extension_weight = self.extension_weight();
437		info
438	}
439}
440
441/// A struct holding value for each `DispatchClass`.
442#[derive(Clone, Eq, PartialEq, Default, Debug, Encode, Decode, TypeInfo, MaxEncodedLen)]
443pub struct PerDispatchClass<T> {
444	/// Value for `Normal` extrinsics.
445	normal: T,
446	/// Value for `Operational` extrinsics.
447	operational: T,
448	/// Value for `Mandatory` extrinsics.
449	mandatory: T,
450}
451
452impl<T> PerDispatchClass<T> {
453	/// Create new `PerDispatchClass` with the same value for every class.
454	pub fn new(val: impl Fn(DispatchClass) -> T) -> Self {
455		Self {
456			normal: val(DispatchClass::Normal),
457			operational: val(DispatchClass::Operational),
458			mandatory: val(DispatchClass::Mandatory),
459		}
460	}
461
462	/// Get a mutable reference to current value of given class.
463	pub fn get_mut(&mut self, class: DispatchClass) -> &mut T {
464		match class {
465			DispatchClass::Operational => &mut self.operational,
466			DispatchClass::Normal => &mut self.normal,
467			DispatchClass::Mandatory => &mut self.mandatory,
468		}
469	}
470
471	/// Get current value for given class.
472	pub fn get(&self, class: DispatchClass) -> &T {
473		match class {
474			DispatchClass::Normal => &self.normal,
475			DispatchClass::Operational => &self.operational,
476			DispatchClass::Mandatory => &self.mandatory,
477		}
478	}
479}
480
481impl<T: Clone> PerDispatchClass<T> {
482	/// Set the value of given class.
483	pub fn set(&mut self, new: T, class: impl OneOrMany<DispatchClass>) {
484		for class in class.into_iter() {
485			*self.get_mut(class) = new.clone();
486		}
487	}
488}
489
490impl PerDispatchClass<Weight> {
491	/// Returns the total weight consumed by all extrinsics in the block.
492	///
493	/// Saturates on overflow.
494	pub fn total(&self) -> Weight {
495		let mut sum = Weight::zero();
496		for class in DispatchClass::all() {
497			sum.saturating_accrue(*self.get(*class));
498		}
499		sum
500	}
501
502	/// Add some weight to the given class. Saturates at the numeric bounds.
503	pub fn add(mut self, weight: Weight, class: DispatchClass) -> Self {
504		self.accrue(weight, class);
505		self
506	}
507
508	/// Increase the weight of the given class. Saturates at the numeric bounds.
509	pub fn accrue(&mut self, weight: Weight, class: DispatchClass) {
510		self.get_mut(class).saturating_accrue(weight);
511	}
512
513	/// Try to increase the weight of the given class. Saturates at the numeric bounds.
514	pub fn checked_accrue(&mut self, weight: Weight, class: DispatchClass) -> Result<(), ()> {
515		self.get_mut(class).checked_accrue(weight).ok_or(())
516	}
517
518	/// Reduce the weight of the given class. Saturates at the numeric bounds.
519	pub fn reduce(&mut self, weight: Weight, class: DispatchClass) {
520		self.get_mut(class).saturating_reduce(weight);
521	}
522}
523
524/// Means of weighing some particular kind of data (`T`).
525pub trait WeighData<T> {
526	/// Weigh the data `T` given by `target`. When implementing this for a dispatchable, `T` will be
527	/// a tuple of all arguments given to the function (except origin).
528	fn weigh_data(&self, target: T) -> Weight;
529}
530
531impl<T> WeighData<T> for Weight {
532	fn weigh_data(&self, _: T) -> Weight {
533		return *self;
534	}
535}
536
537impl<T> PaysFee<T> for (Weight, DispatchClass, Pays) {
538	fn pays_fee(&self, _: T) -> Pays {
539		self.2
540	}
541}
542
543impl<T> WeighData<T> for (Weight, DispatchClass) {
544	fn weigh_data(&self, args: T) -> Weight {
545		return self.0.weigh_data(args);
546	}
547}
548
549impl<T> WeighData<T> for (Weight, DispatchClass, Pays) {
550	fn weigh_data(&self, args: T) -> Weight {
551		return self.0.weigh_data(args);
552	}
553}
554
555impl<T> ClassifyDispatch<T> for (Weight, DispatchClass) {
556	fn classify_dispatch(&self, _: T) -> DispatchClass {
557		self.1
558	}
559}
560
561impl<T> PaysFee<T> for (Weight, DispatchClass) {
562	fn pays_fee(&self, _: T) -> Pays {
563		Pays::Yes
564	}
565}
566
567impl<T> WeighData<T> for (Weight, Pays) {
568	fn weigh_data(&self, args: T) -> Weight {
569		return self.0.weigh_data(args);
570	}
571}
572
573impl<T> ClassifyDispatch<T> for (Weight, Pays) {
574	fn classify_dispatch(&self, _: T) -> DispatchClass {
575		DispatchClass::Normal
576	}
577}
578
579impl<T> PaysFee<T> for (Weight, Pays) {
580	fn pays_fee(&self, _: T) -> Pays {
581		self.1
582	}
583}
584
585impl From<(Option<Weight>, Pays)> for PostDispatchInfo {
586	fn from(post_weight_info: (Option<Weight>, Pays)) -> Self {
587		let (actual_weight, pays_fee) = post_weight_info;
588		Self { actual_weight, pays_fee }
589	}
590}
591
592impl From<Option<Weight>> for PostDispatchInfo {
593	fn from(actual_weight: Option<Weight>) -> Self {
594		Self { actual_weight, pays_fee: Default::default() }
595	}
596}
597
598impl<T> ClassifyDispatch<T> for Weight {
599	fn classify_dispatch(&self, _: T) -> DispatchClass {
600		DispatchClass::Normal
601	}
602}
603
604impl<T> PaysFee<T> for Weight {
605	fn pays_fee(&self, _: T) -> Pays {
606		Pays::Yes
607	}
608}
609
610impl<T> ClassifyDispatch<T> for (Weight, DispatchClass, Pays) {
611	fn classify_dispatch(&self, _: T) -> DispatchClass {
612		self.1
613	}
614}
615
616impl RefundWeight for PostDispatchInfo {
617	fn refund(&mut self, weight: Weight) {
618		if let Some(actual_weight) = self.actual_weight.as_mut() {
619			actual_weight.saturating_reduce(weight);
620		}
621	}
622}
623
624impl ExtensionPostDispatchWeightHandler<DispatchInfo> for PostDispatchInfo {
625	fn set_extension_weight(&mut self, info: &DispatchInfo) {
626		let actual_weight = self
627			.actual_weight
628			.unwrap_or(info.call_weight)
629			.saturating_add(info.extension_weight);
630		self.actual_weight = Some(actual_weight);
631	}
632}
633
634impl ExtensionPostDispatchWeightHandler<()> for PostDispatchInfo {
635	fn set_extension_weight(&mut self, _: &()) {}
636}
637
638// TODO: Eventually remove these
639
640impl<T> ClassifyDispatch<T> for u64 {
641	fn classify_dispatch(&self, _: T) -> DispatchClass {
642		DispatchClass::Normal
643	}
644}
645
646impl<T> PaysFee<T> for u64 {
647	fn pays_fee(&self, _: T) -> Pays {
648		Pays::Yes
649	}
650}
651
652impl<T> WeighData<T> for u64 {
653	fn weigh_data(&self, _: T) -> Weight {
654		return Weight::from_parts(*self, 0);
655	}
656}
657
658impl<T> WeighData<T> for (u64, DispatchClass, Pays) {
659	fn weigh_data(&self, args: T) -> Weight {
660		return self.0.weigh_data(args);
661	}
662}
663
664impl<T> ClassifyDispatch<T> for (u64, DispatchClass, Pays) {
665	fn classify_dispatch(&self, _: T) -> DispatchClass {
666		self.1
667	}
668}
669
670impl<T> PaysFee<T> for (u64, DispatchClass, Pays) {
671	fn pays_fee(&self, _: T) -> Pays {
672		self.2
673	}
674}
675
676impl<T> WeighData<T> for (u64, DispatchClass) {
677	fn weigh_data(&self, args: T) -> Weight {
678		return self.0.weigh_data(args);
679	}
680}
681
682impl<T> ClassifyDispatch<T> for (u64, DispatchClass) {
683	fn classify_dispatch(&self, _: T) -> DispatchClass {
684		self.1
685	}
686}
687
688impl<T> PaysFee<T> for (u64, DispatchClass) {
689	fn pays_fee(&self, _: T) -> Pays {
690		Pays::Yes
691	}
692}
693
694impl<T> WeighData<T> for (u64, Pays) {
695	fn weigh_data(&self, args: T) -> Weight {
696		return self.0.weigh_data(args);
697	}
698}
699
700impl<T> ClassifyDispatch<T> for (u64, Pays) {
701	fn classify_dispatch(&self, _: T) -> DispatchClass {
702		DispatchClass::Normal
703	}
704}
705
706impl<T> PaysFee<T> for (u64, Pays) {
707	fn pays_fee(&self, _: T) -> Pays {
708		self.1
709	}
710}
711
712// END TODO
713
714#[cfg(test)]
715// Do not complain about unused `dispatch` and `dispatch_aux`.
716#[allow(dead_code)]
717mod weight_tests {
718	use super::*;
719	use sp_core::parameter_types;
720	use sp_runtime::{generic, traits::BlakeTwo256};
721	use sp_weights::RuntimeDbWeight;
722
723	pub use self::frame_system::{Call, Config};
724
725	fn from_actual_ref_time(ref_time: Option<u64>) -> PostDispatchInfo {
726		PostDispatchInfo {
727			actual_weight: ref_time.map(|t| Weight::from_all(t)),
728			pays_fee: Default::default(),
729		}
730	}
731
732	fn from_post_weight_info(ref_time: Option<u64>, pays_fee: Pays) -> PostDispatchInfo {
733		PostDispatchInfo { actual_weight: ref_time.map(|t| Weight::from_all(t)), pays_fee }
734	}
735
736	#[crate::pallet(dev_mode)]
737	pub mod frame_system {
738		use super::{frame_system, frame_system::pallet_prelude::*};
739		pub use crate::dispatch::RawOrigin;
740		use crate::pallet_prelude::*;
741
742		#[pallet::pallet]
743		pub struct Pallet<T>(_);
744
745		#[pallet::config]
746		#[pallet::disable_frame_system_supertrait_check]
747		pub trait Config: 'static {
748			type Block: Parameter + sp_runtime::traits::Block;
749			type AccountId;
750			type Balance;
751			type BaseCallFilter: crate::traits::Contains<Self::RuntimeCall>;
752			type RuntimeOrigin;
753			type RuntimeCall;
754			type RuntimeTask;
755			type PalletInfo: crate::traits::PalletInfo;
756			type DbWeight: Get<crate::weights::RuntimeDbWeight>;
757		}
758
759		#[pallet::error]
760		pub enum Error<T> {
761			/// Required by construct_runtime
762			CallFiltered,
763		}
764
765		#[pallet::origin]
766		pub type Origin<T> = RawOrigin<<T as Config>::AccountId>;
767
768		#[pallet::call]
769		impl<T: Config> Pallet<T> {
770			// no arguments, fixed weight
771			#[pallet::weight(1000)]
772			pub fn f00(_origin: OriginFor<T>) -> DispatchResult {
773				unimplemented!();
774			}
775
776			#[pallet::weight((1000, DispatchClass::Mandatory))]
777			pub fn f01(_origin: OriginFor<T>) -> DispatchResult {
778				unimplemented!();
779			}
780
781			#[pallet::weight((1000, Pays::No))]
782			pub fn f02(_origin: OriginFor<T>) -> DispatchResult {
783				unimplemented!();
784			}
785
786			#[pallet::weight((1000, DispatchClass::Operational, Pays::No))]
787			pub fn f03(_origin: OriginFor<T>) -> DispatchResult {
788				unimplemented!();
789			}
790
791			// weight = a x 10 + b
792			#[pallet::weight(((_a * 10 + _eb * 1) as u64, DispatchClass::Normal, Pays::Yes))]
793			pub fn f11(_origin: OriginFor<T>, _a: u32, _eb: u32) -> DispatchResult {
794				unimplemented!();
795			}
796
797			#[pallet::weight((0, DispatchClass::Operational, Pays::Yes))]
798			pub fn f12(_origin: OriginFor<T>, _a: u32, _eb: u32) -> DispatchResult {
799				unimplemented!();
800			}
801
802			#[pallet::weight(T::DbWeight::get().reads(3) + T::DbWeight::get().writes(2) + Weight::from_all(10_000))]
803			pub fn f20(_origin: OriginFor<T>) -> DispatchResult {
804				unimplemented!();
805			}
806
807			#[pallet::weight(T::DbWeight::get().reads_writes(6, 5) + Weight::from_all(40_000))]
808			pub fn f21(_origin: OriginFor<T>) -> DispatchResult {
809				unimplemented!();
810			}
811
812			#[pallet::weight(1000)]
813			pub fn f99(_origin: OriginFor<T>) -> DispatchResult {
814				Ok(())
815			}
816
817			#[pallet::weight(1000)]
818			pub fn f100(_origin: OriginFor<T>) -> DispatchResultWithPostInfo {
819				Ok(crate::dispatch::PostDispatchInfo {
820					actual_weight: Some(Weight::from_parts(500, 0)),
821					pays_fee: Pays::Yes,
822				})
823			}
824		}
825
826		pub mod pallet_prelude {
827			pub type OriginFor<T> = <T as super::Config>::RuntimeOrigin;
828
829			pub type HeaderFor<T> =
830				<<T as super::Config>::Block as sp_runtime::traits::HeaderProvider>::HeaderT;
831
832			pub type BlockNumberFor<T> = <HeaderFor<T> as sp_runtime::traits::Header>::Number;
833		}
834	}
835
836	type BlockNumber = u32;
837	type AccountId = u32;
838	type Balance = u32;
839	type Header = generic::Header<BlockNumber, BlakeTwo256>;
840	type UncheckedExtrinsic = generic::UncheckedExtrinsic<u32, RuntimeCall, (), ()>;
841	type Block = generic::Block<Header, UncheckedExtrinsic>;
842
843	crate::construct_runtime!(
844		pub enum Runtime
845		{
846			System: self::frame_system,
847		}
848	);
849
850	parameter_types! {
851		pub const DbWeight: RuntimeDbWeight = RuntimeDbWeight {
852			read: 100,
853			write: 1000,
854		};
855	}
856
857	impl Config for Runtime {
858		type Block = Block;
859		type AccountId = AccountId;
860		type Balance = Balance;
861		type BaseCallFilter = crate::traits::Everything;
862		type RuntimeOrigin = RuntimeOrigin;
863		type RuntimeCall = RuntimeCall;
864		type RuntimeTask = RuntimeTask;
865		type DbWeight = DbWeight;
866		type PalletInfo = PalletInfo;
867	}
868
869	#[test]
870	fn weights_are_correct() {
871		// #[pallet::weight(1000)]
872		let info = Call::<Runtime>::f00 {}.get_dispatch_info();
873		assert_eq!(info.total_weight(), Weight::from_parts(1000, 0));
874		assert_eq!(info.class, DispatchClass::Normal);
875		assert_eq!(info.pays_fee, Pays::Yes);
876
877		// #[pallet::weight((1000, DispatchClass::Mandatory))]
878		let info = Call::<Runtime>::f01 {}.get_dispatch_info();
879		assert_eq!(info.total_weight(), Weight::from_parts(1000, 0));
880		assert_eq!(info.class, DispatchClass::Mandatory);
881		assert_eq!(info.pays_fee, Pays::Yes);
882
883		// #[pallet::weight((1000, Pays::No))]
884		let info = Call::<Runtime>::f02 {}.get_dispatch_info();
885		assert_eq!(info.total_weight(), Weight::from_parts(1000, 0));
886		assert_eq!(info.class, DispatchClass::Normal);
887		assert_eq!(info.pays_fee, Pays::No);
888
889		// #[pallet::weight((1000, DispatchClass::Operational, Pays::No))]
890		let info = Call::<Runtime>::f03 {}.get_dispatch_info();
891		assert_eq!(info.total_weight(), Weight::from_parts(1000, 0));
892		assert_eq!(info.class, DispatchClass::Operational);
893		assert_eq!(info.pays_fee, Pays::No);
894
895		// #[pallet::weight(((_a * 10 + _eb * 1) as u64, DispatchClass::Normal, Pays::Yes))]
896		let info = Call::<Runtime>::f11 { a: 13, eb: 20 }.get_dispatch_info();
897		assert_eq!(info.total_weight(), Weight::from_parts(150, 0)); // 13*10 + 20
898		assert_eq!(info.class, DispatchClass::Normal);
899		assert_eq!(info.pays_fee, Pays::Yes);
900
901		// #[pallet::weight((0, DispatchClass::Operational, Pays::Yes))]
902		let info = Call::<Runtime>::f12 { a: 10, eb: 20 }.get_dispatch_info();
903		assert_eq!(info.total_weight(), Weight::zero());
904		assert_eq!(info.class, DispatchClass::Operational);
905		assert_eq!(info.pays_fee, Pays::Yes);
906
907		// #[pallet::weight(T::DbWeight::get().reads(3) + T::DbWeight::get().writes(2) +
908		// Weight::from_all(10_000))]
909		let info = Call::<Runtime>::f20 {}.get_dispatch_info();
910		assert_eq!(info.total_weight(), Weight::from_parts(12300, 10000)); // 100*3 + 1000*2 + 10_1000
911		assert_eq!(info.class, DispatchClass::Normal);
912		assert_eq!(info.pays_fee, Pays::Yes);
913
914		// #[pallet::weight(T::DbWeight::get().reads_writes(6, 5) + Weight::from_all(40_000))]
915		let info = Call::<Runtime>::f21 {}.get_dispatch_info();
916		assert_eq!(info.total_weight(), Weight::from_parts(45600, 40000)); // 100*6 + 1000*5 + 40_1000
917		assert_eq!(info.class, DispatchClass::Normal);
918		assert_eq!(info.pays_fee, Pays::Yes);
919	}
920
921	#[test]
922	fn extract_actual_weight_works() {
923		let pre = DispatchInfo {
924			call_weight: Weight::from_parts(1000, 0),
925			extension_weight: Weight::zero(),
926			..Default::default()
927		};
928		assert_eq!(
929			extract_actual_weight(&Ok(from_actual_ref_time(Some(7))), &pre),
930			Weight::from_parts(7, 0)
931		);
932		assert_eq!(
933			extract_actual_weight(&Ok(from_actual_ref_time(Some(1000))), &pre),
934			Weight::from_parts(1000, 0)
935		);
936		assert_eq!(
937			extract_actual_weight(
938				&Err(DispatchError::BadOrigin.with_weight(Weight::from_parts(9, 0))),
939				&pre
940			),
941			Weight::from_parts(9, 0)
942		);
943	}
944
945	#[test]
946	fn extract_actual_weight_caps_at_pre_weight() {
947		let pre = DispatchInfo {
948			call_weight: Weight::from_parts(1000, 0),
949			extension_weight: Weight::zero(),
950			..Default::default()
951		};
952		assert_eq!(
953			extract_actual_weight(&Ok(from_actual_ref_time(Some(1250))), &pre),
954			Weight::from_parts(1000, 0)
955		);
956		assert_eq!(
957			extract_actual_weight(
958				&Err(DispatchError::BadOrigin.with_weight(Weight::from_parts(1300, 0))),
959				&pre
960			),
961			Weight::from_parts(1000, 0),
962		);
963	}
964
965	#[test]
966	fn extract_actual_pays_fee_works() {
967		let pre = DispatchInfo {
968			call_weight: Weight::from_parts(1000, 0),
969			extension_weight: Weight::zero(),
970			..Default::default()
971		};
972		assert_eq!(extract_actual_pays_fee(&Ok(from_actual_ref_time(Some(7))), &pre), Pays::Yes);
973		assert_eq!(
974			extract_actual_pays_fee(&Ok(from_actual_ref_time(Some(1000)).into()), &pre),
975			Pays::Yes
976		);
977		assert_eq!(
978			extract_actual_pays_fee(&Ok(from_post_weight_info(Some(1000), Pays::Yes)), &pre),
979			Pays::Yes
980		);
981		assert_eq!(
982			extract_actual_pays_fee(&Ok(from_post_weight_info(Some(1000), Pays::No)), &pre),
983			Pays::No
984		);
985		assert_eq!(
986			extract_actual_pays_fee(
987				&Err(DispatchError::BadOrigin.with_weight(Weight::from_parts(9, 0))),
988				&pre
989			),
990			Pays::Yes
991		);
992		assert_eq!(
993			extract_actual_pays_fee(
994				&Err(DispatchErrorWithPostInfo {
995					post_info: PostDispatchInfo { actual_weight: None, pays_fee: Pays::No },
996					error: DispatchError::BadOrigin,
997				}),
998				&pre
999			),
1000			Pays::No
1001		);
1002
1003		let pre = DispatchInfo {
1004			call_weight: Weight::from_parts(1000, 0),
1005			extension_weight: Weight::zero(),
1006			pays_fee: Pays::No,
1007			..Default::default()
1008		};
1009		assert_eq!(extract_actual_pays_fee(&Ok(from_actual_ref_time(Some(7))), &pre), Pays::No);
1010		assert_eq!(extract_actual_pays_fee(&Ok(from_actual_ref_time(Some(1000))), &pre), Pays::No);
1011		assert_eq!(
1012			extract_actual_pays_fee(&Ok(from_post_weight_info(Some(1000), Pays::Yes)), &pre),
1013			Pays::No
1014		);
1015	}
1016
1017	#[test]
1018	fn weight_accrue_works() {
1019		let mut post_dispatch = PostDispatchInfo {
1020			actual_weight: Some(Weight::from_parts(1100, 25)),
1021			pays_fee: Pays::Yes,
1022		};
1023		post_dispatch.refund(Weight::from_parts(100, 15));
1024		assert_eq!(
1025			post_dispatch,
1026			PostDispatchInfo {
1027				actual_weight: Some(Weight::from_parts(1000, 10)),
1028				pays_fee: Pays::Yes
1029			}
1030		);
1031
1032		let mut post_dispatch = PostDispatchInfo { actual_weight: None, pays_fee: Pays::Yes };
1033		post_dispatch.refund(Weight::from_parts(100, 15));
1034		assert_eq!(post_dispatch, PostDispatchInfo { actual_weight: None, pays_fee: Pays::Yes });
1035	}
1036}
1037
1038#[cfg(test)]
1039mod per_dispatch_class_tests {
1040	use super::*;
1041	use sp_runtime::traits::Zero;
1042	use DispatchClass::*;
1043
1044	#[test]
1045	fn add_works() {
1046		let a = PerDispatchClass {
1047			normal: (5, 10).into(),
1048			operational: (20, 30).into(),
1049			mandatory: Weight::MAX,
1050		};
1051		assert_eq!(
1052			a.clone()
1053				.add((20, 5).into(), Normal)
1054				.add((10, 10).into(), Operational)
1055				.add((u64::MAX, 3).into(), Mandatory),
1056			PerDispatchClass {
1057				normal: (25, 15).into(),
1058				operational: (30, 40).into(),
1059				mandatory: Weight::MAX
1060			}
1061		);
1062		let b = a
1063			.add(Weight::MAX, Normal)
1064			.add(Weight::MAX, Operational)
1065			.add(Weight::MAX, Mandatory);
1066		assert_eq!(
1067			b,
1068			PerDispatchClass {
1069				normal: Weight::MAX,
1070				operational: Weight::MAX,
1071				mandatory: Weight::MAX
1072			}
1073		);
1074		assert_eq!(b.total(), Weight::MAX);
1075	}
1076
1077	#[test]
1078	fn accrue_works() {
1079		let mut a = PerDispatchClass::default();
1080
1081		a.accrue((10, 15).into(), Normal);
1082		assert_eq!(a.normal, (10, 15).into());
1083		assert_eq!(a.total(), (10, 15).into());
1084
1085		a.accrue((20, 25).into(), Operational);
1086		assert_eq!(a.operational, (20, 25).into());
1087		assert_eq!(a.total(), (30, 40).into());
1088
1089		a.accrue((30, 35).into(), Mandatory);
1090		assert_eq!(a.mandatory, (30, 35).into());
1091		assert_eq!(a.total(), (60, 75).into());
1092
1093		a.accrue((u64::MAX, 10).into(), Operational);
1094		assert_eq!(a.operational, (u64::MAX, 35).into());
1095		assert_eq!(a.total(), (u64::MAX, 85).into());
1096
1097		a.accrue((10, u64::MAX).into(), Normal);
1098		assert_eq!(a.normal, (20, u64::MAX).into());
1099		assert_eq!(a.total(), Weight::MAX);
1100	}
1101
1102	#[test]
1103	fn reduce_works() {
1104		let mut a = PerDispatchClass {
1105			normal: (10, u64::MAX).into(),
1106			mandatory: (u64::MAX, 10).into(),
1107			operational: (20, 20).into(),
1108		};
1109
1110		a.reduce((5, 100).into(), Normal);
1111		assert_eq!(a.normal, (5, u64::MAX - 100).into());
1112		assert_eq!(a.total(), (u64::MAX, u64::MAX - 70).into());
1113
1114		a.reduce((15, 5).into(), Operational);
1115		assert_eq!(a.operational, (5, 15).into());
1116		assert_eq!(a.total(), (u64::MAX, u64::MAX - 75).into());
1117
1118		a.reduce((50, 0).into(), Mandatory);
1119		assert_eq!(a.mandatory, (u64::MAX - 50, 10).into());
1120		assert_eq!(a.total(), (u64::MAX - 40, u64::MAX - 75).into());
1121
1122		a.reduce((u64::MAX, 100).into(), Operational);
1123		assert!(a.operational.is_zero());
1124		assert_eq!(a.total(), (u64::MAX - 45, u64::MAX - 90).into());
1125
1126		a.reduce((5, u64::MAX).into(), Normal);
1127		assert!(a.normal.is_zero());
1128		assert_eq!(a.total(), (u64::MAX - 50, 10).into());
1129	}
1130
1131	#[test]
1132	fn checked_accrue_works() {
1133		let mut a = PerDispatchClass::default();
1134
1135		a.checked_accrue((1, 2).into(), Normal).unwrap();
1136		a.checked_accrue((3, 4).into(), Operational).unwrap();
1137		a.checked_accrue((5, 6).into(), Mandatory).unwrap();
1138		a.checked_accrue((7, 8).into(), Operational).unwrap();
1139		a.checked_accrue((9, 0).into(), Normal).unwrap();
1140
1141		assert_eq!(
1142			a,
1143			PerDispatchClass {
1144				normal: (10, 2).into(),
1145				operational: (10, 12).into(),
1146				mandatory: (5, 6).into(),
1147			}
1148		);
1149
1150		a.checked_accrue((u64::MAX - 10, u64::MAX - 2).into(), Normal).unwrap();
1151		a.checked_accrue((0, 0).into(), Normal).unwrap();
1152		a.checked_accrue((1, 0).into(), Normal).unwrap_err();
1153		a.checked_accrue((0, 1).into(), Normal).unwrap_err();
1154
1155		assert_eq!(
1156			a,
1157			PerDispatchClass {
1158				normal: Weight::MAX,
1159				operational: (10, 12).into(),
1160				mandatory: (5, 6).into(),
1161			}
1162		);
1163	}
1164
1165	#[test]
1166	fn checked_accrue_does_not_modify_on_error() {
1167		let mut a = PerDispatchClass {
1168			normal: 0.into(),
1169			operational: Weight::MAX / 2 + 2.into(),
1170			mandatory: 10.into(),
1171		};
1172
1173		a.checked_accrue(Weight::MAX / 2, Operational).unwrap_err();
1174		a.checked_accrue(Weight::MAX - 9.into(), Mandatory).unwrap_err();
1175		a.checked_accrue(Weight::MAX, Normal).unwrap(); // This one works
1176
1177		assert_eq!(
1178			a,
1179			PerDispatchClass {
1180				normal: Weight::MAX,
1181				operational: Weight::MAX / 2 + 2.into(),
1182				mandatory: 10.into(),
1183			}
1184		);
1185	}
1186
1187	#[test]
1188	fn total_works() {
1189		assert!(PerDispatchClass::default().total().is_zero());
1190
1191		assert_eq!(
1192			PerDispatchClass {
1193				normal: 0.into(),
1194				operational: (10, 20).into(),
1195				mandatory: (20, u64::MAX).into(),
1196			}
1197			.total(),
1198			(30, u64::MAX).into()
1199		);
1200
1201		assert_eq!(
1202			PerDispatchClass {
1203				normal: (u64::MAX - 10, 10).into(),
1204				operational: (3, u64::MAX).into(),
1205				mandatory: (4, u64::MAX).into(),
1206			}
1207			.total(),
1208			(u64::MAX - 3, u64::MAX).into()
1209		);
1210	}
1211}
1212
1213#[cfg(test)]
1214mod test_extensions {
1215	use codec::{Decode, DecodeWithMemTracking, Encode};
1216	use scale_info::TypeInfo;
1217	use sp_runtime::{
1218		impl_tx_ext_default,
1219		traits::{
1220			DispatchInfoOf, DispatchOriginOf, Dispatchable, PostDispatchInfoOf,
1221			TransactionExtension,
1222		},
1223		transaction_validity::TransactionValidityError,
1224	};
1225	use sp_weights::Weight;
1226
1227	use super::{DispatchResult, PostDispatchInfo};
1228
1229	/// Test extension that refunds half its cost if the preset inner flag is set.
1230	#[derive(Clone, Eq, PartialEq, Debug, Encode, Decode, DecodeWithMemTracking, TypeInfo)]
1231	pub struct HalfCostIf(pub bool);
1232
1233	impl<RuntimeCall: Dispatchable> TransactionExtension<RuntimeCall> for HalfCostIf {
1234		const IDENTIFIER: &'static str = "HalfCostIf";
1235		type Implicit = ();
1236		type Val = ();
1237		type Pre = bool;
1238
1239		fn weight(&self, _: &RuntimeCall) -> sp_weights::Weight {
1240			Weight::from_parts(100, 0)
1241		}
1242
1243		fn prepare(
1244			self,
1245			_val: Self::Val,
1246			_origin: &DispatchOriginOf<RuntimeCall>,
1247			_call: &RuntimeCall,
1248			_info: &DispatchInfoOf<RuntimeCall>,
1249			_len: usize,
1250		) -> Result<Self::Pre, TransactionValidityError> {
1251			Ok(self.0)
1252		}
1253
1254		fn post_dispatch_details(
1255			pre: Self::Pre,
1256			_info: &DispatchInfoOf<RuntimeCall>,
1257			_post_info: &PostDispatchInfoOf<RuntimeCall>,
1258			_len: usize,
1259			_result: &DispatchResult,
1260		) -> Result<Weight, TransactionValidityError> {
1261			if pre {
1262				Ok(Weight::from_parts(50, 0))
1263			} else {
1264				Ok(Weight::zero())
1265			}
1266		}
1267		impl_tx_ext_default!(RuntimeCall; validate);
1268	}
1269
1270	/// Test extension that refunds its cost if the actual post dispatch weight up until this point
1271	/// in the extension pipeline is less than the preset inner `ref_time` amount.
1272	#[derive(Clone, Eq, PartialEq, Debug, Encode, Decode, DecodeWithMemTracking, TypeInfo)]
1273	pub struct FreeIfUnder(pub u64);
1274
1275	impl<RuntimeCall: Dispatchable> TransactionExtension<RuntimeCall> for FreeIfUnder
1276	where
1277		RuntimeCall: Dispatchable<PostInfo = PostDispatchInfo>,
1278	{
1279		const IDENTIFIER: &'static str = "FreeIfUnder";
1280		type Implicit = ();
1281		type Val = ();
1282		type Pre = u64;
1283
1284		fn weight(&self, _: &RuntimeCall) -> sp_weights::Weight {
1285			Weight::from_parts(200, 0)
1286		}
1287
1288		fn prepare(
1289			self,
1290			_val: Self::Val,
1291			_origin: &DispatchOriginOf<RuntimeCall>,
1292			_call: &RuntimeCall,
1293			_info: &DispatchInfoOf<RuntimeCall>,
1294			_len: usize,
1295		) -> Result<Self::Pre, TransactionValidityError> {
1296			Ok(self.0)
1297		}
1298
1299		fn post_dispatch_details(
1300			pre: Self::Pre,
1301			_info: &DispatchInfoOf<RuntimeCall>,
1302			post_info: &PostDispatchInfoOf<RuntimeCall>,
1303			_len: usize,
1304			_result: &DispatchResult,
1305		) -> Result<Weight, TransactionValidityError> {
1306			if let Some(actual) = post_info.actual_weight {
1307				if pre > actual.ref_time() {
1308					return Ok(Weight::from_parts(200, 0));
1309				}
1310			}
1311			Ok(Weight::zero())
1312		}
1313		impl_tx_ext_default!(RuntimeCall; validate);
1314	}
1315
1316	/// Test extension that sets its actual post dispatch `ref_time` weight to the preset inner
1317	/// amount.
1318	#[derive(Clone, Eq, PartialEq, Debug, Encode, Decode, DecodeWithMemTracking, TypeInfo)]
1319	pub struct ActualWeightIs(pub u64);
1320
1321	impl<RuntimeCall: Dispatchable> TransactionExtension<RuntimeCall> for ActualWeightIs {
1322		const IDENTIFIER: &'static str = "ActualWeightIs";
1323		type Implicit = ();
1324		type Val = ();
1325		type Pre = u64;
1326
1327		fn weight(&self, _: &RuntimeCall) -> sp_weights::Weight {
1328			Weight::from_parts(300, 0)
1329		}
1330
1331		fn prepare(
1332			self,
1333			_val: Self::Val,
1334			_origin: &DispatchOriginOf<RuntimeCall>,
1335			_call: &RuntimeCall,
1336			_info: &DispatchInfoOf<RuntimeCall>,
1337			_len: usize,
1338		) -> Result<Self::Pre, TransactionValidityError> {
1339			Ok(self.0)
1340		}
1341
1342		fn post_dispatch_details(
1343			pre: Self::Pre,
1344			_info: &DispatchInfoOf<RuntimeCall>,
1345			_post_info: &PostDispatchInfoOf<RuntimeCall>,
1346			_len: usize,
1347			_result: &DispatchResult,
1348		) -> Result<Weight, TransactionValidityError> {
1349			Ok(Weight::from_parts(300u64.saturating_sub(pre), 0))
1350		}
1351		impl_tx_ext_default!(RuntimeCall; validate);
1352	}
1353}
1354
1355#[cfg(test)]
1356// Do not complain about unused `dispatch` and `dispatch_aux`.
1357#[allow(dead_code)]
1358mod extension_weight_tests {
1359	use crate::assert_ok;
1360
1361	use super::*;
1362	use sp_core::parameter_types;
1363	use sp_runtime::{
1364		generic::{self, ExtrinsicFormat},
1365		traits::{Applyable, BlakeTwo256, DispatchTransaction, TransactionExtension},
1366	};
1367	use sp_weights::RuntimeDbWeight;
1368	use test_extensions::{ActualWeightIs, FreeIfUnder, HalfCostIf};
1369
1370	use super::weight_tests::frame_system;
1371	use frame_support::construct_runtime;
1372
1373	pub type TxExtension = (HalfCostIf, FreeIfUnder, ActualWeightIs);
1374	pub type UncheckedExtrinsic = generic::UncheckedExtrinsic<u64, RuntimeCall, (), TxExtension>;
1375	pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
1376	pub type Block = generic::Block<Header, UncheckedExtrinsic>;
1377	pub type AccountId = u64;
1378	pub type Balance = u32;
1379	pub type BlockNumber = u32;
1380
1381	construct_runtime!(
1382		pub enum ExtRuntime {
1383			System: frame_system,
1384		}
1385	);
1386
1387	impl frame_system::Config for ExtRuntime {
1388		type Block = Block;
1389		type AccountId = AccountId;
1390		type Balance = Balance;
1391		type BaseCallFilter = crate::traits::Everything;
1392		type RuntimeOrigin = RuntimeOrigin;
1393		type RuntimeCall = RuntimeCall;
1394		type RuntimeTask = RuntimeTask;
1395		type DbWeight = DbWeight;
1396		type PalletInfo = PalletInfo;
1397	}
1398
1399	parameter_types! {
1400		pub const DbWeight: RuntimeDbWeight = RuntimeDbWeight {
1401			read: 100,
1402			write: 1000,
1403		};
1404	}
1405
1406	pub struct ExtBuilder {}
1407
1408	impl Default for ExtBuilder {
1409		fn default() -> Self {
1410			Self {}
1411		}
1412	}
1413
1414	impl ExtBuilder {
1415		pub fn build(self) -> sp_io::TestExternalities {
1416			let mut ext = sp_io::TestExternalities::new(Default::default());
1417			ext.execute_with(|| {});
1418			ext
1419		}
1420
1421		pub fn build_and_execute(self, test: impl FnOnce() -> ()) {
1422			self.build().execute_with(|| {
1423				test();
1424			})
1425		}
1426	}
1427
1428	#[test]
1429	fn no_post_dispatch_with_no_refund() {
1430		ExtBuilder::default().build_and_execute(|| {
1431			let call = RuntimeCall::System(frame_system::Call::<ExtRuntime>::f99 {});
1432			let ext: TxExtension = (HalfCostIf(false), FreeIfUnder(1500), ActualWeightIs(0));
1433			let uxt = UncheckedExtrinsic::new_signed(call.clone(), 0, (), ext.clone());
1434			assert_eq!(uxt.extension_weight(), Weight::from_parts(600, 0));
1435
1436			let mut info = call.get_dispatch_info();
1437			assert_eq!(info.total_weight(), Weight::from_parts(1000, 0));
1438			info.extension_weight = ext.weight(&call);
1439			let (pre, _) = ext.validate_and_prepare(Some(0).into(), &call, &info, 0, 0).unwrap();
1440			let res = call.dispatch(Some(0).into());
1441			let mut post_info = res.unwrap();
1442			assert!(post_info.actual_weight.is_none());
1443			assert_ok!(<TxExtension as TransactionExtension<RuntimeCall>>::post_dispatch(
1444				pre,
1445				&info,
1446				&mut post_info,
1447				0,
1448				&Ok(()),
1449			));
1450			assert!(post_info.actual_weight.is_none());
1451		});
1452	}
1453
1454	#[test]
1455	fn no_post_dispatch_refunds_when_dispatched() {
1456		ExtBuilder::default().build_and_execute(|| {
1457			let call = RuntimeCall::System(frame_system::Call::<ExtRuntime>::f99 {});
1458			let ext: TxExtension = (HalfCostIf(true), FreeIfUnder(100), ActualWeightIs(0));
1459			let uxt = UncheckedExtrinsic::new_signed(call.clone(), 0, (), ext.clone());
1460			assert_eq!(uxt.extension_weight(), Weight::from_parts(600, 0));
1461
1462			let mut info = call.get_dispatch_info();
1463			assert_eq!(info.total_weight(), Weight::from_parts(1000, 0));
1464			info.extension_weight = ext.weight(&call);
1465			let post_info =
1466				ext.dispatch_transaction(Some(0).into(), call, &info, 0, 0).unwrap().unwrap();
1467			// 1000 call weight + 50 + 200 + 0
1468			assert_eq!(post_info.actual_weight, Some(Weight::from_parts(1250, 0)));
1469		});
1470	}
1471
1472	#[test]
1473	fn post_dispatch_with_refunds() {
1474		ExtBuilder::default().build_and_execute(|| {
1475			let call = RuntimeCall::System(frame_system::Call::<ExtRuntime>::f100 {});
1476			// First testcase
1477			let ext: TxExtension = (HalfCostIf(false), FreeIfUnder(2000), ActualWeightIs(0));
1478			let uxt = UncheckedExtrinsic::new_signed(call.clone(), 0, (), ext.clone());
1479			assert_eq!(uxt.extension_weight(), Weight::from_parts(600, 0));
1480
1481			let mut info = call.get_dispatch_info();
1482			assert_eq!(info.call_weight, Weight::from_parts(1000, 0));
1483			info.extension_weight = ext.weight(&call);
1484			assert_eq!(info.total_weight(), Weight::from_parts(1600, 0));
1485			let (pre, _) = ext.validate_and_prepare(Some(0).into(), &call, &info, 0, 0).unwrap();
1486			let res = call.clone().dispatch(Some(0).into());
1487			let mut post_info = res.unwrap();
1488			// 500 actual call weight
1489			assert_eq!(post_info.actual_weight, Some(Weight::from_parts(500, 0)));
1490			// add the 600 worst case extension weight
1491			post_info.set_extension_weight(&info);
1492			// extension weight should be refunded
1493			assert_ok!(<TxExtension as TransactionExtension<RuntimeCall>>::post_dispatch(
1494				pre,
1495				&info,
1496				&mut post_info,
1497				0,
1498				&Ok(()),
1499			));
1500			// 500 actual call weight + 100 + 0 + 0
1501			assert_eq!(post_info.actual_weight, Some(Weight::from_parts(600, 0)));
1502
1503			// Second testcase
1504			let ext: TxExtension = (HalfCostIf(false), FreeIfUnder(1100), ActualWeightIs(200));
1505			let (pre, _) = ext.validate_and_prepare(Some(0).into(), &call, &info, 0, 0).unwrap();
1506			let res = call.clone().dispatch(Some(0).into());
1507			let mut post_info = res.unwrap();
1508			// 500 actual call weight
1509			assert_eq!(post_info.actual_weight, Some(Weight::from_parts(500, 0)));
1510			// add the 600 worst case extension weight
1511			post_info.set_extension_weight(&info);
1512			// extension weight should be refunded
1513			assert_ok!(<TxExtension as TransactionExtension<RuntimeCall>>::post_dispatch(
1514				pre,
1515				&info,
1516				&mut post_info,
1517				0,
1518				&Ok(()),
1519			));
1520			// 500 actual call weight + 100 + 200 + 200
1521			assert_eq!(post_info.actual_weight, Some(Weight::from_parts(1000, 0)));
1522
1523			// Third testcase
1524			let ext: TxExtension = (HalfCostIf(true), FreeIfUnder(1060), ActualWeightIs(200));
1525			let (pre, _) = ext.validate_and_prepare(Some(0).into(), &call, &info, 0, 0).unwrap();
1526			let res = call.clone().dispatch(Some(0).into());
1527			let mut post_info = res.unwrap();
1528			// 500 actual call weight
1529			assert_eq!(post_info.actual_weight, Some(Weight::from_parts(500, 0)));
1530			// add the 600 worst case extension weight
1531			post_info.set_extension_weight(&info);
1532			// extension weight should be refunded
1533			assert_ok!(<TxExtension as TransactionExtension<RuntimeCall>>::post_dispatch(
1534				pre,
1535				&info,
1536				&mut post_info,
1537				0,
1538				&Ok(()),
1539			));
1540			// 500 actual call weight + 50 + 0 + 200
1541			assert_eq!(post_info.actual_weight, Some(Weight::from_parts(750, 0)));
1542
1543			// Fourth testcase
1544			let ext: TxExtension = (HalfCostIf(false), FreeIfUnder(100), ActualWeightIs(300));
1545			let (pre, _) = ext.validate_and_prepare(Some(0).into(), &call, &info, 0, 0).unwrap();
1546			let res = call.clone().dispatch(Some(0).into());
1547			let mut post_info = res.unwrap();
1548			// 500 actual call weight
1549			assert_eq!(post_info.actual_weight, Some(Weight::from_parts(500, 0)));
1550			// add the 600 worst case extension weight
1551			post_info.set_extension_weight(&info);
1552			// extension weight should be refunded
1553			assert_ok!(<TxExtension as TransactionExtension<RuntimeCall>>::post_dispatch(
1554				pre,
1555				&info,
1556				&mut post_info,
1557				0,
1558				&Ok(()),
1559			));
1560			// 500 actual call weight + 100 + 200 + 300
1561			assert_eq!(post_info.actual_weight, Some(Weight::from_parts(1100, 0)));
1562		});
1563	}
1564
1565	#[test]
1566	fn checked_extrinsic_apply() {
1567		ExtBuilder::default().build_and_execute(|| {
1568			let call = RuntimeCall::System(frame_system::Call::<ExtRuntime>::f100 {});
1569			// First testcase
1570			let ext: TxExtension = (HalfCostIf(false), FreeIfUnder(2000), ActualWeightIs(0));
1571			let xt = CheckedExtrinsic {
1572				format: ExtrinsicFormat::<_, _>::Signed(0, ext.clone()),
1573				function: call.clone(),
1574			};
1575			assert_eq!(xt.extension_weight(), Weight::from_parts(600, 0));
1576			let mut info = call.get_dispatch_info();
1577			assert_eq!(info.call_weight, Weight::from_parts(1000, 0));
1578			info.extension_weight = ext.weight(&call);
1579			assert_eq!(info.total_weight(), Weight::from_parts(1600, 0));
1580			let post_info = xt.apply::<ExtRuntime>(&info, 0).unwrap().unwrap();
1581			// 500 actual call weight + 100 + 0 + 0
1582			assert_eq!(post_info.actual_weight, Some(Weight::from_parts(600, 0)));
1583
1584			// Second testcase
1585			let ext: TxExtension = (HalfCostIf(false), FreeIfUnder(1100), ActualWeightIs(200));
1586			let xt = CheckedExtrinsic {
1587				format: ExtrinsicFormat::<_, _>::Signed(0, ext),
1588				function: call.clone(),
1589			};
1590			let post_info = xt.apply::<ExtRuntime>(&info, 0).unwrap().unwrap();
1591			// 500 actual call weight + 100 + 200 + 200
1592			assert_eq!(post_info.actual_weight, Some(Weight::from_parts(1000, 0)));
1593
1594			// Third testcase
1595			let ext: TxExtension = (HalfCostIf(true), FreeIfUnder(1060), ActualWeightIs(200));
1596			let xt = CheckedExtrinsic {
1597				format: ExtrinsicFormat::<_, _>::Signed(0, ext),
1598				function: call.clone(),
1599			};
1600			let post_info = xt.apply::<ExtRuntime>(&info, 0).unwrap().unwrap();
1601			// 500 actual call weight + 50 + 0 + 200
1602			assert_eq!(post_info.actual_weight, Some(Weight::from_parts(750, 0)));
1603
1604			// Fourth testcase
1605			let ext: TxExtension = (HalfCostIf(false), FreeIfUnder(100), ActualWeightIs(300));
1606			let xt = CheckedExtrinsic {
1607				format: ExtrinsicFormat::<_, _>::Signed(0, ext),
1608				function: call.clone(),
1609			};
1610			let post_info = xt.apply::<ExtRuntime>(&info, 0).unwrap().unwrap();
1611			// 500 actual call weight + 100 + 200 + 300
1612			assert_eq!(post_info.actual_weight, Some(Weight::from_parts(1100, 0)));
1613		});
1614	}
1615}