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

Commit 8b5306e

Browse files
authored
Add dedicated FeePolynomial struct (#13612)
* Add FeePolynomial struct Signed-off-by: Oliver Tale-Yazdi <[email protected]> * Add Weight::without_{ref_time, proof_size} Signed-off-by: Oliver Tale-Yazdi <[email protected]> * Docs Signed-off-by: Oliver Tale-Yazdi <[email protected]> * Cleanup code Signed-off-by: Oliver Tale-Yazdi <[email protected]> * Add docs Signed-off-by: Oliver Tale-Yazdi <[email protected]> * doc Signed-off-by: Oliver Tale-Yazdi <[email protected]> * Fix docs Signed-off-by: Oliver Tale-Yazdi <[email protected]> * docs Signed-off-by: Oliver Tale-Yazdi <[email protected]> --------- Signed-off-by: Oliver Tale-Yazdi <[email protected]>
1 parent 36ed840 commit 8b5306e

File tree

2 files changed

+82
-23
lines changed

2 files changed

+82
-23
lines changed

primitives/weights/src/lib.rs

Lines changed: 72 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ use scale_info::TypeInfo;
3030
use serde::{Deserialize, Serialize};
3131
use smallvec::SmallVec;
3232
use sp_arithmetic::{
33-
traits::{BaseArithmetic, SaturatedConversion, Saturating, Unsigned},
33+
traits::{BaseArithmetic, SaturatedConversion, Unsigned},
3434
Perbill,
3535
};
3636
use sp_core::Get;
@@ -118,9 +118,77 @@ pub struct WeightToFeeCoefficient<Balance> {
118118
pub degree: u8,
119119
}
120120

121-
/// A list of coefficients that represent one polynomial.
121+
impl<Balance> WeightToFeeCoefficient<Balance>
122+
where
123+
Balance: BaseArithmetic + From<u32> + Copy + Unsigned,
124+
{
125+
/// Evaluate the term at `x` and saturatingly amalgamate into `result`.
126+
///
127+
/// The unsigned value for the term is calculated as:
128+
/// ```ignore
129+
/// (frac * x^(degree) + integer * x^(degree))
130+
/// ```
131+
/// Depending on the value of `negative`, it is added or subtracted from the `result`.
132+
pub fn saturating_eval(&self, mut result: Balance, x: Balance) -> Balance {
133+
let power = x.saturating_pow(self.degree.into());
134+
135+
let frac = self.coeff_frac * power; // Overflow safe.
136+
let integer = self.coeff_integer.saturating_mul(power);
137+
// Do not add them together here to avoid an underflow.
138+
139+
if self.negative {
140+
result = result.saturating_sub(frac);
141+
result = result.saturating_sub(integer);
142+
} else {
143+
result = result.saturating_add(frac);
144+
result = result.saturating_add(integer);
145+
}
146+
147+
result
148+
}
149+
}
150+
151+
/// A list of coefficients that represent a polynomial.
122152
pub type WeightToFeeCoefficients<T> = SmallVec<[WeightToFeeCoefficient<T>; 4]>;
123153

154+
/// A list of coefficients that represent a polynomial.
155+
///
156+
/// Can be [eval](Self::eval)uated at a specific `u64` to get the fee. The evaluations happens by
157+
/// summing up all term [results](`WeightToFeeCoefficient::saturating_eval`). The order of the
158+
/// coefficients matters since it uses saturating arithmetic. This struct does therefore not model a
159+
/// polynomial in the mathematical sense (polynomial ring).
160+
///
161+
/// For visualization purposes, the formulas of the unsigned terms look like:
162+
///
163+
/// ```ignore
164+
/// (c[0].frac * x^(c[0].degree) + c[0].integer * x^(c[0].degree))
165+
/// (c[1].frac * x^(c[1].degree) + c[1].integer * x^(c[1].degree))
166+
/// ...
167+
/// ```
168+
/// Depending on the value of `c[i].negative`, each term is added or subtracted from the result.
169+
/// The result is initialized as zero.
170+
pub struct FeePolynomial<Balance> {
171+
coefficients: SmallVec<[WeightToFeeCoefficient<Balance>; 4]>,
172+
}
173+
174+
impl<Balance> From<WeightToFeeCoefficients<Balance>> for FeePolynomial<Balance> {
175+
fn from(coefficients: WeightToFeeCoefficients<Balance>) -> Self {
176+
Self { coefficients }
177+
}
178+
}
179+
180+
impl<Balance> FeePolynomial<Balance>
181+
where
182+
Balance: BaseArithmetic + From<u32> + Copy + Unsigned,
183+
{
184+
/// Evaluate the polynomial at a specific `x`.
185+
pub fn eval(&self, x: u64) -> Balance {
186+
self.coefficients.iter().fold(Balance::zero(), |acc, term| {
187+
term.saturating_eval(acc, Balance::saturated_from(x))
188+
})
189+
}
190+
}
191+
124192
/// A trait that describes the weight to fee calculation.
125193
pub trait WeightToFee {
126194
/// The type that is returned as result from calculation.
@@ -157,27 +225,8 @@ where
157225
/// This should not be overridden in most circumstances. Calculation is done in the
158226
/// `Balance` type and never overflows. All evaluation is saturating.
159227
fn weight_to_fee(weight: &Weight) -> Self::Balance {
160-
Self::polynomial()
161-
.iter()
162-
.fold(Self::Balance::saturated_from(0u32), |mut acc, args| {
163-
let w = Self::Balance::saturated_from(weight.ref_time())
164-
.saturating_pow(args.degree.into());
165-
166-
// The sum could get negative. Therefore we only sum with the accumulator.
167-
// The Perbill Mul implementation is non overflowing.
168-
let frac = args.coeff_frac * w;
169-
let integer = args.coeff_integer.saturating_mul(w);
170-
171-
if args.negative {
172-
acc = acc.saturating_sub(frac);
173-
acc = acc.saturating_sub(integer);
174-
} else {
175-
acc = acc.saturating_add(frac);
176-
acc = acc.saturating_add(integer);
177-
}
178-
179-
acc
180-
})
228+
let poly: FeePolynomial<Self::Balance> = Self::polynomial().into();
229+
poly.eval(weight.ref_time())
181230
}
182231
}
183232

primitives/weights/src/weight_v2.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,16 @@ impl Weight {
7474
&mut self.proof_size
7575
}
7676

77+
/// Return self but discard any reference time.
78+
pub const fn without_ref_time(&self) -> Self {
79+
Self { ref_time: 0, proof_size: self.proof_size }
80+
}
81+
82+
/// Return self but discard any proof size.
83+
pub const fn without_proof_size(&self) -> Self {
84+
Self { ref_time: self.ref_time, proof_size: 0 }
85+
}
86+
7787
pub const MAX: Self = Self { ref_time: u64::MAX, proof_size: u64::MAX };
7888

7989
/// Get the conservative min of `self` and `other` weight.

0 commit comments

Comments
 (0)