1#![cfg_attr(not(feature = "std"), no_std)]
21
22extern crate self as sp_weights;
23
24mod weight_meter;
25mod weight_v2;
26
27use bounded_collections::Get;
28use codec::{Decode, Encode};
29use scale_info::TypeInfo;
30#[cfg(feature = "serde")]
31use serde::{Deserialize, Serialize};
32use smallvec::SmallVec;
33use sp_arithmetic::{
34 traits::{BaseArithmetic, SaturatedConversion, Unsigned},
35 Perbill,
36};
37use sp_debug_derive::RuntimeDebug;
38
39pub use weight_meter::*;
40pub use weight_v2::*;
41
42pub mod constants {
43 pub const WEIGHT_REF_TIME_PER_SECOND: u64 = 1_000_000_000_000;
44 pub const WEIGHT_REF_TIME_PER_MILLIS: u64 = 1_000_000_000;
45 pub const WEIGHT_REF_TIME_PER_MICROS: u64 = 1_000_000;
46 pub const WEIGHT_REF_TIME_PER_NANOS: u64 = 1_000;
47
48 pub const WEIGHT_PROOF_SIZE_PER_MB: u64 = 1024 * 1024;
49 pub const WEIGHT_PROOF_SIZE_PER_KB: u64 = 1024;
50}
51
52#[derive(Clone, Copy, Eq, PartialEq, Default, RuntimeDebug, Encode, Decode, TypeInfo)]
57pub struct RuntimeDbWeight {
58 pub read: u64,
59 pub write: u64,
60}
61
62impl RuntimeDbWeight {
63 pub fn reads(self, r: u64) -> Weight {
64 Weight::from_parts(self.read.saturating_mul(r), 0)
65 }
66
67 pub fn writes(self, w: u64) -> Weight {
68 Weight::from_parts(self.write.saturating_mul(w), 0)
69 }
70
71 pub fn reads_writes(self, r: u64, w: u64) -> Weight {
72 let read_weight = self.read.saturating_mul(r);
73 let write_weight = self.write.saturating_mul(w);
74 Weight::from_parts(read_weight.saturating_add(write_weight), 0)
75 }
76}
77
78#[derive(Clone, Encode, Decode, TypeInfo)]
89pub struct WeightToFeeCoefficient<Balance> {
90 pub coeff_integer: Balance,
92 pub coeff_frac: Perbill,
94 pub negative: bool,
96 pub degree: u8,
98}
99
100impl<Balance> WeightToFeeCoefficient<Balance>
101where
102 Balance: BaseArithmetic + From<u32> + Copy + Unsigned,
103{
104 pub fn saturating_eval(&self, mut result: Balance, x: Balance) -> Balance {
112 let power = x.saturating_pow(self.degree.into());
113
114 let frac = self.coeff_frac * power; let integer = self.coeff_integer.saturating_mul(power);
116 if self.negative {
119 result = result.saturating_sub(frac);
120 result = result.saturating_sub(integer);
121 } else {
122 result = result.saturating_add(frac);
123 result = result.saturating_add(integer);
124 }
125
126 result
127 }
128}
129
130pub type WeightToFeeCoefficients<T> = SmallVec<[WeightToFeeCoefficient<T>; 4]>;
132
133pub struct FeePolynomial<Balance> {
150 coefficients: SmallVec<[WeightToFeeCoefficient<Balance>; 4]>,
151}
152
153impl<Balance> From<WeightToFeeCoefficients<Balance>> for FeePolynomial<Balance> {
154 fn from(coefficients: WeightToFeeCoefficients<Balance>) -> Self {
155 Self { coefficients }
156 }
157}
158
159impl<Balance> FeePolynomial<Balance>
160where
161 Balance: BaseArithmetic + From<u32> + Copy + Unsigned,
162{
163 pub fn eval(&self, x: u64) -> Balance {
165 self.coefficients.iter().fold(Balance::zero(), |acc, term| {
166 term.saturating_eval(acc, Balance::saturated_from(x))
167 })
168 }
169}
170
171pub trait WeightToFee {
173 type Balance: BaseArithmetic + From<u32> + Copy + Unsigned;
175
176 fn weight_to_fee(weight: &Weight) -> Self::Balance;
178}
179
180pub trait WeightToFeePolynomial {
184 type Balance: BaseArithmetic + From<u32> + Copy + Unsigned;
186
187 fn polynomial() -> WeightToFeeCoefficients<Self::Balance>;
194}
195
196impl<T> WeightToFee for T
197where
198 T: WeightToFeePolynomial,
199{
200 type Balance = <Self as WeightToFeePolynomial>::Balance;
201
202 fn weight_to_fee(weight: &Weight) -> Self::Balance {
207 let poly: FeePolynomial<Self::Balance> = Self::polynomial().into();
208 poly.eval(weight.ref_time())
209 }
210}
211
212pub struct IdentityFee<T>(core::marker::PhantomData<T>);
214
215impl<T> WeightToFee for IdentityFee<T>
216where
217 T: BaseArithmetic + From<u32> + Copy + Unsigned,
218{
219 type Balance = T;
220
221 fn weight_to_fee(weight: &Weight) -> Self::Balance {
222 Self::Balance::saturated_from(weight.ref_time())
223 }
224}
225
226pub struct FixedFee<const F: u32, T>(core::marker::PhantomData<T>);
228
229impl<const F: u32, T> WeightToFee for FixedFee<F, T>
230where
231 T: BaseArithmetic + From<u32> + Copy + Unsigned,
232{
233 type Balance = T;
234
235 fn weight_to_fee(_: &Weight) -> Self::Balance {
236 F.into()
237 }
238}
239
240pub type NoFee<T> = FixedFee<0, T>;
242
243pub struct ConstantMultiplier<T, M>(core::marker::PhantomData<(T, M)>);
254
255impl<T, M> WeightToFee for ConstantMultiplier<T, M>
256where
257 T: BaseArithmetic + From<u32> + Copy + Unsigned,
258 M: Get<T>,
259{
260 type Balance = T;
261
262 fn weight_to_fee(weight: &Weight) -> Self::Balance {
263 Self::Balance::saturated_from(weight.ref_time()).saturating_mul(M::get())
264 }
265}
266
267#[cfg(test)]
268#[allow(dead_code)]
269mod tests {
270 use super::*;
271 use smallvec::smallvec;
272
273 type Balance = u64;
274
275 struct Poly;
277 impl WeightToFeePolynomial for Poly {
278 type Balance = Balance;
279
280 fn polynomial() -> WeightToFeeCoefficients<Self::Balance> {
281 smallvec![
282 WeightToFeeCoefficient {
283 coeff_integer: 0,
284 coeff_frac: Perbill::from_float(0.5),
285 negative: false,
286 degree: 3
287 },
288 WeightToFeeCoefficient {
289 coeff_integer: 2,
290 coeff_frac: Perbill::from_rational(1u32, 3u32),
291 negative: false,
292 degree: 2
293 },
294 WeightToFeeCoefficient {
295 coeff_integer: 7,
296 coeff_frac: Perbill::zero(),
297 negative: false,
298 degree: 1
299 },
300 WeightToFeeCoefficient {
301 coeff_integer: 10_000,
302 coeff_frac: Perbill::zero(),
303 negative: true,
304 degree: 0
305 },
306 ]
307 }
308 }
309
310 #[test]
311 fn polynomial_works() {
312 assert_eq!(Poly::weight_to_fee(&Weight::from_parts(100, 0)), 514033);
314 assert_eq!(Poly::weight_to_fee(&Weight::from_parts(10_123, 0)), 518917034928);
316 }
317
318 #[test]
319 fn polynomial_does_not_underflow() {
320 assert_eq!(Poly::weight_to_fee(&Weight::zero()), 0);
321 assert_eq!(Poly::weight_to_fee(&Weight::from_parts(10, 0)), 0);
322 }
323
324 #[test]
325 fn polynomial_does_not_overflow() {
326 assert_eq!(Poly::weight_to_fee(&Weight::MAX), Balance::max_value() - 10_000);
327 }
328
329 #[test]
330 fn identity_fee_works() {
331 assert_eq!(IdentityFee::<Balance>::weight_to_fee(&Weight::zero()), 0);
332 assert_eq!(IdentityFee::<Balance>::weight_to_fee(&Weight::from_parts(50, 0)), 50);
333 assert_eq!(IdentityFee::<Balance>::weight_to_fee(&Weight::MAX), Balance::max_value());
334 }
335
336 #[test]
337 fn constant_fee_works() {
338 use bounded_collections::ConstU128;
339 assert_eq!(
340 ConstantMultiplier::<u128, ConstU128<100u128>>::weight_to_fee(&Weight::zero()),
341 0
342 );
343 assert_eq!(
344 ConstantMultiplier::<u128, ConstU128<10u128>>::weight_to_fee(&Weight::from_parts(
345 50, 0
346 )),
347 500
348 );
349 assert_eq!(
350 ConstantMultiplier::<u128, ConstU128<1024u128>>::weight_to_fee(&Weight::from_parts(
351 16, 0
352 )),
353 16384
354 );
355 assert_eq!(
356 ConstantMultiplier::<u128, ConstU128<{ u128::MAX }>>::weight_to_fee(
357 &Weight::from_parts(2, 0)
358 ),
359 u128::MAX
360 );
361 }
362}