Create sp-weights crate to store weight primitives (#12219)

* Create sp-weights crate to store weight primitives

* Fix templates

* Fix templates

* Fixes

* Fixes

* cargo fmt

* Fixes

* Fixes

* Use deprecated type alias instead of deprecated unit types

* Use deprecated subtraits instead of deprecated hollow new traits

* Fixes

* Allow deprecation in macro expansion

* Add missing where clause during call macro expansion

* cargo fmt

* Fixes

* cargo fmt

* Fixes

* Fixes

* Fixes

* Fixes

* Move FRAME-specific weight files back to frame_support

* Fixes

* Update frame/support/src/dispatch.rs

Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com>

* Update frame/support/src/dispatch.rs

Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com>

* Update frame/support/src/dispatch.rs

Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com>

* Add missing header

* Rewrite module docs

* Fixes

* Fixes

* Fixes

* Fixes

* cargo fmt

Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com>
Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com>
This commit is contained in:
Keith Yeung
2022-09-13 21:23:44 +08:00
committed by GitHub
parent 214eb25f87
commit 30e7b1e8cd
69 changed files with 1316 additions and 1225 deletions
+744 -10
View File
@@ -31,18 +31,22 @@ pub use crate::{
traits::{
CallMetadata, GetCallMetadata, GetCallName, GetStorageVersion, UnfilteredDispatchable,
},
weights::{
ClassifyDispatch, DispatchInfo, GetDispatchInfo, PaysFee, PostDispatchInfo,
TransactionPriority, WeighData, Weight, WithPostDispatchInfo,
},
};
pub use sp_runtime::{traits::Dispatchable, DispatchError, RuntimeDebug};
#[cfg(feature = "std")]
use serde::{Deserialize, Serialize};
use sp_runtime::{
generic::{CheckedExtrinsic, UncheckedExtrinsic},
traits::SignedExtension,
};
pub use sp_runtime::{
traits::Dispatchable, transaction_validity::TransactionPriority, DispatchError, RuntimeDebug,
};
pub use sp_weights::Weight;
/// The return type of a `Dispatchable` in frame. When returned explicitly from
/// a dispatchable function it allows overriding the default `PostDispatchInfo`
/// returned from a dispatch.
pub type DispatchResultWithPostInfo =
sp_runtime::DispatchResultWithInfo<crate::weights::PostDispatchInfo>;
pub type DispatchResultWithPostInfo = sp_runtime::DispatchResultWithInfo<PostDispatchInfo>;
/// Unaugmented version of `DispatchResultWithPostInfo` that can be returned from
/// dispatchable functions and is automatically converted to the augmented type. Should be
@@ -51,8 +55,7 @@ pub type DispatchResultWithPostInfo =
pub type DispatchResult = Result<(), sp_runtime::DispatchError>;
/// The error type contained in a `DispatchResultWithPostInfo`.
pub type DispatchErrorWithPostInfo =
sp_runtime::DispatchErrorWithPostInfo<crate::weights::PostDispatchInfo>;
pub type DispatchErrorWithPostInfo = sp_runtime::DispatchErrorWithPostInfo<PostDispatchInfo>;
/// Serializable version of pallet dispatchable.
pub trait Callable<T> {
@@ -91,6 +94,552 @@ impl<AccountId> From<Option<AccountId>> for RawOrigin<AccountId> {
pub trait Parameter: Codec + EncodeLike + Clone + Eq + fmt::Debug + scale_info::TypeInfo {}
impl<T> Parameter for T where T: Codec + EncodeLike + Clone + Eq + fmt::Debug + scale_info::TypeInfo {}
/// Means of classifying a dispatchable function.
pub trait ClassifyDispatch<T> {
/// Classify the dispatch function based on input data `target` of type `T`. When implementing
/// this for a dispatchable, `T` will be a tuple of all arguments given to the function (except
/// origin).
fn classify_dispatch(&self, target: T) -> DispatchClass;
}
/// Indicates if dispatch function should pay fees or not.
///
/// If set to `Pays::No`, the block resource limits are applied, yet no fee is deducted.
pub trait PaysFee<T> {
fn pays_fee(&self, _target: T) -> Pays;
}
/// Explicit enum to denote if a transaction pays fee or not.
#[derive(Clone, Copy, Eq, PartialEq, RuntimeDebug, Encode, Decode, TypeInfo)]
pub enum Pays {
/// Transactor will pay related fees.
Yes,
/// Transactor will NOT pay related fees.
No,
}
impl Default for Pays {
fn default() -> Self {
Self::Yes
}
}
impl From<Pays> for PostDispatchInfo {
fn from(pays_fee: Pays) -> Self {
Self { actual_weight: None, pays_fee }
}
}
/// A generalized group of dispatch types.
///
/// NOTE whenever upgrading the enum make sure to also update
/// [DispatchClass::all] and [DispatchClass::non_mandatory] helper functions.
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))]
#[derive(PartialEq, Eq, Clone, Copy, Encode, Decode, RuntimeDebug, TypeInfo)]
pub enum DispatchClass {
/// A normal dispatch.
Normal,
/// An operational dispatch.
Operational,
/// A mandatory dispatch. These kinds of dispatch are always included regardless of their
/// weight, therefore it is critical that they are separately validated to ensure that a
/// malicious validator cannot craft a valid but impossibly heavy block. Usually this just
/// means ensuring that the extrinsic can only be included once and that it is always very
/// light.
///
/// Do *NOT* use it for extrinsics that can be heavy.
///
/// The only real use case for this is inherent extrinsics that are required to execute in a
/// block for the block to be valid, and it solves the issue in the case that the block
/// initialization is sufficiently heavy to mean that those inherents do not fit into the
/// block. Essentially, we assume that in these exceptional circumstances, it is better to
/// allow an overweight block to be created than to not allow any block at all to be created.
Mandatory,
}
impl Default for DispatchClass {
fn default() -> Self {
Self::Normal
}
}
impl DispatchClass {
/// Returns an array containing all dispatch classes.
pub fn all() -> &'static [DispatchClass] {
&[DispatchClass::Normal, DispatchClass::Operational, DispatchClass::Mandatory]
}
/// Returns an array of all dispatch classes except `Mandatory`.
pub fn non_mandatory() -> &'static [DispatchClass] {
&[DispatchClass::Normal, DispatchClass::Operational]
}
}
/// A trait that represents one or many values of given type.
///
/// Useful to accept as parameter type to let the caller pass either a single value directly
/// or an iterator.
pub trait OneOrMany<T> {
/// The iterator type.
type Iter: Iterator<Item = T>;
/// Convert this item into an iterator.
fn into_iter(self) -> Self::Iter;
}
impl OneOrMany<DispatchClass> for DispatchClass {
type Iter = sp_std::iter::Once<DispatchClass>;
fn into_iter(self) -> Self::Iter {
sp_std::iter::once(self)
}
}
impl<'a> OneOrMany<DispatchClass> for &'a [DispatchClass] {
type Iter = sp_std::iter::Cloned<sp_std::slice::Iter<'a, DispatchClass>>;
fn into_iter(self) -> Self::Iter {
self.iter().cloned()
}
}
/// A bundle of static information collected from the `#[pallet::weight]` attributes.
#[derive(Clone, Copy, Eq, PartialEq, Default, RuntimeDebug, Encode, Decode, TypeInfo)]
pub struct DispatchInfo {
/// Weight of this transaction.
pub weight: Weight,
/// Class of this transaction.
pub class: DispatchClass,
/// Does this transaction pay fees.
pub pays_fee: Pays,
}
/// A `Dispatchable` function (aka transaction) that can carry some static information along with
/// it, using the `#[pallet::weight]` attribute.
pub trait GetDispatchInfo {
/// Return a `DispatchInfo`, containing relevant information of this dispatch.
///
/// This is done independently of its encoded size.
fn get_dispatch_info(&self) -> DispatchInfo;
}
impl GetDispatchInfo for () {
fn get_dispatch_info(&self) -> DispatchInfo {
DispatchInfo::default()
}
}
/// Extract the actual weight from a dispatch result if any or fall back to the default weight.
pub fn extract_actual_weight(result: &DispatchResultWithPostInfo, info: &DispatchInfo) -> Weight {
match result {
Ok(post_info) => post_info,
Err(err) => &err.post_info,
}
.calc_actual_weight(info)
}
/// Extract the actual pays_fee from a dispatch result if any or fall back to the default weight.
pub fn extract_actual_pays_fee(result: &DispatchResultWithPostInfo, info: &DispatchInfo) -> Pays {
match result {
Ok(post_info) => post_info,
Err(err) => &err.post_info,
}
.pays_fee(info)
}
/// Weight information that is only available post dispatch.
/// NOTE: This can only be used to reduce the weight or fee, not increase it.
#[derive(Clone, Copy, Eq, PartialEq, Default, RuntimeDebug, Encode, Decode, TypeInfo)]
pub struct PostDispatchInfo {
/// Actual weight consumed by a call or `None` which stands for the worst case static weight.
pub actual_weight: Option<Weight>,
/// Whether this transaction should pay fees when all is said and done.
pub pays_fee: Pays,
}
impl PostDispatchInfo {
/// Calculate how much (if any) weight was not used by the `Dispatchable`.
pub fn calc_unspent(&self, info: &DispatchInfo) -> Weight {
info.weight - self.calc_actual_weight(info)
}
/// Calculate how much weight was actually spent by the `Dispatchable`.
pub fn calc_actual_weight(&self, info: &DispatchInfo) -> Weight {
if let Some(actual_weight) = self.actual_weight {
actual_weight.min(info.weight)
} else {
info.weight
}
}
/// Determine if user should actually pay fees at the end of the dispatch.
pub fn pays_fee(&self, info: &DispatchInfo) -> Pays {
// If they originally were not paying fees, or the post dispatch info
// says they should not pay fees, then they don't pay fees.
// This is because the pre dispatch information must contain the
// worst case for weight and fees paid.
if info.pays_fee == Pays::No || self.pays_fee == Pays::No {
Pays::No
} else {
// Otherwise they pay.
Pays::Yes
}
}
}
impl From<()> for PostDispatchInfo {
fn from(_: ()) -> Self {
Self { actual_weight: None, pays_fee: Default::default() }
}
}
impl sp_runtime::traits::Printable for PostDispatchInfo {
fn print(&self) {
"actual_weight=".print();
match self.actual_weight {
Some(weight) => weight.print(),
None => "max-weight".print(),
};
"pays_fee=".print();
match self.pays_fee {
Pays::Yes => "Yes".print(),
Pays::No => "No".print(),
}
}
}
/// Allows easy conversion from `DispatchError` to `DispatchErrorWithPostInfo` for dispatchables
/// that want to return a custom a posterior weight on error.
pub trait WithPostDispatchInfo {
/// Call this on your modules custom errors type in order to return a custom weight on error.
///
/// # Example
///
/// ```ignore
/// let who = ensure_signed(origin).map_err(|e| e.with_weight(Weight::from_ref_time(100)))?;
/// ensure!(who == me, Error::<T>::NotMe.with_weight(200_000));
/// ```
fn with_weight(self, actual_weight: Weight) -> DispatchErrorWithPostInfo;
}
impl<T> WithPostDispatchInfo for T
where
T: Into<DispatchError>,
{
fn with_weight(self, actual_weight: Weight) -> DispatchErrorWithPostInfo {
DispatchErrorWithPostInfo {
post_info: PostDispatchInfo {
actual_weight: Some(actual_weight),
pays_fee: Default::default(),
},
error: self.into(),
}
}
}
/// Implementation for unchecked extrinsic.
impl<Address, Call, Signature, Extra> GetDispatchInfo
for UncheckedExtrinsic<Address, Call, Signature, Extra>
where
Call: GetDispatchInfo,
Extra: SignedExtension,
{
fn get_dispatch_info(&self) -> DispatchInfo {
self.function.get_dispatch_info()
}
}
/// Implementation for checked extrinsic.
impl<AccountId, Call, Extra> GetDispatchInfo for CheckedExtrinsic<AccountId, Call, Extra>
where
Call: GetDispatchInfo,
{
fn get_dispatch_info(&self) -> DispatchInfo {
self.function.get_dispatch_info()
}
}
/// Implementation for test extrinsic.
#[cfg(feature = "std")]
impl<Call: Encode, Extra: Encode> GetDispatchInfo for sp_runtime::testing::TestXt<Call, Extra> {
fn get_dispatch_info(&self) -> DispatchInfo {
// for testing: weight == size.
DispatchInfo {
weight: Weight::from_ref_time(self.encode().len() as _),
pays_fee: Pays::Yes,
..Default::default()
}
}
}
/// A struct holding value for each `DispatchClass`.
#[derive(Clone, Eq, PartialEq, Default, RuntimeDebug, Encode, Decode, TypeInfo, MaxEncodedLen)]
pub struct PerDispatchClass<T> {
/// Value for `Normal` extrinsics.
normal: T,
/// Value for `Operational` extrinsics.
operational: T,
/// Value for `Mandatory` extrinsics.
mandatory: T,
}
impl<T> PerDispatchClass<T> {
/// Create new `PerDispatchClass` with the same value for every class.
pub fn new(val: impl Fn(DispatchClass) -> T) -> Self {
Self {
normal: val(DispatchClass::Normal),
operational: val(DispatchClass::Operational),
mandatory: val(DispatchClass::Mandatory),
}
}
/// Get a mutable reference to current value of given class.
pub fn get_mut(&mut self, class: DispatchClass) -> &mut T {
match class {
DispatchClass::Operational => &mut self.operational,
DispatchClass::Normal => &mut self.normal,
DispatchClass::Mandatory => &mut self.mandatory,
}
}
/// Get current value for given class.
pub fn get(&self, class: DispatchClass) -> &T {
match class {
DispatchClass::Normal => &self.normal,
DispatchClass::Operational => &self.operational,
DispatchClass::Mandatory => &self.mandatory,
}
}
}
impl<T: Clone> PerDispatchClass<T> {
/// Set the value of given class.
pub fn set(&mut self, new: T, class: impl OneOrMany<DispatchClass>) {
for class in class.into_iter() {
*self.get_mut(class) = new.clone();
}
}
}
impl PerDispatchClass<Weight> {
/// Returns the total weight consumed by all extrinsics in the block.
pub fn total(&self) -> Weight {
let mut sum = Weight::zero();
for class in DispatchClass::all() {
sum = sum.saturating_add(*self.get(*class));
}
sum
}
/// Add some weight of a specific dispatch class, saturating at the numeric bounds of `Weight`.
pub fn add(&mut self, weight: Weight, class: DispatchClass) {
let value = self.get_mut(class);
*value = value.saturating_add(weight);
}
/// Try to add some weight of a specific dispatch class, returning Err(()) if overflow would
/// occur.
pub fn checked_add(&mut self, weight: Weight, class: DispatchClass) -> Result<(), ()> {
let value = self.get_mut(class);
*value = value.checked_add(&weight).ok_or(())?;
Ok(())
}
/// Subtract some weight of a specific dispatch class, saturating at the numeric bounds of
/// `Weight`.
pub fn sub(&mut self, weight: Weight, class: DispatchClass) {
let value = self.get_mut(class);
*value = value.saturating_sub(weight);
}
}
/// Means of weighing some particular kind of data (`T`).
pub trait WeighData<T> {
/// Weigh the data `T` given by `target`. When implementing this for a dispatchable, `T` will be
/// a tuple of all arguments given to the function (except origin).
fn weigh_data(&self, target: T) -> Weight;
}
impl<T> WeighData<T> for Weight {
fn weigh_data(&self, _: T) -> Weight {
return *self
}
}
impl<T> PaysFee<T> for (Weight, DispatchClass, Pays) {
fn pays_fee(&self, _: T) -> Pays {
self.2
}
}
impl<T> WeighData<T> for (Weight, DispatchClass) {
fn weigh_data(&self, args: T) -> Weight {
return self.0.weigh_data(args)
}
}
impl<T> WeighData<T> for (Weight, DispatchClass, Pays) {
fn weigh_data(&self, args: T) -> Weight {
return self.0.weigh_data(args)
}
}
impl<T> ClassifyDispatch<T> for (Weight, DispatchClass) {
fn classify_dispatch(&self, _: T) -> DispatchClass {
self.1
}
}
impl<T> PaysFee<T> for (Weight, DispatchClass) {
fn pays_fee(&self, _: T) -> Pays {
Pays::Yes
}
}
impl<T> WeighData<T> for (Weight, Pays) {
fn weigh_data(&self, args: T) -> Weight {
return self.0.weigh_data(args)
}
}
impl<T> ClassifyDispatch<T> for (Weight, Pays) {
fn classify_dispatch(&self, _: T) -> DispatchClass {
DispatchClass::Normal
}
}
impl<T> PaysFee<T> for (Weight, Pays) {
fn pays_fee(&self, _: T) -> Pays {
self.1
}
}
impl From<(Option<Weight>, Pays)> for PostDispatchInfo {
fn from(post_weight_info: (Option<Weight>, Pays)) -> Self {
let (actual_weight, pays_fee) = post_weight_info;
Self { actual_weight, pays_fee }
}
}
impl From<Option<Weight>> for PostDispatchInfo {
fn from(actual_weight: Option<Weight>) -> Self {
Self { actual_weight, pays_fee: Default::default() }
}
}
impl<T> ClassifyDispatch<T> for Weight {
fn classify_dispatch(&self, _: T) -> DispatchClass {
DispatchClass::Normal
}
}
impl<T> PaysFee<T> for Weight {
fn pays_fee(&self, _: T) -> Pays {
Pays::Yes
}
}
impl<T> ClassifyDispatch<T> for (Weight, DispatchClass, Pays) {
fn classify_dispatch(&self, _: T) -> DispatchClass {
self.1
}
}
// TODO: Eventually remove these
impl From<Option<u64>> for PostDispatchInfo {
fn from(maybe_actual_computation: Option<u64>) -> Self {
let actual_weight = match maybe_actual_computation {
Some(actual_computation) => Some(Weight::zero().set_ref_time(actual_computation)),
None => None,
};
Self { actual_weight, pays_fee: Default::default() }
}
}
impl From<(Option<u64>, Pays)> for PostDispatchInfo {
fn from(post_weight_info: (Option<u64>, Pays)) -> Self {
let (maybe_actual_time, pays_fee) = post_weight_info;
let actual_weight = match maybe_actual_time {
Some(actual_time) => Some(Weight::zero().set_ref_time(actual_time)),
None => None,
};
Self { actual_weight, pays_fee }
}
}
impl<T> ClassifyDispatch<T> for u64 {
fn classify_dispatch(&self, _: T) -> DispatchClass {
DispatchClass::Normal
}
}
impl<T> PaysFee<T> for u64 {
fn pays_fee(&self, _: T) -> Pays {
Pays::Yes
}
}
impl<T> WeighData<T> for u64 {
fn weigh_data(&self, _: T) -> Weight {
return Weight::zero().set_ref_time(*self)
}
}
impl<T> WeighData<T> for (u64, DispatchClass, Pays) {
fn weigh_data(&self, args: T) -> Weight {
return self.0.weigh_data(args)
}
}
impl<T> ClassifyDispatch<T> for (u64, DispatchClass, Pays) {
fn classify_dispatch(&self, _: T) -> DispatchClass {
self.1
}
}
impl<T> PaysFee<T> for (u64, DispatchClass, Pays) {
fn pays_fee(&self, _: T) -> Pays {
self.2
}
}
impl<T> WeighData<T> for (u64, DispatchClass) {
fn weigh_data(&self, args: T) -> Weight {
return self.0.weigh_data(args)
}
}
impl<T> ClassifyDispatch<T> for (u64, DispatchClass) {
fn classify_dispatch(&self, _: T) -> DispatchClass {
self.1
}
}
impl<T> PaysFee<T> for (u64, DispatchClass) {
fn pays_fee(&self, _: T) -> Pays {
Pays::Yes
}
}
impl<T> WeighData<T> for (u64, Pays) {
fn weigh_data(&self, args: T) -> Weight {
return self.0.weigh_data(args)
}
}
impl<T> ClassifyDispatch<T> for (u64, Pays) {
fn classify_dispatch(&self, _: T) -> DispatchClass {
DispatchClass::Normal
}
}
impl<T> PaysFee<T> for (u64, Pays) {
fn pays_fee(&self, _: T) -> Pays {
self.1
}
}
// END TODO
/// Declares a `Module` struct and a `Call` enum, which implements the dispatch logic.
///
/// ## Declaration
@@ -2629,13 +3178,14 @@ macro_rules! __check_reserved_fn_name {
mod tests {
use super::*;
use crate::{
dispatch::{DispatchClass, DispatchInfo, Pays},
metadata::*,
traits::{
CrateVersion, Get, GetCallName, IntegrityTest, OnFinalize, OnIdle, OnInitialize,
OnRuntimeUpgrade, PalletInfo,
},
weights::{DispatchClass, DispatchInfo, Pays, RuntimeDbWeight},
};
use sp_weights::RuntimeDbWeight;
pub trait Config: system::Config + Sized
where
@@ -2940,3 +3490,187 @@ mod tests {
Call::<TraitImpl>::new_call_variant_aux_0();
}
}
#[cfg(test)]
// Do not complain about unused `dispatch` and `dispatch_aux`.
#[allow(dead_code)]
mod weight_tests {
use super::*;
use sp_core::{parameter_types, Get};
use sp_weights::RuntimeDbWeight;
pub trait Config: 'static {
type Origin;
type Balance;
type BlockNumber;
type DbWeight: Get<RuntimeDbWeight>;
type PalletInfo: crate::traits::PalletInfo;
}
pub struct TraitImpl {}
parameter_types! {
pub const DbWeight: RuntimeDbWeight = RuntimeDbWeight {
read: 100,
write: 1000,
};
}
impl Config for TraitImpl {
type Origin = u32;
type BlockNumber = u32;
type Balance = u32;
type DbWeight = DbWeight;
type PalletInfo = crate::tests::PanicPalletInfo;
}
decl_module! {
pub struct Module<T: Config> for enum Call where origin: T::Origin, system=self {
// no arguments, fixed weight
#[weight = 1000]
fn f00(_origin) { unimplemented!(); }
#[weight = (1000, DispatchClass::Mandatory)]
fn f01(_origin) { unimplemented!(); }
#[weight = (1000, Pays::No)]
fn f02(_origin) { unimplemented!(); }
#[weight = (1000, DispatchClass::Operational, Pays::No)]
fn f03(_origin) { unimplemented!(); }
// weight = a x 10 + b
#[weight = ((_a * 10 + _eb * 1) as u64, DispatchClass::Normal, Pays::Yes)]
fn f11(_origin, _a: u32, _eb: u32) { unimplemented!(); }
#[weight = (0, DispatchClass::Operational, Pays::Yes)]
fn f12(_origin, _a: u32, _eb: u32) { unimplemented!(); }
#[weight = T::DbWeight::get().reads(3) + T::DbWeight::get().writes(2) + Weight::from_ref_time(10_000)]
fn f20(_origin) { unimplemented!(); }
#[weight = T::DbWeight::get().reads_writes(6, 5) + Weight::from_ref_time(40_000)]
fn f21(_origin) { unimplemented!(); }
}
}
#[test]
fn weights_are_correct() {
// #[weight = 1000]
let info = Call::<TraitImpl>::f00 {}.get_dispatch_info();
assert_eq!(info.weight, Weight::from_ref_time(1000));
assert_eq!(info.class, DispatchClass::Normal);
assert_eq!(info.pays_fee, Pays::Yes);
// #[weight = (1000, DispatchClass::Mandatory)]
let info = Call::<TraitImpl>::f01 {}.get_dispatch_info();
assert_eq!(info.weight, Weight::from_ref_time(1000));
assert_eq!(info.class, DispatchClass::Mandatory);
assert_eq!(info.pays_fee, Pays::Yes);
// #[weight = (1000, Pays::No)]
let info = Call::<TraitImpl>::f02 {}.get_dispatch_info();
assert_eq!(info.weight, Weight::from_ref_time(1000));
assert_eq!(info.class, DispatchClass::Normal);
assert_eq!(info.pays_fee, Pays::No);
// #[weight = (1000, DispatchClass::Operational, Pays::No)]
let info = Call::<TraitImpl>::f03 {}.get_dispatch_info();
assert_eq!(info.weight, Weight::from_ref_time(1000));
assert_eq!(info.class, DispatchClass::Operational);
assert_eq!(info.pays_fee, Pays::No);
// #[weight = ((_a * 10 + _eb * 1) as Weight, DispatchClass::Normal, Pays::Yes)]
let info = Call::<TraitImpl>::f11 { _a: 13, _eb: 20 }.get_dispatch_info();
assert_eq!(info.weight, Weight::from_ref_time(150)); // 13*10 + 20
assert_eq!(info.class, DispatchClass::Normal);
assert_eq!(info.pays_fee, Pays::Yes);
// #[weight = (0, DispatchClass::Operational, Pays::Yes)]
let info = Call::<TraitImpl>::f12 { _a: 10, _eb: 20 }.get_dispatch_info();
assert_eq!(info.weight, Weight::from_ref_time(0));
assert_eq!(info.class, DispatchClass::Operational);
assert_eq!(info.pays_fee, Pays::Yes);
// #[weight = T::DbWeight::get().reads(3) + T::DbWeight::get().writes(2) + 10_000]
let info = Call::<TraitImpl>::f20 {}.get_dispatch_info();
assert_eq!(info.weight, Weight::from_ref_time(12300)); // 100*3 + 1000*2 + 10_1000
assert_eq!(info.class, DispatchClass::Normal);
assert_eq!(info.pays_fee, Pays::Yes);
// #[weight = T::DbWeight::get().reads_writes(6, 5) + 40_000]
let info = Call::<TraitImpl>::f21 {}.get_dispatch_info();
assert_eq!(info.weight, Weight::from_ref_time(45600)); // 100*6 + 1000*5 + 40_1000
assert_eq!(info.class, DispatchClass::Normal);
assert_eq!(info.pays_fee, Pays::Yes);
}
#[test]
fn extract_actual_weight_works() {
let pre = DispatchInfo { weight: Weight::from_ref_time(1000), ..Default::default() };
assert_eq!(extract_actual_weight(&Ok(Some(7).into()), &pre), Weight::from_ref_time(7));
assert_eq!(
extract_actual_weight(&Ok(Some(1000).into()), &pre),
Weight::from_ref_time(1000)
);
assert_eq!(
extract_actual_weight(
&Err(DispatchError::BadOrigin.with_weight(Weight::from_ref_time(9))),
&pre
),
Weight::from_ref_time(9)
);
}
#[test]
fn extract_actual_weight_caps_at_pre_weight() {
let pre = DispatchInfo { weight: Weight::from_ref_time(1000), ..Default::default() };
assert_eq!(
extract_actual_weight(&Ok(Some(1250).into()), &pre),
Weight::from_ref_time(1000)
);
assert_eq!(
extract_actual_weight(
&Err(DispatchError::BadOrigin.with_weight(Weight::from_ref_time(1300))),
&pre
),
Weight::from_ref_time(1000),
);
}
#[test]
fn extract_actual_pays_fee_works() {
let pre = DispatchInfo { weight: Weight::from_ref_time(1000), ..Default::default() };
assert_eq!(extract_actual_pays_fee(&Ok(Some(7).into()), &pre), Pays::Yes);
assert_eq!(extract_actual_pays_fee(&Ok(Some(1000).into()), &pre), Pays::Yes);
assert_eq!(extract_actual_pays_fee(&Ok((Some(1000), Pays::Yes).into()), &pre), Pays::Yes);
assert_eq!(extract_actual_pays_fee(&Ok((Some(1000), Pays::No).into()), &pre), Pays::No);
assert_eq!(
extract_actual_pays_fee(
&Err(DispatchError::BadOrigin.with_weight(Weight::from_ref_time(9))),
&pre
),
Pays::Yes
);
assert_eq!(
extract_actual_pays_fee(
&Err(DispatchErrorWithPostInfo {
post_info: PostDispatchInfo { actual_weight: None, pays_fee: Pays::No },
error: DispatchError::BadOrigin,
}),
&pre
),
Pays::No
);
let pre = DispatchInfo {
weight: Weight::from_ref_time(1000),
pays_fee: Pays::No,
..Default::default()
};
assert_eq!(extract_actual_pays_fee(&Ok(Some(7).into()), &pre), Pays::No);
assert_eq!(extract_actual_pays_fee(&Ok(Some(1000).into()), &pre), Pays::No);
assert_eq!(extract_actual_pays_fee(&Ok((Some(1000), Pays::Yes).into()), &pre), Pays::No);
}
}
+5 -2
View File
@@ -1376,7 +1376,10 @@ pub mod pallet_prelude {
#[cfg(feature = "std")]
pub use crate::traits::GenesisBuild;
pub use crate::{
dispatch::{DispatchError, DispatchResult, DispatchResultWithPostInfo, Parameter},
dispatch::{
DispatchClass, DispatchError, DispatchResult, DispatchResultWithPostInfo, Parameter,
Pays,
},
ensure,
inherent::{InherentData, InherentIdentifier, ProvideInherent},
storage,
@@ -1391,7 +1394,6 @@ pub mod pallet_prelude {
ConstU32, EnsureOrigin, Get, GetDefault, GetStorageVersion, Hooks, IsType,
PalletInfoAccess, StorageInfoTrait, StorageVersion, TypedGet,
},
weights::{DispatchClass, Pays, Weight},
Blake2_128, Blake2_128Concat, Blake2_256, CloneNoBound, DebugNoBound, EqNoBound, Identity,
PartialEqNoBound, RuntimeDebug, RuntimeDebugNoBound, Twox128, Twox256, Twox64Concat,
};
@@ -1407,6 +1409,7 @@ pub mod pallet_prelude {
MAX_MODULE_ERROR_ENCODED_SIZE,
};
pub use sp_std::marker::PhantomData;
pub use sp_weights::Weight;
}
/// `pallet` attribute macro allows to define a pallet to be used in `construct_runtime!`.
+2 -2
View File
@@ -711,13 +711,13 @@ pub trait EstimateCallFee<Call, Balance> {
///
/// The dispatch info and the length is deduced from the call. The post info can optionally be
/// provided.
fn estimate_call_fee(call: &Call, post_info: crate::weights::PostDispatchInfo) -> Balance;
fn estimate_call_fee(call: &Call, post_info: crate::dispatch::PostDispatchInfo) -> Balance;
}
// Useful for building mocks.
#[cfg(feature = "std")]
impl<Call, Balance: From<u32>, const T: u32> EstimateCallFee<Call, Balance> for ConstU32<T> {
fn estimate_call_fee(_: &Call, _: crate::weights::PostDispatchInfo) -> Balance {
fn estimate_call_fee(_: &Call, _: crate::dispatch::PostDispatchInfo) -> Balance {
T.into()
}
}
+57 -895
View File
@@ -15,102 +15,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//! # Primitives for transaction weighting.
//!
//! Every dispatchable function is responsible for providing `#[weight = $x]` attribute. In this
//! snipped, `$x` can be any user provided struct that implements the following traits:
//!
//! - [`WeighData`]: the weight amount.
//! - [`ClassifyDispatch`]: class of the dispatch.
//! - [`PaysFee`]: whether this weight should be translated to fee and deducted upon dispatch.
//!
//! Substrate then bundles the output information of the three traits into [`DispatchInfo`] struct
//! and provides it by implementing the [`GetDispatchInfo`] for all `Call` both inner and outer call
//! types.
//!
//! Substrate provides two pre-defined ways to annotate weight:
//!
//! ### 1. Fixed values
//!
//! This can only be used when all 3 traits can be resolved statically. You have 3 degrees of
//! configuration:
//!
//! 1. Define only weight, **in which case `ClassifyDispatch` will be `Normal` and `PaysFee` will be
//! `Yes`**.
//!
//! ```
//! # use frame_system::Config;
//! frame_support::decl_module! {
//! pub struct Module<T: Config> for enum Call where origin: T::Origin {
//! #[weight = 1000]
//! fn dispatching(origin) { unimplemented!() }
//! }
//! }
//! # fn main() {}
//! ```
//!
//! 2.1 Define weight and class, **in which case `PaysFee` would be `Yes`**.
//!
//! ```
//! # use frame_system::Config;
//! # use frame_support::weights::DispatchClass;
//! frame_support::decl_module! {
//! pub struct Module<T: Config> for enum Call where origin: T::Origin {
//! #[weight = (1000, DispatchClass::Operational)]
//! fn dispatching(origin) { unimplemented!() }
//! }
//! }
//! # fn main() {}
//! ```
//!
//! 2.2 Define weight and `PaysFee`, **in which case `ClassifyDispatch` would be `Normal`**.
//!
//! ```
//! # use frame_system::Config;
//! # use frame_support::weights::Pays;
//! frame_support::decl_module! {
//! pub struct Module<T: Config> for enum Call where origin: T::Origin {
//! #[weight = (1000, Pays::No)]
//! fn dispatching(origin) { unimplemented!() }
//! }
//! }
//! # fn main() {}
//! ```
//!
//! 3. Define all 3 parameters.
//!
//! ```
//! # use frame_system::Config;
//! # use frame_support::weights::{DispatchClass, Pays};
//! frame_support::decl_module! {
//! pub struct Module<T: Config> for enum Call where origin: T::Origin {
//! #[weight = (1000, DispatchClass::Operational, Pays::No)]
//! fn dispatching(origin) { unimplemented!() }
//! }
//! }
//! # fn main() {}
//! ```
//!
//! ### 2. Define weights as a function of input arguments.
//!
//! The arguments of the dispatch are available in the weight expressions as a borrowed value.
//!
//! ```
//! # use frame_system::Config;
//! # use frame_support::weights::{DispatchClass, Pays};
//! frame_support::decl_module! {
//! pub struct Module<T: Config> for enum Call where origin: T::Origin {
//! #[weight = (
//! *a as u64 + *b,
//! DispatchClass::Operational,
//! if *a > 1000 { Pays::Yes } else { Pays::No }
//! )]
//! fn dispatching(origin, a: u32, b: u64) { unimplemented!() }
//! }
//! }
//! # fn main() {}
//! ```
//! FRAME assumes a weight of `1_000_000_000_000` equals 1 second of compute on a standard machine.
//! Re-exports `sp-weights` public API, and contains benchmarked weight constants specific to
//! FRAME.
//!
//! Latest machine specification used to benchmark are:
//! - Digital Ocean: ubuntu-s-2vcpu-4gb-ams3-01
@@ -123,41 +29,14 @@ mod block_weights;
mod extrinsic_weights;
mod paritydb_weights;
mod rocksdb_weights;
mod weight_v2;
use crate::{
dispatch::{DispatchError, DispatchErrorWithPostInfo, DispatchResultWithPostInfo},
traits::Get,
};
use codec::{Decode, Encode, MaxEncodedLen};
use scale_info::TypeInfo;
#[cfg(feature = "std")]
use serde::{Deserialize, Serialize};
use smallvec::SmallVec;
use sp_arithmetic::{
traits::{BaseArithmetic, Saturating, Unsigned},
Perbill,
};
use sp_runtime::{
generic::{CheckedExtrinsic, UncheckedExtrinsic},
traits::{SaturatedConversion, SignedExtension},
RuntimeDebug,
};
/// Re-export priority as type
pub use sp_runtime::transaction_validity::TransactionPriority;
pub use weight_v2::*;
use crate::dispatch;
pub use sp_weights::*;
/// These constants are specific to FRAME, and the current implementation of its various components.
/// For example: FRAME System, FRAME Executive, our FRAME support libraries, etc...
pub mod constants {
use super::Weight;
pub const WEIGHT_PER_SECOND: Weight = Weight::from_ref_time(1_000_000_000_000);
pub const WEIGHT_PER_MILLIS: Weight = Weight::from_ref_time(1_000_000_000);
pub const WEIGHT_PER_MICROS: Weight = Weight::from_ref_time(1_000_000);
pub const WEIGHT_PER_NANOS: Weight = Weight::from_ref_time(1_000);
pub use sp_weights::constants::*;
// Expose the Block and Extrinsic base weights.
pub use super::{block_weights::BlockExecutionWeight, extrinsic_weights::ExtrinsicBaseWeight};
@@ -168,786 +47,69 @@ pub mod constants {
};
}
/// Means of weighing some particular kind of data (`T`).
pub trait WeighData<T> {
/// Weigh the data `T` given by `target`. When implementing this for a dispatchable, `T` will be
/// a tuple of all arguments given to the function (except origin).
fn weigh_data(&self, target: T) -> Weight;
#[deprecated = "Function has moved to `frame_support::dispatch`"]
pub fn extract_actual_pays_fee(
res: &dispatch::DispatchResultWithPostInfo,
info: &dispatch::DispatchInfo,
) -> dispatch::Pays {
dispatch::extract_actual_pays_fee(res, info)
}
/// Means of classifying a dispatchable function.
pub trait ClassifyDispatch<T> {
/// Classify the dispatch function based on input data `target` of type `T`. When implementing
/// this for a dispatchable, `T` will be a tuple of all arguments given to the function (except
/// origin).
fn classify_dispatch(&self, target: T) -> DispatchClass;
#[deprecated = "Function has moved to `frame_support::dispatch`"]
pub fn extract_actual_weight(
res: &dispatch::DispatchResultWithPostInfo,
info: &dispatch::DispatchInfo,
) -> Weight {
dispatch::extract_actual_weight(res, info)
}
/// Indicates if dispatch function should pay fees or not.
/// If set to `Pays::No`, the block resource limits are applied, yet no fee is deducted.
pub trait PaysFee<T> {
fn pays_fee(&self, _target: T) -> Pays;
}
/// Explicit enum to denote if a transaction pays fee or not.
#[derive(Clone, Copy, Eq, PartialEq, RuntimeDebug, Encode, Decode, TypeInfo)]
pub enum Pays {
/// Transactor will pay related fees.
Yes,
/// Transactor will NOT pay related fees.
No,
}
impl Default for Pays {
fn default() -> Self {
Self::Yes
#[deprecated = "Trait has moved to `frame_support::dispatch`"]
pub trait ClassifyDispatch<T>: dispatch::ClassifyDispatch<T> {
fn classify_dispatch(&self, target: T) -> dispatch::DispatchClass {
<Self as dispatch::ClassifyDispatch<T>>::classify_dispatch(self, target)
}
}
impl From<Pays> for PostDispatchInfo {
fn from(pays_fee: Pays) -> Self {
Self { actual_weight: None, pays_fee }
#[deprecated = "Enum has moved to `frame_support::dispatch`"]
pub type DispatchClass = dispatch::DispatchClass;
#[deprecated = "Struct has moved to `frame_support::dispatch`"]
pub type DispatchInfo = dispatch::DispatchInfo;
#[deprecated = "Trait has moved to `frame_support::dispatch`"]
pub trait GetDispatchInfo: dispatch::GetDispatchInfo {
fn get_dispatch_info(&self) -> dispatch::DispatchInfo {
<Self as dispatch::GetDispatchInfo>::get_dispatch_info(self)
}
}
/// A generalized group of dispatch types.
///
/// NOTE whenever upgrading the enum make sure to also update
/// [DispatchClass::all] and [DispatchClass::non_mandatory] helper functions.
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))]
#[derive(PartialEq, Eq, Clone, Copy, Encode, Decode, RuntimeDebug, TypeInfo)]
pub enum DispatchClass {
/// A normal dispatch.
Normal,
/// An operational dispatch.
Operational,
/// A mandatory dispatch. These kinds of dispatch are always included regardless of their
/// weight, therefore it is critical that they are separately validated to ensure that a
/// malicious validator cannot craft a valid but impossibly heavy block. Usually this just
/// means ensuring that the extrinsic can only be included once and that it is always very
/// light.
///
/// Do *NOT* use it for extrinsics that can be heavy.
///
/// The only real use case for this is inherent extrinsics that are required to execute in a
/// block for the block to be valid, and it solves the issue in the case that the block
/// initialization is sufficiently heavy to mean that those inherents do not fit into the
/// block. Essentially, we assume that in these exceptional circumstances, it is better to
/// allow an overweight block to be created than to not allow any block at all to be created.
Mandatory,
}
impl Default for DispatchClass {
fn default() -> Self {
Self::Normal
#[deprecated = "Trait has moved to `frame_support::dispatch`"]
pub trait OneOrMany<T>: dispatch::OneOrMany<T> {
fn into_iter(self) -> Self::Iter
where
Self: Sized,
{
<Self as dispatch::OneOrMany<T>>::into_iter(self)
}
}
impl DispatchClass {
/// Returns an array containing all dispatch classes.
pub fn all() -> &'static [DispatchClass] {
&[DispatchClass::Normal, DispatchClass::Operational, DispatchClass::Mandatory]
}
/// Returns an array of all dispatch classes except `Mandatory`.
pub fn non_mandatory() -> &'static [DispatchClass] {
&[DispatchClass::Normal, DispatchClass::Operational]
#[deprecated = "Enum has moved to `frame_support::dispatch`"]
pub type Pays = dispatch::Pays;
#[deprecated = "Trait has moved to `frame_support::dispatch`"]
pub trait PaysFee<T>: dispatch::PaysFee<T> {
fn pays_fee(&self, target: T) -> dispatch::Pays {
<Self as dispatch::PaysFee<T>>::pays_fee(self, target)
}
}
/// A trait that represents one or many values of given type.
///
/// Useful to accept as parameter type to let the caller pass either a single value directly
/// or an iterator.
pub trait OneOrMany<T> {
/// The iterator type.
type Iter: Iterator<Item = T>;
/// Convert this item into an iterator.
fn into_iter(self) -> Self::Iter;
}
impl OneOrMany<DispatchClass> for DispatchClass {
type Iter = sp_std::iter::Once<DispatchClass>;
fn into_iter(self) -> Self::Iter {
sp_std::iter::once(self)
#[deprecated = "Struct has moved to `frame_support::dispatch`"]
pub type PerDispatchClass<T> = dispatch::PerDispatchClass<T>;
#[deprecated = "Struct has moved to `frame_support::dispatch`"]
pub type PostDispatchInfo = dispatch::PostDispatchInfo;
#[deprecated = "Trait has moved to `frame_support::dispatch`"]
pub trait WeighData<T>: dispatch::WeighData<T> {
fn weigh_data(&self, target: T) -> Weight {
<Self as dispatch::WeighData<T>>::weigh_data(self, target)
}
}
impl<'a> OneOrMany<DispatchClass> for &'a [DispatchClass] {
type Iter = sp_std::iter::Cloned<sp_std::slice::Iter<'a, DispatchClass>>;
fn into_iter(self) -> Self::Iter {
self.iter().cloned()
}
}
/// A bundle of static information collected from the `#[weight = $x]` attributes.
#[derive(Clone, Copy, Eq, PartialEq, Default, RuntimeDebug, Encode, Decode, TypeInfo)]
pub struct DispatchInfo {
/// Weight of this transaction.
pub weight: Weight,
/// Class of this transaction.
pub class: DispatchClass,
/// Does this transaction pay fees.
pub pays_fee: Pays,
}
/// A `Dispatchable` function (aka transaction) that can carry some static information along with
/// it, using the `#[weight]` attribute.
pub trait GetDispatchInfo {
/// Return a `DispatchInfo`, containing relevant information of this dispatch.
///
/// This is done independently of its encoded size.
fn get_dispatch_info(&self) -> DispatchInfo;
}
impl GetDispatchInfo for () {
fn get_dispatch_info(&self) -> DispatchInfo {
DispatchInfo::default()
}
}
/// Weight information that is only available post dispatch.
/// NOTE: This can only be used to reduce the weight or fee, not increase it.
#[derive(Clone, Copy, Eq, PartialEq, Default, RuntimeDebug, Encode, Decode, TypeInfo)]
pub struct PostDispatchInfo {
/// Actual weight consumed by a call or `None` which stands for the worst case static weight.
pub actual_weight: Option<Weight>,
/// Whether this transaction should pay fees when all is said and done.
pub pays_fee: Pays,
}
impl PostDispatchInfo {
/// Calculate how much (if any) weight was not used by the `Dispatchable`.
pub fn calc_unspent(&self, info: &DispatchInfo) -> Weight {
info.weight - self.calc_actual_weight(info)
}
/// Calculate how much weight was actually spent by the `Dispatchable`.
pub fn calc_actual_weight(&self, info: &DispatchInfo) -> Weight {
if let Some(actual_weight) = self.actual_weight {
actual_weight.min(info.weight)
} else {
info.weight
}
}
/// Determine if user should actually pay fees at the end of the dispatch.
pub fn pays_fee(&self, info: &DispatchInfo) -> Pays {
// If they originally were not paying fees, or the post dispatch info
// says they should not pay fees, then they don't pay fees.
// This is because the pre dispatch information must contain the
// worst case for weight and fees paid.
if info.pays_fee == Pays::No || self.pays_fee == Pays::No {
Pays::No
} else {
// Otherwise they pay.
Pays::Yes
}
}
}
/// Extract the actual weight from a dispatch result if any or fall back to the default weight.
pub fn extract_actual_weight(result: &DispatchResultWithPostInfo, info: &DispatchInfo) -> Weight {
match result {
Ok(post_info) => post_info,
Err(err) => &err.post_info,
}
.calc_actual_weight(info)
}
/// Extract the actual pays_fee from a dispatch result if any or fall back to the default weight.
pub fn extract_actual_pays_fee(result: &DispatchResultWithPostInfo, info: &DispatchInfo) -> Pays {
match result {
Ok(post_info) => post_info,
Err(err) => &err.post_info,
}
.pays_fee(info)
}
impl From<()> for PostDispatchInfo {
fn from(_: ()) -> Self {
Self { actual_weight: None, pays_fee: Default::default() }
}
}
impl sp_runtime::traits::Printable for PostDispatchInfo {
fn print(&self) {
"actual_weight=".print();
match self.actual_weight {
Some(weight) => weight.print(),
None => "max-weight".print(),
};
"pays_fee=".print();
match self.pays_fee {
Pays::Yes => "Yes".print(),
Pays::No => "No".print(),
}
}
}
/// Allows easy conversion from `DispatchError` to `DispatchErrorWithPostInfo` for dispatchables
/// that want to return a custom a posterior weight on error.
pub trait WithPostDispatchInfo {
/// Call this on your modules custom errors type in order to return a custom weight on error.
///
/// # Example
///
/// ```ignore
/// let who = ensure_signed(origin).map_err(|e| e.with_weight(Weight::from_ref_time(100)))?;
/// ensure!(who == me, Error::<T>::NotMe.with_weight(200_000));
/// ```
fn with_weight(self, actual_weight: Weight) -> DispatchErrorWithPostInfo;
}
impl<T> WithPostDispatchInfo for T
where
T: Into<DispatchError>,
{
fn with_weight(self, actual_weight: Weight) -> DispatchErrorWithPostInfo {
DispatchErrorWithPostInfo {
post_info: PostDispatchInfo {
actual_weight: Some(actual_weight),
pays_fee: Default::default(),
},
error: self.into(),
}
}
}
/// Implementation for unchecked extrinsic.
impl<Address, Call, Signature, Extra> GetDispatchInfo
for UncheckedExtrinsic<Address, Call, Signature, Extra>
where
Call: GetDispatchInfo,
Extra: SignedExtension,
{
fn get_dispatch_info(&self) -> DispatchInfo {
self.function.get_dispatch_info()
}
}
/// Implementation for checked extrinsic.
impl<AccountId, Call, Extra> GetDispatchInfo for CheckedExtrinsic<AccountId, Call, Extra>
where
Call: GetDispatchInfo,
{
fn get_dispatch_info(&self) -> DispatchInfo {
self.function.get_dispatch_info()
}
}
/// Implementation for test extrinsic.
#[cfg(feature = "std")]
impl<Call: Encode, Extra: Encode> GetDispatchInfo for sp_runtime::testing::TestXt<Call, Extra> {
fn get_dispatch_info(&self) -> DispatchInfo {
// for testing: weight == size.
DispatchInfo {
weight: Weight::from_ref_time(self.encode().len() as _),
pays_fee: Pays::Yes,
..Default::default()
}
}
}
/// The weight of database operations that the runtime can invoke.
///
/// NOTE: This is currently only measured in computational time, and will probably
/// be updated all together once proof size is accounted for.
#[derive(Clone, Copy, Eq, PartialEq, Default, RuntimeDebug, Encode, Decode, TypeInfo)]
pub struct RuntimeDbWeight {
pub read: u64,
pub write: u64,
}
impl RuntimeDbWeight {
pub fn reads(self, r: u64) -> Weight {
Weight::from_ref_time(self.read.saturating_mul(r))
}
pub fn writes(self, w: u64) -> Weight {
Weight::from_ref_time(self.write.saturating_mul(w))
}
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_ref_time(read_weight.saturating_add(write_weight))
}
}
/// One coefficient and its position in the `WeightToFee`.
///
/// One term of polynomial is calculated as:
///
/// ```ignore
/// coeff_integer * x^(degree) + coeff_frac * x^(degree)
/// ```
///
/// The `negative` value encodes whether the term is added or substracted from the
/// overall polynomial result.
#[derive(Clone, Encode, Decode, TypeInfo)]
pub struct WeightToFeeCoefficient<Balance> {
/// The integral part of the coefficient.
pub coeff_integer: Balance,
/// The fractional part of the coefficient.
pub coeff_frac: Perbill,
/// True iff the coefficient should be interpreted as negative.
pub negative: bool,
/// Degree/exponent of the term.
pub degree: u8,
}
/// A list of coefficients that represent one polynomial.
pub type WeightToFeeCoefficients<T> = SmallVec<[WeightToFeeCoefficient<T>; 4]>;
/// A trait that describes the weight to fee calculation.
pub trait WeightToFee {
/// The type that is returned as result from calculation.
type Balance: BaseArithmetic + From<u32> + Copy + Unsigned;
/// Calculates the fee from the passed `weight`.
fn weight_to_fee(weight: &Weight) -> Self::Balance;
}
/// A trait that describes the weight to fee calculation as polynomial.
///
/// An implementor should only implement the `polynomial` function.
pub trait WeightToFeePolynomial {
/// The type that is returned as result from polynomial evaluation.
type Balance: BaseArithmetic + From<u32> + Copy + Unsigned;
/// Returns a polynomial that describes the weight to fee conversion.
///
/// This is the only function that should be manually implemented. Please note
/// that all calculation is done in the probably unsigned `Balance` type. This means
/// that the order of coefficients is important as putting the negative coefficients
/// first will most likely saturate the result to zero mid evaluation.
fn polynomial() -> WeightToFeeCoefficients<Self::Balance>;
}
impl<T> WeightToFee for T
where
T: WeightToFeePolynomial,
{
type Balance = <Self as WeightToFeePolynomial>::Balance;
/// Calculates the fee from the passed `weight` according to the `polynomial`.
///
/// This should not be overridden in most circumstances. Calculation is done in the
/// `Balance` type and never overflows. All evaluation is saturating.
fn weight_to_fee(weight: &Weight) -> Self::Balance {
Self::polynomial()
.iter()
.fold(Self::Balance::saturated_from(0u32), |mut acc, args| {
let w = Self::Balance::saturated_from(weight.ref_time())
.saturating_pow(args.degree.into());
// The sum could get negative. Therefore we only sum with the accumulator.
// The Perbill Mul implementation is non overflowing.
let frac = args.coeff_frac * w;
let integer = args.coeff_integer.saturating_mul(w);
if args.negative {
acc = acc.saturating_sub(frac);
acc = acc.saturating_sub(integer);
} else {
acc = acc.saturating_add(frac);
acc = acc.saturating_add(integer);
}
acc
})
}
}
/// Implementor of `WeightToFee` that maps one unit of weight to one unit of fee.
pub struct IdentityFee<T>(sp_std::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())
}
}
/// Implementor of [`WeightToFee`] that uses a constant multiplier.
/// # Example
///
/// ```
/// # use frame_support::traits::ConstU128;
/// # use frame_support::weights::ConstantMultiplier;
/// // Results in a multiplier of 10 for each unit of weight (or length)
/// type LengthToFee = ConstantMultiplier::<u128, ConstU128<10u128>>;
/// ```
pub struct ConstantMultiplier<T, M>(sp_std::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())
}
}
/// A struct holding value for each `DispatchClass`.
#[derive(Clone, Eq, PartialEq, Default, RuntimeDebug, Encode, Decode, TypeInfo, MaxEncodedLen)]
pub struct PerDispatchClass<T> {
/// Value for `Normal` extrinsics.
normal: T,
/// Value for `Operational` extrinsics.
operational: T,
/// Value for `Mandatory` extrinsics.
mandatory: T,
}
impl<T> PerDispatchClass<T> {
/// Create new `PerDispatchClass` with the same value for every class.
pub fn new(val: impl Fn(DispatchClass) -> T) -> Self {
Self {
normal: val(DispatchClass::Normal),
operational: val(DispatchClass::Operational),
mandatory: val(DispatchClass::Mandatory),
}
}
/// Get a mutable reference to current value of given class.
pub fn get_mut(&mut self, class: DispatchClass) -> &mut T {
match class {
DispatchClass::Operational => &mut self.operational,
DispatchClass::Normal => &mut self.normal,
DispatchClass::Mandatory => &mut self.mandatory,
}
}
/// Get current value for given class.
pub fn get(&self, class: DispatchClass) -> &T {
match class {
DispatchClass::Normal => &self.normal,
DispatchClass::Operational => &self.operational,
DispatchClass::Mandatory => &self.mandatory,
}
}
}
impl<T: Clone> PerDispatchClass<T> {
/// Set the value of given class.
pub fn set(&mut self, new: T, class: impl OneOrMany<DispatchClass>) {
for class in class.into_iter() {
*self.get_mut(class) = new.clone();
}
}
}
impl PerDispatchClass<Weight> {
/// Returns the total weight consumed by all extrinsics in the block.
pub fn total(&self) -> Weight {
let mut sum = Weight::zero();
for class in DispatchClass::all() {
sum = sum.saturating_add(*self.get(*class));
}
sum
}
/// Add some weight of a specific dispatch class, saturating at the numeric bounds of `Weight`.
pub fn add(&mut self, weight: Weight, class: DispatchClass) {
let value = self.get_mut(class);
*value = value.saturating_add(weight);
}
/// Try to add some weight of a specific dispatch class, returning Err(()) if overflow would
/// occur.
pub fn checked_add(&mut self, weight: Weight, class: DispatchClass) -> Result<(), ()> {
let value = self.get_mut(class);
*value = value.checked_add(&weight).ok_or(())?;
Ok(())
}
/// Subtract some weight of a specific dispatch class, saturating at the numeric bounds of
/// `Weight`.
pub fn sub(&mut self, weight: Weight, class: DispatchClass) {
let value = self.get_mut(class);
*value = value.saturating_sub(weight);
}
}
#[cfg(test)]
#[allow(dead_code)]
mod tests {
use super::*;
use crate::{decl_module, parameter_types, traits::Get};
use smallvec::smallvec;
pub trait Config: 'static {
type Origin;
type Balance;
type BlockNumber;
type DbWeight: Get<RuntimeDbWeight>;
type PalletInfo: crate::traits::PalletInfo;
}
pub struct TraitImpl {}
parameter_types! {
pub const DbWeight: RuntimeDbWeight = RuntimeDbWeight {
read: 100,
write: 1000,
};
}
impl Config for TraitImpl {
type Origin = u32;
type BlockNumber = u32;
type Balance = u32;
type DbWeight = DbWeight;
type PalletInfo = crate::tests::PanicPalletInfo;
}
decl_module! {
pub struct Module<T: Config> for enum Call where origin: T::Origin, system=self {
// no arguments, fixed weight
#[weight = 1000]
fn f00(_origin) { unimplemented!(); }
#[weight = (1000, DispatchClass::Mandatory)]
fn f01(_origin) { unimplemented!(); }
#[weight = (1000, Pays::No)]
fn f02(_origin) { unimplemented!(); }
#[weight = (1000, DispatchClass::Operational, Pays::No)]
fn f03(_origin) { unimplemented!(); }
// weight = a x 10 + b
#[weight = ((_a * 10 + _eb * 1) as u64, DispatchClass::Normal, Pays::Yes)]
fn f11(_origin, _a: u32, _eb: u32) { unimplemented!(); }
#[weight = (0, DispatchClass::Operational, Pays::Yes)]
fn f12(_origin, _a: u32, _eb: u32) { unimplemented!(); }
#[weight = T::DbWeight::get().reads(3) + T::DbWeight::get().writes(2) + Weight::from_ref_time(10_000)]
fn f20(_origin) { unimplemented!(); }
#[weight = T::DbWeight::get().reads_writes(6, 5) + Weight::from_ref_time(40_000)]
fn f21(_origin) { unimplemented!(); }
}
}
#[test]
fn weights_are_correct() {
// #[weight = 1000]
let info = Call::<TraitImpl>::f00 {}.get_dispatch_info();
assert_eq!(info.weight, Weight::from_ref_time(1000));
assert_eq!(info.class, DispatchClass::Normal);
assert_eq!(info.pays_fee, Pays::Yes);
// #[weight = (1000, DispatchClass::Mandatory)]
let info = Call::<TraitImpl>::f01 {}.get_dispatch_info();
assert_eq!(info.weight, Weight::from_ref_time(1000));
assert_eq!(info.class, DispatchClass::Mandatory);
assert_eq!(info.pays_fee, Pays::Yes);
// #[weight = (1000, Pays::No)]
let info = Call::<TraitImpl>::f02 {}.get_dispatch_info();
assert_eq!(info.weight, Weight::from_ref_time(1000));
assert_eq!(info.class, DispatchClass::Normal);
assert_eq!(info.pays_fee, Pays::No);
// #[weight = (1000, DispatchClass::Operational, Pays::No)]
let info = Call::<TraitImpl>::f03 {}.get_dispatch_info();
assert_eq!(info.weight, Weight::from_ref_time(1000));
assert_eq!(info.class, DispatchClass::Operational);
assert_eq!(info.pays_fee, Pays::No);
// #[weight = ((_a * 10 + _eb * 1) as Weight, DispatchClass::Normal, Pays::Yes)]
let info = Call::<TraitImpl>::f11 { _a: 13, _eb: 20 }.get_dispatch_info();
assert_eq!(info.weight, Weight::from_ref_time(150)); // 13*10 + 20
assert_eq!(info.class, DispatchClass::Normal);
assert_eq!(info.pays_fee, Pays::Yes);
// #[weight = (0, DispatchClass::Operational, Pays::Yes)]
let info = Call::<TraitImpl>::f12 { _a: 10, _eb: 20 }.get_dispatch_info();
assert_eq!(info.weight, Weight::from_ref_time(0));
assert_eq!(info.class, DispatchClass::Operational);
assert_eq!(info.pays_fee, Pays::Yes);
// #[weight = T::DbWeight::get().reads(3) + T::DbWeight::get().writes(2) + 10_000]
let info = Call::<TraitImpl>::f20 {}.get_dispatch_info();
assert_eq!(info.weight, Weight::from_ref_time(12300)); // 100*3 + 1000*2 + 10_1000
assert_eq!(info.class, DispatchClass::Normal);
assert_eq!(info.pays_fee, Pays::Yes);
// #[weight = T::DbWeight::get().reads_writes(6, 5) + 40_000]
let info = Call::<TraitImpl>::f21 {}.get_dispatch_info();
assert_eq!(info.weight, Weight::from_ref_time(45600)); // 100*6 + 1000*5 + 40_1000
assert_eq!(info.class, DispatchClass::Normal);
assert_eq!(info.pays_fee, Pays::Yes);
}
#[test]
fn extract_actual_weight_works() {
let pre = DispatchInfo { weight: Weight::from_ref_time(1000), ..Default::default() };
assert_eq!(extract_actual_weight(&Ok(Some(7).into()), &pre), Weight::from_ref_time(7));
assert_eq!(
extract_actual_weight(&Ok(Some(1000).into()), &pre),
Weight::from_ref_time(1000)
);
assert_eq!(
extract_actual_weight(
&Err(DispatchError::BadOrigin.with_weight(Weight::from_ref_time(9))),
&pre
),
Weight::from_ref_time(9)
);
}
#[test]
fn extract_actual_weight_caps_at_pre_weight() {
let pre = DispatchInfo { weight: Weight::from_ref_time(1000), ..Default::default() };
assert_eq!(
extract_actual_weight(&Ok(Some(1250).into()), &pre),
Weight::from_ref_time(1000)
);
assert_eq!(
extract_actual_weight(
&Err(DispatchError::BadOrigin.with_weight(Weight::from_ref_time(1300))),
&pre
),
Weight::from_ref_time(1000),
);
}
#[test]
fn extract_actual_pays_fee_works() {
let pre = DispatchInfo { weight: Weight::from_ref_time(1000), ..Default::default() };
assert_eq!(extract_actual_pays_fee(&Ok(Some(7).into()), &pre), Pays::Yes);
assert_eq!(extract_actual_pays_fee(&Ok(Some(1000).into()), &pre), Pays::Yes);
assert_eq!(extract_actual_pays_fee(&Ok((Some(1000), Pays::Yes).into()), &pre), Pays::Yes);
assert_eq!(extract_actual_pays_fee(&Ok((Some(1000), Pays::No).into()), &pre), Pays::No);
assert_eq!(
extract_actual_pays_fee(
&Err(DispatchError::BadOrigin.with_weight(Weight::from_ref_time(9))),
&pre
),
Pays::Yes
);
assert_eq!(
extract_actual_pays_fee(
&Err(DispatchErrorWithPostInfo {
post_info: PostDispatchInfo { actual_weight: None, pays_fee: Pays::No },
error: DispatchError::BadOrigin,
}),
&pre
),
Pays::No
);
let pre = DispatchInfo {
weight: Weight::from_ref_time(1000),
pays_fee: Pays::No,
..Default::default()
};
assert_eq!(extract_actual_pays_fee(&Ok(Some(7).into()), &pre), Pays::No);
assert_eq!(extract_actual_pays_fee(&Ok(Some(1000).into()), &pre), Pays::No);
assert_eq!(extract_actual_pays_fee(&Ok((Some(1000), Pays::Yes).into()), &pre), Pays::No);
}
type Balance = u64;
// 0.5x^3 + 2.333x^2 + 7x - 10_000
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() {
// 100^3/2=500000 100^2*(2+1/3)=23333 700 -10000
assert_eq!(Poly::weight_to_fee(&Weight::from_ref_time(100)), 514033);
// 10123^3/2=518677865433 10123^2*(2+1/3)=239108634 70861 -10000
assert_eq!(Poly::weight_to_fee(&Weight::from_ref_time(10_123)), 518917034928);
}
#[test]
fn polynomial_does_not_underflow() {
assert_eq!(Poly::weight_to_fee(&Weight::zero()), 0);
assert_eq!(Poly::weight_to_fee(&Weight::from_ref_time(10)), 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_ref_time(50)), 50);
assert_eq!(IdentityFee::<Balance>::weight_to_fee(&Weight::MAX), Balance::max_value());
}
#[test]
fn constant_fee_works() {
use crate::traits::ConstU128;
assert_eq!(
ConstantMultiplier::<u128, ConstU128<100u128>>::weight_to_fee(&Weight::zero()),
0
);
assert_eq!(
ConstantMultiplier::<u128, ConstU128<10u128>>::weight_to_fee(&Weight::from_ref_time(
50
)),
500
);
assert_eq!(
ConstantMultiplier::<u128, ConstU128<1024u128>>::weight_to_fee(&Weight::from_ref_time(
16
)),
16384
);
assert_eq!(
ConstantMultiplier::<u128, ConstU128<{ u128::MAX }>>::weight_to_fee(
&Weight::from_ref_time(2)
),
u128::MAX
);
#[deprecated = "Trait has moved to `frame_support::dispatch`"]
pub trait WithPostDispatchInfo: dispatch::WithPostDispatchInfo {
fn with_weight(self, actual_weight: Weight) -> dispatch::DispatchErrorWithPostInfo
where
Self: Sized,
{
<Self as dispatch::WithPostDispatchInfo>::with_weight(self, actual_weight)
}
}
@@ -34,10 +34,8 @@
// --warmup=10
// --repeat=100
use frame_support::{
parameter_types,
weights::{constants::WEIGHT_PER_NANOS, Weight},
};
use sp_core::parameter_types;
use sp_weights::{constants::WEIGHT_PER_NANOS, Weight};
parameter_types! {
/// Time to execute an empty block.
@@ -58,7 +56,7 @@ parameter_types! {
#[cfg(test)]
mod test_weights {
use frame_support::weights::constants;
use sp_weights::constants;
/// Checks that the weight exists and is sane.
// NOTE: If this test fails but you are sure that the generated values are fine,
@@ -34,10 +34,8 @@
// --warmup=10
// --repeat=100
use frame_support::{
parameter_types,
weights::{constants::WEIGHT_PER_NANOS, Weight},
};
use sp_core::parameter_types;
use sp_weights::{constants::WEIGHT_PER_NANOS, Weight};
parameter_types! {
/// Time to execute a NO-OP extrinsic, for example `System::remark`.
@@ -58,7 +56,7 @@ parameter_types! {
#[cfg(test)]
mod test_weights {
use frame_support::weights::constants;
use sp_weights::constants;
/// Checks that the weight exists and is sane.
// NOTE: If this test fails but you are sure that the generated values are fine,
@@ -16,10 +16,9 @@
// limitations under the License.
pub mod constants {
use frame_support::{
parameter_types,
weights::{constants, RuntimeDbWeight},
};
use frame_support::weights::constants;
use sp_core::parameter_types;
use sp_weights::RuntimeDbWeight;
parameter_types! {
/// ParityDB can be enabled with a feature flag, but is still experimental. These weights
@@ -33,7 +32,7 @@ pub mod constants {
#[cfg(test)]
mod test_db_weights {
use super::constants::ParityDbWeight as W;
use frame_support::weights::constants;
use sp_weights::constants;
/// Checks that all weights exist and have sane values.
// NOTE: If this test fails but you are sure that the generated values are fine,
@@ -16,10 +16,9 @@
// limitations under the License.
pub mod constants {
use frame_support::{
parameter_types,
weights::{constants, RuntimeDbWeight},
};
use frame_support::weights::constants;
use sp_core::parameter_types;
use sp_weights::RuntimeDbWeight;
parameter_types! {
/// By default, Substrate uses RocksDB, so this will be the weight used throughout
@@ -33,7 +32,7 @@ pub mod constants {
#[cfg(test)]
mod test_db_weights {
use super::constants::RocksDbWeight as W;
use frame_support::weights::constants;
use sp_weights::constants;
/// Checks that all weights exist and have sane values.
// NOTE: If this test fails but you are sure that the generated values are fine,
@@ -1,526 +0,0 @@
// This file is part of Substrate.
// Copyright (C) 2022 Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use codec::{CompactAs, Decode, Encode, MaxEncodedLen};
use core::ops::{Add, AddAssign, Div, Mul, Sub, SubAssign};
use sp_runtime::{
traits::{Bounded, CheckedAdd, CheckedSub, Zero},
RuntimeDebug,
};
use super::*;
#[derive(
Encode,
Decode,
MaxEncodedLen,
TypeInfo,
Eq,
PartialEq,
Copy,
Clone,
RuntimeDebug,
Default,
CompactAs,
)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
pub struct Weight {
/// The weight of computational time used based on some reference hardware.
ref_time: u64,
}
impl Weight {
/// Set the reference time part of the weight.
pub const fn set_ref_time(mut self, c: u64) -> Self {
self.ref_time = c;
self
}
/// Return the reference time part of the weight.
pub const fn ref_time(&self) -> u64 {
self.ref_time
}
/// Return a mutable reference time part of the weight.
pub fn ref_time_mut(&mut self) -> &mut u64 {
&mut self.ref_time
}
pub const MAX: Self = Self { ref_time: u64::MAX };
/// Get the conservative min of `self` and `other` weight.
pub fn min(&self, other: Self) -> Self {
Self { ref_time: self.ref_time.min(other.ref_time) }
}
/// Get the aggressive max of `self` and `other` weight.
pub fn max(&self, other: Self) -> Self {
Self { ref_time: self.ref_time.max(other.ref_time) }
}
/// Try to add some `other` weight while upholding the `limit`.
pub fn try_add(&self, other: &Self, limit: &Self) -> Option<Self> {
let total = self.checked_add(other)?;
if total.ref_time > limit.ref_time {
None
} else {
Some(total)
}
}
/// Construct [`Weight`] with reference time weight.
pub const fn from_ref_time(ref_time: u64) -> Self {
Self { ref_time }
}
/// Saturating [`Weight`] addition. Computes `self + rhs`, saturating at the numeric bounds of
/// all fields instead of overflowing.
pub const fn saturating_add(self, rhs: Self) -> Self {
Self { ref_time: self.ref_time.saturating_add(rhs.ref_time) }
}
/// Saturating [`Weight`] subtraction. Computes `self - rhs`, saturating at the numeric bounds
/// of all fields instead of overflowing.
pub const fn saturating_sub(self, rhs: Self) -> Self {
Self { ref_time: self.ref_time.saturating_sub(rhs.ref_time) }
}
/// Saturating [`Weight`] scalar multiplication. Computes `self.field * scalar` for all fields,
/// saturating at the numeric bounds of all fields instead of overflowing.
pub const fn saturating_mul(self, scalar: u64) -> Self {
Self { ref_time: self.ref_time.saturating_mul(scalar) }
}
/// Saturating [`Weight`] scalar division. Computes `self.field / scalar` for all fields,
/// saturating at the numeric bounds of all fields instead of overflowing.
pub const fn saturating_div(self, scalar: u64) -> Self {
Self { ref_time: self.ref_time.saturating_div(scalar) }
}
/// Saturating [`Weight`] scalar exponentiation. Computes `self.field.pow(exp)` for all fields,
/// saturating at the numeric bounds of all fields instead of overflowing.
pub const fn saturating_pow(self, exp: u32) -> Self {
Self { ref_time: self.ref_time.saturating_pow(exp) }
}
/// Increment [`Weight`] by `amount` via saturating addition.
pub fn saturating_accrue(&mut self, amount: Self) {
*self = self.saturating_add(amount);
}
/// Checked [`Weight`] addition. Computes `self + rhs`, returning `None` if overflow occurred.
pub const fn checked_add(&self, rhs: &Self) -> Option<Self> {
match self.ref_time.checked_add(rhs.ref_time) {
Some(ref_time) => Some(Self { ref_time }),
None => None,
}
}
/// Checked [`Weight`] subtraction. Computes `self - rhs`, returning `None` if overflow
/// occurred.
pub const fn checked_sub(&self, rhs: &Self) -> Option<Self> {
match self.ref_time.checked_sub(rhs.ref_time) {
Some(ref_time) => Some(Self { ref_time }),
None => None,
}
}
/// Checked [`Weight`] scalar multiplication. Computes `self.field * scalar` for each field,
/// returning `None` if overflow occurred.
pub const fn checked_mul(self, scalar: u64) -> Option<Self> {
match self.ref_time.checked_mul(scalar) {
Some(ref_time) => Some(Self { ref_time }),
None => None,
}
}
/// Checked [`Weight`] scalar division. Computes `self.field / scalar` for each field, returning
/// `None` if overflow occurred.
pub const fn checked_div(self, scalar: u64) -> Option<Self> {
match self.ref_time.checked_div(scalar) {
Some(ref_time) => Some(Self { ref_time }),
None => None,
}
}
/// Return a [`Weight`] where all fields are zero.
pub const fn zero() -> Self {
Self { ref_time: 0 }
}
/// Returns true if any of `self`'s constituent weights is strictly greater than that of the
/// `other`'s, otherwise returns false.
pub const fn any_gt(self, other: Self) -> bool {
self.ref_time > other.ref_time
}
/// Returns true if all of `self`'s constituent weights is strictly greater than that of the
/// `other`'s, otherwise returns false.
pub const fn all_gt(self, other: Self) -> bool {
self.ref_time > other.ref_time
}
/// Returns true if any of `self`'s constituent weights is strictly less than that of the
/// `other`'s, otherwise returns false.
pub const fn any_lt(self, other: Self) -> bool {
self.ref_time < other.ref_time
}
/// Returns true if all of `self`'s constituent weights is strictly less than that of the
/// `other`'s, otherwise returns false.
pub const fn all_lt(self, other: Self) -> bool {
self.ref_time < other.ref_time
}
/// Returns true if any of `self`'s constituent weights is greater than or equal to that of the
/// `other`'s, otherwise returns false.
pub const fn any_gte(self, other: Self) -> bool {
self.ref_time >= other.ref_time
}
/// Returns true if all of `self`'s constituent weights is greater than or equal to that of the
/// `other`'s, otherwise returns false.
pub const fn all_gte(self, other: Self) -> bool {
self.ref_time >= other.ref_time
}
/// Returns true if any of `self`'s constituent weights is less than or equal to that of the
/// `other`'s, otherwise returns false.
pub const fn any_lte(self, other: Self) -> bool {
self.ref_time <= other.ref_time
}
/// Returns true if all of `self`'s constituent weights is less than or equal to that of the
/// `other`'s, otherwise returns false.
pub const fn all_lte(self, other: Self) -> bool {
self.ref_time <= other.ref_time
}
/// Returns true if any of `self`'s constituent weights is equal to that of the `other`'s,
/// otherwise returns false.
pub const fn any_eq(self, other: Self) -> bool {
self.ref_time == other.ref_time
}
// NOTE: `all_eq` does not exist, as it's simply the `eq` method from the `PartialEq` trait.
}
impl Zero for Weight {
fn zero() -> Self {
Self::zero()
}
fn is_zero(&self) -> bool {
self.ref_time == 0
}
}
impl Add for Weight {
type Output = Self;
fn add(self, rhs: Self) -> Self {
Self { ref_time: self.ref_time + rhs.ref_time }
}
}
impl Sub for Weight {
type Output = Self;
fn sub(self, rhs: Self) -> Self {
Self { ref_time: self.ref_time - rhs.ref_time }
}
}
impl<T> Mul<T> for Weight
where
T: Mul<u64, Output = u64> + Copy,
{
type Output = Self;
fn mul(self, b: T) -> Self {
Self { ref_time: b * self.ref_time }
}
}
macro_rules! weight_mul_per_impl {
($($t:ty),* $(,)?) => {
$(
impl Mul<Weight> for $t {
type Output = Weight;
fn mul(self, b: Weight) -> Weight {
Weight { ref_time: self * b.ref_time }
}
}
)*
}
}
weight_mul_per_impl!(
sp_runtime::Percent,
sp_runtime::PerU16,
sp_runtime::Permill,
sp_runtime::Perbill,
sp_runtime::Perquintill,
);
macro_rules! weight_mul_primitive_impl {
($($t:ty),* $(,)?) => {
$(
impl Mul<Weight> for $t {
type Output = Weight;
fn mul(self, b: Weight) -> Weight {
Weight { ref_time: u64::from(self) * b.ref_time }
}
}
)*
}
}
weight_mul_primitive_impl!(u8, u16, u32, u64);
impl<T> Div<T> for Weight
where
u64: Div<T, Output = u64>,
T: Copy,
{
type Output = Self;
fn div(self, b: T) -> Self {
Self { ref_time: self.ref_time / b }
}
}
impl CheckedAdd for Weight {
fn checked_add(&self, rhs: &Self) -> Option<Self> {
self.checked_add(rhs)
}
}
impl CheckedSub for Weight {
fn checked_sub(&self, rhs: &Self) -> Option<Self> {
self.checked_sub(rhs)
}
}
impl<T> PaysFee<T> for (Weight, DispatchClass, Pays) {
fn pays_fee(&self, _: T) -> Pays {
self.2
}
}
impl<T> WeighData<T> for (Weight, DispatchClass) {
fn weigh_data(&self, args: T) -> Weight {
return self.0.weigh_data(args)
}
}
impl<T> WeighData<T> for (Weight, DispatchClass, Pays) {
fn weigh_data(&self, args: T) -> Weight {
return self.0.weigh_data(args)
}
}
impl<T> ClassifyDispatch<T> for (Weight, DispatchClass) {
fn classify_dispatch(&self, _: T) -> DispatchClass {
self.1
}
}
impl<T> PaysFee<T> for (Weight, DispatchClass) {
fn pays_fee(&self, _: T) -> Pays {
Pays::Yes
}
}
impl<T> WeighData<T> for (Weight, Pays) {
fn weigh_data(&self, args: T) -> Weight {
return self.0.weigh_data(args)
}
}
impl<T> ClassifyDispatch<T> for (Weight, Pays) {
fn classify_dispatch(&self, _: T) -> DispatchClass {
DispatchClass::Normal
}
}
impl<T> PaysFee<T> for (Weight, Pays) {
fn pays_fee(&self, _: T) -> Pays {
self.1
}
}
impl From<(Option<Weight>, Pays)> for PostDispatchInfo {
fn from(post_weight_info: (Option<Weight>, Pays)) -> Self {
let (actual_weight, pays_fee) = post_weight_info;
Self { actual_weight, pays_fee }
}
}
impl From<Option<Weight>> for PostDispatchInfo {
fn from(actual_weight: Option<Weight>) -> Self {
Self { actual_weight, pays_fee: Default::default() }
}
}
impl<T> WeighData<T> for Weight {
fn weigh_data(&self, _: T) -> Weight {
return *self
}
}
impl<T> ClassifyDispatch<T> for Weight {
fn classify_dispatch(&self, _: T) -> DispatchClass {
DispatchClass::Normal
}
}
impl<T> PaysFee<T> for Weight {
fn pays_fee(&self, _: T) -> Pays {
Pays::Yes
}
}
impl<T> ClassifyDispatch<T> for (Weight, DispatchClass, Pays) {
fn classify_dispatch(&self, _: T) -> DispatchClass {
self.1
}
}
impl core::fmt::Display for Weight {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "Weight(ref_time: {})", self.ref_time)
}
}
impl Bounded for Weight {
fn min_value() -> Self {
Zero::zero()
}
fn max_value() -> Self {
Self::MAX
}
}
impl AddAssign for Weight {
fn add_assign(&mut self, other: Self) {
*self = Self { ref_time: self.ref_time + other.ref_time };
}
}
impl SubAssign for Weight {
fn sub_assign(&mut self, other: Self) {
*self = Self { ref_time: self.ref_time - other.ref_time };
}
}
impl sp_runtime::traits::Printable for Weight {
fn print(&self) {
self.ref_time().print()
}
}
// TODO: Eventually remove these
impl From<Option<u64>> for PostDispatchInfo {
fn from(maybe_actual_computation: Option<u64>) -> Self {
let actual_weight = match maybe_actual_computation {
Some(actual_computation) => Some(Weight::zero().set_ref_time(actual_computation)),
None => None,
};
Self { actual_weight, pays_fee: Default::default() }
}
}
impl From<(Option<u64>, Pays)> for PostDispatchInfo {
fn from(post_weight_info: (Option<u64>, Pays)) -> Self {
let (maybe_actual_time, pays_fee) = post_weight_info;
let actual_weight = match maybe_actual_time {
Some(actual_time) => Some(Weight::zero().set_ref_time(actual_time)),
None => None,
};
Self { actual_weight, pays_fee }
}
}
impl<T> WeighData<T> for u64 {
fn weigh_data(&self, _: T) -> Weight {
return Weight::zero().set_ref_time(*self)
}
}
impl<T> ClassifyDispatch<T> for u64 {
fn classify_dispatch(&self, _: T) -> DispatchClass {
DispatchClass::Normal
}
}
impl<T> PaysFee<T> for u64 {
fn pays_fee(&self, _: T) -> Pays {
Pays::Yes
}
}
impl<T> WeighData<T> for (u64, DispatchClass, Pays) {
fn weigh_data(&self, args: T) -> Weight {
return self.0.weigh_data(args)
}
}
impl<T> ClassifyDispatch<T> for (u64, DispatchClass, Pays) {
fn classify_dispatch(&self, _: T) -> DispatchClass {
self.1
}
}
impl<T> PaysFee<T> for (u64, DispatchClass, Pays) {
fn pays_fee(&self, _: T) -> Pays {
self.2
}
}
impl<T> WeighData<T> for (u64, DispatchClass) {
fn weigh_data(&self, args: T) -> Weight {
return self.0.weigh_data(args)
}
}
impl<T> ClassifyDispatch<T> for (u64, DispatchClass) {
fn classify_dispatch(&self, _: T) -> DispatchClass {
self.1
}
}
impl<T> PaysFee<T> for (u64, DispatchClass) {
fn pays_fee(&self, _: T) -> Pays {
Pays::Yes
}
}
impl<T> WeighData<T> for (u64, Pays) {
fn weigh_data(&self, args: T) -> Weight {
return self.0.weigh_data(args)
}
}
impl<T> ClassifyDispatch<T> for (u64, Pays) {
fn classify_dispatch(&self, _: T) -> DispatchClass {
DispatchClass::Normal
}
}
impl<T> PaysFee<T> for (u64, Pays) {
fn pays_fee(&self, _: T) -> Pays {
self.1
}
}
// END TODO