1
// This file is part of Substrate.
2

            
3
// Copyright (C) Parity Technologies (UK) Ltd.
4
// SPDX-License-Identifier: Apache-2.0
5

            
6
// Licensed under the Apache License, Version 2.0 (the "License");
7
// you may not use this file except in compliance with the License.
8
// You may obtain a copy of the License at
9
//
10
// 	http://www.apache.org/licenses/LICENSE-2.0
11
//
12
// Unless required by applicable law or agreed to in writing, software
13
// distributed under the License is distributed on an "AS IS" BASIS,
14
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
// See the License for the specific language governing permissions and
16
// limitations under the License.
17

            
18
//! # Primitives for transaction weighting.
19

            
20
#![cfg_attr(not(feature = "std"), no_std)]
21

            
22
extern crate self as sp_weights;
23

            
24
mod weight_meter;
25
mod weight_v2;
26

            
27
use bounded_collections::Get;
28
use codec::{Decode, Encode};
29
use scale_info::TypeInfo;
30
#[cfg(feature = "serde")]
31
use serde::{Deserialize, Serialize};
32
use smallvec::SmallVec;
33
use sp_arithmetic::{
34
	traits::{BaseArithmetic, SaturatedConversion, Unsigned},
35
	Perbill,
36
};
37
use sp_debug_derive::RuntimeDebug;
38

            
39
pub use weight_meter::*;
40
pub use weight_v2::*;
41

            
42
pub 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
/// The weight of database operations that the runtime can invoke.
53
///
54
/// NOTE: This is currently only measured in computational time, and will probably
55
/// be updated all together once proof size is accounted for.
56
#[derive(Clone, Copy, Eq, PartialEq, Default, RuntimeDebug, Encode, Decode, TypeInfo)]
57
pub struct RuntimeDbWeight {
58
	pub read: u64,
59
	pub write: u64,
60
}
61

            
62
impl RuntimeDbWeight {
63
3957780
	pub fn reads(self, r: u64) -> Weight {
64
3957780
		Weight::from_parts(self.read.saturating_mul(r), 0)
65
3957780
	}
66

            
67
3114236
	pub fn writes(self, w: u64) -> Weight {
68
3114236
		Weight::from_parts(self.write.saturating_mul(w), 0)
69
3114236
	}
70

            
71
1475712
	pub fn reads_writes(self, r: u64, w: u64) -> Weight {
72
1475712
		let read_weight = self.read.saturating_mul(r);
73
1475712
		let write_weight = self.write.saturating_mul(w);
74
1475712
		Weight::from_parts(read_weight.saturating_add(write_weight), 0)
75
1475712
	}
76
}
77

            
78
/// One coefficient and its position in the `WeightToFee`.
79
///
80
/// One term of polynomial is calculated as:
81
///
82
/// ```ignore
83
/// coeff_integer * x^(degree) + coeff_frac * x^(degree)
84
/// ```
85
///
86
/// The `negative` value encodes whether the term is added or subtracted from the
87
/// overall polynomial result.
88
#[derive(Clone, Encode, Decode, TypeInfo)]
89
pub struct WeightToFeeCoefficient<Balance> {
90
	/// The integral part of the coefficient.
91
	pub coeff_integer: Balance,
92
	/// The fractional part of the coefficient.
93
	pub coeff_frac: Perbill,
94
	/// True iff the coefficient should be interpreted as negative.
95
	pub negative: bool,
96
	/// Degree/exponent of the term.
97
	pub degree: u8,
98
}
99

            
100
impl<Balance> WeightToFeeCoefficient<Balance>
101
where
102
	Balance: BaseArithmetic + From<u32> + Copy + Unsigned,
103
{
104
	/// Evaluate the term at `x` and saturatingly amalgamate into `result`.
105
	///
106
	/// The unsigned value for the term is calculated as:
107
	/// ```ignore
108
	/// (frac * x^(degree) + integer * x^(degree))
109
	/// ```
110
	/// Depending on the value of `negative`, it is added or subtracted from the `result`.
111
12
	pub fn saturating_eval(&self, mut result: Balance, x: Balance) -> Balance {
112
12
		let power = x.saturating_pow(self.degree.into());
113
12

            
114
12
		let frac = self.coeff_frac * power; // Overflow safe.
115
12
		let integer = self.coeff_integer.saturating_mul(power);
116
12
		// Do not add them together here to avoid an underflow.
117
12

            
118
12
		if self.negative {
119
			result = result.saturating_sub(frac);
120
			result = result.saturating_sub(integer);
121
12
		} else {
122
12
			result = result.saturating_add(frac);
123
12
			result = result.saturating_add(integer);
124
12
		}
125

            
126
12
		result
127
12
	}
128
}
129

            
130
/// A list of coefficients that represent a polynomial.
131
pub type WeightToFeeCoefficients<T> = SmallVec<[WeightToFeeCoefficient<T>; 4]>;
132

            
133
/// A list of coefficients that represent a polynomial.
134
///
135
/// Can be [eval](Self::eval)uated at a specific `u64` to get the fee. The evaluations happens by
136
/// summing up all term [results](`WeightToFeeCoefficient::saturating_eval`). The order of the
137
/// coefficients matters since it uses saturating arithmetic. This struct does therefore not model a
138
/// polynomial in the mathematical sense (polynomial ring).
139
///
140
/// For visualization purposes, the formulas of the unsigned terms look like:
141
///
142
/// ```ignore
143
/// (c[0].frac * x^(c[0].degree) + c[0].integer * x^(c[0].degree))
144
/// (c[1].frac * x^(c[1].degree) + c[1].integer * x^(c[1].degree))
145
/// ...
146
/// ```
147
/// Depending on the value of `c[i].negative`, each term is added or subtracted from the result.
148
/// The result is initialized as zero.
149
pub struct FeePolynomial<Balance> {
150
	coefficients: SmallVec<[WeightToFeeCoefficient<Balance>; 4]>,
151
}
152

            
153
impl<Balance> From<WeightToFeeCoefficients<Balance>> for FeePolynomial<Balance> {
154
12
	fn from(coefficients: WeightToFeeCoefficients<Balance>) -> Self {
155
12
		Self { coefficients }
156
12
	}
157
}
158

            
159
impl<Balance> FeePolynomial<Balance>
160
where
161
	Balance: BaseArithmetic + From<u32> + Copy + Unsigned,
162
{
163
	/// Evaluate the polynomial at a specific `x`.
164
12
	pub fn eval(&self, x: u64) -> Balance {
165
12
		self.coefficients.iter().fold(Balance::zero(), |acc, term| {
166
12
			term.saturating_eval(acc, Balance::saturated_from(x))
167
12
		})
168
12
	}
169
}
170

            
171
/// A trait that describes the weight to fee calculation.
172
pub trait WeightToFee {
173
	/// The type that is returned as result from calculation.
174
	type Balance: BaseArithmetic + From<u32> + Copy + Unsigned;
175

            
176
	/// Calculates the fee from the passed `weight`.
177
	fn weight_to_fee(weight: &Weight) -> Self::Balance;
178
}
179

            
180
/// A trait that describes the weight to fee calculation as polynomial.
181
///
182
/// An implementor should only implement the `polynomial` function.
183
pub trait WeightToFeePolynomial {
184
	/// The type that is returned as result from polynomial evaluation.
185
	type Balance: BaseArithmetic + From<u32> + Copy + Unsigned;
186

            
187
	/// Returns a polynomial that describes the weight to fee conversion.
188
	///
189
	/// This is the only function that should be manually implemented. Please note
190
	/// that all calculation is done in the probably unsigned `Balance` type. This means
191
	/// that the order of coefficients is important as putting the negative coefficients
192
	/// first will most likely saturate the result to zero mid evaluation.
193
	fn polynomial() -> WeightToFeeCoefficients<Self::Balance>;
194
}
195

            
196
impl<T> WeightToFee for T
197
where
198
	T: WeightToFeePolynomial,
199
{
200
	type Balance = <Self as WeightToFeePolynomial>::Balance;
201

            
202
	/// Calculates the fee from the passed `weight` according to the `polynomial`.
203
	///
204
	/// This should not be overridden in most circumstances. Calculation is done in the
205
	/// `Balance` type and never overflows. All evaluation is saturating.
206
12
	fn weight_to_fee(weight: &Weight) -> Self::Balance {
207
12
		let poly: FeePolynomial<Self::Balance> = Self::polynomial().into();
208
12
		poly.eval(weight.ref_time())
209
12
	}
210
}
211

            
212
/// Implementor of `WeightToFee` that maps one unit of weight to one unit of fee.
213
pub struct IdentityFee<T>(core::marker::PhantomData<T>);
214

            
215
impl<T> WeightToFee for IdentityFee<T>
216
where
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

            
226
/// Implementor of [`WeightToFee`] such that it maps any unit of weight to a fixed fee.
227
pub struct FixedFee<const F: u32, T>(core::marker::PhantomData<T>);
228

            
229
impl<const F: u32, T> WeightToFee for FixedFee<F, T>
230
where
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

            
240
/// An implementation of [`WeightToFee`] that collects no fee.
241
pub type NoFee<T> = FixedFee<0, T>;
242

            
243
/// Implementor of [`WeightToFee`] that uses a constant multiplier.
244
///
245
/// # Example
246
///
247
/// ```
248
/// # use bounded_collections::ConstU128;
249
/// # use sp_weights::ConstantMultiplier;
250
/// // Results in a multiplier of 10 for each unit of weight (or length)
251
/// type LengthToFee = ConstantMultiplier::<u128, ConstU128<10u128>>;
252
/// ```
253
pub struct ConstantMultiplier<T, M>(core::marker::PhantomData<(T, M)>);
254

            
255
impl<T, M> WeightToFee for ConstantMultiplier<T, M>
256
where
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)]
269
mod tests {
270
	use super::*;
271
	use smallvec::smallvec;
272

            
273
	type Balance = u64;
274

            
275
	// 0.5x^3 + 2.333x^2 + 7x - 10_000
276
	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
		// 100^3/2=500000 100^2*(2+1/3)=23333 700 -10000
313
		assert_eq!(Poly::weight_to_fee(&Weight::from_parts(100, 0)), 514033);
314
		// 10123^3/2=518677865433 10123^2*(2+1/3)=239108634 70861 -10000
315
		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
}