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