diff --git a/bin/node-template/runtime/src/lib.rs b/bin/node-template/runtime/src/lib.rs index 93cf234fa52b8..40adbb0388111 100644 --- a/bin/node-template/runtime/src/lib.rs +++ b/bin/node-template/runtime/src/lib.rs @@ -249,15 +249,11 @@ impl pallet_balances::Config for Runtime { type WeightInfo = pallet_balances::weights::SubstrateWeight; } -parameter_types! { - pub const TransactionByteFee: Balance = 1; -} - impl pallet_transaction_payment::Config for Runtime { type OnChargeTransaction = CurrencyAdapter; - type TransactionByteFee = TransactionByteFee; type OperationalFeeMultiplier = ConstU8<5>; type WeightToFee = IdentityFee; + type LengthToFee = IdentityFee; type FeeMultiplierUpdate = (); } diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 565f151ce2a08..57584bed39b2c 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -35,7 +35,7 @@ use frame_support::{ }, weights::{ constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND}, - DispatchClass, IdentityFee, Weight, + ConstantMultiplier, DispatchClass, IdentityFee, Weight, }, PalletId, RuntimeDebug, }; @@ -444,9 +444,9 @@ parameter_types! { impl pallet_transaction_payment::Config for Runtime { type OnChargeTransaction = CurrencyAdapter; - type TransactionByteFee = TransactionByteFee; type OperationalFeeMultiplier = OperationalFeeMultiplier; type WeightToFee = IdentityFee; + type LengthToFee = ConstantMultiplier; type FeeMultiplierUpdate = TargetedFeeAdjustment; } diff --git a/frame/balances/src/tests_composite.rs b/frame/balances/src/tests_composite.rs index a24be44927375..4a2cc1d91936d 100644 --- a/frame/balances/src/tests_composite.rs +++ b/frame/balances/src/tests_composite.rs @@ -78,9 +78,9 @@ impl frame_system::Config for Test { impl pallet_transaction_payment::Config for Test { type OnChargeTransaction = CurrencyAdapter, ()>; - type TransactionByteFee = ConstU64<1>; type OperationalFeeMultiplier = ConstU8<5>; type WeightToFee = IdentityFee; + type LengthToFee = IdentityFee; type FeeMultiplierUpdate = (); } diff --git a/frame/balances/src/tests_local.rs b/frame/balances/src/tests_local.rs index ae56f3b1f0f2c..cfc7f84ab3a38 100644 --- a/frame/balances/src/tests_local.rs +++ b/frame/balances/src/tests_local.rs @@ -79,9 +79,9 @@ impl frame_system::Config for Test { impl pallet_transaction_payment::Config for Test { type OnChargeTransaction = CurrencyAdapter, ()>; - type TransactionByteFee = ConstU64<1>; type OperationalFeeMultiplier = ConstU8<5>; type WeightToFee = IdentityFee; + type LengthToFee = IdentityFee; type FeeMultiplierUpdate = (); } diff --git a/frame/balances/src/tests_reentrancy.rs b/frame/balances/src/tests_reentrancy.rs index 4303efc2322c5..7037e9615afd8 100644 --- a/frame/balances/src/tests_reentrancy.rs +++ b/frame/balances/src/tests_reentrancy.rs @@ -85,9 +85,9 @@ impl frame_system::Config for Test { impl pallet_transaction_payment::Config for Test { type OnChargeTransaction = CurrencyAdapter, ()>; - type TransactionByteFee = ConstU64<1>; type OperationalFeeMultiplier = ConstU8<5>; type WeightToFee = IdentityFee; + type LengthToFee = IdentityFee; type FeeMultiplierUpdate = (); } diff --git a/frame/executive/src/lib.rs b/frame/executive/src/lib.rs index d19ea8127bad3..de1cc3b916404 100644 --- a/frame/executive/src/lib.rs +++ b/frame/executive/src/lib.rs @@ -576,7 +576,9 @@ mod tests { ConstU32, ConstU64, ConstU8, Currency, LockIdentifier, LockableCurrency, WithdrawReasons, }, - weights::{IdentityFee, RuntimeDbWeight, Weight, WeightToFeePolynomial}, + weights::{ + ConstantMultiplier, IdentityFee, RuntimeDbWeight, Weight, WeightToFeePolynomial, + }, }; use frame_system::{Call as SystemCall, ChainContext, LastRuntimeUpgradeInfo}; use pallet_balances::Call as BalancesCall; @@ -787,9 +789,9 @@ mod tests { } impl pallet_transaction_payment::Config for Runtime { type OnChargeTransaction = CurrencyAdapter; - type TransactionByteFee = TransactionByteFee; type OperationalFeeMultiplier = ConstU8<5>; type WeightToFee = IdentityFee; + type LengthToFee = ConstantMultiplier; type FeeMultiplierUpdate = (); } impl custom::Config for Runtime {} diff --git a/frame/support/src/weights.rs b/frame/support/src/weights.rs index b3ed42bb45fc4..4c3fcaa0fd423 100644 --- a/frame/support/src/weights.rs +++ b/frame/support/src/weights.rs @@ -132,7 +132,10 @@ mod extrinsic_weights; mod paritydb_weights; mod rocksdb_weights; -use crate::dispatch::{DispatchError, DispatchErrorWithPostInfo, DispatchResultWithPostInfo}; +use crate::{ + dispatch::{DispatchError, DispatchErrorWithPostInfo, DispatchResultWithPostInfo}, + traits::Get, +}; use codec::{Decode, Encode}; use scale_info::TypeInfo; #[cfg(feature = "std")] @@ -709,6 +712,34 @@ where } } +/// Implementor of [`WeightToFeePolynomial`] that uses a constant multiplier. +/// # Example +/// +/// ``` +/// # use frame_support::traits::ConstU128; +/// # use frame_support::weights::ConstantMultiplier; +/// // Results in a multiplier of 10 for each unit of weight (or length) +/// type LengthToFee = ConstantMultiplier::>; +/// ``` +pub struct ConstantMultiplier(sp_std::marker::PhantomData<(T, M)>); + +impl WeightToFeePolynomial for ConstantMultiplier +where + T: BaseArithmetic + From + Copy + Unsigned, + M: Get, +{ + type Balance = T; + + fn polynomial() -> WeightToFeeCoefficients { + smallvec!(WeightToFeeCoefficient { + coeff_integer: M::get(), + coeff_frac: Perbill::zero(), + negative: false, + degree: 1, + }) + } +} + /// A struct holding value for each `DispatchClass`. #[derive(Clone, Eq, PartialEq, Default, RuntimeDebug, Encode, Decode, TypeInfo)] pub struct PerDispatchClass { @@ -983,4 +1014,13 @@ mod tests { assert_eq!(IdentityFee::::calc(&50), 50); assert_eq!(IdentityFee::::calc(&Weight::max_value()), Balance::max_value()); } + + #[test] + fn constant_fee_works() { + use crate::traits::ConstU128; + assert_eq!(ConstantMultiplier::>::calc(&0), 0); + assert_eq!(ConstantMultiplier::>::calc(&50), 500); + assert_eq!(ConstantMultiplier::>::calc(&16), 16384); + assert_eq!(ConstantMultiplier::>::calc(&2), u128::MAX); + } } diff --git a/frame/transaction-payment/asset-tx-payment/src/tests.rs b/frame/transaction-payment/asset-tx-payment/src/tests.rs index f2a1ad1406575..d72a288ac7a33 100644 --- a/frame/transaction-payment/asset-tx-payment/src/tests.rs +++ b/frame/transaction-payment/asset-tx-payment/src/tests.rs @@ -145,8 +145,8 @@ impl WeightToFeePolynomial for WeightToFee { impl pallet_transaction_payment::Config for Runtime { type OnChargeTransaction = CurrencyAdapter; - type TransactionByteFee = TransactionByteFee; type WeightToFee = WeightToFee; + type LengthToFee = WeightToFee; type FeeMultiplierUpdate = (); type OperationalFeeMultiplier = ConstU8<5>; } diff --git a/frame/transaction-payment/src/lib.rs b/frame/transaction-payment/src/lib.rs index 37fecf20cc528..4ec4fe901ffef 100644 --- a/frame/transaction-payment/src/lib.rs +++ b/frame/transaction-payment/src/lib.rs @@ -260,10 +260,6 @@ pub mod pallet { /// might be refunded. In the end the fees can be deposited. type OnChargeTransaction: OnChargeTransaction; - /// The fee to be paid for making a transaction; the per-byte portion. - #[pallet::constant] - type TransactionByteFee: Get>; - /// A fee mulitplier for `Operational` extrinsics to compute "virtual tip" to boost their /// `priority` /// @@ -291,6 +287,9 @@ pub mod pallet { /// Convert a weight value into a deductible fee based on the currency type. type WeightToFee: WeightToFeePolynomial>; + /// Convert a length value into a deductible fee based on the currency type. + type LengthToFee: WeightToFeePolynomial>; + /// Update the multiplier of the next block, based on the previous block's weight. type FeeMultiplierUpdate: MultiplierUpdate; } @@ -302,6 +301,12 @@ pub mod pallet { fn weight_to_fee_polynomial() -> Vec>> { T::WeightToFee::polynomial().to_vec() } + + /// The polynomial that is applied in order to derive fee from length. + #[pallet::constant_name(LengthToFee)] + fn length_to_fee_polynomial() -> Vec>> { + T::LengthToFee::polynomial().to_vec() + } } #[pallet::type_value] @@ -510,25 +515,18 @@ where class: DispatchClass, ) -> FeeDetails> { if pays_fee == Pays::Yes { - let len = >::from(len); - let per_byte = T::TransactionByteFee::get(); - - // length fee. this is not adjusted. - let fixed_len_fee = per_byte.saturating_mul(len); - // the adjustable part of the fee. let unadjusted_weight_fee = Self::weight_to_fee(weight); let multiplier = Self::next_fee_multiplier(); // final adjusted weight fee. let adjusted_weight_fee = multiplier.saturating_mul_int(unadjusted_weight_fee); + // length fee. this is adjusted via `LengthToFee`. + let len_fee = Self::length_to_fee(len); + let base_fee = Self::weight_to_fee(T::BlockWeights::get().get(class).base_extrinsic); FeeDetails { - inclusion_fee: Some(InclusionFee { - base_fee, - len_fee: fixed_len_fee, - adjusted_weight_fee, - }), + inclusion_fee: Some(InclusionFee { base_fee, len_fee, adjusted_weight_fee }), tip, } } else { @@ -536,6 +534,10 @@ where } } + fn length_to_fee(length: u32) -> BalanceOf { + T::LengthToFee::calc(&(length as Weight)) + } + fn weight_to_fee(weight: Weight) -> BalanceOf { // cap the weight to the maximum defined in runtime, otherwise it will be the // `Bounded` maximum of its data type, which is not desired. @@ -835,8 +837,8 @@ mod tests { } parameter_types! { - pub static TransactionByteFee: u64 = 1; pub static WeightToFee: u64 = 1; + pub static TransactionByteFee: u64 = 1; pub static OperationalFeeMultiplier: u8 = 5; } @@ -892,6 +894,19 @@ mod tests { } } + impl WeightToFeePolynomial for TransactionByteFee { + type Balance = u64; + + fn polynomial() -> WeightToFeeCoefficients { + smallvec![WeightToFeeCoefficient { + degree: 1, + coeff_frac: Perbill::zero(), + coeff_integer: TRANSACTION_BYTE_FEE.with(|v| *v.borrow()), + negative: false, + }] + } + } + thread_local! { static TIP_UNBALANCED_AMOUNT: RefCell = RefCell::new(0); static FEE_UNBALANCED_AMOUNT: RefCell = RefCell::new(0); @@ -913,9 +928,9 @@ mod tests { impl Config for Runtime { type OnChargeTransaction = CurrencyAdapter; - type TransactionByteFee = TransactionByteFee; type OperationalFeeMultiplier = OperationalFeeMultiplier; type WeightToFee = WeightToFee; + type LengthToFee = TransactionByteFee; type FeeMultiplierUpdate = (); } diff --git a/frame/transaction-payment/src/payment.rs b/frame/transaction-payment/src/payment.rs index 58e6ef63109a3..5b4a613102792 100644 --- a/frame/transaction-payment/src/payment.rs +++ b/frame/transaction-payment/src/payment.rs @@ -12,7 +12,7 @@ use sp_runtime::{ use sp_std::{fmt::Debug, marker::PhantomData}; use frame_support::{ - traits::{Currency, ExistenceRequirement, Get, Imbalance, OnUnbalanced, WithdrawReasons}, + traits::{Currency, ExistenceRequirement, Imbalance, OnUnbalanced, WithdrawReasons}, unsigned::TransactionValidityError, }; @@ -73,7 +73,6 @@ pub struct CurrencyAdapter(PhantomData<(C, OU)>); impl OnChargeTransaction for CurrencyAdapter where T: Config, - T::TransactionByteFee: Get<::AccountId>>::Balance>, C: Currency<::AccountId>, C::PositiveImbalance: Imbalance< ::AccountId>>::Balance,