@@ -30,7 +30,7 @@ use scale_info::TypeInfo;
3030use serde:: { Deserialize , Serialize } ;
3131use smallvec:: SmallVec ;
3232use sp_arithmetic:: {
33- traits:: { BaseArithmetic , SaturatedConversion , Saturating , Unsigned } ,
33+ traits:: { BaseArithmetic , SaturatedConversion , Unsigned } ,
3434 Perbill ,
3535} ;
3636use 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.
122152pub 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.
125193pub 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
0 commit comments