#![cfg_attr(not(feature = "std"), no_std)]
extern crate self as sp_weights;
mod weight_meter;
mod weight_v2;
use bounded_collections::Get;
use codec::{Decode, Encode};
use scale_info::TypeInfo;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use smallvec::SmallVec;
use sp_arithmetic::{
traits::{BaseArithmetic, SaturatedConversion, Unsigned},
Perbill,
};
pub use weight_meter::*;
pub use weight_v2::*;
pub mod constants {
pub const WEIGHT_REF_TIME_PER_SECOND: u64 = 1_000_000_000_000;
pub const WEIGHT_REF_TIME_PER_MILLIS: u64 = 1_000_000_000;
pub const WEIGHT_REF_TIME_PER_MICROS: u64 = 1_000_000;
pub const WEIGHT_REF_TIME_PER_NANOS: u64 = 1_000;
pub const WEIGHT_PROOF_SIZE_PER_MB: u64 = 1024 * 1024;
pub const WEIGHT_PROOF_SIZE_PER_KB: u64 = 1024;
}
#[derive(Clone, Copy, Eq, PartialEq, Default, Debug, Encode, Decode, TypeInfo)]
pub struct RuntimeDbWeight {
pub read: u64,
pub write: u64,
}
impl RuntimeDbWeight {
pub fn reads(self, r: u64) -> Weight {
Weight::from_parts(self.read.saturating_mul(r), 0)
}
pub fn writes(self, w: u64) -> Weight {
Weight::from_parts(self.write.saturating_mul(w), 0)
}
pub fn reads_writes(self, r: u64, w: u64) -> Weight {
let read_weight = self.read.saturating_mul(r);
let write_weight = self.write.saturating_mul(w);
Weight::from_parts(read_weight.saturating_add(write_weight), 0)
}
}
#[derive(Clone, Encode, Decode, TypeInfo)]
pub struct WeightToFeeCoefficient<Balance> {
pub coeff_integer: Balance,
pub coeff_frac: Perbill,
pub negative: bool,
pub degree: u8,
}
impl<Balance> WeightToFeeCoefficient<Balance>
where
Balance: BaseArithmetic + From<u32> + Copy + Unsigned,
{
pub fn saturating_eval(&self, mut result: Balance, x: Balance) -> Balance {
let power = x.saturating_pow(self.degree.into());
let frac = self.coeff_frac * power; let integer = self.coeff_integer.saturating_mul(power);
if self.negative {
result = result.saturating_sub(frac);
result = result.saturating_sub(integer);
} else {
result = result.saturating_add(frac);
result = result.saturating_add(integer);
}
result
}
}
pub type WeightToFeeCoefficients<T> = SmallVec<[WeightToFeeCoefficient<T>; 4]>;
pub struct FeePolynomial<Balance> {
coefficients: SmallVec<[WeightToFeeCoefficient<Balance>; 4]>,
}
impl<Balance> From<WeightToFeeCoefficients<Balance>> for FeePolynomial<Balance> {
fn from(coefficients: WeightToFeeCoefficients<Balance>) -> Self {
Self { coefficients }
}
}
impl<Balance> FeePolynomial<Balance>
where
Balance: BaseArithmetic + From<u32> + Copy + Unsigned,
{
pub fn eval(&self, x: u64) -> Balance {
self.coefficients.iter().fold(Balance::zero(), |acc, term| {
term.saturating_eval(acc, Balance::saturated_from(x))
})
}
}
pub trait WeightToFee {
type Balance: BaseArithmetic + From<u32> + Copy + Unsigned;
fn weight_to_fee(weight: &Weight) -> Self::Balance;
}
pub trait WeightToFeePolynomial {
type Balance: BaseArithmetic + From<u32> + Copy + Unsigned;
fn polynomial() -> WeightToFeeCoefficients<Self::Balance>;
}
impl<T> WeightToFee for T
where
T: WeightToFeePolynomial,
{
type Balance = <Self as WeightToFeePolynomial>::Balance;
fn weight_to_fee(weight: &Weight) -> Self::Balance {
let poly: FeePolynomial<Self::Balance> = Self::polynomial().into();
poly.eval(weight.ref_time())
}
}
pub struct IdentityFee<T>(core::marker::PhantomData<T>);
impl<T> WeightToFee for IdentityFee<T>
where
T: BaseArithmetic + From<u32> + Copy + Unsigned,
{
type Balance = T;
fn weight_to_fee(weight: &Weight) -> Self::Balance {
Self::Balance::saturated_from(weight.ref_time())
}
}
pub struct FixedFee<const F: u32, T>(core::marker::PhantomData<T>);
impl<const F: u32, T> WeightToFee for FixedFee<F, T>
where
T: BaseArithmetic + From<u32> + Copy + Unsigned,
{
type Balance = T;
fn weight_to_fee(_: &Weight) -> Self::Balance {
F.into()
}
}
pub type NoFee<T> = FixedFee<0, T>;
pub struct ConstantMultiplier<T, M>(core::marker::PhantomData<(T, M)>);
impl<T, M> WeightToFee for ConstantMultiplier<T, M>
where
T: BaseArithmetic + From<u32> + Copy + Unsigned,
M: Get<T>,
{
type Balance = T;
fn weight_to_fee(weight: &Weight) -> Self::Balance {
Self::Balance::saturated_from(weight.ref_time()).saturating_mul(M::get())
}
}
#[cfg(test)]
#[allow(dead_code)]
mod tests {
use super::*;
use smallvec::smallvec;
type Balance = u64;
struct Poly;
impl WeightToFeePolynomial for Poly {
type Balance = Balance;
fn polynomial() -> WeightToFeeCoefficients<Self::Balance> {
smallvec![
WeightToFeeCoefficient {
coeff_integer: 0,
coeff_frac: Perbill::from_float(0.5),
negative: false,
degree: 3
},
WeightToFeeCoefficient {
coeff_integer: 2,
coeff_frac: Perbill::from_rational(1u32, 3u32),
negative: false,
degree: 2
},
WeightToFeeCoefficient {
coeff_integer: 7,
coeff_frac: Perbill::zero(),
negative: false,
degree: 1
},
WeightToFeeCoefficient {
coeff_integer: 10_000,
coeff_frac: Perbill::zero(),
negative: true,
degree: 0
},
]
}
}
#[test]
fn polynomial_works() {
assert_eq!(Poly::weight_to_fee(&Weight::from_parts(100, 0)), 514033);
assert_eq!(Poly::weight_to_fee(&Weight::from_parts(10_123, 0)), 518917034928);
}
#[test]
fn polynomial_does_not_underflow() {
assert_eq!(Poly::weight_to_fee(&Weight::zero()), 0);
assert_eq!(Poly::weight_to_fee(&Weight::from_parts(10, 0)), 0);
}
#[test]
fn polynomial_does_not_overflow() {
assert_eq!(Poly::weight_to_fee(&Weight::MAX), Balance::max_value() - 10_000);
}
#[test]
fn identity_fee_works() {
assert_eq!(IdentityFee::<Balance>::weight_to_fee(&Weight::zero()), 0);
assert_eq!(IdentityFee::<Balance>::weight_to_fee(&Weight::from_parts(50, 0)), 50);
assert_eq!(IdentityFee::<Balance>::weight_to_fee(&Weight::MAX), Balance::max_value());
}
#[test]
fn constant_fee_works() {
use bounded_collections::ConstU128;
assert_eq!(
ConstantMultiplier::<u128, ConstU128<100u128>>::weight_to_fee(&Weight::zero()),
0
);
assert_eq!(
ConstantMultiplier::<u128, ConstU128<10u128>>::weight_to_fee(&Weight::from_parts(
50, 0
)),
500
);
assert_eq!(
ConstantMultiplier::<u128, ConstU128<1024u128>>::weight_to_fee(&Weight::from_parts(
16, 0
)),
16384
);
assert_eq!(
ConstantMultiplier::<u128, ConstU128<{ u128::MAX }>>::weight_to_fee(
&Weight::from_parts(2, 0)
),
u128::MAX
);
}
}