Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Transaction Fee Multiplier #2854

Merged
merged 77 commits into from
Jul 19, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
77 commits
Select commit Hold shift + click to select a range
6c14a33
added fee calculations; need some type conversions
4meta5 Jun 12, 2019
20cc3e3
cleaned up make_payment and other stuff
4meta5 Jun 12, 2019
7e6133f
rename vars to compile
4meta5 Jun 13, 2019
3bfa6ee
add WeightToFee type
4meta5 Jun 13, 2019
a79beb2
clean test files after new type added to balances
4meta5 Jun 13, 2019
28bfe18
fmting
4meta5 Jun 13, 2019
8b686df
fix balance configs in tests
4meta5 Jun 13, 2019
a103566
more fixing mocks and tests
4meta5 Jun 13, 2019
5004f68
more comprehensive block weight limit test
4meta5 Jun 13, 2019
25016e5
fix compilation errors
4meta5 Jun 14, 2019
237f00b
more srml/executive tests && started fixing node/executor tests
4meta5 Jun 14, 2019
c473cd5
new fee multiplier; still overflows :(
4meta5 Jun 15, 2019
90501bc
perbill at the end attempt; needs to be changed
4meta5 Jun 15, 2019
838b4da
clean fmting, rename some vars
4meta5 Jun 15, 2019
074bac6
new PoC implementation.
kianenigma Jun 15, 2019
ec2d388
Merge branch 'amar/tx-fee-multiplier' of github.com:paritytech/substr…
kianenigma Jun 15, 2019
dcc8401
test weight_to_fee range and verify functionality
4meta5 Jun 18, 2019
ca81626
12 of 15 tests in node executor are passing
4meta5 Jun 19, 2019
a130696
1 test failing; big_block imports are failing for wrong reasons
4meta5 Jun 19, 2019
d9f4ffa
Update srml/executive/src/lib.rs
4meta5 Jun 22, 2019
6d8f3f0
Some cleanup.
kianenigma Jun 24, 2019
7cd2ceb
consolidate tests in runtime impls
4meta5 Jun 27, 2019
68de4b9
clean and condition executive for stateful fee range test
4meta5 Jun 28, 2019
035cb70
remove comments to self
4meta5 Jun 29, 2019
4ef0384
Major cleanup.
kianenigma Jul 1, 2019
83abfb7
Master.into() + Fix tests.
kianenigma Jul 2, 2019
e931f03
More cleanup.
kianenigma Jul 2, 2019
74e0dd1
Merge branch 'master' of github.com:paritytech/substrate into amar/tx…
kianenigma Jul 2, 2019
1297445
Fix lock files.
kianenigma Jul 2, 2019
7ad863d
Master.into()
kianenigma Jul 2, 2019
57691da
Fix build.
kianenigma Jul 2, 2019
197c703
Update node-template/runtime/Cargo.toml
4meta5 Jul 2, 2019
da9174a
Update node/executor/src/lib.rs
4meta5 Jul 2, 2019
db1bfd6
Update node/executor/src/lib.rs
4meta5 Jul 2, 2019
af39f71
Update node/executor/src/lib.rs
4meta5 Jul 2, 2019
d98232b
Update node/executor/src/lib.rs
4meta5 Jul 2, 2019
f4ce8cb
Update node/executor/src/lib.rs
4meta5 Jul 2, 2019
c5fedee
Update node/executor/src/lib.rs
4meta5 Jul 2, 2019
6bf8c1f
Per-block update.
kianenigma Jul 2, 2019
bd9b8ad
Master.into() + Fix tests.
kianenigma Jul 2, 2019
79a29c2
nit.
kianenigma Jul 2, 2019
69f391f
Update docs.
kianenigma Jul 2, 2019
c25a910
Fix contracts test.
kianenigma Jul 2, 2019
24aea1d
Stateful fee update.
kianenigma Jul 3, 2019
1578763
Master.into()
kianenigma Jul 3, 2019
480ce73
Update lock files.
kianenigma Jul 3, 2019
a7ad634
Update node/runtime/src/impls.rs
4meta5 Jul 4, 2019
75ddb98
Revamped again with fixed64.
kianenigma Jul 5, 2019
5f88b16
Merge branch 'amar/tx-fee-multiplier' of github.com:paritytech/substr…
kianenigma Jul 5, 2019
1a6033c
Master.into()
kianenigma Jul 5, 2019
6d93145
fix cargo file.
kianenigma Jul 5, 2019
3f0f30d
nits.
kianenigma Jul 5, 2019
e6db494
Some cleanup.
kianenigma Jul 6, 2019
212b666
Some nits.
kianenigma Jul 9, 2019
e00f353
Master.into()
kianenigma Jul 9, 2019
a26b8c0
Fix build.
kianenigma Jul 9, 2019
d66ff3e
Bump.
kianenigma Jul 9, 2019
e5cec3f
Rename to WeightMultiplier
kianenigma Jul 10, 2019
96aa67c
Master.into()
kianenigma Jul 10, 2019
1c07451
Update node/executor/src/lib.rs
kianenigma Jul 10, 2019
034129c
Add weight to election module mock.
kianenigma Jul 10, 2019
0f011f5
Merge branch 'amar/tx-fee-multiplier' of github.com:paritytech/substr…
kianenigma Jul 10, 2019
d0a23a2
Fix build.
kianenigma Jul 10, 2019
a94d0a3
Master.into()
kianenigma Jul 10, 2019
99bd89c
finalize merge
kianenigma Jul 10, 2019
3b29928
Update srml/system/src/lib.rs
gavofyork Jul 15, 2019
f37c690
Master.into()
kianenigma Jul 16, 2019
3e03fb3
Merge branch 'amar/tx-fee-multiplier' of github.com:paritytech/substr…
kianenigma Jul 16, 2019
73c1ad8
Bring back fees.
kianenigma Jul 16, 2019
7d21fca
Some nits.
kianenigma Jul 16, 2019
af14c50
Master.into()
kianenigma Jul 17, 2019
cb54a82
Code shifting for simplicity.
kianenigma Jul 19, 2019
257d791
Fix build + more tests.
kianenigma Jul 19, 2019
cc72a6e
Update weights.rs
gavofyork Jul 19, 2019
79aa423
Update core/sr-primitives/src/weights.rs
gavofyork Jul 19, 2019
394157d
Update lib.rs
gavofyork Jul 19, 2019
40ef12b
Fix test build
kianenigma Jul 19, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
161 changes: 142 additions & 19 deletions core/sr-primitives/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand All @@ -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;
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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()))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't checked_div be used here to avoid divide by zero issue?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.max(0)

}

/// 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 {
gavofyork marked this conversation as resolved.
Show resolved Hide resolved
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)]
Expand Down Expand Up @@ -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) => {
Expand Down Expand Up @@ -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));
}
}

Expand All @@ -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]
Expand All @@ -850,20 +973,20 @@ 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]
fn per_things_one_minus_one_part() {
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()
);
}
Expand Down
92 changes: 86 additions & 6 deletions core/sr-primitives/src/weights.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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!`.
///
Expand Down Expand Up @@ -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 {
gavofyork marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should just be called multiply_accumulate and moved into Fixed64.

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); });
}
}
4 changes: 2 additions & 2 deletions node-template/runtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ indices = { package = "srml-indices", path = "../../srml/indices", default_featu
system = { package = "srml-system", path = "../../srml/system", default_features = false }
timestamp = { package = "srml-timestamp", path = "../../srml/timestamp", default_features = false }
sudo = { package = "srml-sudo", path = "../../srml/sudo", default_features = false }
runtime-primitives = { package = "sr-primitives", path = "../../core/sr-primitives", default_features = false }
sr-primitives = { path = "../../core/sr-primitives", default_features = false }
client = { package = "substrate-client", path = "../../core/client", default_features = false }
consensus-aura = { package = "substrate-consensus-aura-primitives", path = "../../core/consensus/aura/primitives", default_features = false }
offchain-primitives = { package = "substrate-offchain-primitives", path = "../../core/offchain/primitives", default-features = false }
Expand All @@ -41,7 +41,7 @@ std = [
"aura/std",
"indices/std",
"primitives/std",
"runtime-primitives/std",
"sr-primitives/std",
"system/std",
"timestamp/std",
"sudo/std",
Expand Down
Loading