refactor: Transaction-Payment module (#3816)

* Initial draft that compiles

* Extract payment stuff from balances

* Extract multiplier update stuff from system

* Some fixes.

* Update len-fee as well

* some review comments.

* Remove todo

* bump
This commit is contained in:
Kian Paimani
2019-10-17 14:21:32 +02:00
committed by GitHub
parent 1711483fb6
commit 183c188111
59 changed files with 784 additions and 596 deletions
-1
View File
@@ -271,7 +271,6 @@ mod tests {
type AccountId = u64;
type Lookup = IdentityLookup<Self::AccountId>;
type Header = Header;
type WeightMultiplierUpdate = ();
type Event = ();
type BlockHashCount = BlockHashCount;
type MaximumBlockWeight = MaximumBlockWeight;
-1
View File
@@ -54,7 +54,6 @@ impl system::Trait for Test {
type AccountId = u64;
type Lookup = IdentityLookup<Self::AccountId>;
type Header = Header;
type WeightMultiplierUpdate = ();
type Event = ();
type BlockHashCount = BlockHashCount;
type MaximumBlockWeight = MaximumBlockWeight;
@@ -204,7 +204,6 @@ mod tests {
type AccountId = AuthorityId;
type Lookup = IdentityLookup<Self::AccountId>;
type Header = Header;
type WeightMultiplierUpdate = ();
type Event = ();
type BlockHashCount = BlockHashCount;
type MaximumBlockWeight = MaximumBlockWeight;
-1
View File
@@ -442,7 +442,6 @@ mod tests {
type AccountId = u64;
type Lookup = IdentityLookup<Self::AccountId>;
type Header = Header;
type WeightMultiplierUpdate = ();
type Event = ();
type BlockHashCount = BlockHashCount;
type MaximumBlockWeight = MaximumBlockWeight;
-1
View File
@@ -62,7 +62,6 @@ impl system::Trait for Test {
type AccountId = DummyValidatorId;
type Lookup = IdentityLookup<Self::AccountId>;
type Header = Header;
type WeightMultiplierUpdate = ();
type Event = ();
type BlockHashCount = BlockHashCount;
type MaximumBlockWeight = MaximumBlockWeight;
+1
View File
@@ -17,6 +17,7 @@ system = { package = "srml-system", path = "../system", default-features = false
[dev-dependencies]
runtime-io = { package = "sr-io", path = "../../core/sr-io" }
primitives = { package = "substrate-primitives", path = "../../core/primitives" }
transaction-payment = { package = "srml-transaction-payment", path = "../transaction-payment" }
[features]
default = ["std"]
+3 -138
View File
@@ -86,17 +86,6 @@
//!
//! - `vesting_balance` - Get the amount that is currently being vested and cannot be transferred out of this account.
//!
//! ### Signed Extensions
//!
//! The balances module defines the following extensions:
//!
//! - [`TakeFees`]: Consumes fees proportional to the length and weight of the transaction.
//! Additionally, it can contain a single encoded payload as a `tip`. The inclusion priority
//! is increased proportional to the tip.
//!
//! Lookup the runtime aggregator file (e.g. `node/runtime`) to see the full list of signed
//! extensions included in a chain.
//!
//! ## Usage
//!
//! The following examples show how to use the Balances module in your custom module.
@@ -171,15 +160,11 @@ use support::{
dispatch::Result,
};
use sr_primitives::{
transaction_validity::{
TransactionPriority, ValidTransaction, InvalidTransaction, TransactionValidityError,
TransactionValidity,
},
traits::{
Zero, SimpleArithmetic, StaticLookup, Member, CheckedAdd, CheckedSub, MaybeSerializeDebug,
Saturating, Bounded, SignedExtension, SaturatedConversion, Convert,
Saturating, Bounded,
},
weights::{DispatchInfo, SimpleDispatchInfo, Weight},
weights::SimpleDispatchInfo,
};
use system::{IsDeadAccount, OnNewAccount, ensure_signed, ensure_root};
@@ -210,15 +195,6 @@ pub trait Subtrait<I: Instance = DefaultInstance>: system::Trait {
/// The fee required to create an account.
type CreationFee: Get<Self::Balance>;
/// The fee to be paid for making a transaction; the base.
type TransactionBaseFee: Get<Self::Balance>;
/// The fee to be paid for making a transaction; the per-byte portion.
type TransactionByteFee: Get<Self::Balance>;
/// Convert a weight value into a deductible fee based on the currency type.
type WeightToFee: Convert<Weight, Self::Balance>;
}
pub trait Trait<I: Instance = DefaultInstance>: system::Trait {
@@ -235,9 +211,6 @@ pub trait Trait<I: Instance = DefaultInstance>: system::Trait {
/// Handler for when a new account is created.
type OnNewAccount: OnNewAccount<Self::AccountId>;
/// Handler for the unbalanced reduction when taking transaction fees.
type TransactionPayment: OnUnbalanced<NegativeImbalance<Self, I>>;
/// Handler for the unbalanced reduction when taking fees associated with balance
/// transfer (which may also include account creation).
type TransferPayment: OnUnbalanced<NegativeImbalance<Self, I>>;
@@ -256,15 +229,6 @@ pub trait Trait<I: Instance = DefaultInstance>: system::Trait {
/// The fee required to create an account.
type CreationFee: Get<Self::Balance>;
/// The fee to be paid for making a transaction; the base.
type TransactionBaseFee: Get<Self::Balance>;
/// The fee to be paid for making a transaction; the per-byte portion.
type TransactionByteFee: Get<Self::Balance>;
/// Convert a weight value into a deductible fee based on the currency type.
type WeightToFee: Convert<Weight, Self::Balance>;
}
impl<T: Trait<I>, I: Instance> Subtrait<I> for T {
@@ -274,9 +238,6 @@ impl<T: Trait<I>, I: Instance> Subtrait<I> for T {
type ExistentialDeposit = T::ExistentialDeposit;
type TransferFee = T::TransferFee;
type CreationFee = T::CreationFee;
type TransactionBaseFee = T::TransactionBaseFee;
type TransactionByteFee = T::TransactionByteFee;
type WeightToFee = T::WeightToFee;
}
decl_event!(
@@ -414,12 +375,6 @@ decl_module! {
/// The fee required to create an account.
const CreationFee: T::Balance = T::CreationFee::get();
/// The fee to be paid for making a transaction; the base.
const TransactionBaseFee: T::Balance = T::TransactionBaseFee::get();
/// The fee to be paid for making a transaction; the per-byte portion.
const TransactionByteFee: T::Balance = T::TransactionByteFee::get();
fn deposit_event() = default;
/// Transfer some liquid free balance to another account.
@@ -776,7 +731,7 @@ mod imbalances {
// This works as long as `increase_total_issuance_by` doesn't use the Imbalance
// types (basically for charging fees).
// This should eventually be refactored so that the three type items that do
// depend on the Imbalance type (TransactionPayment, TransferPayment, DustRemoval)
// depend on the Imbalance type (TransferPayment, DustRemoval)
// are placed in their own SRML module.
struct ElevatedTrait<T: Subtrait<I>, I: Instance>(T, I);
impl<T: Subtrait<I>, I: Instance> Clone for ElevatedTrait<T, I> {
@@ -796,7 +751,6 @@ impl<T: Subtrait<I>, I: Instance> system::Trait for ElevatedTrait<T, I> {
type AccountId = T::AccountId;
type Lookup = T::Lookup;
type Header = T::Header;
type WeightMultiplierUpdate = T::WeightMultiplierUpdate;
type Event = ();
type BlockHashCount = T::BlockHashCount;
type MaximumBlockWeight = T::MaximumBlockWeight;
@@ -809,15 +763,11 @@ impl<T: Subtrait<I>, I: Instance> Trait<I> for ElevatedTrait<T, I> {
type OnFreeBalanceZero = T::OnFreeBalanceZero;
type OnNewAccount = T::OnNewAccount;
type Event = ();
type TransactionPayment = ();
type TransferPayment = ();
type DustRemoval = ();
type ExistentialDeposit = T::ExistentialDeposit;
type TransferFee = T::TransferFee;
type CreationFee = T::CreationFee;
type TransactionBaseFee = T::TransactionBaseFee;
type TransactionByteFee = T::TransactionByteFee;
type WeightToFee = T::WeightToFee;
}
impl<T: Trait<I>, I: Instance> Currency<T::AccountId> for Module<T, I>
@@ -1194,91 +1144,6 @@ where
}
}
/// Require the transactor pay for themselves and maybe include a tip to gain additional priority
/// in the queue.
#[derive(Encode, Decode, Clone, Eq, PartialEq)]
pub struct TakeFees<T: Trait<I>, I: Instance = DefaultInstance>(#[codec(compact)] T::Balance);
impl<T: Trait<I>, I: Instance> TakeFees<T, I> {
/// utility constructor. Used only in client/factory code.
pub fn from(fee: T::Balance) -> Self {
Self(fee)
}
/// Compute the final fee value for a particular transaction.
///
/// The final fee is composed of:
/// - _length-fee_: This is the amount paid merely to pay for size of the transaction.
/// - _weight-fee_: This amount is computed based on the weight of the transaction. Unlike
/// size-fee, this is not input dependent and reflects the _complexity_ of the execution
/// and the time it consumes.
/// - (optional) _tip_: if included in the transaction, it will be added on top. Only signed
/// transactions can have a tip.
fn compute_fee(len: usize, info: DispatchInfo, tip: T::Balance) -> T::Balance {
let len_fee = if info.pay_length_fee() {
let len = T::Balance::from(len as u32);
let base = T::TransactionBaseFee::get();
let per_byte = T::TransactionByteFee::get();
base.saturating_add(per_byte.saturating_mul(len))
} else {
Zero::zero()
};
let weight_fee = {
// 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 = info.weight.min(<T as system::Trait>::MaximumBlockWeight::get());
let weight_update = <system::Module<T>>::next_weight_multiplier();
let adjusted_weight = weight_update.apply_to(capped_weight);
T::WeightToFee::convert(adjusted_weight)
};
len_fee.saturating_add(weight_fee).saturating_add(tip)
}
}
#[cfg(feature = "std")]
impl<T: Trait<I>, I: Instance> rstd::fmt::Debug for TakeFees<T, I> {
fn fmt(&self, f: &mut rstd::fmt::Formatter) -> rstd::fmt::Result {
self.0.fmt(f)
}
}
impl<T: Trait<I>, I: Instance + Clone + Eq> SignedExtension for TakeFees<T, I> {
type AccountId = T::AccountId;
type Call = T::Call;
type AdditionalSigned = ();
type Pre = ();
fn additional_signed(&self) -> rstd::result::Result<(), TransactionValidityError> { Ok(()) }
fn validate(
&self,
who: &Self::AccountId,
_call: &Self::Call,
info: DispatchInfo,
len: usize,
) -> TransactionValidity {
// pay any fees.
let fee = Self::compute_fee(len, info, self.0);
let imbalance = match <Module<T, I>>::withdraw(
who,
fee,
WithdrawReason::TransactionPayment,
ExistenceRequirement::KeepAlive,
) {
Ok(imbalance) => imbalance,
Err(_) => return InvalidTransaction::Payment.into(),
};
T::TransactionPayment::on_unbalanced(imbalance);
let mut r = ValidTransaction::default();
// NOTE: we probably want to maximize the _fee (of any type) per weight unit_ here, which
// will be a bit more than setting the priority to tip. For now, this is enough.
r.priority = fee.saturated_into::<TransactionPriority>();
Ok(r)
}
}
impl<T: Trait<I>, I: Instance> IsDeadAccount<T::AccountId> for Module<T, I>
where
T::Balance: MaybeSerializeDebug
+13 -43
View File
@@ -18,7 +18,7 @@
#![cfg(test)]
use sr_primitives::{Perbill, traits::{Convert, IdentityLookup}, testing::Header,
use sr_primitives::{Perbill, traits::{ConvertInto, IdentityLookup}, testing::Header,
weights::{DispatchInfo, Weight}};
use primitives::H256;
use runtime_io;
@@ -35,10 +35,6 @@ thread_local! {
static EXISTENTIAL_DEPOSIT: RefCell<u64> = RefCell::new(0);
static TRANSFER_FEE: RefCell<u64> = RefCell::new(0);
static CREATION_FEE: RefCell<u64> = RefCell::new(0);
static TRANSACTION_BASE_FEE: RefCell<u64> = RefCell::new(0);
static TRANSACTION_BYTE_FEE: RefCell<u64> = RefCell::new(1);
static TRANSACTION_WEIGHT_FEE: RefCell<u64> = RefCell::new(1);
static WEIGHT_TO_FEE: RefCell<u64> = RefCell::new(1);
}
pub struct ExistentialDeposit;
@@ -56,23 +52,6 @@ impl Get<u64> for CreationFee {
fn get() -> u64 { CREATION_FEE.with(|v| *v.borrow()) }
}
pub struct TransactionBaseFee;
impl Get<u64> for TransactionBaseFee {
fn get() -> u64 { TRANSACTION_BASE_FEE.with(|v| *v.borrow()) }
}
pub struct TransactionByteFee;
impl Get<u64> for TransactionByteFee {
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))
}
}
// Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted.
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct Runtime;
@@ -92,7 +71,6 @@ impl system::Trait for Runtime {
type AccountId = u64;
type Lookup = IdentityLookup<Self::AccountId>;
type Header = Header;
type WeightMultiplierUpdate = ();
type Event = ();
type BlockHashCount = BlockHashCount;
type MaximumBlockWeight = MaximumBlockWeight;
@@ -100,26 +78,31 @@ impl system::Trait for Runtime {
type AvailableBlockRatio = AvailableBlockRatio;
type Version = ();
}
parameter_types! {
pub const TransactionBaseFee: u64 = 0;
pub const TransactionByteFee: u64 = 1;
}
impl transaction_payment::Trait for Runtime {
type Currency = Module<Runtime>;
type OnTransactionPayment = ();
type TransactionBaseFee = TransactionBaseFee;
type TransactionByteFee = TransactionByteFee;
type WeightToFee = ConvertInto;
type FeeMultiplierUpdate = ();
}
impl Trait for Runtime {
type Balance = u64;
type OnFreeBalanceZero = ();
type OnNewAccount = ();
type Event = ();
type TransactionPayment = ();
type DustRemoval = ();
type TransferPayment = ();
type ExistentialDeposit = ExistentialDeposit;
type TransferFee = TransferFee;
type CreationFee = CreationFee;
type TransactionBaseFee = TransactionBaseFee;
type TransactionByteFee = TransactionByteFee;
type WeightToFee = WeightToFee;
}
pub struct ExtBuilder {
transaction_base_fee: u64,
transaction_byte_fee: u64,
weight_to_fee: u64,
existential_deposit: u64,
transfer_fee: u64,
creation_fee: u64,
@@ -129,9 +112,6 @@ pub struct ExtBuilder {
impl Default for ExtBuilder {
fn default() -> Self {
Self {
transaction_base_fee: 0,
transaction_byte_fee: 0,
weight_to_fee: 0,
existential_deposit: 0,
transfer_fee: 0,
creation_fee: 0,
@@ -141,12 +121,6 @@ impl Default for ExtBuilder {
}
}
impl ExtBuilder {
pub fn transaction_fees(mut self, base_fee: u64, byte_fee: u64, weight_fee: u64) -> Self {
self.transaction_base_fee = base_fee;
self.transaction_byte_fee = byte_fee;
self.weight_to_fee = weight_fee;
self
}
pub fn existential_deposit(mut self, existential_deposit: u64) -> Self {
self.existential_deposit = existential_deposit;
self
@@ -175,9 +149,6 @@ impl ExtBuilder {
EXISTENTIAL_DEPOSIT.with(|v| *v.borrow_mut() = self.existential_deposit);
TRANSFER_FEE.with(|v| *v.borrow_mut() = self.transfer_fee);
CREATION_FEE.with(|v| *v.borrow_mut() = self.creation_fee);
TRANSACTION_BASE_FEE.with(|v| *v.borrow_mut() = self.transaction_base_fee);
TRANSACTION_BYTE_FEE.with(|v| *v.borrow_mut() = self.transaction_byte_fee);
WEIGHT_TO_FEE.with(|v| *v.borrow_mut() = self.weight_to_fee);
}
pub fn build(self) -> runtime_io::TestExternalities {
self.set_associated_consts();
@@ -211,7 +182,6 @@ impl ExtBuilder {
pub type System = system::Module<Runtime>;
pub type Balances = Module<Runtime>;
pub const CALL: &<Runtime as system::Trait>::Call = &();
/// create a transaction info struct from weight. Handy to avoid building the whole struct.
+8 -91
View File
@@ -20,12 +20,13 @@
use super::*;
use mock::{Balances, ExtBuilder, Runtime, System, info_from_weight, CALL};
use sr_primitives::traits::SignedExtension;
use support::{
assert_noop, assert_ok, assert_err,
traits::{LockableCurrency, LockIdentifier, WithdrawReason, WithdrawReasons,
Currency, ReservableCurrency}
};
use sr_primitives::weights::DispatchClass;
use transaction_payment::ChargeTransactionPayment;
use system::RawOrigin;
const ID_1: LockIdentifier = *b"1 ";
@@ -115,7 +116,6 @@ fn lock_reasons_should_work() {
ExtBuilder::default()
.existential_deposit(1)
.monied(true)
.transaction_fees(0, 1, 0)
.build()
.execute_with(|| {
Balances::set_lock(ID_1, &1, 10, u64::max_value(), WithdrawReason::Transfer.into());
@@ -125,8 +125,8 @@ fn lock_reasons_should_work() {
);
assert_ok!(<Balances as ReservableCurrency<_>>::reserve(&1, 1));
// NOTE: this causes a fee payment.
assert!(<TakeFees<Runtime> as SignedExtension>::pre_dispatch(
TakeFees::from(1),
assert!(<ChargeTransactionPayment<Runtime> as SignedExtension>::pre_dispatch(
ChargeTransactionPayment::from(1),
&1,
CALL,
info_from_weight(1),
@@ -139,8 +139,8 @@ fn lock_reasons_should_work() {
<Balances as ReservableCurrency<_>>::reserve(&1, 1),
"account liquidity restrictions prevent withdrawal"
);
assert!(<TakeFees<Runtime> as SignedExtension>::pre_dispatch(
TakeFees::from(1),
assert!(<ChargeTransactionPayment<Runtime> as SignedExtension>::pre_dispatch(
ChargeTransactionPayment::from(1),
&1,
CALL,
info_from_weight(1),
@@ -150,8 +150,8 @@ fn lock_reasons_should_work() {
Balances::set_lock(ID_1, &1, 10, u64::max_value(), WithdrawReason::TransactionPayment.into());
assert_ok!(<Balances as Currency<_>>::transfer(&1, &2, 1));
assert_ok!(<Balances as ReservableCurrency<_>>::reserve(&1, 1));
assert!(<TakeFees<Runtime> as SignedExtension>::pre_dispatch(
TakeFees::from(1),
assert!(<ChargeTransactionPayment<Runtime> as SignedExtension>::pre_dispatch(
ChargeTransactionPayment::from(1),
&1,
CALL,
info_from_weight(1),
@@ -736,89 +736,6 @@ fn liquid_funds_should_transfer_with_delayed_vesting() {
});
}
#[test]
fn signed_extension_take_fees_work() {
ExtBuilder::default()
.existential_deposit(10)
.transaction_fees(10, 1, 5)
.monied(true)
.build()
.execute_with(|| {
let len = 10;
assert!(
TakeFees::<Runtime>::from(0)
.pre_dispatch(&1, CALL, info_from_weight(5), len)
.is_ok()
);
assert_eq!(Balances::free_balance(&1), 100 - 20 - 25);
assert!(
TakeFees::<Runtime>::from(5 /* tipped */)
.pre_dispatch(&1, CALL, info_from_weight(3), len)
.is_ok()
);
assert_eq!(Balances::free_balance(&1), 100 - 20 - 25 - 20 - 5 - 15);
});
}
#[test]
fn signed_extension_take_fees_is_bounded() {
ExtBuilder::default()
.existential_deposit(1000)
.transaction_fees(0, 0, 1)
.monied(true)
.build()
.execute_with(|| {
use sr_primitives::weights::Weight;
// maximum weight possible
assert!(
TakeFees::<Runtime>::from(0)
.pre_dispatch(&1, CALL, info_from_weight(Weight::max_value()), 10)
.is_ok()
);
// fee will be proportional to what is the actual maximum weight in the runtime.
assert_eq!(
Balances::free_balance(&1),
(10000 - <Runtime as system::Trait>::MaximumBlockWeight::get()) as u64
);
});
}
#[test]
fn signed_extension_allows_free_transactions() {
ExtBuilder::default()
.transaction_fees(100, 1, 1)
.monied(false)
.build()
.execute_with(|| {
// 1 ain't have a penny.
assert_eq!(Balances::free_balance(&1), 0);
// like a FreeOperational
let operational_transaction = DispatchInfo {
weight: 0,
class: DispatchClass::Operational
};
let len = 100;
assert!(
TakeFees::<Runtime>::from(0)
.validate(&1, CALL, operational_transaction , len)
.is_ok()
);
// like a FreeNormal
let free_transaction = DispatchInfo {
weight: 0,
class: DispatchClass::Normal
};
assert!(
TakeFees::<Runtime>::from(0)
.validate(&1, CALL, free_transaction , len)
.is_err()
);
});
}
#[test]
fn burn_must_work() {
ExtBuilder::default().monied(true).build().execute_with(|| {
-1
View File
@@ -406,7 +406,6 @@ mod tests {
type Lookup = IdentityLookup<Self::AccountId>;
type Header = Header;
type Event = Event;
type WeightMultiplierUpdate = ();
type BlockHashCount = BlockHashCount;
type MaximumBlockWeight = MaximumBlockWeight;
type MaximumBlockLength = MaximumBlockLength;
+1 -1
View File
@@ -442,7 +442,7 @@ where
}
/// The default dispatch fee computor computes the fee in the same way that
/// the implementation of `TakeFees` for the Balances module does. Note that this only takes a fixed
/// the implementation of `ChargeTransactionPayment` for the Balances module does. Note that this only takes a fixed
/// fee based on size. Unlike the balances module, weight-fee is applied.
pub struct DefaultDispatchFeeComputor<T: Trait>(PhantomData<T>);
impl<T: Trait> ComputeDispatchFee<<T as Trait>::Call, BalanceOf<T>> for DefaultDispatchFeeComputor<T> {
-7
View File
@@ -96,8 +96,6 @@ parameter_types! {
pub const BlockHashCount: u64 = 250;
pub const MaximumBlockWeight: u32 = 1024;
pub const MaximumBlockLength: u32 = 2 * 1024;
pub const BalancesTransactionBaseFee: u64 = 0;
pub const BalancesTransactionByteFee: u64 = 0;
pub const AvailableBlockRatio: Perbill = Perbill::one();
}
impl system::Trait for Test {
@@ -110,7 +108,6 @@ impl system::Trait for Test {
type AccountId = u64;
type Lookup = IdentityLookup<Self::AccountId>;
type Header = Header;
type WeightMultiplierUpdate = ();
type Event = MetaEvent;
type BlockHashCount = BlockHashCount;
type MaximumBlockWeight = MaximumBlockWeight;
@@ -123,15 +120,11 @@ impl balances::Trait for Test {
type OnFreeBalanceZero = Contract;
type OnNewAccount = ();
type Event = MetaEvent;
type TransactionPayment = ();
type DustRemoval = ();
type TransferPayment = ();
type ExistentialDeposit = ExistentialDeposit;
type TransferFee = TransferFee;
type CreationFee = CreationFee;
type TransactionBaseFee = BalancesTransactionBaseFee;
type TransactionByteFee = BalancesTransactionByteFee;
type WeightToFee = ();
}
parameter_types! {
pub const MinimumPeriod: u64 = 1;
-7
View File
@@ -114,7 +114,6 @@ mod tests {
type AccountId = u64;
type Lookup = IdentityLookup<Self::AccountId>;
type Header = Header;
type WeightMultiplierUpdate = ();
type Event = Event;
type Error = Error;
type BlockHashCount = BlockHashCount;
@@ -127,24 +126,18 @@ mod tests {
pub const ExistentialDeposit: u64 = 0;
pub const TransferFee: u64 = 0;
pub const CreationFee: u64 = 0;
pub const TransactionBaseFee: u64 = 1;
pub const TransactionByteFee: u64 = 0;
}
impl balances::Trait for Test {
type Balance = u64;
type OnNewAccount = ();
type OnFreeBalanceZero = ();
type Event = Event;
type TransactionPayment = ();
type TransferPayment = ();
type DustRemoval = ();
type Error = Error;
type ExistentialDeposit = ExistentialDeposit;
type TransferFee = TransferFee;
type CreationFee = CreationFee;
type TransactionBaseFee = TransactionBaseFee;
type TransactionByteFee = TransactionByteFee;
type WeightToFee = ();
}
parameter_types! {
pub const LaunchPeriod: u64 = 1;
-7
View File
@@ -1015,7 +1015,6 @@ mod tests {
type AccountId = u64;
type Lookup = IdentityLookup<Self::AccountId>;
type Header = Header;
type WeightMultiplierUpdate = ();
type Event = ();
type BlockHashCount = BlockHashCount;
type MaximumBlockWeight = MaximumBlockWeight;
@@ -1027,23 +1026,17 @@ mod tests {
pub const ExistentialDeposit: u64 = 0;
pub const TransferFee: u64 = 0;
pub const CreationFee: u64 = 0;
pub const TransactionBaseFee: u64 = 0;
pub const TransactionByteFee: u64 = 0;
}
impl balances::Trait for Test {
type Balance = u64;
type OnFreeBalanceZero = ();
type OnNewAccount = ();
type Event = ();
type TransactionPayment = ();
type TransferPayment = ();
type DustRemoval = ();
type ExistentialDeposit = ExistentialDeposit;
type TransferFee = TransferFee;
type CreationFee = CreationFee;
type TransactionBaseFee = TransactionBaseFee;
type TransactionByteFee = TransactionByteFee;
type WeightToFee = ();
}
parameter_types! {
pub const LaunchPeriod: u64 = 2;
@@ -616,7 +616,6 @@ mod tests {
type Lookup = IdentityLookup<Self::AccountId>;
type Header = Header;
type Event = Event;
type WeightMultiplierUpdate = ();
type BlockHashCount = BlockHashCount;
type MaximumBlockWeight = MaximumBlockWeight;
type MaximumBlockLength = MaximumBlockLength;
@@ -628,8 +627,6 @@ mod tests {
pub const ExistentialDeposit: u64 = 1;
pub const TransferFee: u64 = 0;
pub const CreationFee: u64 = 0;
pub const TransactionBaseFee: u64 = 0;
pub const TransactionByteFee: u64 = 0;
}
impl balances::Trait for Test {
@@ -637,15 +634,11 @@ mod tests {
type OnNewAccount = ();
type OnFreeBalanceZero = ();
type Event = Event;
type TransactionPayment = ();
type TransferPayment = ();
type DustRemoval = ();
type ExistentialDeposit = ExistentialDeposit;
type TransferFee = TransferFee;
type CreationFee = CreationFee;
type TransactionBaseFee = TransactionBaseFee;
type TransactionByteFee = TransactionByteFee;
type WeightToFee = ();
}
parameter_types! {
-7
View File
@@ -47,7 +47,6 @@ impl system::Trait for Test {
type Lookup = IdentityLookup<Self::AccountId>;
type Header = Header;
type Event = Event;
type WeightMultiplierUpdate = ();
type BlockHashCount = BlockHashCount;
type MaximumBlockWeight = MaximumBlockWeight;
type MaximumBlockLength = MaximumBlockLength;
@@ -59,23 +58,17 @@ parameter_types! {
pub const ExistentialDeposit: u64 = 0;
pub const TransferFee: u64 = 0;
pub const CreationFee: u64 = 0;
pub const TransactionBaseFee: u64 = 0;
pub const TransactionByteFee: u64 = 0;
}
impl balances::Trait for Test {
type Balance = u64;
type OnNewAccount = ();
type OnFreeBalanceZero = ();
type Event = Event;
type TransactionPayment = ();
type TransferPayment = ();
type DustRemoval = ();
type ExistentialDeposit = ExistentialDeposit;
type TransferFee = TransferFee;
type CreationFee = CreationFee;
type TransactionBaseFee = TransactionBaseFee;
type TransactionByteFee = TransactionByteFee;
type WeightToFee = ();
}
parameter_types! {
-7
View File
@@ -667,7 +667,6 @@ mod tests {
type AccountId = u64;
type Lookup = IdentityLookup<Self::AccountId>;
type Header = Header;
type WeightMultiplierUpdate = ();
type Event = ();
type BlockHashCount = BlockHashCount;
type MaximumBlockWeight = MaximumBlockWeight;
@@ -679,23 +678,17 @@ mod tests {
pub const ExistentialDeposit: u64 = 0;
pub const TransferFee: u64 = 0;
pub const CreationFee: u64 = 0;
pub const TransactionBaseFee: u64 = 0;
pub const TransactionByteFee: u64 = 0;
}
impl balances::Trait for Test {
type Balance = u64;
type OnFreeBalanceZero = ();
type OnNewAccount = ();
type Event = ();
type TransactionPayment = ();
type TransferPayment = ();
type DustRemoval = ();
type ExistentialDeposit = ExistentialDeposit;
type TransferFee = TransferFee;
type CreationFee = CreationFee;
type TransactionBaseFee = TransactionBaseFee;
type TransactionByteFee = TransactionByteFee;
type WeightToFee = ();
}
impl Trait for Test {
type Event = ();
+1
View File
@@ -18,6 +18,7 @@ hex-literal = "0.2.1"
primitives = { package = "substrate-primitives", path = "../../core/primitives" }
srml-indices = { path = "../indices" }
balances = { package = "srml-balances", path = "../balances" }
transaction-payment = { package = "srml-transaction-payment", path = "../transaction-payment" }
[features]
default = ["std"]
+13 -7
View File
@@ -347,7 +347,6 @@ mod tests {
type Header = Header;
type Event = MetaEvent;
type BlockHashCount = BlockHashCount;
type WeightMultiplierUpdate = ();
type MaximumBlockWeight = MaximumBlockWeight;
type AvailableBlockRatio = AvailableBlockRatio;
type MaximumBlockLength = MaximumBlockLength;
@@ -357,23 +356,30 @@ mod tests {
pub const ExistentialDeposit: u64 = 0;
pub const TransferFee: u64 = 0;
pub const CreationFee: u64 = 0;
pub const TransactionBaseFee: u64 = 10;
pub const TransactionByteFee: u64 = 0;
}
impl balances::Trait for Runtime {
type Balance = u64;
type OnFreeBalanceZero = ();
type OnNewAccount = ();
type Event = MetaEvent;
type TransactionPayment = ();
type DustRemoval = ();
type TransferPayment = ();
type ExistentialDeposit = ExistentialDeposit;
type TransferFee = TransferFee;
type CreationFee = CreationFee;
}
parameter_types! {
pub const TransactionBaseFee: u64 = 10;
pub const TransactionByteFee: u64 = 0;
}
impl transaction_payment::Trait for Runtime {
type Currency = Balances;
type OnTransactionPayment = ();
type TransactionBaseFee = TransactionBaseFee;
type TransactionByteFee = TransactionByteFee;
type WeightToFee = ConvertInto;
type FeeMultiplierUpdate = ();
}
impl ValidateUnsigned for Runtime {
@@ -391,7 +397,7 @@ mod tests {
system::CheckEra<Runtime>,
system::CheckNonce<Runtime>,
system::CheckWeight<Runtime>,
balances::TakeFees<Runtime>
transaction_payment::ChargeTransactionPayment<Runtime>
);
type TestXt = sr_primitives::testing::TestXt<Call, SignedExtra>;
type Executive = super::Executive<Runtime, Block<TestXt>, system::ChainContext<Runtime>, Runtime, ()>;
@@ -401,7 +407,7 @@ mod tests {
system::CheckEra::from(Era::Immortal),
system::CheckNonce::from(nonce),
system::CheckWeight::new(),
balances::TakeFees::from(fee)
transaction_payment::ChargeTransactionPayment::from(fee)
)
}
@@ -450,7 +456,7 @@ mod tests {
header: Header {
parent_hash: [69u8; 32].into(),
number: 1,
state_root: hex!("a6378d7fdd31029d13718d54bdff10a370e75cc624aaf94a90e7e7d4a24e0bcc").into(),
state_root: hex!("f0d1d66255c2e5b40580eb8b93ddbe732491478487f85e358e1d167d369e398e").into(),
extrinsics_root: hex!("03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314").into(),
digest: Digest { logs: vec![], },
},
@@ -298,7 +298,6 @@ mod tests {
type AccountId = u64;
type Lookup = IdentityLookup<u64>;
type Header = Header;
type WeightMultiplierUpdate = ();
type Event = ();
type BlockHashCount = BlockHashCount;
type MaximumBlockWeight = MaximumBlockWeight;
-1
View File
@@ -1056,7 +1056,6 @@ impl<T: Subtrait> system::Trait for ElevatedTrait<T> {
type MaximumBlockWeight = T::MaximumBlockWeight;
type MaximumBlockLength = T::MaximumBlockLength;
type AvailableBlockRatio = T::AvailableBlockRatio;
type WeightMultiplierUpdate = ();
type BlockHashCount = T::BlockHashCount;
type Version = T::Version;
}
-1
View File
@@ -56,7 +56,6 @@ impl system::Trait for Test {
type Lookup = IdentityLookup<u64>;
type Header = Header;
type Event = TestEvent;
type WeightMultiplierUpdate = ();
type MaximumBlockWeight = MaximumBlockWeight;
type MaximumBlockLength = MaximumBlockLength;
type AvailableBlockRatio = AvailableBlockRatio;
-1
View File
@@ -57,7 +57,6 @@ impl system::Trait for Test {
type AccountId = u64;
type Lookup = IdentityLookup<Self::AccountId>;
type Header = Header;
type WeightMultiplierUpdate = ();
type Event = TestEvent;
type BlockHashCount = BlockHashCount;
type MaximumBlockWeight = MaximumBlockWeight;
-1
View File
@@ -111,7 +111,6 @@ impl system::Trait for Runtime {
type AccountId = u64;
type Lookup = IdentityLookup<Self::AccountId>;
type Header = Header;
type WeightMultiplierUpdate = ();
type Event = ();
type BlockHashCount = BlockHashCount;
type MaximumBlockWeight = MaximumBlockWeight;
-1
View File
@@ -81,7 +81,6 @@ impl system::Trait for Runtime {
type AccountId = u64;
type Lookup = Indices;
type Header = Header;
type WeightMultiplierUpdate = ();
type Event = ();
type BlockHashCount = BlockHashCount;
type MaximumBlockWeight = MaximumBlockWeight;
-1
View File
@@ -224,7 +224,6 @@ mod tests {
type AccountId = u64;
type Lookup = IdentityLookup<Self::AccountId>;
type Header = Header;
type WeightMultiplierUpdate = ();
type Event = ();
type BlockHashCount = BlockHashCount;
type MaximumBlockWeight = MaximumBlockWeight;
-1
View File
@@ -78,7 +78,6 @@ impl system::Trait for Runtime {
type AccountId = u64;
type Lookup = IdentityLookup<Self::AccountId>;
type Header = Header;
type WeightMultiplierUpdate = ();
type Event = TestEvent;
type BlockHashCount = BlockHashCount;
type MaximumBlockWeight = MaximumBlockWeight;
@@ -182,7 +182,6 @@ mod tests {
type AccountId = u64;
type Lookup = IdentityLookup<Self::AccountId>;
type Header = Header;
type WeightMultiplierUpdate = ();
type Event = ();
type BlockHashCount = BlockHashCount;
type MaximumBlockWeight = MaximumBlockWeight;
-7
View File
@@ -52,8 +52,6 @@ parameter_types! {
pub const ExistentialDeposit: u64 = 0;
pub const TransferFee: u64 = 0;
pub const CreationFee: u64 = 0;
pub const TransactionBaseFee: u64 = 0;
pub const TransactionByteFee: u64 = 0;
}
impl system::Trait for Test {
@@ -66,7 +64,6 @@ impl system::Trait for Test {
type AccountId = u64;
type Lookup = IdentityLookup<Self::AccountId>;
type Header = Header;
type WeightMultiplierUpdate = ();
type Event = ();
type BlockHashCount = BlockHashCount;
type MaximumBlockWeight = MaximumBlockWeight;
@@ -80,15 +77,11 @@ impl balances::Trait for Test {
type OnFreeBalanceZero = ();
type OnNewAccount = ();
type Event = ();
type TransactionPayment = ();
type TransferPayment = ();
type DustRemoval = ();
type ExistentialDeposit = ExistentialDeposit;
type TransferFee = TransferFee;
type CreationFee = CreationFee;
type TransactionBaseFee = TransactionBaseFee;
type TransactionByteFee = TransactionByteFee;
type WeightToFee = ();
}
thread_local! {
-1
View File
@@ -168,7 +168,6 @@ impl system::Trait for Test {
type AccountId = u64;
type Lookup = IdentityLookup<Self::AccountId>;
type Header = Header;
type WeightMultiplierUpdate = ();
type Event = ();
type BlockHashCount = BlockHashCount;
type MaximumBlockWeight = MaximumBlockWeight;
-7
View File
@@ -118,7 +118,6 @@ impl system::Trait for Test {
type AccountId = AccountId;
type Lookup = IdentityLookup<Self::AccountId>;
type Header = Header;
type WeightMultiplierUpdate = ();
type Event = ();
type BlockHashCount = BlockHashCount;
type MaximumBlockWeight = MaximumBlockWeight;
@@ -129,23 +128,17 @@ impl system::Trait for Test {
parameter_types! {
pub const TransferFee: Balance = 0;
pub const CreationFee: Balance = 0;
pub const TransactionBaseFee: u64 = 0;
pub const TransactionByteFee: u64 = 0;
}
impl balances::Trait for Test {
type Balance = Balance;
type OnFreeBalanceZero = Staking;
type OnNewAccount = ();
type Event = ();
type TransactionPayment = ();
type TransferPayment = ();
type DustRemoval = ();
type ExistentialDeposit = ExistentialDeposit;
type TransferFee = TransferFee;
type CreationFee = CreationFee;
type TransactionBaseFee = TransactionBaseFee;
type TransactionByteFee = TransactionByteFee;
type WeightToFee = ();
}
parameter_types! {
pub const Period: BlockNumber = 1;
-1
View File
@@ -68,7 +68,6 @@ impl system::Trait for Runtime {
type AccountId = u64;
type Lookup = IdentityLookup<Self::AccountId>;
type Header = Header;
type WeightMultiplierUpdate = ();
type Event = Event;
type BlockHashCount = BlockHashCount;
type MaximumBlockWeight = MaximumBlockWeight;
+2 -26
View File
@@ -97,13 +97,13 @@ use rstd::marker::PhantomData;
use sr_version::RuntimeVersion;
use sr_primitives::{
generic::{self, Era}, Perbill, ApplyError, ApplyOutcome, DispatchError,
weights::{Weight, DispatchInfo, DispatchClass, WeightMultiplier, SimpleDispatchInfo},
weights::{Weight, DispatchInfo, DispatchClass, SimpleDispatchInfo},
transaction_validity::{
ValidTransaction, TransactionPriority, TransactionLongevity, TransactionValidityError,
InvalidTransaction, TransactionValidity,
},
traits::{
self, CheckEqual, SimpleArithmetic, Zero, SignedExtension, Convert, Lookup, LookupError,
self, CheckEqual, SimpleArithmetic, Zero, SignedExtension, Lookup, LookupError,
SimpleBitOps, Hash, Member, MaybeDisplay, EnsureOrigin, SaturatedConversion,
MaybeSerializeDebugButNotDeserialize, MaybeSerializeDebug, StaticLookup, One, Bounded,
},
@@ -188,14 +188,6 @@ pub trait Trait: 'static + Eq + Clone {
/// (e.g. Indices module) may provide more functional/efficient alternatives.
type Lookup: StaticLookup<Target = Self::AccountId>;
/// Handler for updating the weight multiplier at the end of each block.
///
/// It receives the current block's weight as input and returns the next weight multiplier for next
/// block.
///
/// Note that passing `()` will keep the value constant.
type WeightMultiplierUpdate: Convert<(Weight, WeightMultiplier), WeightMultiplier>;
/// The block header.
type Header: Parameter + traits::Header<
Number = Self::BlockNumber,
@@ -381,9 +373,6 @@ decl_storage! {
AllExtrinsicsWeight: Option<Weight>;
/// Total length (in bytes) for all extrinsics put together, for the current block.
AllExtrinsicsLen: Option<u32>;
/// The next weight multiplier. This should be updated at the end of each block based on the
/// saturation level (weight).
pub NextWeightMultiplier get(next_weight_multiplier): WeightMultiplier = Default::default();
/// Map of block numbers to block hashes.
pub BlockHash get(block_hash) build(|_| vec![(T::BlockNumber::zero(), hash69())]): map T::BlockNumber => T::Hash;
/// Extrinsics data for the current block (maps an extrinsic's index to its data).
@@ -612,17 +601,6 @@ impl<T: Trait> Module<T> {
AllExtrinsicsLen::get().unwrap_or_default()
}
/// Update the next weight multiplier.
///
/// This should be called at then end of each block, before `all_extrinsics_weight` is cleared.
pub fn update_weight_multiplier() {
// update the multiplier based on block weight.
let current_weight = Self::all_extrinsics_weight();
NextWeightMultiplier::mutate(|fm| {
*fm = T::WeightMultiplierUpdate::convert((current_weight, *fm))
});
}
/// Start the execution of a particular block.
pub fn initialize(
number: &T::BlockNumber,
@@ -645,7 +623,6 @@ impl<T: Trait> Module<T> {
/// Remove temporary "environment" entries in storage.
pub fn finalize() -> T::Header {
ExtrinsicCount::kill();
Self::update_weight_multiplier();
AllExtrinsicsWeight::kill();
AllExtrinsicsLen::kill();
@@ -1118,7 +1095,6 @@ mod tests {
type AccountId = u64;
type Lookup = IdentityLookup<Self::AccountId>;
type Header = Header;
type WeightMultiplierUpdate = ();
type Event = u16;
type BlockHashCount = BlockHashCount;
type MaximumBlockWeight = MaximumBlockWeight;
-1
View File
@@ -348,7 +348,6 @@ mod tests {
type AccountId = u64;
type Lookup = IdentityLookup<Self::AccountId>;
type Header = Header;
type WeightMultiplierUpdate = ();
type Event = ();
type BlockHashCount = BlockHashCount;
type MaximumBlockWeight = MaximumBlockWeight;
@@ -0,0 +1,27 @@
[package]
name = "srml-transaction-payment"
version = "2.0.0"
authors = ["Parity Technologies <admin@parity.io>"]
edition = "2018"
[dependencies]
codec = { package = "parity-scale-codec", version = "1.0.0", default-features = false, features = ["derive"] }
rstd = { package = "sr-std", path = "../../core/sr-std", default-features = false }
sr-primitives = { path = "../../core/sr-primitives", default-features = false }
support = { package = "srml-support", path = "../support", default-features = false }
system = { package = "srml-system", path = "../system", default-features = false }
[dev-dependencies]
runtime-io = { package = "sr-io", path = "../../core/sr-io" }
primitives = { package = "substrate-primitives", path = "../../core/primitives" }
balances = { package = "srml-balances", path = "../balances" }
[features]
default = ["std"]
std = [
"codec/std",
"rstd/std",
"sr-primitives/std",
"support/std",
"system/std",
]
@@ -0,0 +1,455 @@
// Copyright 2019 Parity Technologies (UK) Ltd.
// This file is part of Substrate.
// Substrate is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
//! # Transaction Payment Module
//!
//! This module provides the basic logic needed to pay the absolute minimum amount needed for a
//! transaction to be included. This includes:
//! - _weight fee_: A fee proportional to amount of weight a transaction consumes.
//! - _length fee_: A fee proportional to the encoded length of the transaction.
//! - _tip_: An optional tip. Tip increases the priority of the transaction, giving it a higher
//! chance to be included by the transaction queue.
//!
//! Additionally, this module allows one to configure:
//! - The mapping between one unit of weight to one unit of fee via [`WeightToFee`].
//! - A means of updating the fee for the next block, via defining a multiplier, based on the
//! final state of the chain at the end of the previous block. This can be configured via
//! [`FeeMultiplierUpdate`]
#![cfg_attr(not(feature = "std"), no_std)]
use rstd::prelude::*;
use codec::{Encode, Decode};
use support::{
decl_storage, decl_module,
traits::{Currency, Get, OnUnbalanced, ExistenceRequirement, WithdrawReason},
};
use sr_primitives::{
Fixed64,
transaction_validity::{
TransactionPriority, ValidTransaction, InvalidTransaction, TransactionValidityError,
TransactionValidity,
},
traits::{Zero, Saturating, SignedExtension, SaturatedConversion, Convert},
weights::{Weight, DispatchInfo},
};
type Multiplier = Fixed64;
type BalanceOf<T> =
<<T as Trait>::Currency as Currency<<T as system::Trait>::AccountId>>::Balance;
type NegativeImbalanceOf<T> =
<<T as Trait>::Currency as Currency<<T as system::Trait>::AccountId>>::NegativeImbalance;
pub trait Trait: system::Trait {
/// The currency type in which fees will be paid.
type Currency: Currency<Self::AccountId>;
/// Handler for the unbalanced reduction when taking transaction fees.
type OnTransactionPayment: OnUnbalanced<NegativeImbalanceOf<Self>>;
/// The fee to be paid for making a transaction; the base.
type TransactionBaseFee: Get<BalanceOf<Self>>;
/// The fee to be paid for making a transaction; the per-byte portion.
type TransactionByteFee: Get<BalanceOf<Self>>;
/// Convert a weight value into a deductible fee based on the currency type.
type WeightToFee: Convert<Weight, BalanceOf<Self>>;
/// Update the multiplier of the next block, based on the previous block's weight.
// TODO: maybe this does not need previous weight and can just read it
type FeeMultiplierUpdate: Convert<(Weight, Multiplier), Multiplier>;
}
decl_storage! {
trait Store for Module<T: Trait> as Balances {
NextFeeMultiplier get(next_fee_multiplier): Multiplier = Multiplier::from_parts(0);
}
}
decl_module! {
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
/// The fee to be paid for making a transaction; the base.
const TransactionBaseFee: BalanceOf<T> = T::TransactionBaseFee::get();
/// The fee to be paid for making a transaction; the per-byte portion.
const TransactionByteFee: BalanceOf<T> = T::TransactionByteFee::get();
fn on_finalize() {
let current_weight = <system::Module<T>>::all_extrinsics_weight();
NextFeeMultiplier::mutate(|fm| {
*fm = T::FeeMultiplierUpdate::convert((current_weight, *fm))
});
}
}
}
impl<T: Trait> Module<T> {}
/// Require the transactor pay for themselves and maybe include a tip to gain additional priority
/// in the queue.
#[derive(Encode, Decode, Clone, Eq, PartialEq)]
pub struct ChargeTransactionPayment<T: Trait + Send + Sync>(#[codec(compact)] BalanceOf<T>);
impl<T: Trait + Send + Sync> ChargeTransactionPayment<T> {
/// utility constructor. Used only in client/factory code.
pub fn from(fee: BalanceOf<T>) -> Self {
Self(fee)
}
/// Compute the final fee value for a particular transaction.
///
/// The final fee is composed of:
/// - _length-fee_: This is the amount paid merely to pay for size of the transaction.
/// - _weight-fee_: This amount is computed based on the weight of the transaction. Unlike
/// size-fee, this is not input dependent and reflects the _complexity_ of the execution
/// and the time it consumes.
/// - (optional) _tip_: if included in the transaction, it will be added on top. Only signed
/// transactions can have a tip.
fn compute_fee(len: usize, info: DispatchInfo, tip: BalanceOf<T>) -> BalanceOf<T> {
let len_fee = if info.pay_length_fee() {
let len = <BalanceOf<T>>::from(len as u32);
let base = T::TransactionBaseFee::get();
let per_byte = T::TransactionByteFee::get();
base.saturating_add(per_byte.saturating_mul(len))
} else {
Zero::zero()
};
let weight_fee = {
// 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 = info.weight.min(<T as system::Trait>::MaximumBlockWeight::get());
T::WeightToFee::convert(capped_weight)
};
// everything except for tip
let basic_fee = len_fee.saturating_add(weight_fee);
let fee_update = NextFeeMultiplier::get();
let adjusted_fee = fee_update.saturated_multiply_accumulate(basic_fee);
adjusted_fee.saturating_add(tip)
}
}
#[cfg(feature = "std")]
impl<T: Trait + Send + Sync> rstd::fmt::Debug for ChargeTransactionPayment<T> {
fn fmt(&self, f: &mut rstd::fmt::Formatter) -> rstd::fmt::Result {
write!(f, "ChargeTransactionPayment<{:?}>", self.0)
}
}
impl<T: Trait + Send + Sync> SignedExtension for ChargeTransactionPayment<T>
where BalanceOf<T>: Send + Sync
{
type AccountId = T::AccountId;
type Call = T::Call;
type AdditionalSigned = ();
type Pre = ();
fn additional_signed(&self) -> rstd::result::Result<(), TransactionValidityError> { Ok(()) }
fn validate(
&self,
who: &Self::AccountId,
_call: &Self::Call,
info: DispatchInfo,
len: usize,
) -> TransactionValidity {
// pay any fees.
let fee = Self::compute_fee(len, info, self.0);
let imbalance = match T::Currency::withdraw(
who,
fee,
WithdrawReason::TransactionPayment,
ExistenceRequirement::KeepAlive,
) {
Ok(imbalance) => imbalance,
Err(_) => return InvalidTransaction::Payment.into(),
};
T::OnTransactionPayment::on_unbalanced(imbalance);
let mut r = ValidTransaction::default();
// NOTE: we probably want to maximize the _fee (of any type) per weight unit_ here, which
// will be a bit more than setting the priority to tip. For now, this is enough.
r.priority = fee.saturated_into::<TransactionPriority>();
Ok(r)
}
}
#[cfg(test)]
mod tests {
use super::*;
use support::{parameter_types, impl_outer_origin};
use primitives::H256;
use sr_primitives::{
Perbill,
testing::Header,
traits::{BlakeTwo256, IdentityLookup},
weights::DispatchClass,
};
use rstd::cell::RefCell;
const CALL: &<Runtime as system::Trait>::Call = &();
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct Runtime;
impl_outer_origin!{
pub enum Origin for Runtime {}
}
parameter_types! {
pub const BlockHashCount: u64 = 250;
pub const MaximumBlockWeight: u32 = 1024;
pub const MaximumBlockLength: u32 = 2 * 1024;
pub const AvailableBlockRatio: Perbill = Perbill::one();
}
impl system::Trait for Runtime {
type Origin = Origin;
type Index = u64;
type BlockNumber = u64;
type Call = ();
type Hash = H256;
type Hashing = BlakeTwo256;
type AccountId = u64;
type Lookup = IdentityLookup<Self::AccountId>;
type Header = Header;
type Event = ();
type BlockHashCount = BlockHashCount;
type MaximumBlockWeight = MaximumBlockWeight;
type MaximumBlockLength = MaximumBlockLength;
type AvailableBlockRatio = AvailableBlockRatio;
type Version = ();
}
parameter_types! {
pub const TransferFee: u64 = 0;
pub const CreationFee: u64 = 0;
pub const ExistentialDeposit: u64 = 0;
}
impl balances::Trait for Runtime {
type Balance = u64;
type OnFreeBalanceZero = ();
type OnNewAccount = ();
type Event = ();
type TransferPayment = ();
type DustRemoval = ();
type ExistentialDeposit = ExistentialDeposit;
type TransferFee = TransferFee;
type CreationFee = CreationFee;
}
thread_local! {
static TRANSACTION_BASE_FEE: RefCell<u64> = RefCell::new(0);
static TRANSACTION_BYTE_FEE: RefCell<u64> = RefCell::new(1);
static WEIGHT_TO_FEE: RefCell<u64> = RefCell::new(1);
}
pub struct TransactionBaseFee;
impl Get<u64> for TransactionBaseFee {
fn get() -> u64 { TRANSACTION_BASE_FEE.with(|v| *v.borrow()) }
}
pub struct TransactionByteFee;
impl Get<u64> for TransactionByteFee {
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))
}
}
impl Trait for Runtime {
type Currency = balances::Module<Runtime>;
type OnTransactionPayment = ();
type TransactionBaseFee = TransactionBaseFee;
type TransactionByteFee = TransactionByteFee;
type WeightToFee = WeightToFee;
type FeeMultiplierUpdate = ();
}
type Balances = balances::Module<Runtime>;
pub struct ExtBuilder {
balance_factor: u64,
base_fee: u64,
byte_fee: u64,
weight_to_fee: u64
}
impl Default for ExtBuilder {
fn default() -> Self {
Self {
balance_factor: 1,
base_fee: 0,
byte_fee: 1,
weight_to_fee: 1,
}
}
}
impl ExtBuilder {
pub fn fees(mut self, base: u64, byte: u64, weight: u64) -> Self {
self.base_fee = base;
self.byte_fee = byte;
self.weight_to_fee = weight;
self
}
pub fn balance_factor(mut self, factor: u64) -> Self {
self.balance_factor = factor;
self
}
fn set_constants(&self) {
TRANSACTION_BASE_FEE.with(|v| *v.borrow_mut() = self.base_fee);
TRANSACTION_BYTE_FEE.with(|v| *v.borrow_mut() = self.byte_fee);
WEIGHT_TO_FEE.with(|v| *v.borrow_mut() = self.weight_to_fee);
}
pub fn build(self) -> runtime_io::TestExternalities {
self.set_constants();
let mut t = system::GenesisConfig::default().build_storage::<Runtime>().unwrap();
balances::GenesisConfig::<Runtime> {
balances: vec![
(1, 10 * self.balance_factor),
(2, 20 * self.balance_factor),
(3, 30 * self.balance_factor),
(4, 40 * self.balance_factor),
(5, 50 * self.balance_factor),
(6, 60 * self.balance_factor)
],
vesting: vec![],
}.assimilate_storage(&mut t).unwrap();
t.into()
}
}
/// create a transaction info struct from weight. Handy to avoid building the whole struct.
pub fn info_from_weight(w: Weight) -> DispatchInfo {
DispatchInfo { weight: w, ..Default::default() }
}
#[test]
fn signed_extension_transaction_payment_work() {
ExtBuilder::default()
.balance_factor(10) // 100
.fees(5, 1, 1) // 5 fixed, 1 per byte, 1 per weight
.build()
.execute_with(||
{
let len = 10;
assert!(
ChargeTransactionPayment::<Runtime>::from(0)
.pre_dispatch(&1, CALL, info_from_weight(5), len)
.is_ok()
);
assert_eq!(Balances::free_balance(&1), 100 - 5 - 5 - 10);
assert!(
ChargeTransactionPayment::<Runtime>::from(5 /* tipped */)
.pre_dispatch(&2, CALL, info_from_weight(3), len)
.is_ok()
);
assert_eq!(Balances::free_balance(&2), 200 - 5 - 10 - 3 - 5);
});
}
#[test]
fn signed_extension_transaction_payment_is_bounded() {
ExtBuilder::default()
.balance_factor(1000)
.fees(0, 0, 1)
.build()
.execute_with(||
{
use sr_primitives::weights::Weight;
// maximum weight possible
assert!(
ChargeTransactionPayment::<Runtime>::from(0)
.pre_dispatch(&1, CALL, info_from_weight(Weight::max_value()), 10)
.is_ok()
);
// fee will be proportional to what is the actual maximum weight in the runtime.
assert_eq!(
Balances::free_balance(&1),
(10000 - <Runtime as system::Trait>::MaximumBlockWeight::get()) as u64
);
});
}
#[test]
fn signed_extension_allows_free_transactions() {
ExtBuilder::default()
.fees(100, 1, 1)
.balance_factor(0)
.build()
.execute_with(||
{
// 1 ain't have a penny.
assert_eq!(Balances::free_balance(&1), 0);
// like a FreeOperational
let operational_transaction = DispatchInfo {
weight: 0,
class: DispatchClass::Operational
};
let len = 100;
assert!(
ChargeTransactionPayment::<Runtime>::from(0)
.validate(&1, CALL, operational_transaction , len)
.is_ok()
);
// like a FreeNormal
let free_transaction = DispatchInfo {
weight: 0,
class: DispatchClass::Normal
};
assert!(
ChargeTransactionPayment::<Runtime>::from(0)
.validate(&1, CALL, free_transaction , len)
.is_err()
);
});
}
#[test]
fn signed_ext_length_fee_is_also_updated_per_congestion() {
ExtBuilder::default()
.fees(5, 1, 1)
.balance_factor(10)
.build()
.execute_with(||
{
// all fees should be x1.5
NextFeeMultiplier::put(Fixed64::from_rational(1, 2));
let len = 10;
assert!(
ChargeTransactionPayment::<Runtime>::from(10) // tipped
.pre_dispatch(&1, CALL, info_from_weight(3), len)
.is_ok()
);
assert_eq!(Balances::free_balance(&1), 100 - 10 - (5 + 10 + 3) * 3 / 2);
})
}
}
-7
View File
@@ -383,7 +383,6 @@ mod tests {
type AccountId = u64;
type Lookup = IdentityLookup<Self::AccountId>;
type Header = Header;
type WeightMultiplierUpdate = ();
type Event = ();
type BlockHashCount = BlockHashCount;
type MaximumBlockWeight = MaximumBlockWeight;
@@ -395,23 +394,17 @@ mod tests {
pub const ExistentialDeposit: u64 = 0;
pub const TransferFee: u64 = 0;
pub const CreationFee: u64 = 0;
pub const TransactionBaseFee: u64 = 0;
pub const TransactionByteFee: u64 = 0;
}
impl balances::Trait for Test {
type Balance = u64;
type OnNewAccount = ();
type OnFreeBalanceZero = ();
type Event = ();
type TransactionPayment = ();
type TransferPayment = ();
type DustRemoval = ();
type ExistentialDeposit = ExistentialDeposit;
type TransferFee = TransferFee;
type CreationFee = CreationFee;
type TransactionBaseFee = TransactionBaseFee;
type TransactionByteFee = TransactionByteFee;
type WeightToFee = ();
}
parameter_types! {
pub const ProposalBond: Permill = Permill::from_percent(5);
-7
View File
@@ -99,7 +99,6 @@ mod tests {
type AccountId = u64;
type Lookup = IdentityLookup<Self::AccountId>;
type Header = Header;
type WeightMultiplierUpdate = ();
type Event = ();
type BlockHashCount = BlockHashCount;
type MaximumBlockWeight = MaximumBlockWeight;
@@ -111,23 +110,17 @@ mod tests {
pub const ExistentialDeposit: u64 = 0;
pub const TransferFee: u64 = 0;
pub const CreationFee: u64 = 0;
pub const TransactionBaseFee: u64 = 0;
pub const TransactionByteFee: u64 = 0;
}
impl balances::Trait for Test {
type Balance = u64;
type OnFreeBalanceZero = ();
type OnNewAccount = ();
type Event = ();
type TransactionPayment = ();
type TransferPayment = ();
type DustRemoval = ();
type ExistentialDeposit = ExistentialDeposit;
type TransferFee = TransferFee;
type CreationFee = CreationFee;
type TransactionBaseFee = TransactionBaseFee;
type TransactionByteFee = TransactionByteFee;
type WeightToFee = ();
}
impl Trait for Test {
type Event = ();