mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-13 09:21:05 +00:00
Allow fee calculation to happen off-chain (#6076)
* Emit a PaymentParameters event once per block This contains per-block paramaters need to calculate fees off-chain. * Add WeightToFee trait * Add documentation to polynomial types * Ignore pseudo code snippet for doc tests * Use `Mul` implementation of Perbill * Add tests for WeightToFeePolynomial * Revert "Emit a PaymentParameters event once per block" This reverts commit 6c4763baff3d8179676a3c1660fe7063fd56a8ca. Co-authored-by: Gavin Wood <gavin@parity.io>
This commit is contained in:
committed by
GitHub
parent
e04f237152
commit
9dd21b1eed
Generated
+24
-22
@@ -749,7 +749,7 @@ dependencies = [
|
||||
"log",
|
||||
"regalloc",
|
||||
"serde",
|
||||
"smallvec 1.3.0",
|
||||
"smallvec 1.4.0",
|
||||
"target-lexicon",
|
||||
"thiserror",
|
||||
]
|
||||
@@ -787,7 +787,7 @@ checksum = "e45f82e3446dd1ebb8c2c2f6a6b0e6cd6cd52965c7e5f7b1b35e9a9ace31ccde"
|
||||
dependencies = [
|
||||
"cranelift-codegen",
|
||||
"log",
|
||||
"smallvec 1.3.0",
|
||||
"smallvec 1.4.0",
|
||||
"target-lexicon",
|
||||
]
|
||||
|
||||
@@ -1488,6 +1488,7 @@ dependencies = [
|
||||
"paste",
|
||||
"pretty_assertions",
|
||||
"serde",
|
||||
"smallvec 1.4.0",
|
||||
"sp-arithmetic",
|
||||
"sp-core",
|
||||
"sp-inherents",
|
||||
@@ -1875,7 +1876,7 @@ dependencies = [
|
||||
"byteorder 1.3.4",
|
||||
"fallible-iterator",
|
||||
"indexmap",
|
||||
"smallvec 1.3.0",
|
||||
"smallvec 1.4.0",
|
||||
"stable_deref_trait",
|
||||
]
|
||||
|
||||
@@ -2495,7 +2496,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e763b2a9b500ba47948061d1e8bc3b5f03a8a1f067dbcf822a4d2c84d2b54a3a"
|
||||
dependencies = [
|
||||
"parity-util-mem",
|
||||
"smallvec 1.3.0",
|
||||
"smallvec 1.4.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2524,7 +2525,7 @@ dependencies = [
|
||||
"parking_lot 0.10.2",
|
||||
"regex",
|
||||
"rocksdb",
|
||||
"smallvec 1.3.0",
|
||||
"smallvec 1.4.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2630,7 +2631,7 @@ dependencies = [
|
||||
"parity-multiaddr 0.9.0",
|
||||
"parking_lot 0.10.2",
|
||||
"pin-project",
|
||||
"smallvec 1.3.0",
|
||||
"smallvec 1.4.0",
|
||||
"wasm-timer",
|
||||
]
|
||||
|
||||
@@ -2661,7 +2662,7 @@ dependencies = [
|
||||
"ring",
|
||||
"rw-stream-sink",
|
||||
"sha2",
|
||||
"smallvec 1.3.0",
|
||||
"smallvec 1.4.0",
|
||||
"thiserror",
|
||||
"unsigned-varint",
|
||||
"void",
|
||||
@@ -2714,7 +2715,7 @@ dependencies = [
|
||||
"prost",
|
||||
"prost-build",
|
||||
"rand 0.7.3",
|
||||
"smallvec 1.3.0",
|
||||
"smallvec 1.4.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2737,7 +2738,7 @@ dependencies = [
|
||||
"prost-build",
|
||||
"rand 0.7.3",
|
||||
"sha2",
|
||||
"smallvec 1.3.0",
|
||||
"smallvec 1.4.0",
|
||||
"unsigned-varint",
|
||||
"wasm-timer",
|
||||
]
|
||||
@@ -2754,7 +2755,7 @@ dependencies = [
|
||||
"log",
|
||||
"prost",
|
||||
"prost-build",
|
||||
"smallvec 1.3.0",
|
||||
"smallvec 1.4.0",
|
||||
"wasm-timer",
|
||||
]
|
||||
|
||||
@@ -2778,7 +2779,7 @@ dependencies = [
|
||||
"prost-build",
|
||||
"rand 0.7.3",
|
||||
"sha2",
|
||||
"smallvec 1.3.0",
|
||||
"smallvec 1.4.0",
|
||||
"uint",
|
||||
"unsigned-varint",
|
||||
"void",
|
||||
@@ -2802,7 +2803,7 @@ dependencies = [
|
||||
"log",
|
||||
"net2",
|
||||
"rand 0.7.3",
|
||||
"smallvec 1.3.0",
|
||||
"smallvec 1.4.0",
|
||||
"void",
|
||||
"wasm-timer",
|
||||
]
|
||||
@@ -2931,7 +2932,7 @@ dependencies = [
|
||||
"libp2p-core",
|
||||
"log",
|
||||
"rand 0.7.3",
|
||||
"smallvec 1.3.0",
|
||||
"smallvec 1.4.0",
|
||||
"void",
|
||||
"wasm-timer",
|
||||
]
|
||||
@@ -3299,7 +3300,7 @@ dependencies = [
|
||||
"futures 0.3.4",
|
||||
"log",
|
||||
"pin-project",
|
||||
"smallvec 1.3.0",
|
||||
"smallvec 1.4.0",
|
||||
"unsigned-varint",
|
||||
]
|
||||
|
||||
@@ -4652,6 +4653,7 @@ dependencies = [
|
||||
"pallet-balances",
|
||||
"pallet-transaction-payment-rpc-runtime-api",
|
||||
"parity-scale-codec",
|
||||
"smallvec 1.4.0",
|
||||
"sp-core",
|
||||
"sp-io",
|
||||
"sp-runtime",
|
||||
@@ -4847,7 +4849,7 @@ dependencies = [
|
||||
"parity-util-mem-derive",
|
||||
"parking_lot 0.10.2",
|
||||
"primitive-types",
|
||||
"smallvec 1.3.0",
|
||||
"smallvec 1.4.0",
|
||||
"winapi 0.3.8",
|
||||
]
|
||||
|
||||
@@ -4923,7 +4925,7 @@ dependencies = [
|
||||
"cloudabi",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"smallvec 1.3.0",
|
||||
"smallvec 1.4.0",
|
||||
"winapi 0.3.8",
|
||||
]
|
||||
|
||||
@@ -5614,7 +5616,7 @@ checksum = "b27b256b41986ac5141b37b8bbba85d314fbf546c182eb255af6720e07e4f804"
|
||||
dependencies = [
|
||||
"log",
|
||||
"rustc-hash",
|
||||
"smallvec 1.3.0",
|
||||
"smallvec 1.4.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -7198,9 +7200,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.3.0"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05720e22615919e4734f6a99ceae50d00226c3c5aca406e102ebc33298214e0a"
|
||||
checksum = "c7cb5678e1615754284ec264d9bb5b4c27d2018577fd90ac0ceb578591ed5ee4"
|
||||
|
||||
[[package]]
|
||||
name = "snow"
|
||||
@@ -7247,7 +7249,7 @@ dependencies = [
|
||||
"log",
|
||||
"rand 0.7.3",
|
||||
"sha1",
|
||||
"smallvec 1.3.0",
|
||||
"smallvec 1.4.0",
|
||||
"static_assertions",
|
||||
"thiserror",
|
||||
]
|
||||
@@ -8973,7 +8975,7 @@ dependencies = [
|
||||
"hashbrown",
|
||||
"log",
|
||||
"rustc-hex",
|
||||
"smallvec 1.3.0",
|
||||
"smallvec 1.4.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -9077,7 +9079,7 @@ version = "0.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5479532badd04e128284890390c1e876ef7a993d0570b3597ae43dfa1d59afa4"
|
||||
dependencies = [
|
||||
"smallvec 1.3.0",
|
||||
"smallvec 1.4.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@@ -15,8 +15,7 @@ use sp_runtime::{
|
||||
transaction_validity::{TransactionValidity, TransactionSource},
|
||||
};
|
||||
use sp_runtime::traits::{
|
||||
BlakeTwo256, Block as BlockT, IdentityLookup, Verify, ConvertInto, IdentifyAccount, NumberFor,
|
||||
Saturating,
|
||||
BlakeTwo256, Block as BlockT, IdentityLookup, Verify, IdentifyAccount, NumberFor, Saturating,
|
||||
};
|
||||
use sp_api::impl_runtime_apis;
|
||||
use sp_consensus_aura::sr25519::AuthorityId as AuraId;
|
||||
@@ -36,7 +35,7 @@ pub use frame_support::{
|
||||
construct_runtime, parameter_types, StorageValue,
|
||||
traits::{KeyOwnerProofSystem, Randomness},
|
||||
weights::{
|
||||
Weight,
|
||||
Weight, IdentityFee,
|
||||
constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},
|
||||
},
|
||||
};
|
||||
@@ -244,7 +243,7 @@ impl transaction_payment::Trait for Runtime {
|
||||
type Currency = balances::Module<Runtime>;
|
||||
type OnTransactionPayment = ();
|
||||
type TransactionByteFee = TransactionByteFee;
|
||||
type WeightToFee = ConvertInto;
|
||||
type WeightToFee = IdentityFee<Balance>;
|
||||
type FeeMultiplierUpdate = ();
|
||||
}
|
||||
|
||||
|
||||
@@ -19,12 +19,15 @@ use codec::{Encode, Decode, Joiner};
|
||||
use frame_support::{
|
||||
StorageValue, StorageMap,
|
||||
traits::Currency,
|
||||
weights::{GetDispatchInfo, DispatchInfo, DispatchClass, constants::ExtrinsicBaseWeight},
|
||||
weights::{
|
||||
GetDispatchInfo, DispatchInfo, DispatchClass, constants::ExtrinsicBaseWeight,
|
||||
WeightToFeePolynomial,
|
||||
},
|
||||
};
|
||||
use sp_core::{NeverNativeValue, traits::Externalities, storage::well_known_keys};
|
||||
use sp_runtime::{
|
||||
ApplyExtrinsicResult, Fixed128,
|
||||
traits::{Hash as HashT, Convert},
|
||||
traits::Hash as HashT,
|
||||
transaction_validity::InvalidTransaction,
|
||||
};
|
||||
use pallet_contracts::ContractAddressFor;
|
||||
@@ -54,9 +57,9 @@ fn transfer_fee<E: Encode>(extrinsic: &E, fee_multiplier: Fixed128) -> Balance {
|
||||
let length_fee = TransactionByteFee::get() * (extrinsic.encode().len() as Balance);
|
||||
|
||||
let base_weight = ExtrinsicBaseWeight::get();
|
||||
let base_fee = <Runtime as pallet_transaction_payment::Trait>::WeightToFee::convert(base_weight);
|
||||
let base_fee = <Runtime as pallet_transaction_payment::Trait>::WeightToFee::calc(&base_weight);
|
||||
let weight = default_transfer_call().get_dispatch_info().weight;
|
||||
let weight_fee = <Runtime as pallet_transaction_payment::Trait>::WeightToFee::convert(weight);
|
||||
let weight_fee = <Runtime as pallet_transaction_payment::Trait>::WeightToFee::calc(&weight);
|
||||
|
||||
base_fee + fee_multiplier.saturated_multiply_accumulate(length_fee + weight_fee)
|
||||
}
|
||||
|
||||
@@ -19,16 +19,15 @@ use codec::{Encode, Joiner};
|
||||
use frame_support::{
|
||||
StorageValue, StorageMap,
|
||||
traits::Currency,
|
||||
weights::{GetDispatchInfo, constants::ExtrinsicBaseWeight},
|
||||
weights::{GetDispatchInfo, constants::ExtrinsicBaseWeight, IdentityFee, WeightToFeePolynomial},
|
||||
};
|
||||
use sp_core::NeverNativeValue;
|
||||
use sp_runtime::{Fixed128, Perbill, traits::Convert};
|
||||
use sp_runtime::{Fixed128, Perbill};
|
||||
use node_runtime::{
|
||||
CheckedExtrinsic, Call, Runtime, Balances, TransactionPayment,
|
||||
TransactionByteFee, WeightFeeCoefficient,
|
||||
TransactionByteFee,
|
||||
constants::currency::*,
|
||||
};
|
||||
use node_runtime::impls::LinearWeightToFee;
|
||||
use node_primitives::Balance;
|
||||
use node_testing::keyring::*;
|
||||
|
||||
@@ -181,13 +180,13 @@ fn transaction_fee_is_correct_ultimate() {
|
||||
let mut balance_alice = (100 - 69) * DOLLARS;
|
||||
|
||||
let base_weight = ExtrinsicBaseWeight::get();
|
||||
let base_fee = LinearWeightToFee::<WeightFeeCoefficient>::convert(base_weight);
|
||||
let base_fee = IdentityFee::<Balance>::calc(&base_weight);
|
||||
|
||||
let length_fee = TransactionByteFee::get() * (xt.clone().encode().len() as Balance);
|
||||
balance_alice -= length_fee;
|
||||
|
||||
let weight = default_transfer_call().get_dispatch_info().weight;
|
||||
let weight_fee = LinearWeightToFee::<WeightFeeCoefficient>::convert(weight);
|
||||
let weight_fee = IdentityFee::<Balance>::calc(&weight);
|
||||
|
||||
// we know that weight to fee multiplier is effect-less in block 1.
|
||||
// current weight of transfer = 200_000_000
|
||||
|
||||
@@ -21,7 +21,9 @@ use core::num::NonZeroI128;
|
||||
use node_primitives::Balance;
|
||||
use sp_runtime::traits::{Convert, Saturating};
|
||||
use sp_runtime::{Fixed128, Perquintill};
|
||||
use frame_support::{traits::{OnUnbalanced, Currency, Get}, weights::Weight};
|
||||
use frame_support::{
|
||||
traits::{OnUnbalanced, Currency, Get},
|
||||
};
|
||||
use crate::{Balances, System, Authorship, MaximumBlockWeight, NegativeImbalance};
|
||||
|
||||
pub struct Author;
|
||||
@@ -47,18 +49,6 @@ impl Convert<u128, Balance> for CurrencyToVoteHandler {
|
||||
fn convert(x: u128) -> Balance { x * Self::factor() }
|
||||
}
|
||||
|
||||
/// Convert from weight to balance via a simple coefficient multiplication
|
||||
/// The associated type C encapsulates a constant in units of balance per weight
|
||||
pub struct LinearWeightToFee<C>(sp_std::marker::PhantomData<C>);
|
||||
|
||||
impl<C: Get<Balance>> Convert<Weight, Balance> for LinearWeightToFee<C> {
|
||||
fn convert(w: Weight) -> Balance {
|
||||
// setting this to zero will disable the weight fee.
|
||||
let coefficient = C::get();
|
||||
Balance::from(w).saturating_mul(coefficient)
|
||||
}
|
||||
}
|
||||
|
||||
/// Update the given multiplier based on the following formula
|
||||
///
|
||||
/// diff = (previous_block_weight - target_weight)/max_weight
|
||||
@@ -120,7 +110,7 @@ mod tests {
|
||||
use sp_runtime::assert_eq_error_rate;
|
||||
use crate::{MaximumBlockWeight, AvailableBlockRatio, Runtime};
|
||||
use crate::{constants::currency::*, TransactionPayment, TargetBlockFullness};
|
||||
use frame_support::weights::Weight;
|
||||
use frame_support::weights::{Weight, WeightToFeePolynomial};
|
||||
use core::num::NonZeroI128;
|
||||
|
||||
fn max() -> Weight {
|
||||
@@ -228,7 +218,8 @@ mod tests {
|
||||
if fm == next { panic!("The fee should ever increase"); }
|
||||
fm = next;
|
||||
iterations += 1;
|
||||
let fee = <Runtime as pallet_transaction_payment::Trait>::WeightToFee::convert(tx_weight);
|
||||
let fee =
|
||||
<Runtime as pallet_transaction_payment::Trait>::WeightToFee::calc(&tx_weight);
|
||||
let adjusted_fee = fm.saturated_multiply_accumulate(fee);
|
||||
println!(
|
||||
"iteration {}, new fm = {:?}. Fee at this point is: {} units / {} millicents, \
|
||||
|
||||
@@ -26,7 +26,7 @@ use sp_std::prelude::*;
|
||||
use frame_support::{
|
||||
construct_runtime, parameter_types, debug,
|
||||
weights::{
|
||||
Weight,
|
||||
Weight, IdentityFee,
|
||||
constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},
|
||||
},
|
||||
traits::{Currency, Imbalance, KeyOwnerProofSystem, OnUnbalanced, Randomness, LockIdentifier},
|
||||
@@ -74,7 +74,7 @@ pub use pallet_staking::StakerStatus;
|
||||
|
||||
/// Implementations of some helper traits passed into runtime modules as associated types.
|
||||
pub mod impls;
|
||||
use impls::{CurrencyToVoteHandler, Author, LinearWeightToFee, TargetedFeeAdjustment};
|
||||
use impls::{CurrencyToVoteHandler, Author, TargetedFeeAdjustment};
|
||||
|
||||
/// Constant values used within the runtime.
|
||||
pub mod constants;
|
||||
@@ -228,9 +228,6 @@ impl pallet_balances::Trait for Runtime {
|
||||
|
||||
parameter_types! {
|
||||
pub const TransactionByteFee: Balance = 10 * MILLICENTS;
|
||||
// In the Substrate node, a weight of 10_000_000 (smallest non-zero weight)
|
||||
// is mapped to 10_000_000 units of fees, hence:
|
||||
pub const WeightFeeCoefficient: Balance = 1;
|
||||
// for a sane configuration, this should always be less than `AvailableBlockRatio`.
|
||||
pub const TargetBlockFullness: Perquintill = Perquintill::from_percent(25);
|
||||
}
|
||||
@@ -239,7 +236,9 @@ impl pallet_transaction_payment::Trait for Runtime {
|
||||
type Currency = Balances;
|
||||
type OnTransactionPayment = DealWithFees;
|
||||
type TransactionByteFee = TransactionByteFee;
|
||||
type WeightToFee = LinearWeightToFee<WeightFeeCoefficient>;
|
||||
// In the Substrate node, a weight of 10_000_000 (smallest non-zero weight)
|
||||
// is mapped to 10_000_000 units of fees, hence:
|
||||
type WeightToFee = IdentityFee<Balance>;
|
||||
type FeeMultiplierUpdate = TargetedFeeAdjustment<TargetBlockFullness>;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,14 +21,14 @@
|
||||
|
||||
use sp_runtime::{
|
||||
Perbill,
|
||||
traits::{ConvertInto, IdentityLookup},
|
||||
traits::IdentityLookup,
|
||||
testing::Header,
|
||||
};
|
||||
use sp_core::H256;
|
||||
use sp_io;
|
||||
use frame_support::{impl_outer_origin, parameter_types};
|
||||
use frame_support::traits::Get;
|
||||
use frame_support::weights::{Weight, DispatchInfo};
|
||||
use frame_support::weights::{Weight, DispatchInfo, IdentityFee};
|
||||
use std::cell::RefCell;
|
||||
use crate::{GenesisConfig, Module, Trait, decl_tests, tests::CallWithDispatchInfo};
|
||||
|
||||
@@ -87,7 +87,7 @@ impl pallet_transaction_payment::Trait for Test {
|
||||
type Currency = Module<Test>;
|
||||
type OnTransactionPayment = ();
|
||||
type TransactionByteFee = TransactionByteFee;
|
||||
type WeightToFee = ConvertInto;
|
||||
type WeightToFee = IdentityFee<u64>;
|
||||
type FeeMultiplierUpdate = ();
|
||||
}
|
||||
impl Trait for Test {
|
||||
|
||||
@@ -21,14 +21,14 @@
|
||||
|
||||
use sp_runtime::{
|
||||
Perbill,
|
||||
traits::{ConvertInto, IdentityLookup},
|
||||
traits::IdentityLookup,
|
||||
testing::Header,
|
||||
};
|
||||
use sp_core::H256;
|
||||
use sp_io;
|
||||
use frame_support::{impl_outer_origin, parameter_types};
|
||||
use frame_support::traits::{Get, StorageMapShim};
|
||||
use frame_support::weights::{Weight, DispatchInfo};
|
||||
use frame_support::weights::{Weight, DispatchInfo, IdentityFee};
|
||||
use std::cell::RefCell;
|
||||
use crate::{GenesisConfig, Module, Trait, decl_tests, tests::CallWithDispatchInfo};
|
||||
|
||||
@@ -87,7 +87,7 @@ impl pallet_transaction_payment::Trait for Test {
|
||||
type Currency = Module<Test>;
|
||||
type OnTransactionPayment = ();
|
||||
type TransactionByteFee = TransactionByteFee;
|
||||
type WeightToFee = ConvertInto;
|
||||
type WeightToFee = IdentityFee<u64>;
|
||||
type FeeMultiplierUpdate = ();
|
||||
}
|
||||
impl Trait for Test {
|
||||
|
||||
@@ -37,7 +37,7 @@ use frame_support::{
|
||||
assert_ok, assert_err, assert_err_ignore_postinfo, impl_outer_dispatch, impl_outer_event,
|
||||
impl_outer_origin, parameter_types,
|
||||
storage::child, StorageMap, StorageValue, traits::{Currency, Get},
|
||||
weights::{DispatchInfo, DispatchClass, Weight, PostDispatchInfo, Pays},
|
||||
weights::{DispatchInfo, DispatchClass, Weight, PostDispatchInfo, Pays, IdentityFee},
|
||||
};
|
||||
use std::{cell::RefCell, sync::atomic::{AtomicUsize, Ordering}};
|
||||
use sp_core::storage::well_known_keys;
|
||||
@@ -152,7 +152,7 @@ impl pallet_transaction_payment::Trait for Test {
|
||||
type Currency = Balances;
|
||||
type OnTransactionPayment = ();
|
||||
type TransactionByteFee = TransactionByteFee;
|
||||
type WeightToFee = Test;
|
||||
type WeightToFee = IdentityFee<BalanceOf<Self>>;
|
||||
type FeeMultiplierUpdate = ();
|
||||
}
|
||||
|
||||
|
||||
@@ -454,12 +454,12 @@ mod tests {
|
||||
use sp_core::H256;
|
||||
use sp_runtime::{
|
||||
generic::Era, Perbill, DispatchError, testing::{Digest, Header, Block},
|
||||
traits::{Header as HeaderT, BlakeTwo256, IdentityLookup, Convert, ConvertInto},
|
||||
traits::{Header as HeaderT, BlakeTwo256, IdentityLookup},
|
||||
transaction_validity::{InvalidTransaction, UnknownTransaction, TransactionValidityError},
|
||||
};
|
||||
use frame_support::{
|
||||
impl_outer_event, impl_outer_origin, parameter_types, impl_outer_dispatch,
|
||||
weights::{Weight, RuntimeDbWeight},
|
||||
weights::{Weight, RuntimeDbWeight, IdentityFee, WeightToFeePolynomial},
|
||||
traits::{Currency, LockIdentifier, LockableCurrency, WithdrawReasons, WithdrawReason},
|
||||
};
|
||||
use frame_system::{self as system, Call as SystemCall, ChainContext, LastRuntimeUpgradeInfo};
|
||||
@@ -589,7 +589,7 @@ mod tests {
|
||||
type Currency = Balances;
|
||||
type OnTransactionPayment = ();
|
||||
type TransactionByteFee = TransactionByteFee;
|
||||
type WeightToFee = ConvertInto;
|
||||
type WeightToFee = IdentityFee<Balance>;
|
||||
type FeeMultiplierUpdate = ();
|
||||
}
|
||||
impl custom::Trait for Runtime {}
|
||||
@@ -675,7 +675,8 @@ mod tests {
|
||||
}.assimilate_storage(&mut t).unwrap();
|
||||
let xt = TestXt::new(Call::Balances(BalancesCall::transfer(2, 69)), sign_extra(1, 0, 0));
|
||||
let weight = xt.get_dispatch_info().weight + <Runtime as frame_system::Trait>::ExtrinsicBaseWeight::get();
|
||||
let fee: Balance = <Runtime as pallet_transaction_payment::Trait>::WeightToFee::convert(weight);
|
||||
let fee: Balance
|
||||
= <Runtime as pallet_transaction_payment::Trait>::WeightToFee::calc(&weight);
|
||||
let mut t = sp_io::TestExternalities::new(t);
|
||||
t.execute_with(|| {
|
||||
Executive::initialize_block(&Header::new(
|
||||
@@ -871,7 +872,8 @@ mod tests {
|
||||
);
|
||||
let weight = xt.get_dispatch_info().weight
|
||||
+ <Runtime as frame_system::Trait>::ExtrinsicBaseWeight::get();
|
||||
let fee: Balance = <Runtime as pallet_transaction_payment::Trait>::WeightToFee::convert(weight);
|
||||
let fee: Balance =
|
||||
<Runtime as pallet_transaction_payment::Trait>::WeightToFee::calc(&weight);
|
||||
Executive::initialize_block(&Header::new(
|
||||
1,
|
||||
H256::default(),
|
||||
|
||||
@@ -29,6 +29,7 @@ once_cell = { version = "1", default-features = false, optional = true }
|
||||
sp-state-machine = { version = "0.8.0-dev", optional = true, path = "../../primitives/state-machine" }
|
||||
bitmask = { version = "0.5.0", default-features = false }
|
||||
impl-trait-for-tuples = "0.1.3"
|
||||
smallvec = "1.4.0"
|
||||
|
||||
[dev-dependencies]
|
||||
pretty_assertions = "0.6.1"
|
||||
|
||||
@@ -135,6 +135,9 @@ use sp_runtime::{
|
||||
generic::{CheckedExtrinsic, UncheckedExtrinsic},
|
||||
};
|
||||
use crate::dispatch::{DispatchErrorWithPostInfo, DispatchResultWithPostInfo, DispatchError};
|
||||
use sp_runtime::traits::SaturatedConversion;
|
||||
use sp_arithmetic::{Perbill, traits::{BaseArithmetic, Saturating}};
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
|
||||
/// Re-export priority as type
|
||||
pub use sp_runtime::transaction_validity::TransactionPriority;
|
||||
@@ -530,6 +533,90 @@ impl RuntimeDbWeight {
|
||||
}
|
||||
}
|
||||
|
||||
/// One coefficient and its position in the `WeightToFeePolynomial`.
|
||||
///
|
||||
/// One term of polynomial is calculated as:
|
||||
///
|
||||
/// ```ignore
|
||||
/// coeff_integer * x^(degree) + coeff_frac * x^(degree)
|
||||
/// ```
|
||||
///
|
||||
/// The `negative` value encodes whether the term is added or substracted from the
|
||||
/// overall polynomial result.
|
||||
#[derive(Clone, Encode, Decode)]
|
||||
pub struct WeightToFeeCoefficient<Balance> {
|
||||
/// The integral part of the coefficient.
|
||||
pub coeff_integer: Balance,
|
||||
/// The fractional part of the coefficient.
|
||||
pub coeff_frac: Perbill,
|
||||
/// True iff the coefficient should be interpreted as negative.
|
||||
pub negative: bool,
|
||||
/// Degree/exponent of the term.
|
||||
pub degree: u8,
|
||||
}
|
||||
|
||||
/// A list of coefficients that represent one polynomial.
|
||||
pub type WeightToFeeCoefficients<T> = SmallVec<[WeightToFeeCoefficient<T>; 4]>;
|
||||
|
||||
/// A trait that describes the weight to fee calculation as polynomial.
|
||||
///
|
||||
/// An implementor should only implement the `polynomial` function.
|
||||
pub trait WeightToFeePolynomial {
|
||||
/// The type that is returned as result from polynomial evaluation.
|
||||
type Balance: BaseArithmetic + From<u32> + Copy;
|
||||
|
||||
/// Returns a polynomial that describes the weight to fee conversion.
|
||||
///
|
||||
/// This is the only function that should be manually implemented. Please note
|
||||
/// that all calculation is done in the probably unsigned `Balance` type. This means
|
||||
/// that the order of coefficients is important as putting the negative coefficients
|
||||
/// first will most likely saturate the result to zero mid evaluation.
|
||||
fn polynomial() -> WeightToFeeCoefficients<Self::Balance>;
|
||||
|
||||
/// Calculates the fee from the passed `weight` according to the `polynomial`.
|
||||
///
|
||||
/// This should not be overriden in most circumstances. Calculation is done in the
|
||||
/// `Balance` type and never overflows. All evaluation is saturating.
|
||||
fn calc(weight: &Weight) -> Self::Balance {
|
||||
Self::polynomial().iter().fold(Self::Balance::saturated_from(0u32), |mut acc, args| {
|
||||
let w = Self::Balance::saturated_from(*weight).saturating_pow(args.degree.into());
|
||||
|
||||
// The sum could get negative. Therefore we only sum with the accumulator.
|
||||
// The Perbill Mul implementation is non overflowing.
|
||||
let frac = args.coeff_frac * w;
|
||||
let integer = args.coeff_integer.saturating_mul(w);
|
||||
|
||||
if args.negative {
|
||||
acc = acc.saturating_sub(frac);
|
||||
acc = acc.saturating_sub(integer);
|
||||
} else {
|
||||
acc = acc.saturating_add(frac);
|
||||
acc = acc.saturating_add(integer);
|
||||
}
|
||||
|
||||
acc
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Implementor of `WeightToFeePolynomial` that maps one unit of weight to one unit of fee.
|
||||
pub struct IdentityFee<T>(sp_std::marker::PhantomData<T>);
|
||||
|
||||
impl<T> WeightToFeePolynomial for IdentityFee<T> where
|
||||
T: BaseArithmetic + From<u32> + Copy
|
||||
{
|
||||
type Balance = T;
|
||||
|
||||
fn polynomial() -> WeightToFeeCoefficients<Self::Balance> {
|
||||
smallvec!(WeightToFeeCoefficient {
|
||||
coeff_integer: 1u32.into(),
|
||||
coeff_frac: Perbill::zero(),
|
||||
negative: false,
|
||||
degree: 1,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(dead_code)]
|
||||
mod tests {
|
||||
@@ -651,4 +738,64 @@ mod tests {
|
||||
1000
|
||||
);
|
||||
}
|
||||
|
||||
type Balance = u64;
|
||||
|
||||
// 0.5x^3 + 2.333x2 + 7x - 10_000
|
||||
struct Poly;
|
||||
impl WeightToFeePolynomial for Poly {
|
||||
type Balance = Balance;
|
||||
|
||||
fn polynomial() -> WeightToFeeCoefficients<Self::Balance> {
|
||||
smallvec![
|
||||
WeightToFeeCoefficient {
|
||||
coeff_integer: 0,
|
||||
coeff_frac: Perbill::from_fraction(0.5),
|
||||
negative: false,
|
||||
degree: 3
|
||||
},
|
||||
WeightToFeeCoefficient {
|
||||
coeff_integer: 2,
|
||||
coeff_frac: Perbill::from_rational_approximation(1u32, 3u32),
|
||||
negative: false,
|
||||
degree: 2
|
||||
},
|
||||
WeightToFeeCoefficient {
|
||||
coeff_integer: 7,
|
||||
coeff_frac: Perbill::zero(),
|
||||
negative: false,
|
||||
degree: 1
|
||||
},
|
||||
WeightToFeeCoefficient {
|
||||
coeff_integer: 10_000,
|
||||
coeff_frac: Perbill::zero(),
|
||||
negative: true,
|
||||
degree: 0
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn polynomial_works() {
|
||||
assert_eq!(Poly::calc(&100), 514033);
|
||||
assert_eq!(Poly::calc(&10_123), 518917034928);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn polynomial_does_not_underflow() {
|
||||
assert_eq!(Poly::calc(&0), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn polynomial_does_not_overflow() {
|
||||
assert_eq!(Poly::calc(&Weight::max_value()), Balance::max_value() - 10_000);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn identity_fee_works() {
|
||||
assert_eq!(IdentityFee::<Balance>::calc(&0), 0);
|
||||
assert_eq!(IdentityFee::<Balance>::calc(&50), 50);
|
||||
assert_eq!(IdentityFee::<Balance>::calc(&Weight::max_value()), Balance::max_value());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ sp-runtime = { version = "2.0.0-dev", default-features = false, path = "../../pr
|
||||
frame-support = { version = "2.0.0-dev", default-features = false, path = "../support" }
|
||||
frame-system = { version = "2.0.0-dev", default-features = false, path = "../system" }
|
||||
pallet-transaction-payment-rpc-runtime-api = { version = "2.0.0-dev", default-features = false, path = "./rpc/runtime-api" }
|
||||
smallvec = "1.4.0"
|
||||
|
||||
[dev-dependencies]
|
||||
sp-io = { version = "2.0.0-dev", path = "../../primitives/io" }
|
||||
|
||||
@@ -37,7 +37,10 @@ use codec::{Encode, Decode};
|
||||
use frame_support::{
|
||||
decl_storage, decl_module,
|
||||
traits::{Currency, Get, OnUnbalanced, ExistenceRequirement, WithdrawReason, Imbalance},
|
||||
weights::{Weight, DispatchInfo, PostDispatchInfo, GetDispatchInfo, Pays},
|
||||
weights::{
|
||||
Weight, DispatchInfo, PostDispatchInfo, GetDispatchInfo, Pays, WeightToFeePolynomial,
|
||||
WeightToFeeCoefficient,
|
||||
},
|
||||
dispatch::DispatchResult,
|
||||
};
|
||||
use sp_runtime::{
|
||||
@@ -72,7 +75,7 @@ pub trait Trait: frame_system::Trait {
|
||||
type TransactionByteFee: Get<BalanceOf<Self>>;
|
||||
|
||||
/// Convert a weight value into a deductible fee based on the currency type.
|
||||
type WeightToFee: Convert<Weight, BalanceOf<Self>>;
|
||||
type WeightToFee: WeightToFeePolynomial<Balance=BalanceOf<Self>>;
|
||||
|
||||
/// Update the multiplier of the next block, based on the previous block's weight.
|
||||
type FeeMultiplierUpdate: Convert<Multiplier, Multiplier>;
|
||||
@@ -89,9 +92,13 @@ decl_module! {
|
||||
/// The fee to be paid for making a transaction; the per-byte portion.
|
||||
const TransactionByteFee: BalanceOf<T> = T::TransactionByteFee::get();
|
||||
|
||||
/// The polynomial that is applied in order to derive fee from weight.
|
||||
const WeightToFee: Vec<WeightToFeeCoefficient<BalanceOf<T>>> =
|
||||
T::WeightToFee::polynomial().to_vec();
|
||||
|
||||
fn on_finalize() {
|
||||
NextFeeMultiplier::mutate(|fm| {
|
||||
*fm = T::FeeMultiplierUpdate::convert(*fm)
|
||||
*fm = T::FeeMultiplierUpdate::convert(*fm);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -183,7 +190,7 @@ impl<T: Trait> Module<T> {
|
||||
// cap the weight to the maximum defined in runtime, otherwise it will be the
|
||||
// `Bounded` maximum of its data type, which is not desired.
|
||||
let capped_weight = weight.min(<T as frame_system::Trait>::MaximumBlockWeight::get());
|
||||
T::WeightToFee::convert(capped_weight)
|
||||
T::WeightToFee::calc(&capped_weight)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -318,7 +325,10 @@ mod tests {
|
||||
use codec::Encode;
|
||||
use frame_support::{
|
||||
impl_outer_dispatch, impl_outer_origin, parameter_types,
|
||||
weights::{DispatchClass, DispatchInfo, PostDispatchInfo, GetDispatchInfo, Weight},
|
||||
weights::{
|
||||
DispatchClass, DispatchInfo, PostDispatchInfo, GetDispatchInfo, Weight,
|
||||
WeightToFeePolynomial, WeightToFeeCoefficients, WeightToFeeCoefficient,
|
||||
},
|
||||
};
|
||||
use pallet_balances::Call as BalancesCall;
|
||||
use pallet_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo;
|
||||
@@ -329,6 +339,7 @@ mod tests {
|
||||
Perbill,
|
||||
};
|
||||
use std::cell::RefCell;
|
||||
use smallvec::smallvec;
|
||||
|
||||
const CALL: &<Runtime as frame_system::Trait>::Call =
|
||||
&Call::Balances(BalancesCall::transfer(2, 69));
|
||||
@@ -411,10 +422,17 @@ mod tests {
|
||||
fn get() -> u64 { TRANSACTION_BYTE_FEE.with(|v| *v.borrow()) }
|
||||
}
|
||||
|
||||
pub struct WeightToFee(u64);
|
||||
impl Convert<Weight, u64> for WeightToFee {
|
||||
fn convert(t: Weight) -> u64 {
|
||||
WEIGHT_TO_FEE.with(|v| *v.borrow() * (t as u64))
|
||||
pub struct WeightToFee;
|
||||
impl WeightToFeePolynomial for WeightToFee {
|
||||
type Balance = u64;
|
||||
|
||||
fn polynomial() -> WeightToFeeCoefficients<Self::Balance> {
|
||||
smallvec![WeightToFeeCoefficient {
|
||||
degree: 1,
|
||||
coeff_frac: Perbill::zero(),
|
||||
coeff_integer: WEIGHT_TO_FEE.with(|v| *v.borrow()),
|
||||
negative: false,
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user