referrerpolicy=no-referrer-when-downgrade

pallet_transaction_payment/
lib.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//! # Transaction Payment Pallet
19//!
20//! This pallet provides the basic logic needed to pay the absolute minimum amount needed for a
21//! transaction to be included. This includes:
22//!   - _base fee_: This is the minimum amount a user pays for a transaction. It is declared
23//! 	as a base _weight_ in the runtime and converted to a fee using `WeightToFee`.
24//!   - _weight fee_: A fee proportional to amount of weight a transaction consumes.
25//!   - _length fee_: A fee proportional to the encoded length of the transaction.
26//!   - _tip_: An optional tip. Tip increases the priority of the transaction, giving it a higher
27//!     chance to be included by the transaction queue.
28//!
29//! The base fee and adjusted weight and length fees constitute the _inclusion fee_, which is
30//! the minimum fee for a transaction to be included in a block.
31//!
32//! The formula of final fee:
33//!   ```ignore
34//!   inclusion_fee = base_fee + length_fee + [targeted_fee_adjustment * weight_fee];
35//!   final_fee = inclusion_fee + tip;
36//!   ```
37//!
38//!   - `targeted_fee_adjustment`: This is a multiplier that can tune the final fee based on
39//! 	the congestion of the network.
40//!
41//! Additionally, this pallet allows one to configure:
42//!   - The mapping between one unit of weight to one unit of fee via [`Config::WeightToFee`].
43//!   - A means of updating the fee for the next block, via defining a multiplier, based on the
44//!     final state of the chain at the end of the previous block. This can be configured via
45//!     [`Config::FeeMultiplierUpdate`]
46//!   - How the fees are paid via [`Config::OnChargeTransaction`].
47
48#![cfg_attr(not(feature = "std"), no_std)]
49
50use codec::{Decode, DecodeWithMemTracking, Encode, MaxEncodedLen};
51use scale_info::TypeInfo;
52
53use frame_support::{
54	dispatch::{
55		DispatchClass, DispatchInfo, DispatchResult, GetDispatchInfo, Pays, PostDispatchInfo,
56	},
57	pallet_prelude::TransactionSource,
58	traits::{Defensive, EstimateCallFee, Get},
59	weights::{Weight, WeightToFee},
60	RuntimeDebugNoBound,
61};
62pub use pallet::*;
63pub use payment::*;
64use sp_runtime::{
65	traits::{
66		Convert, DispatchInfoOf, Dispatchable, One, PostDispatchInfoOf, SaturatedConversion,
67		Saturating, TransactionExtension, Zero,
68	},
69	transaction_validity::{TransactionPriority, TransactionValidityError, ValidTransaction},
70	FixedPointNumber, FixedU128, Perbill, Perquintill, RuntimeDebug,
71};
72pub use types::{FeeDetails, InclusionFee, RuntimeDispatchInfo};
73pub use weights::WeightInfo;
74
75#[cfg(test)]
76mod mock;
77#[cfg(test)]
78mod tests;
79
80#[cfg(feature = "runtime-benchmarks")]
81mod benchmarking;
82
83mod payment;
84mod types;
85pub mod weights;
86
87/// Fee multiplier.
88pub type Multiplier = FixedU128;
89
90type BalanceOf<T> = <<T as Config>::OnChargeTransaction as OnChargeTransaction<T>>::Balance;
91
92/// A struct to update the weight multiplier per block. It implements `Convert<Multiplier,
93/// Multiplier>`, meaning that it can convert the previous multiplier to the next one. This should
94/// be called on `on_finalize` of a block, prior to potentially cleaning the weight data from the
95/// system pallet.
96///
97/// given:
98/// 	s = previous block weight
99/// 	s'= ideal block weight
100/// 	m = maximum block weight
101/// 		diff = (s - s')/m
102/// 		v = 0.00001
103/// 		t1 = (v * diff)
104/// 		t2 = (v * diff)^2 / 2
105/// 	then:
106/// 	next_multiplier = prev_multiplier * (1 + t1 + t2)
107///
108/// Where `(s', v)` must be given as the `Get` implementation of the `T` generic type. Moreover, `M`
109/// must provide the minimum allowed value for the multiplier. Note that a runtime should ensure
110/// with tests that the combination of this `M` and `V` is not such that the multiplier can drop to
111/// zero and never recover.
112///
113/// Note that `s'` is interpreted as a portion in the _normal transaction_ capacity of the block.
114/// For example, given `s' == 0.25` and `AvailableBlockRatio = 0.75`, then the target fullness is
115/// _0.25 of the normal capacity_ and _0.1875 of the entire block_.
116///
117/// Since block weight is multi-dimension, we use the scarcer resource, referred as limiting
118/// dimension, for calculation of fees. We determine the limiting dimension by comparing the
119/// dimensions using the ratio of `dimension_value / max_dimension_value` and selecting the largest
120/// ratio. For instance, if a block is 30% full based on `ref_time` and 25% full based on
121/// `proof_size`, we identify `ref_time` as the limiting dimension, indicating that the block is 30%
122/// full.
123///
124/// This implementation implies the bound:
125/// - `v ≤ p / k * (s − s')`
126/// - or, solving for `p`: `p >= v * k * (s - s')`
127///
128/// where `p` is the amount of change over `k` blocks.
129///
130/// Hence:
131/// - in a fully congested chain: `p >= v * k * (1 - s')`.
132/// - in an empty chain: `p >= v * k * (-s')`.
133///
134/// For example, when all blocks are full and there are 28800 blocks per day (default in
135/// `substrate-node`) and v == 0.00001, s' == 0.1875, we'd have:
136///
137/// p >= 0.00001 * 28800 * 0.8125
138/// p >= 0.234
139///
140/// Meaning that fees can change by around ~23% per day, given extreme congestion.
141///
142/// More info can be found at:
143/// <https://research.web3.foundation/Polkadot/overview/token-economics>
144pub struct TargetedFeeAdjustment<T, S, V, M, X>(core::marker::PhantomData<(T, S, V, M, X)>);
145
146/// Something that can convert the current multiplier to the next one.
147pub trait MultiplierUpdate: Convert<Multiplier, Multiplier> {
148	/// Minimum multiplier. Any outcome of the `convert` function should be at least this.
149	fn min() -> Multiplier;
150	/// Maximum multiplier. Any outcome of the `convert` function should be less or equal this.
151	fn max() -> Multiplier;
152	/// Target block saturation level
153	fn target() -> Perquintill;
154	/// Variability factor
155	fn variability() -> Multiplier;
156}
157
158impl MultiplierUpdate for () {
159	fn min() -> Multiplier {
160		Default::default()
161	}
162	fn max() -> Multiplier {
163		<Multiplier as sp_runtime::traits::Bounded>::max_value()
164	}
165	fn target() -> Perquintill {
166		Default::default()
167	}
168	fn variability() -> Multiplier {
169		Default::default()
170	}
171}
172
173impl<T, S, V, M, X> MultiplierUpdate for TargetedFeeAdjustment<T, S, V, M, X>
174where
175	T: frame_system::Config,
176	S: Get<Perquintill>,
177	V: Get<Multiplier>,
178	M: Get<Multiplier>,
179	X: Get<Multiplier>,
180{
181	fn min() -> Multiplier {
182		M::get()
183	}
184	fn max() -> Multiplier {
185		X::get()
186	}
187	fn target() -> Perquintill {
188		S::get()
189	}
190	fn variability() -> Multiplier {
191		V::get()
192	}
193}
194
195impl<T, S, V, M, X> Convert<Multiplier, Multiplier> for TargetedFeeAdjustment<T, S, V, M, X>
196where
197	T: frame_system::Config,
198	S: Get<Perquintill>,
199	V: Get<Multiplier>,
200	M: Get<Multiplier>,
201	X: Get<Multiplier>,
202{
203	fn convert(previous: Multiplier) -> Multiplier {
204		// Defensive only. The multiplier in storage should always be at most positive. Nonetheless
205		// we recover here in case of errors, because any value below this would be stale and can
206		// never change.
207		let min_multiplier = M::get();
208		let max_multiplier = X::get();
209		let previous = previous.max(min_multiplier);
210
211		let weights = T::BlockWeights::get();
212		// the computed ratio is only among the normal class.
213		let normal_max_weight =
214			weights.get(DispatchClass::Normal).max_total.unwrap_or(weights.max_block);
215		let current_block_weight = frame_system::Pallet::<T>::block_weight();
216		let normal_block_weight =
217			current_block_weight.get(DispatchClass::Normal).min(normal_max_weight);
218
219		// Normalize dimensions so they can be compared. Ensure (defensive) max weight is non-zero.
220		let normalized_ref_time = Perbill::from_rational(
221			normal_block_weight.ref_time(),
222			normal_max_weight.ref_time().max(1),
223		);
224		let normalized_proof_size = Perbill::from_rational(
225			normal_block_weight.proof_size(),
226			normal_max_weight.proof_size().max(1),
227		);
228
229		// Pick the limiting dimension. If the proof size is the limiting dimension, then the
230		// multiplier is adjusted by the proof size. Otherwise, it is adjusted by the ref time.
231		let (normal_limiting_dimension, max_limiting_dimension) =
232			if normalized_ref_time < normalized_proof_size {
233				(normal_block_weight.proof_size(), normal_max_weight.proof_size())
234			} else {
235				(normal_block_weight.ref_time(), normal_max_weight.ref_time())
236			};
237
238		let target_block_fullness = S::get();
239		let adjustment_variable = V::get();
240
241		let target_weight = (target_block_fullness * max_limiting_dimension) as u128;
242		let block_weight = normal_limiting_dimension as u128;
243
244		// determines if the first_term is positive
245		let positive = block_weight >= target_weight;
246		let diff_abs = block_weight.max(target_weight) - block_weight.min(target_weight);
247
248		// defensive only, a test case assures that the maximum weight diff can fit in Multiplier
249		// without any saturation.
250		let diff = Multiplier::saturating_from_rational(diff_abs, max_limiting_dimension.max(1));
251		let diff_squared = diff.saturating_mul(diff);
252
253		let v_squared_2 = adjustment_variable.saturating_mul(adjustment_variable) /
254			Multiplier::saturating_from_integer(2);
255
256		let first_term = adjustment_variable.saturating_mul(diff);
257		let second_term = v_squared_2.saturating_mul(diff_squared);
258
259		if positive {
260			let excess = first_term.saturating_add(second_term).saturating_mul(previous);
261			previous.saturating_add(excess).clamp(min_multiplier, max_multiplier)
262		} else {
263			// Defensive-only: first_term > second_term. Safe subtraction.
264			let negative = first_term.saturating_sub(second_term).saturating_mul(previous);
265			previous.saturating_sub(negative).clamp(min_multiplier, max_multiplier)
266		}
267	}
268}
269
270/// A struct to make the fee multiplier a constant
271pub struct ConstFeeMultiplier<M: Get<Multiplier>>(core::marker::PhantomData<M>);
272
273impl<M: Get<Multiplier>> MultiplierUpdate for ConstFeeMultiplier<M> {
274	fn min() -> Multiplier {
275		M::get()
276	}
277	fn max() -> Multiplier {
278		M::get()
279	}
280	fn target() -> Perquintill {
281		Default::default()
282	}
283	fn variability() -> Multiplier {
284		Default::default()
285	}
286}
287
288impl<M> Convert<Multiplier, Multiplier> for ConstFeeMultiplier<M>
289where
290	M: Get<Multiplier>,
291{
292	fn convert(_previous: Multiplier) -> Multiplier {
293		Self::min()
294	}
295}
296
297/// Storage releases of the pallet.
298#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)]
299pub enum Releases {
300	/// Original version of the pallet.
301	V1Ancient,
302	/// One that bumps the usage to FixedU128 from FixedI128.
303	V2,
304}
305
306impl Default for Releases {
307	fn default() -> Self {
308		Releases::V1Ancient
309	}
310}
311
312/// Default value for NextFeeMultiplier. This is used in genesis and is also used in
313/// NextFeeMultiplierOnEmpty() to provide a value when none exists in storage.
314const MULTIPLIER_DEFAULT_VALUE: Multiplier = Multiplier::from_u32(1);
315
316#[frame_support::pallet]
317pub mod pallet {
318	use frame_support::pallet_prelude::*;
319	use frame_system::pallet_prelude::*;
320
321	use super::*;
322
323	#[pallet::pallet]
324	pub struct Pallet<T>(_);
325
326	pub mod config_preludes {
327		use super::*;
328		use frame_support::derive_impl;
329
330		/// Default prelude sensible to be used in a testing environment.
331		pub struct TestDefaultConfig;
332
333		#[derive_impl(frame_system::config_preludes::TestDefaultConfig, no_aggregated_types)]
334		impl frame_system::DefaultConfig for TestDefaultConfig {}
335
336		#[frame_support::register_default_impl(TestDefaultConfig)]
337		impl DefaultConfig for TestDefaultConfig {
338			#[inject_runtime_type]
339			type RuntimeEvent = ();
340			type FeeMultiplierUpdate = ();
341			type OperationalFeeMultiplier = ();
342			type WeightInfo = ();
343		}
344	}
345
346	#[pallet::config(with_default)]
347	pub trait Config: frame_system::Config {
348		/// The overarching event type.
349		#[pallet::no_default_bounds]
350		#[allow(deprecated)]
351		type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
352
353		/// Handler for withdrawing, refunding and depositing the transaction fee.
354		/// Transaction fees are withdrawn before the transaction is executed.
355		/// After the transaction was executed the transaction weight can be
356		/// adjusted, depending on the used resources by the transaction. If the
357		/// transaction weight is lower than expected, parts of the transaction fee
358		/// might be refunded. In the end the fees can be deposited.
359		#[pallet::no_default]
360		type OnChargeTransaction: OnChargeTransaction<Self>;
361
362		/// Convert a weight value into a deductible fee based on the currency type.
363		#[pallet::no_default]
364		type WeightToFee: WeightToFee<Balance = BalanceOf<Self>>;
365
366		/// Convert a length value into a deductible fee based on the currency type.
367		#[pallet::no_default]
368		type LengthToFee: WeightToFee<Balance = BalanceOf<Self>>;
369
370		/// Update the multiplier of the next block, based on the previous block's weight.
371		type FeeMultiplierUpdate: MultiplierUpdate;
372
373		/// A fee multiplier for `Operational` extrinsics to compute "virtual tip" to boost their
374		/// `priority`
375		///
376		/// This value is multiplied by the `final_fee` to obtain a "virtual tip" that is later
377		/// added to a tip component in regular `priority` calculations.
378		/// It means that a `Normal` transaction can front-run a similarly-sized `Operational`
379		/// extrinsic (with no tip), by including a tip value greater than the virtual tip.
380		///
381		/// ```rust,ignore
382		/// // For `Normal`
383		/// let priority = priority_calc(tip);
384		///
385		/// // For `Operational`
386		/// let virtual_tip = (inclusion_fee + tip) * OperationalFeeMultiplier;
387		/// let priority = priority_calc(tip + virtual_tip);
388		/// ```
389		///
390		/// Note that since we use `final_fee` the multiplier applies also to the regular `tip`
391		/// sent with the transaction. So, not only does the transaction get a priority bump based
392		/// on the `inclusion_fee`, but we also amplify the impact of tips applied to `Operational`
393		/// transactions.
394		#[pallet::constant]
395		type OperationalFeeMultiplier: Get<u8>;
396
397		/// The weight information of this pallet.
398		type WeightInfo: WeightInfo;
399	}
400
401	#[pallet::type_value]
402	pub fn NextFeeMultiplierOnEmpty() -> Multiplier {
403		MULTIPLIER_DEFAULT_VALUE
404	}
405
406	#[pallet::storage]
407	#[pallet::whitelist_storage]
408	pub type NextFeeMultiplier<T: Config> =
409		StorageValue<_, Multiplier, ValueQuery, NextFeeMultiplierOnEmpty>;
410
411	#[pallet::storage]
412	pub type StorageVersion<T: Config> = StorageValue<_, Releases, ValueQuery>;
413
414	#[pallet::genesis_config]
415	pub struct GenesisConfig<T: Config> {
416		pub multiplier: Multiplier,
417		#[serde(skip)]
418		pub _config: core::marker::PhantomData<T>,
419	}
420
421	impl<T: Config> Default for GenesisConfig<T> {
422		fn default() -> Self {
423			Self { multiplier: MULTIPLIER_DEFAULT_VALUE, _config: Default::default() }
424		}
425	}
426
427	#[pallet::genesis_build]
428	impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
429		fn build(&self) {
430			StorageVersion::<T>::put(Releases::V2);
431			NextFeeMultiplier::<T>::put(self.multiplier);
432		}
433	}
434
435	#[pallet::event]
436	#[pallet::generate_deposit(pub(super) fn deposit_event)]
437	pub enum Event<T: Config> {
438		/// A transaction fee `actual_fee`, of which `tip` was added to the minimum inclusion fee,
439		/// has been paid by `who`.
440		TransactionFeePaid { who: T::AccountId, actual_fee: BalanceOf<T>, tip: BalanceOf<T> },
441	}
442
443	#[pallet::hooks]
444	impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
445		fn on_finalize(_: frame_system::pallet_prelude::BlockNumberFor<T>) {
446			NextFeeMultiplier::<T>::mutate(|fm| {
447				*fm = T::FeeMultiplierUpdate::convert(*fm);
448			});
449		}
450
451		#[cfg(feature = "std")]
452		fn integrity_test() {
453			// given weight == u64, we build multipliers from `diff` of two weight values, which can
454			// at most be maximum block weight. Make sure that this can fit in a multiplier without
455			// loss.
456			assert!(
457				<Multiplier as sp_runtime::traits::Bounded>::max_value() >=
458					Multiplier::checked_from_integer::<u128>(
459						T::BlockWeights::get().max_block.ref_time().try_into().unwrap()
460					)
461					.unwrap(),
462			);
463
464			let target = T::FeeMultiplierUpdate::target() *
465				T::BlockWeights::get().get(DispatchClass::Normal).max_total.expect(
466					"Setting `max_total` for `Normal` dispatch class is not compatible with \
467					`transaction-payment` pallet.",
468				);
469			// add 1 percent;
470			let addition = target / 100;
471			if addition == Weight::zero() {
472				// this is most likely because in a test setup we set everything to ()
473				// or to `ConstFeeMultiplier`.
474				return
475			}
476
477			// This is the minimum value of the multiplier. Make sure that if we collapse to this
478			// value, we can recover with a reasonable amount of traffic. For this test we assert
479			// that if we collapse to minimum, the trend will be positive with a weight value which
480			// is 1% more than the target.
481			let min_value = T::FeeMultiplierUpdate::min();
482			let target = target + addition;
483
484			frame_system::Pallet::<T>::set_block_consumed_resources(target, 0);
485			let next = T::FeeMultiplierUpdate::convert(min_value);
486			assert!(
487				next > min_value,
488				"The minimum bound of the multiplier is too low. When \
489				block saturation is more than target by 1% and multiplier is minimal then \
490				the multiplier doesn't increase."
491			);
492		}
493	}
494}
495
496impl<T: Config> Pallet<T> {
497	/// Public function to access the next fee multiplier.
498	pub fn next_fee_multiplier() -> Multiplier {
499		NextFeeMultiplier::<T>::get()
500	}
501
502	/// Query the data that we know about the fee of a given `call`.
503	///
504	/// This pallet is not and cannot be aware of the internals of a signed extension, for example
505	/// a tip. It only interprets the extrinsic as some encoded value and accounts for its weight
506	/// and length, the runtime's extrinsic base weight, and the current fee multiplier.
507	///
508	/// All dispatchables must be annotated with weight and will have some fee info. This function
509	/// always returns.
510	pub fn query_info<Extrinsic: sp_runtime::traits::ExtrinsicLike + GetDispatchInfo>(
511		unchecked_extrinsic: Extrinsic,
512		len: u32,
513	) -> RuntimeDispatchInfo<BalanceOf<T>>
514	where
515		T::RuntimeCall: Dispatchable<Info = DispatchInfo>,
516	{
517		// NOTE: we can actually make it understand `ChargeTransactionPayment`, but would be some
518		// hassle for sure. We have to make it aware of the index of `ChargeTransactionPayment` in
519		// `Extra`. Alternatively, we could actually execute the tx's per-dispatch and record the
520		// balance of the sender before and after the pipeline.. but this is way too much hassle for
521		// a very very little potential gain in the future.
522		let dispatch_info = <Extrinsic as GetDispatchInfo>::get_dispatch_info(&unchecked_extrinsic);
523
524		let partial_fee = if unchecked_extrinsic.is_bare() {
525			// Bare extrinsics have no partial fee.
526			0u32.into()
527		} else {
528			Self::compute_fee(len, &dispatch_info, 0u32.into())
529		};
530
531		let DispatchInfo { class, .. } = dispatch_info;
532
533		RuntimeDispatchInfo { weight: dispatch_info.total_weight(), class, partial_fee }
534	}
535
536	/// Query the detailed fee of a given `call`.
537	pub fn query_fee_details<Extrinsic: sp_runtime::traits::ExtrinsicLike + GetDispatchInfo>(
538		unchecked_extrinsic: Extrinsic,
539		len: u32,
540	) -> FeeDetails<BalanceOf<T>>
541	where
542		T::RuntimeCall: Dispatchable<Info = DispatchInfo>,
543	{
544		let dispatch_info = <Extrinsic as GetDispatchInfo>::get_dispatch_info(&unchecked_extrinsic);
545
546		let tip = 0u32.into();
547
548		if unchecked_extrinsic.is_bare() {
549			// Bare extrinsics have no inclusion fee.
550			FeeDetails { inclusion_fee: None, tip }
551		} else {
552			Self::compute_fee_details(len, &dispatch_info, tip)
553		}
554	}
555
556	/// Query information of a dispatch class, weight, and fee of a given encoded `Call`.
557	pub fn query_call_info(call: T::RuntimeCall, len: u32) -> RuntimeDispatchInfo<BalanceOf<T>>
558	where
559		T::RuntimeCall: Dispatchable<Info = DispatchInfo> + GetDispatchInfo,
560	{
561		let dispatch_info = <T::RuntimeCall as GetDispatchInfo>::get_dispatch_info(&call);
562		let DispatchInfo { class, .. } = dispatch_info;
563
564		RuntimeDispatchInfo {
565			weight: dispatch_info.total_weight(),
566			class,
567			partial_fee: Self::compute_fee(len, &dispatch_info, 0u32.into()),
568		}
569	}
570
571	/// Query fee details of a given encoded `Call`.
572	pub fn query_call_fee_details(call: T::RuntimeCall, len: u32) -> FeeDetails<BalanceOf<T>>
573	where
574		T::RuntimeCall: Dispatchable<Info = DispatchInfo> + GetDispatchInfo,
575	{
576		let dispatch_info = <T::RuntimeCall as GetDispatchInfo>::get_dispatch_info(&call);
577		let tip = 0u32.into();
578
579		Self::compute_fee_details(len, &dispatch_info, tip)
580	}
581
582	/// Compute the final fee value for a particular transaction.
583	pub fn compute_fee(
584		len: u32,
585		info: &DispatchInfoOf<T::RuntimeCall>,
586		tip: BalanceOf<T>,
587	) -> BalanceOf<T>
588	where
589		T::RuntimeCall: Dispatchable<Info = DispatchInfo>,
590	{
591		Self::compute_fee_details(len, info, tip).final_fee()
592	}
593
594	/// Compute the fee details for a particular transaction.
595	pub fn compute_fee_details(
596		len: u32,
597		info: &DispatchInfoOf<T::RuntimeCall>,
598		tip: BalanceOf<T>,
599	) -> FeeDetails<BalanceOf<T>>
600	where
601		T::RuntimeCall: Dispatchable<Info = DispatchInfo>,
602	{
603		Self::compute_fee_raw(len, info.total_weight(), tip, info.pays_fee, info.class)
604	}
605
606	/// Compute the actual post dispatch fee for a particular transaction.
607	///
608	/// Identical to `compute_fee` with the only difference that the post dispatch corrected
609	/// weight is used for the weight fee calculation.
610	pub fn compute_actual_fee(
611		len: u32,
612		info: &DispatchInfoOf<T::RuntimeCall>,
613		post_info: &PostDispatchInfoOf<T::RuntimeCall>,
614		tip: BalanceOf<T>,
615	) -> BalanceOf<T>
616	where
617		T::RuntimeCall: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo>,
618	{
619		Self::compute_actual_fee_details(len, info, post_info, tip).final_fee()
620	}
621
622	/// Compute the actual post dispatch fee details for a particular transaction.
623	pub fn compute_actual_fee_details(
624		len: u32,
625		info: &DispatchInfoOf<T::RuntimeCall>,
626		post_info: &PostDispatchInfoOf<T::RuntimeCall>,
627		tip: BalanceOf<T>,
628	) -> FeeDetails<BalanceOf<T>>
629	where
630		T::RuntimeCall: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo>,
631	{
632		Self::compute_fee_raw(
633			len,
634			post_info.calc_actual_weight(info),
635			tip,
636			post_info.pays_fee(info),
637			info.class,
638		)
639	}
640
641	fn compute_fee_raw(
642		len: u32,
643		weight: Weight,
644		tip: BalanceOf<T>,
645		pays_fee: Pays,
646		class: DispatchClass,
647	) -> FeeDetails<BalanceOf<T>> {
648		if pays_fee == Pays::Yes {
649			// the adjustable part of the fee.
650			let unadjusted_weight_fee = Self::weight_to_fee(weight);
651			let multiplier = NextFeeMultiplier::<T>::get();
652			// final adjusted weight fee.
653			let adjusted_weight_fee = multiplier.saturating_mul_int(unadjusted_weight_fee);
654
655			// length fee. this is adjusted via `LengthToFee`.
656			let len_fee = Self::length_to_fee(len);
657
658			let base_fee = Self::weight_to_fee(T::BlockWeights::get().get(class).base_extrinsic);
659			FeeDetails {
660				inclusion_fee: Some(InclusionFee { base_fee, len_fee, adjusted_weight_fee }),
661				tip,
662			}
663		} else {
664			FeeDetails { inclusion_fee: None, tip }
665		}
666	}
667
668	/// Compute the length portion of a fee by invoking the configured `LengthToFee` impl.
669	pub fn length_to_fee(length: u32) -> BalanceOf<T> {
670		T::LengthToFee::weight_to_fee(&Weight::from_parts(length as u64, 0))
671	}
672
673	/// Compute the unadjusted portion of the weight fee by invoking the configured `WeightToFee`
674	/// impl. Note that the input `weight` is capped by the maximum block weight before computation.
675	pub fn weight_to_fee(weight: Weight) -> BalanceOf<T> {
676		// cap the weight to the maximum defined in runtime, otherwise it will be the
677		// `Bounded` maximum of its data type, which is not desired.
678		let capped_weight = weight.min(T::BlockWeights::get().max_block);
679		T::WeightToFee::weight_to_fee(&capped_weight)
680	}
681
682	/// Deposit the [`Event::TransactionFeePaid`] event.
683	pub fn deposit_fee_paid_event(who: T::AccountId, actual_fee: BalanceOf<T>, tip: BalanceOf<T>) {
684		Self::deposit_event(Event::TransactionFeePaid { who, actual_fee, tip });
685	}
686}
687
688impl<T> Convert<Weight, BalanceOf<T>> for Pallet<T>
689where
690	T: Config,
691{
692	/// Compute the fee for the specified weight.
693	///
694	/// This fee is already adjusted by the per block fee adjustment factor and is therefore the
695	/// share that the weight contributes to the overall fee of a transaction. It is mainly
696	/// for informational purposes and not used in the actual fee calculation.
697	fn convert(weight: Weight) -> BalanceOf<T> {
698		NextFeeMultiplier::<T>::get().saturating_mul_int(Self::weight_to_fee(weight))
699	}
700}
701
702/// Require the transactor pay for themselves and maybe include a tip to gain additional priority
703/// in the queue.
704///
705/// # Transaction Validity
706///
707/// This extension sets the `priority` field of `TransactionValidity` depending on the amount
708/// of tip being paid per weight unit.
709///
710/// Operational transactions will receive an additional priority bump, so that they are normally
711/// considered before regular transactions.
712#[derive(Encode, Decode, DecodeWithMemTracking, Clone, Eq, PartialEq, TypeInfo)]
713#[scale_info(skip_type_params(T))]
714pub struct ChargeTransactionPayment<T: Config>(#[codec(compact)] BalanceOf<T>);
715
716impl<T: Config> ChargeTransactionPayment<T>
717where
718	T::RuntimeCall: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo>,
719	BalanceOf<T>: Send + Sync,
720{
721	/// utility constructor. Used only in client/factory code.
722	pub fn from(fee: BalanceOf<T>) -> Self {
723		Self(fee)
724	}
725
726	/// Returns the tip as being chosen by the transaction sender.
727	pub fn tip(&self) -> BalanceOf<T> {
728		self.0
729	}
730
731	fn withdraw_fee(
732		&self,
733		who: &T::AccountId,
734		call: &T::RuntimeCall,
735		info: &DispatchInfoOf<T::RuntimeCall>,
736		fee: BalanceOf<T>,
737	) -> Result<
738		(
739			BalanceOf<T>,
740			<<T as Config>::OnChargeTransaction as OnChargeTransaction<T>>::LiquidityInfo,
741		),
742		TransactionValidityError,
743	> {
744		let tip = self.0;
745
746		<<T as Config>::OnChargeTransaction as OnChargeTransaction<T>>::withdraw_fee(
747			who, call, info, fee, tip,
748		)
749		.map(|i| (fee, i))
750	}
751
752	fn can_withdraw_fee(
753		&self,
754		who: &T::AccountId,
755		call: &T::RuntimeCall,
756		info: &DispatchInfoOf<T::RuntimeCall>,
757		len: usize,
758	) -> Result<BalanceOf<T>, TransactionValidityError> {
759		let tip = self.0;
760		let fee = Pallet::<T>::compute_fee(len as u32, info, tip);
761
762		<<T as Config>::OnChargeTransaction as OnChargeTransaction<T>>::can_withdraw_fee(
763			who, call, info, fee, tip,
764		)?;
765		Ok(fee)
766	}
767
768	/// Get an appropriate priority for a transaction with the given `DispatchInfo`, encoded length
769	/// and user-included tip.
770	///
771	/// The priority is based on the amount of `tip` the user is willing to pay per unit of either
772	/// `weight` or `length`, depending which one is more limiting. For `Operational` extrinsics
773	/// we add a "virtual tip" to the calculations.
774	///
775	/// The formula should simply be `tip / bounded_{weight|length}`, but since we are using
776	/// integer division, we have no guarantees it's going to give results in any reasonable
777	/// range (might simply end up being zero). Hence we use a scaling factor:
778	/// `tip * (max_block_{weight|length} / bounded_{weight|length})`, since given current
779	/// state of-the-art blockchains, number of per-block transactions is expected to be in a
780	/// range reasonable enough to not saturate the `Balance` type while multiplying by the tip.
781	pub fn get_priority(
782		info: &DispatchInfoOf<T::RuntimeCall>,
783		len: usize,
784		tip: BalanceOf<T>,
785		final_fee: BalanceOf<T>,
786	) -> TransactionPriority {
787		// Calculate how many such extrinsics we could fit into an empty block and take the
788		// limiting factor.
789		let max_block_weight = T::BlockWeights::get().max_block;
790		let max_block_length = *T::BlockLength::get().max.get(info.class) as u64;
791
792		// bounded_weight is used as a divisor later so we keep it non-zero.
793		let bounded_weight =
794			info.total_weight().max(Weight::from_parts(1, 1)).min(max_block_weight);
795		let bounded_length = (len as u64).clamp(1, max_block_length);
796
797		// returns the scarce resource, i.e. the one that is limiting the number of transactions.
798		let max_tx_per_block_weight = max_block_weight
799			.checked_div_per_component(&bounded_weight)
800			.defensive_proof("bounded_weight is non-zero; qed")
801			.unwrap_or(1);
802		let max_tx_per_block_length = max_block_length / bounded_length;
803		// Given our current knowledge this value is going to be in a reasonable range - i.e.
804		// less than 10^9 (2^30), so multiplying by the `tip` value is unlikely to overflow the
805		// balance type. We still use saturating ops obviously, but the point is to end up with some
806		// `priority` distribution instead of having all transactions saturate the priority.
807		let max_tx_per_block = max_tx_per_block_length
808			.min(max_tx_per_block_weight)
809			.saturated_into::<BalanceOf<T>>();
810		let max_reward = |val: BalanceOf<T>| val.saturating_mul(max_tx_per_block);
811
812		// To distribute no-tip transactions a little bit, we increase the tip value by one.
813		// This means that given two transactions without a tip, smaller one will be preferred.
814		let tip = tip.saturating_add(One::one());
815		let scaled_tip = max_reward(tip);
816
817		match info.class {
818			DispatchClass::Normal => {
819				// For normal class we simply take the `tip_per_weight`.
820				scaled_tip
821			},
822			DispatchClass::Mandatory => {
823				// Mandatory extrinsics should be prohibited (e.g. by the [`CheckWeight`]
824				// extensions), but just to be safe let's return the same priority as `Normal` here.
825				scaled_tip
826			},
827			DispatchClass::Operational => {
828				// A "virtual tip" value added to an `Operational` extrinsic.
829				// This value should be kept high enough to allow `Operational` extrinsics
830				// to get in even during congestion period, but at the same time low
831				// enough to prevent a possible spam attack by sending invalid operational
832				// extrinsics which push away regular transactions from the pool.
833				let fee_multiplier = T::OperationalFeeMultiplier::get().saturated_into();
834				let virtual_tip = final_fee.saturating_mul(fee_multiplier);
835				let scaled_virtual_tip = max_reward(virtual_tip);
836
837				scaled_tip.saturating_add(scaled_virtual_tip)
838			},
839		}
840		.saturated_into::<TransactionPriority>()
841	}
842}
843
844impl<T: Config> core::fmt::Debug for ChargeTransactionPayment<T> {
845	#[cfg(feature = "std")]
846	fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
847		write!(f, "ChargeTransactionPayment<{:?}>", self.0)
848	}
849	#[cfg(not(feature = "std"))]
850	fn fmt(&self, _: &mut core::fmt::Formatter) -> core::fmt::Result {
851		Ok(())
852	}
853}
854
855/// The info passed between the validate and prepare steps for the `ChargeAssetTxPayment` extension.
856#[derive(RuntimeDebugNoBound)]
857pub enum Val<T: Config> {
858	Charge {
859		tip: BalanceOf<T>,
860		// who paid the fee
861		who: T::AccountId,
862		// transaction fee
863		fee: BalanceOf<T>,
864	},
865	NoCharge,
866}
867
868/// The info passed between the prepare and post-dispatch steps for the `ChargeAssetTxPayment`
869/// extension.
870pub enum Pre<T: Config> {
871	Charge {
872		tip: BalanceOf<T>,
873		// who paid the fee
874		who: T::AccountId,
875		// imbalance resulting from withdrawing the fee
876		imbalance: <<T as Config>::OnChargeTransaction as OnChargeTransaction<T>>::LiquidityInfo,
877	},
878	NoCharge {
879		// weight initially estimated by the extension, to be refunded
880		refund: Weight,
881	},
882}
883
884impl<T: Config> core::fmt::Debug for Pre<T> {
885	#[cfg(feature = "std")]
886	fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
887		match self {
888			Pre::Charge { tip, who, imbalance: _ } => {
889				write!(f, "Charge {{ tip: {:?}, who: {:?}, imbalance: <stripped> }}", tip, who)
890			},
891			Pre::NoCharge { refund } => write!(f, "NoCharge {{ refund: {:?} }}", refund),
892		}
893	}
894
895	#[cfg(not(feature = "std"))]
896	fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
897		f.write_str("<wasm:stripped>")
898	}
899}
900
901impl<T: Config> TransactionExtension<T::RuntimeCall> for ChargeTransactionPayment<T>
902where
903	T::RuntimeCall: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo>,
904{
905	const IDENTIFIER: &'static str = "ChargeTransactionPayment";
906	type Implicit = ();
907	type Val = Val<T>;
908	type Pre = Pre<T>;
909
910	fn weight(&self, _: &T::RuntimeCall) -> Weight {
911		T::WeightInfo::charge_transaction_payment()
912	}
913
914	fn validate(
915		&self,
916		origin: <T::RuntimeCall as Dispatchable>::RuntimeOrigin,
917		call: &T::RuntimeCall,
918		info: &DispatchInfoOf<T::RuntimeCall>,
919		len: usize,
920		_: (),
921		_implication: &impl Encode,
922		_source: TransactionSource,
923	) -> Result<
924		(ValidTransaction, Self::Val, <T::RuntimeCall as Dispatchable>::RuntimeOrigin),
925		TransactionValidityError,
926	> {
927		let Ok(who) = frame_system::ensure_signed(origin.clone()) else {
928			return Ok((ValidTransaction::default(), Val::NoCharge, origin));
929		};
930		let final_fee = self.can_withdraw_fee(&who, call, info, len)?;
931		let tip = self.0;
932		Ok((
933			ValidTransaction {
934				priority: Self::get_priority(info, len, tip, final_fee),
935				..Default::default()
936			},
937			Val::Charge { tip: self.0, who, fee: final_fee },
938			origin,
939		))
940	}
941
942	fn prepare(
943		self,
944		val: Self::Val,
945		_origin: &<T::RuntimeCall as Dispatchable>::RuntimeOrigin,
946		call: &T::RuntimeCall,
947		info: &DispatchInfoOf<T::RuntimeCall>,
948		_len: usize,
949	) -> Result<Self::Pre, TransactionValidityError> {
950		match val {
951			Val::Charge { tip, who, fee } => {
952				// Mutating call to `withdraw_fee` to actually charge for the transaction.
953				let (_final_fee, imbalance) = self.withdraw_fee(&who, call, info, fee)?;
954				Ok(Pre::Charge { tip, who, imbalance })
955			},
956			Val::NoCharge => Ok(Pre::NoCharge { refund: self.weight(call) }),
957		}
958	}
959
960	fn post_dispatch_details(
961		pre: Self::Pre,
962		info: &DispatchInfoOf<T::RuntimeCall>,
963		post_info: &PostDispatchInfoOf<T::RuntimeCall>,
964		len: usize,
965		_result: &DispatchResult,
966	) -> Result<Weight, TransactionValidityError> {
967		let (tip, who, imbalance) = match pre {
968			Pre::Charge { tip, who, imbalance } => (tip, who, imbalance),
969			Pre::NoCharge { refund } => {
970				// No-op: Refund everything
971				return Ok(refund)
972			},
973		};
974		let actual_fee = Pallet::<T>::compute_actual_fee(len as u32, info, &post_info, tip);
975		T::OnChargeTransaction::correct_and_deposit_fee(
976			&who, info, &post_info, actual_fee, tip, imbalance,
977		)?;
978		Pallet::<T>::deposit_event(Event::<T>::TransactionFeePaid { who, actual_fee, tip });
979		Ok(Weight::zero())
980	}
981}
982
983impl<T: Config, AnyCall: GetDispatchInfo + Encode> EstimateCallFee<AnyCall, BalanceOf<T>>
984	for Pallet<T>
985where
986	T::RuntimeCall: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo>,
987{
988	fn estimate_call_fee(call: &AnyCall, post_info: PostDispatchInfo) -> BalanceOf<T> {
989		let len = call.encoded_size() as u32;
990		let info = call.get_dispatch_info();
991		Self::compute_actual_fee(len, &info, &post_info, Zero::zero())
992	}
993}