referrerpolicy=no-referrer-when-downgrade

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