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

Commit afa5830

Browse files
4meta5kianenigma
authored andcommitted
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 <[email protected]> * 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 <[email protected]> * Update node/executor/src/lib.rs Co-Authored-By: Gavin Wood <[email protected]> * Update node/executor/src/lib.rs Co-Authored-By: Gavin Wood <[email protected]> * Update node/executor/src/lib.rs Co-Authored-By: Gavin Wood <[email protected]> * Update node/executor/src/lib.rs Co-Authored-By: Gavin Wood <[email protected]> * Update node/executor/src/lib.rs Co-Authored-By: Gavin Wood <[email protected]> * Update node/executor/src/lib.rs Co-Authored-By: Gavin Wood <[email protected]> * 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 <[email protected]> * 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
1 parent 77d0cb2 commit afa5830

File tree

36 files changed

+1103
-411
lines changed

36 files changed

+1103
-411
lines changed

core/sr-primitives/src/lib.rs

Lines changed: 142 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ pub use paste;
3434
#[cfg(feature = "std")]
3535
pub use runtime_io::{StorageOverlay, ChildrenStorageOverlay};
3636

37-
use rstd::{prelude::*, ops};
37+
use rstd::{prelude::*, ops, convert::TryInto};
3838
use substrate_primitives::{crypto, ed25519, sr25519, hash::{H256, H512}};
3939
use codec::{Encode, Decode};
4040

@@ -43,7 +43,7 @@ pub mod testing;
4343

4444
pub mod weights;
4545
pub mod traits;
46-
use traits::{SaturatedConversion, UniqueSaturatedInto};
46+
use traits::{SaturatedConversion, UniqueSaturatedInto, Saturating, Bounded, CheckedSub, CheckedAdd};
4747

4848
pub mod generic;
4949
pub mod transaction_validity;
@@ -168,7 +168,7 @@ impl BuildStorage for (StorageOverlay, ChildrenStorageOverlay) {
168168
pub type ConsensusEngineId = [u8; 4];
169169

170170
/// Permill is parts-per-million (i.e. after multiplying by this, divide by 1000000).
171-
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
171+
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug, Ord, PartialOrd))]
172172
#[derive(Encode, Decode, Default, Copy, Clone, PartialEq, Eq)]
173173
pub struct Permill(u32);
174174

@@ -273,7 +273,7 @@ impl From<codec::Compact<Permill>> for Permill {
273273
/// Perbill is parts-per-billion. It stores a value between 0 and 1 in fixed point and
274274
/// provides a means to multiply some other value by that.
275275
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
276-
#[derive(Encode, Decode, Default, Copy, Clone, PartialEq, Eq)]
276+
#[derive(Encode, Decode, Default, Copy, Clone, PartialEq, Eq, Ord, PartialOrd)]
277277
pub struct Perbill(u32);
278278

279279
impl Perbill {
@@ -377,6 +377,128 @@ impl From<codec::Compact<Perbill>> for Perbill {
377377
}
378378
}
379379

380+
381+
/// A fixed point number by the scale of 1 billion.
382+
///
383+
/// cannot hold a value larger than +-`9223372036854775807 / 1_000_000_000` (~9 billion).
384+
#[cfg_attr(feature = "std", derive(Debug))]
385+
#[derive(Encode, Decode, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
386+
pub struct Fixed64(i64);
387+
388+
/// The maximum value of the `Fixed64` type
389+
const DIV: i64 = 1_000_000_000;
390+
391+
impl Fixed64 {
392+
/// creates self from a natural number.
393+
///
394+
/// Note that this might be lossy.
395+
pub fn from_natural(int: i64) -> Self {
396+
Self(int.saturating_mul(DIV))
397+
}
398+
399+
/// Return the accuracy of the type. Given that this function returns the value `X`, it means
400+
/// that an instance composed of `X` parts (`Fixed64::from_parts(X)`) is equal to `1`.
401+
pub fn accuracy() -> i64 {
402+
DIV
403+
}
404+
405+
/// creates self from a rational number. Equal to `n/d`.
406+
///
407+
/// Note that this might be lossy.
408+
pub fn from_rational(n: i64, d: u64) -> Self {
409+
Self((n as i128 * DIV as i128 / (d as i128).max(1)).try_into().unwrap_or(Bounded::max_value()))
410+
}
411+
412+
/// Performs a saturated multiply and accumulate.
413+
///
414+
/// Returns `n + (self * n)`.
415+
pub fn saturated_multiply_accumulate(&self, int: u32) -> u32 {
416+
let parts = self.0;
417+
418+
let positive = parts > 0;
419+
// natural parts might overflow.
420+
let natural_parts = self.clone().saturated_into::<u32>();
421+
// fractional parts can always fit into u32.
422+
let perbill_parts = (parts.abs() % DIV) as u32;
423+
424+
let n = int.saturating_mul(natural_parts);
425+
let p = Perbill::from_parts(perbill_parts) * int;
426+
// everything that needs to be either added or subtracted from the original weight.
427+
let excess = n.saturating_add(p);
428+
429+
if positive {
430+
int.saturating_add(excess)
431+
} else {
432+
int.saturating_sub(excess)
433+
}
434+
}
435+
436+
/// Raw constructor. Equal to `parts / 1_000_000_000`.
437+
pub fn from_parts(parts: i64) -> Self {
438+
Self(parts)
439+
}
440+
}
441+
442+
impl UniqueSaturatedInto<u32> for Fixed64 {
443+
/// Note that the maximum value of Fixed64 might be more than what can fit in u32. This is hence,
444+
/// expected to be lossy.
445+
fn unique_saturated_into(self) -> u32 {
446+
(self.0.abs() / DIV).try_into().unwrap_or(Bounded::max_value())
447+
}
448+
}
449+
450+
impl Saturating for Fixed64 {
451+
fn saturating_add(self, rhs: Self) -> Self {
452+
Self(self.0.saturating_add(rhs.0))
453+
}
454+
fn saturating_mul(self, rhs: Self) -> Self {
455+
Self(self.0.saturating_mul(rhs.0) / DIV)
456+
}
457+
fn saturating_sub(self, rhs: Self) -> Self {
458+
Self(self.0.saturating_sub(rhs.0))
459+
}
460+
}
461+
462+
/// Note that this is a standard, _potentially-panicking_, implementation. Use `Saturating` trait for
463+
/// safe addition.
464+
impl ops::Add for Fixed64 {
465+
type Output = Self;
466+
467+
fn add(self, rhs: Self) -> Self::Output {
468+
Self(self.0 + rhs.0)
469+
}
470+
}
471+
472+
/// Note that this is a standard, _potentially-panicking_, implementation. Use `Saturating` trait for
473+
/// safe subtraction.
474+
impl ops::Sub for Fixed64 {
475+
type Output = Self;
476+
477+
fn sub(self, rhs: Self) -> Self::Output {
478+
Self(self.0 - rhs.0)
479+
}
480+
}
481+
482+
impl CheckedSub for Fixed64 {
483+
fn checked_sub(&self, rhs: &Self) -> Option<Self> {
484+
if let Some(v) = self.0.checked_sub(rhs.0) {
485+
Some(Self(v))
486+
} else {
487+
None
488+
}
489+
}
490+
}
491+
492+
impl CheckedAdd for Fixed64 {
493+
fn checked_add(&self, rhs: &Self) -> Option<Self> {
494+
if let Some(v) = self.0.checked_add(rhs.0) {
495+
Some(Self(v))
496+
} else {
497+
None
498+
}
499+
}
500+
}
501+
380502
/// PerU128 is parts-per-u128-max-value. It stores a value between 0 and 1 in fixed point.
381503
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
382504
#[derive(Encode, Decode, Default, Copy, Clone, PartialEq, Eq)]
@@ -755,6 +877,7 @@ impl traits::Extrinsic for OpaqueExtrinsic {
755877
#[cfg(test)]
756878
mod tests {
757879
use crate::codec::{Encode, Decode};
880+
use super::{Perbill, Permill};
758881

759882
macro_rules! per_thing_upper_test {
760883
($num_type:tt, $per:tt) => {
@@ -798,19 +921,19 @@ mod tests {
798921
fn compact_permill_perbill_encoding() {
799922
let tests = [(0u32, 1usize), (63, 1), (64, 2), (16383, 2), (16384, 4), (1073741823, 4), (1073741824, 5), (u32::max_value(), 5)];
800923
for &(n, l) in &tests {
801-
let compact: crate::codec::Compact<super::Permill> = super::Permill(n).into();
924+
let compact: crate::codec::Compact<Permill> = Permill(n).into();
802925
let encoded = compact.encode();
803926
assert_eq!(encoded.len(), l);
804-
let decoded = <crate::codec::Compact<super::Permill>>::decode(&mut & encoded[..]).unwrap();
805-
let permill: super::Permill = decoded.into();
806-
assert_eq!(permill, super::Permill(n));
927+
let decoded = <crate::codec::Compact<Permill>>::decode(&mut & encoded[..]).unwrap();
928+
let permill: Permill = decoded.into();
929+
assert_eq!(permill, Permill(n));
807930

808-
let compact: crate::codec::Compact<super::Perbill> = super::Perbill(n).into();
931+
let compact: crate::codec::Compact<Perbill> = Perbill(n).into();
809932
let encoded = compact.encode();
810933
assert_eq!(encoded.len(), l);
811-
let decoded = <crate::codec::Compact<super::Perbill>>::decode(&mut & encoded[..]).unwrap();
812-
let perbill: super::Perbill = decoded.into();
813-
assert_eq!(perbill, super::Perbill(n));
934+
let decoded = <crate::codec::Compact<Perbill>>::decode(&mut & encoded[..]).unwrap();
935+
let perbill: Perbill = decoded.into();
936+
assert_eq!(perbill, Perbill(n));
814937
}
815938
}
816939

@@ -821,16 +944,16 @@ mod tests {
821944

822945
#[test]
823946
fn test_has_compact_permill() {
824-
let data = WithCompact { data: super::Permill(1) };
947+
let data = WithCompact { data: Permill(1) };
825948
let encoded = data.encode();
826-
assert_eq!(data, WithCompact::<super::Permill>::decode(&mut &encoded[..]).unwrap());
949+
assert_eq!(data, WithCompact::<Permill>::decode(&mut &encoded[..]).unwrap());
827950
}
828951

829952
#[test]
830953
fn test_has_compact_perbill() {
831-
let data = WithCompact { data: super::Perbill(1) };
954+
let data = WithCompact { data: Perbill(1) };
832955
let encoded = data.encode();
833-
assert_eq!(data, WithCompact::<super::Perbill>::decode(&mut &encoded[..]).unwrap());
956+
assert_eq!(data, WithCompact::<Perbill>::decode(&mut &encoded[..]).unwrap());
834957
}
835958

836959
#[test]
@@ -850,20 +973,20 @@ mod tests {
850973

851974
#[test]
852975
fn per_things_operate_in_output_type() {
853-
assert_eq!(super::Perbill::one() * 255_u64, 255);
976+
assert_eq!(Perbill::one() * 255_u64, 255);
854977
}
855978

856979
#[test]
857980
fn per_things_one_minus_one_part() {
858981
use primitive_types::U256;
859982

860983
assert_eq!(
861-
super::Perbill::from_parts(999_999_999) * std::u128::MAX,
984+
Perbill::from_parts(999_999_999) * std::u128::MAX,
862985
((Into::<U256>::into(std::u128::MAX) * 999_999_999u32) / 1_000_000_000u32).as_u128()
863986
);
864987

865988
assert_eq!(
866-
super::Permill::from_parts(999_999) * std::u128::MAX,
989+
Permill::from_parts(999_999) * std::u128::MAX,
867990
((Into::<U256>::into(std::u128::MAX) * 999_999u32) / 1_000_000u32).as_u128()
868991
);
869992
}

core/sr-primitives/src/weights.rs

Lines changed: 86 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,25 @@
1616

1717
//! Primitives for transaction weighting.
1818
//!
19-
//! Each dispatch function within `decl_module!` can now have an optional
20-
//! `#[weight = $x]` attribute. $x can be any object that implements the
21-
//! `Weighable` trait. By default, All transactions are annotated by
22-
//! `#[weight = TransactionWeight::default()]`.
19+
//! Each dispatch function within `decl_module!` can have an optional `#[weight = $x]` attribute.
20+
//! $x can be any object that implements the `Weighable` trait. By default, All transactions are
21+
//! annotated by `#[weight = TransactionWeight::default()]`.
2322
//!
24-
//! Note that the decl_module macro _cannot_ enforce this and will simply fail
25-
//! if an invalid struct is passed in.
23+
//! Note that the decl_module macro _cannot_ enforce this and will simply fail if an invalid struct
24+
//! (something that does not implement `Weighable`) is passed in.
25+
26+
use crate::{Fixed64, traits::Saturating};
27+
use crate::codec::{Encode, Decode};
2628

2729
/// The final type that each `#[weight = $x:expr]`'s
2830
/// expression must evaluate to.
2931
pub type Weight = u32;
3032

33+
/// Maximum block saturation: 4mb
34+
pub const MAX_TRANSACTIONS_WEIGHT: u32 = 4 * 1024 * 1024;
35+
/// Target block saturation: 25% of max block saturation = 1mb
36+
pub const IDEAL_TRANSACTIONS_WEIGHT: u32 = MAX_TRANSACTIONS_WEIGHT / 4;
37+
3138
/// A `Call` enum (aka transaction) that can be weighted using the custom weight attribute of
3239
/// its dispatchable functions. Is implemented by default in the `decl_module!`.
3340
///
@@ -74,3 +81,76 @@ impl Default for TransactionWeight {
7481
TransactionWeight::Basic(0, 1)
7582
}
7683
}
84+
85+
/// Representation of a weight multiplier. This represents how a fee value can be computed from a
86+
/// weighted transaction.
87+
///
88+
/// This is basically a wrapper for the `Fixed64` type a slightly tailored multiplication to u32
89+
/// in the form of the `apply_to` method.
90+
#[cfg_attr(feature = "std", derive(Debug))]
91+
#[derive(Encode, Decode, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
92+
pub struct WeightMultiplier(Fixed64);
93+
94+
impl WeightMultiplier {
95+
/// Apply the inner Fixed64 as a weight multiplier to a weight value.
96+
///
97+
/// This will perform a saturated `weight + weight * self.0`.
98+
pub fn apply_to(&self, weight: Weight) -> Weight {
99+
self.0.saturated_multiply_accumulate(weight)
100+
}
101+
102+
/// build self from raw parts per billion.
103+
#[cfg(feature = "std")]
104+
pub fn from_parts(parts: i64) -> Self {
105+
Self(Fixed64(parts))
106+
}
107+
108+
/// build self from a fixed64 value.
109+
pub fn from_fixed(f: Fixed64) -> Self {
110+
Self(f)
111+
}
112+
113+
/// Approximate the fraction `n/d`.
114+
pub fn from_rational(n: i64, d: u64) -> Self {
115+
Self(Fixed64::from_rational(n, d))
116+
}
117+
}
118+
119+
impl Saturating for WeightMultiplier {
120+
fn saturating_add(self, rhs: Self) -> Self {
121+
Self(self.0.saturating_add(rhs.0))
122+
}
123+
fn saturating_mul(self, rhs: Self) -> Self {
124+
Self(self.0.saturating_mul(rhs.0))
125+
126+
}
127+
fn saturating_sub(self, rhs: Self) -> Self {
128+
Self(self.0.saturating_sub(rhs.0))
129+
}
130+
}
131+
132+
#[cfg(test)]
133+
mod tests {
134+
use super::*;
135+
136+
#[test]
137+
fn multiplier_apply_to_works() {
138+
let test_set = vec![0, 1, 10, 1000, 1_000_000_000];
139+
140+
// negative (1/2)
141+
let mut fm = WeightMultiplier::from_rational(-1, 2);
142+
test_set.clone().into_iter().for_each(|i| { assert_eq!(fm.apply_to(i) as i32, i as i32 - i as i32 / 2); });
143+
144+
// unit (1) multiplier
145+
fm = WeightMultiplier::from_parts(0);
146+
test_set.clone().into_iter().for_each(|i| { assert_eq!(fm.apply_to(i), i); });
147+
148+
// i.5 multiplier
149+
fm = WeightMultiplier::from_rational(1, 2);
150+
test_set.clone().into_iter().for_each(|i| { assert_eq!(fm.apply_to(i), i * 3 / 2); });
151+
152+
// dual multiplier
153+
fm = WeightMultiplier::from_rational(1, 1);
154+
test_set.clone().into_iter().for_each(|i| { assert_eq!(fm.apply_to(i), i * 2); });
155+
}
156+
}

node-template/runtime/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ indices = { package = "srml-indices", path = "../../srml/indices", default_featu
2020
system = { package = "srml-system", path = "../../srml/system", default_features = false }
2121
timestamp = { package = "srml-timestamp", path = "../../srml/timestamp", default_features = false }
2222
sudo = { package = "srml-sudo", path = "../../srml/sudo", default_features = false }
23-
runtime-primitives = { package = "sr-primitives", path = "../../core/sr-primitives", default_features = false }
23+
sr-primitives = { path = "../../core/sr-primitives", default_features = false }
2424
client = { package = "substrate-client", path = "../../core/client", default_features = false }
2525
consensus-aura = { package = "substrate-consensus-aura-primitives", path = "../../core/consensus/aura/primitives", default_features = false }
2626
offchain-primitives = { package = "substrate-offchain-primitives", path = "../../core/offchain/primitives", default-features = false }
@@ -41,7 +41,7 @@ std = [
4141
"aura/std",
4242
"indices/std",
4343
"primitives/std",
44-
"runtime-primitives/std",
44+
"sr-primitives/std",
4545
"system/std",
4646
"timestamp/std",
4747
"sudo/std",

0 commit comments

Comments
 (0)