mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-13 03:31:10 +00:00
Transaction Fee Multiplier (#2854)
* added fee calculations; need some type conversions * cleaned up make_payment and other stuff * rename vars to compile * add WeightToFee type * clean test files after new type added to balances * fmting * fix balance configs in tests * more fixing mocks and tests * more comprehensive block weight limit test * fix compilation errors * more srml/executive tests && started fixing node/executor tests * new fee multiplier; still overflows :( * perbill at the end attempt; needs to be changed * clean fmting, rename some vars * new PoC implementation. * test weight_to_fee range and verify functionality * 12 of 15 tests in node executor are passing * 1 test failing; big_block imports are failing for wrong reasons * Update srml/executive/src/lib.rs Co-Authored-By: Kian Peymani <Kianenigma@users.noreply.github.com> * Some cleanup. * consolidate tests in runtime impls * clean and condition executive for stateful fee range test * remove comments to self * Major cleanup. * More cleanup. * Fix lock files. * Fix build. * Update node-template/runtime/Cargo.toml Co-Authored-By: Gavin Wood <github@gavwood.com> * Update node/executor/src/lib.rs Co-Authored-By: Gavin Wood <github@gavwood.com> * Update node/executor/src/lib.rs Co-Authored-By: Gavin Wood <github@gavwood.com> * Update node/executor/src/lib.rs Co-Authored-By: Gavin Wood <github@gavwood.com> * Update node/executor/src/lib.rs Co-Authored-By: Gavin Wood <github@gavwood.com> * Update node/executor/src/lib.rs Co-Authored-By: Gavin Wood <github@gavwood.com> * Update node/executor/src/lib.rs Co-Authored-By: Gavin Wood <github@gavwood.com> * Per-block update. * nit. * Update docs. * Fix contracts test. * Stateful fee update. * Update lock files. * Update node/runtime/src/impls.rs * Revamped again with fixed64. * fix cargo file. * nits. * Some cleanup. * Some nits. * Fix build. * Bump. * Rename to WeightMultiplier * Update node/executor/src/lib.rs Co-Authored-By: Tomasz Drwięga <tomusdrw@users.noreply.github.com> * Add weight to election module mock. * Fix build. * finalize merge * Update srml/system/src/lib.rs * Bring back fees. * Some nits. * Code shifting for simplicity. * Fix build + more tests. * Update weights.rs * Update core/sr-primitives/src/weights.rs * Update lib.rs * Fix test build
This commit is contained in:
@@ -34,7 +34,7 @@ pub use paste;
|
||||
#[cfg(feature = "std")]
|
||||
pub use runtime_io::{StorageOverlay, ChildrenStorageOverlay};
|
||||
|
||||
use rstd::{prelude::*, ops};
|
||||
use rstd::{prelude::*, ops, convert::TryInto};
|
||||
use substrate_primitives::{crypto, ed25519, sr25519, hash::{H256, H512}};
|
||||
use codec::{Encode, Decode};
|
||||
|
||||
@@ -43,7 +43,7 @@ pub mod testing;
|
||||
|
||||
pub mod weights;
|
||||
pub mod traits;
|
||||
use traits::{SaturatedConversion, UniqueSaturatedInto};
|
||||
use traits::{SaturatedConversion, UniqueSaturatedInto, Saturating, Bounded, CheckedSub, CheckedAdd};
|
||||
|
||||
pub mod generic;
|
||||
pub mod transaction_validity;
|
||||
@@ -168,7 +168,7 @@ impl BuildStorage for (StorageOverlay, ChildrenStorageOverlay) {
|
||||
pub type ConsensusEngineId = [u8; 4];
|
||||
|
||||
/// Permill is parts-per-million (i.e. after multiplying by this, divide by 1000000).
|
||||
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
|
||||
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug, Ord, PartialOrd))]
|
||||
#[derive(Encode, Decode, Default, Copy, Clone, PartialEq, Eq)]
|
||||
pub struct Permill(u32);
|
||||
|
||||
@@ -273,7 +273,7 @@ impl From<codec::Compact<Permill>> for Permill {
|
||||
/// Perbill is parts-per-billion. It stores a value between 0 and 1 in fixed point and
|
||||
/// provides a means to multiply some other value by that.
|
||||
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
|
||||
#[derive(Encode, Decode, Default, Copy, Clone, PartialEq, Eq)]
|
||||
#[derive(Encode, Decode, Default, Copy, Clone, PartialEq, Eq, Ord, PartialOrd)]
|
||||
pub struct Perbill(u32);
|
||||
|
||||
impl Perbill {
|
||||
@@ -377,6 +377,128 @@ impl From<codec::Compact<Perbill>> for Perbill {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// A fixed point number by the scale of 1 billion.
|
||||
///
|
||||
/// cannot hold a value larger than +-`9223372036854775807 / 1_000_000_000` (~9 billion).
|
||||
#[cfg_attr(feature = "std", derive(Debug))]
|
||||
#[derive(Encode, Decode, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct Fixed64(i64);
|
||||
|
||||
/// The maximum value of the `Fixed64` type
|
||||
const DIV: i64 = 1_000_000_000;
|
||||
|
||||
impl Fixed64 {
|
||||
/// creates self from a natural number.
|
||||
///
|
||||
/// Note that this might be lossy.
|
||||
pub fn from_natural(int: i64) -> Self {
|
||||
Self(int.saturating_mul(DIV))
|
||||
}
|
||||
|
||||
/// Return the accuracy of the type. Given that this function returns the value `X`, it means
|
||||
/// that an instance composed of `X` parts (`Fixed64::from_parts(X)`) is equal to `1`.
|
||||
pub fn accuracy() -> i64 {
|
||||
DIV
|
||||
}
|
||||
|
||||
/// creates self from a rational number. Equal to `n/d`.
|
||||
///
|
||||
/// Note that this might be lossy.
|
||||
pub fn from_rational(n: i64, d: u64) -> Self {
|
||||
Self((n as i128 * DIV as i128 / (d as i128).max(1)).try_into().unwrap_or(Bounded::max_value()))
|
||||
}
|
||||
|
||||
/// Performs a saturated multiply and accumulate.
|
||||
///
|
||||
/// Returns `n + (self * n)`.
|
||||
pub fn saturated_multiply_accumulate(&self, int: u32) -> u32 {
|
||||
let parts = self.0;
|
||||
|
||||
let positive = parts > 0;
|
||||
// natural parts might overflow.
|
||||
let natural_parts = self.clone().saturated_into::<u32>();
|
||||
// fractional parts can always fit into u32.
|
||||
let perbill_parts = (parts.abs() % DIV) as u32;
|
||||
|
||||
let n = int.saturating_mul(natural_parts);
|
||||
let p = Perbill::from_parts(perbill_parts) * int;
|
||||
// everything that needs to be either added or subtracted from the original weight.
|
||||
let excess = n.saturating_add(p);
|
||||
|
||||
if positive {
|
||||
int.saturating_add(excess)
|
||||
} else {
|
||||
int.saturating_sub(excess)
|
||||
}
|
||||
}
|
||||
|
||||
/// Raw constructor. Equal to `parts / 1_000_000_000`.
|
||||
pub fn from_parts(parts: i64) -> Self {
|
||||
Self(parts)
|
||||
}
|
||||
}
|
||||
|
||||
impl UniqueSaturatedInto<u32> for Fixed64 {
|
||||
/// Note that the maximum value of Fixed64 might be more than what can fit in u32. This is hence,
|
||||
/// expected to be lossy.
|
||||
fn unique_saturated_into(self) -> u32 {
|
||||
(self.0.abs() / DIV).try_into().unwrap_or(Bounded::max_value())
|
||||
}
|
||||
}
|
||||
|
||||
impl Saturating for Fixed64 {
|
||||
fn saturating_add(self, rhs: Self) -> Self {
|
||||
Self(self.0.saturating_add(rhs.0))
|
||||
}
|
||||
fn saturating_mul(self, rhs: Self) -> Self {
|
||||
Self(self.0.saturating_mul(rhs.0) / DIV)
|
||||
}
|
||||
fn saturating_sub(self, rhs: Self) -> Self {
|
||||
Self(self.0.saturating_sub(rhs.0))
|
||||
}
|
||||
}
|
||||
|
||||
/// Note that this is a standard, _potentially-panicking_, implementation. Use `Saturating` trait for
|
||||
/// safe addition.
|
||||
impl ops::Add for Fixed64 {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
Self(self.0 + rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
/// Note that this is a standard, _potentially-panicking_, implementation. Use `Saturating` trait for
|
||||
/// safe subtraction.
|
||||
impl ops::Sub for Fixed64 {
|
||||
type Output = Self;
|
||||
|
||||
fn sub(self, rhs: Self) -> Self::Output {
|
||||
Self(self.0 - rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl CheckedSub for Fixed64 {
|
||||
fn checked_sub(&self, rhs: &Self) -> Option<Self> {
|
||||
if let Some(v) = self.0.checked_sub(rhs.0) {
|
||||
Some(Self(v))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CheckedAdd for Fixed64 {
|
||||
fn checked_add(&self, rhs: &Self) -> Option<Self> {
|
||||
if let Some(v) = self.0.checked_add(rhs.0) {
|
||||
Some(Self(v))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// PerU128 is parts-per-u128-max-value. It stores a value between 0 and 1 in fixed point.
|
||||
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
|
||||
#[derive(Encode, Decode, Default, Copy, Clone, PartialEq, Eq)]
|
||||
@@ -755,6 +877,7 @@ impl traits::Extrinsic for OpaqueExtrinsic {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::codec::{Encode, Decode};
|
||||
use super::{Perbill, Permill};
|
||||
|
||||
macro_rules! per_thing_upper_test {
|
||||
($num_type:tt, $per:tt) => {
|
||||
@@ -798,19 +921,19 @@ mod tests {
|
||||
fn compact_permill_perbill_encoding() {
|
||||
let tests = [(0u32, 1usize), (63, 1), (64, 2), (16383, 2), (16384, 4), (1073741823, 4), (1073741824, 5), (u32::max_value(), 5)];
|
||||
for &(n, l) in &tests {
|
||||
let compact: crate::codec::Compact<super::Permill> = super::Permill(n).into();
|
||||
let compact: crate::codec::Compact<Permill> = Permill(n).into();
|
||||
let encoded = compact.encode();
|
||||
assert_eq!(encoded.len(), l);
|
||||
let decoded = <crate::codec::Compact<super::Permill>>::decode(&mut & encoded[..]).unwrap();
|
||||
let permill: super::Permill = decoded.into();
|
||||
assert_eq!(permill, super::Permill(n));
|
||||
let decoded = <crate::codec::Compact<Permill>>::decode(&mut & encoded[..]).unwrap();
|
||||
let permill: Permill = decoded.into();
|
||||
assert_eq!(permill, Permill(n));
|
||||
|
||||
let compact: crate::codec::Compact<super::Perbill> = super::Perbill(n).into();
|
||||
let compact: crate::codec::Compact<Perbill> = Perbill(n).into();
|
||||
let encoded = compact.encode();
|
||||
assert_eq!(encoded.len(), l);
|
||||
let decoded = <crate::codec::Compact<super::Perbill>>::decode(&mut & encoded[..]).unwrap();
|
||||
let perbill: super::Perbill = decoded.into();
|
||||
assert_eq!(perbill, super::Perbill(n));
|
||||
let decoded = <crate::codec::Compact<Perbill>>::decode(&mut & encoded[..]).unwrap();
|
||||
let perbill: Perbill = decoded.into();
|
||||
assert_eq!(perbill, Perbill(n));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -821,16 +944,16 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_has_compact_permill() {
|
||||
let data = WithCompact { data: super::Permill(1) };
|
||||
let data = WithCompact { data: Permill(1) };
|
||||
let encoded = data.encode();
|
||||
assert_eq!(data, WithCompact::<super::Permill>::decode(&mut &encoded[..]).unwrap());
|
||||
assert_eq!(data, WithCompact::<Permill>::decode(&mut &encoded[..]).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_has_compact_perbill() {
|
||||
let data = WithCompact { data: super::Perbill(1) };
|
||||
let data = WithCompact { data: Perbill(1) };
|
||||
let encoded = data.encode();
|
||||
assert_eq!(data, WithCompact::<super::Perbill>::decode(&mut &encoded[..]).unwrap());
|
||||
assert_eq!(data, WithCompact::<Perbill>::decode(&mut &encoded[..]).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -850,7 +973,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn per_things_operate_in_output_type() {
|
||||
assert_eq!(super::Perbill::one() * 255_u64, 255);
|
||||
assert_eq!(Perbill::one() * 255_u64, 255);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -858,12 +981,12 @@ mod tests {
|
||||
use primitive_types::U256;
|
||||
|
||||
assert_eq!(
|
||||
super::Perbill::from_parts(999_999_999) * std::u128::MAX,
|
||||
Perbill::from_parts(999_999_999) * std::u128::MAX,
|
||||
((Into::<U256>::into(std::u128::MAX) * 999_999_999u32) / 1_000_000_000u32).as_u128()
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
super::Permill::from_parts(999_999) * std::u128::MAX,
|
||||
Permill::from_parts(999_999) * std::u128::MAX,
|
||||
((Into::<U256>::into(std::u128::MAX) * 999_999u32) / 1_000_000u32).as_u128()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -16,18 +16,25 @@
|
||||
|
||||
//! Primitives for transaction weighting.
|
||||
//!
|
||||
//! Each dispatch function within `decl_module!` can now have an optional
|
||||
//! `#[weight = $x]` attribute. $x can be any object that implements the
|
||||
//! `Weighable` trait. By default, All transactions are annotated by
|
||||
//! `#[weight = TransactionWeight::default()]`.
|
||||
//! Each dispatch function within `decl_module!` can have an optional `#[weight = $x]` attribute.
|
||||
//! $x can be any object that implements the `Weighable` trait. By default, All transactions are
|
||||
//! annotated by `#[weight = TransactionWeight::default()]`.
|
||||
//!
|
||||
//! Note that the decl_module macro _cannot_ enforce this and will simply fail
|
||||
//! if an invalid struct is passed in.
|
||||
//! Note that the decl_module macro _cannot_ enforce this and will simply fail if an invalid struct
|
||||
//! (something that does not implement `Weighable`) is passed in.
|
||||
|
||||
use crate::{Fixed64, traits::Saturating};
|
||||
use crate::codec::{Encode, Decode};
|
||||
|
||||
/// The final type that each `#[weight = $x:expr]`'s
|
||||
/// expression must evaluate to.
|
||||
pub type Weight = u32;
|
||||
|
||||
/// Maximum block saturation: 4mb
|
||||
pub const MAX_TRANSACTIONS_WEIGHT: u32 = 4 * 1024 * 1024;
|
||||
/// Target block saturation: 25% of max block saturation = 1mb
|
||||
pub const IDEAL_TRANSACTIONS_WEIGHT: u32 = MAX_TRANSACTIONS_WEIGHT / 4;
|
||||
|
||||
/// A `Call` enum (aka transaction) that can be weighted using the custom weight attribute of
|
||||
/// its dispatchable functions. Is implemented by default in the `decl_module!`.
|
||||
///
|
||||
@@ -74,3 +81,76 @@ impl Default for TransactionWeight {
|
||||
TransactionWeight::Basic(0, 1)
|
||||
}
|
||||
}
|
||||
|
||||
/// Representation of a weight multiplier. This represents how a fee value can be computed from a
|
||||
/// weighted transaction.
|
||||
///
|
||||
/// This is basically a wrapper for the `Fixed64` type a slightly tailored multiplication to u32
|
||||
/// in the form of the `apply_to` method.
|
||||
#[cfg_attr(feature = "std", derive(Debug))]
|
||||
#[derive(Encode, Decode, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct WeightMultiplier(Fixed64);
|
||||
|
||||
impl WeightMultiplier {
|
||||
/// Apply the inner Fixed64 as a weight multiplier to a weight value.
|
||||
///
|
||||
/// This will perform a saturated `weight + weight * self.0`.
|
||||
pub fn apply_to(&self, weight: Weight) -> Weight {
|
||||
self.0.saturated_multiply_accumulate(weight)
|
||||
}
|
||||
|
||||
/// build self from raw parts per billion.
|
||||
#[cfg(feature = "std")]
|
||||
pub fn from_parts(parts: i64) -> Self {
|
||||
Self(Fixed64(parts))
|
||||
}
|
||||
|
||||
/// build self from a fixed64 value.
|
||||
pub fn from_fixed(f: Fixed64) -> Self {
|
||||
Self(f)
|
||||
}
|
||||
|
||||
/// Approximate the fraction `n/d`.
|
||||
pub fn from_rational(n: i64, d: u64) -> Self {
|
||||
Self(Fixed64::from_rational(n, d))
|
||||
}
|
||||
}
|
||||
|
||||
impl Saturating for WeightMultiplier {
|
||||
fn saturating_add(self, rhs: Self) -> Self {
|
||||
Self(self.0.saturating_add(rhs.0))
|
||||
}
|
||||
fn saturating_mul(self, rhs: Self) -> Self {
|
||||
Self(self.0.saturating_mul(rhs.0))
|
||||
|
||||
}
|
||||
fn saturating_sub(self, rhs: Self) -> Self {
|
||||
Self(self.0.saturating_sub(rhs.0))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn multiplier_apply_to_works() {
|
||||
let test_set = vec![0, 1, 10, 1000, 1_000_000_000];
|
||||
|
||||
// negative (1/2)
|
||||
let mut fm = WeightMultiplier::from_rational(-1, 2);
|
||||
test_set.clone().into_iter().for_each(|i| { assert_eq!(fm.apply_to(i) as i32, i as i32 - i as i32 / 2); });
|
||||
|
||||
// unit (1) multiplier
|
||||
fm = WeightMultiplier::from_parts(0);
|
||||
test_set.clone().into_iter().for_each(|i| { assert_eq!(fm.apply_to(i), i); });
|
||||
|
||||
// i.5 multiplier
|
||||
fm = WeightMultiplier::from_rational(1, 2);
|
||||
test_set.clone().into_iter().for_each(|i| { assert_eq!(fm.apply_to(i), i * 3 / 2); });
|
||||
|
||||
// dual multiplier
|
||||
fm = WeightMultiplier::from_rational(1, 1);
|
||||
test_set.clone().into_iter().for_each(|i| { assert_eq!(fm.apply_to(i), i * 2); });
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user