Weight v1.5: Opaque Struct (#12138)

* initial idea

* update frame_support

* update a bunch more

* add ord

* adjust RuntimeDbWeight

* frame_system builds

* re-export

* frame_support tests pass

* frame_executive compile

* frame_executive builds

* frame_system tests passing

* pallet-utility tests pass

* fix a bunch of pallets

* more

* phragmen

* state-trie-migration

* scheduler and referenda

* pallet-election-provider-multi-phase

* aura

* staking

* more

* babe

* balances

* bunch more

* sudo

* transaction-payment

* asset-tx-payment

* last pallets

* fix alliance merge

* fix node template runtime

* fix pallet-contracts cc @athei

* fix node runtime

* fix compile on runtime-benchmarks feature

* comment

* fix frame-support-test

* fix more tests

* weight regex

* frame system works

* fix a bunch

* more

* more

* more

* more

* more

* more fixes

* update templates

* fix contracts benchmarks

* Update lib.rs

* Update lib.rs

* fix ui

* make scalar saturating mul const

* more const functions

* scalar div

* refactor using constant functions

* move impl

* fix overhead template

* use compactas

* Update lib.rs
This commit is contained in:
Shawn Tabrizi
2022-08-31 12:26:13 +01:00
committed by GitHub
parent 299f4ba541
commit 30951822ba
187 changed files with 5932 additions and 4930 deletions
+32 -15
View File
@@ -176,18 +176,18 @@ impl<T> Parameter for T where T: Codec + EncodeLike + Clone + Eq + fmt::Debug +
/// ```
/// # #[macro_use]
/// # extern crate frame_support;
/// # use frame_support::dispatch::{DispatchResultWithPostInfo, WithPostDispatchInfo};
/// # use frame_support::{weights::Weight, dispatch::{DispatchResultWithPostInfo, WithPostDispatchInfo}};
/// # use frame_system::{Config, ensure_signed};
/// decl_module! {
/// pub struct Module<T: Config> for enum Call where origin: T::Origin {
/// #[weight = 1_000_000]
/// fn my_long_function(origin, do_expensive_calc: bool) -> DispatchResultWithPostInfo {
/// ensure_signed(origin).map_err(|e| e.with_weight(100_000))?;
/// ensure_signed(origin).map_err(|e| e.with_weight(Weight::from_ref_time(100_000)))?;
/// if do_expensive_calc {
/// // do the expensive calculation
/// // ...
/// // return None to indicate that we are using all weight (the default)
/// return Ok(None.into());
/// return Ok(None::<Weight>.into());
/// }
/// // expensive calculation not executed: use only a portion of the weight
/// Ok(Some(100_000).into())
@@ -1614,7 +1614,7 @@ macro_rules! decl_module {
pallet_name,
);
0
$crate::dispatch::Weight::new()
}
#[cfg(feature = "try-runtime")]
@@ -2649,13 +2649,13 @@ mod tests {
#[weight = (5, DispatchClass::Operational)]
fn operational(_origin) { unreachable!() }
fn on_initialize(n: T::BlockNumber,) -> Weight { if n.into() == 42 { panic!("on_initialize") } 7 }
fn on_initialize(n: T::BlockNumber,) -> Weight { if n.into() == 42 { panic!("on_initialize") } Weight::from_ref_time(7) }
fn on_idle(n: T::BlockNumber, remaining_weight: Weight,) -> Weight {
if n.into() == 42 || remaining_weight == 42 { panic!("on_idle") }
7
if n.into() == 42 || remaining_weight == Weight::from_ref_time(42) { panic!("on_idle") }
Weight::from_ref_time(7)
}
fn on_finalize(n: T::BlockNumber,) { if n.into() == 42 { panic!("on_finalize") } }
fn on_runtime_upgrade() -> Weight { 10 }
fn on_runtime_upgrade() -> Weight { Weight::from_ref_time(10) }
fn offchain_worker() {}
/// Some doc
fn integrity_test() { panic!("integrity_test") }
@@ -2814,24 +2814,30 @@ mod tests {
#[test]
fn on_initialize_should_work_2() {
assert_eq!(<Module<TraitImpl> as OnInitialize<u32>>::on_initialize(10), 7);
assert_eq!(
<Module<TraitImpl> as OnInitialize<u32>>::on_initialize(10),
Weight::from_ref_time(7)
);
}
#[test]
#[should_panic(expected = "on_idle")]
fn on_idle_should_work_1() {
<Module<TraitImpl> as OnIdle<u32>>::on_idle(42, 9);
<Module<TraitImpl> as OnIdle<u32>>::on_idle(42, Weight::from_ref_time(9));
}
#[test]
#[should_panic(expected = "on_idle")]
fn on_idle_should_work_2() {
<Module<TraitImpl> as OnIdle<u32>>::on_idle(9, 42);
<Module<TraitImpl> as OnIdle<u32>>::on_idle(9, Weight::from_ref_time(42));
}
#[test]
fn on_idle_should_work_3() {
assert_eq!(<Module<TraitImpl> as OnIdle<u32>>::on_idle(10, 11), 7);
assert_eq!(
<Module<TraitImpl> as OnIdle<u32>>::on_idle(10, Weight::from_ref_time(11)),
Weight::from_ref_time(7)
);
}
#[test]
@@ -2843,7 +2849,10 @@ mod tests {
#[test]
fn on_runtime_upgrade_should_work() {
sp_io::TestExternalities::default().execute_with(|| {
assert_eq!(<Module<TraitImpl> as OnRuntimeUpgrade>::on_runtime_upgrade(), 10)
assert_eq!(
<Module<TraitImpl> as OnRuntimeUpgrade>::on_runtime_upgrade(),
Weight::from_ref_time(10)
)
});
}
@@ -2852,12 +2861,20 @@ mod tests {
// operational.
assert_eq!(
Call::<TraitImpl>::operational {}.get_dispatch_info(),
DispatchInfo { weight: 5, class: DispatchClass::Operational, pays_fee: Pays::Yes },
DispatchInfo {
weight: Weight::from_ref_time(5),
class: DispatchClass::Operational,
pays_fee: Pays::Yes
},
);
// custom basic
assert_eq!(
Call::<TraitImpl>::aux_3 {}.get_dispatch_info(),
DispatchInfo { weight: 3, class: DispatchClass::Normal, pays_fee: Pays::Yes },
DispatchInfo {
weight: Weight::from_ref_time(3),
class: DispatchClass::Normal,
pays_fee: Pays::Yes
},
);
}
+1 -1
View File
@@ -1374,7 +1374,7 @@ pub mod pallet_prelude {
ConstU32, EnsureOrigin, Get, GetDefault, GetStorageVersion, Hooks, IsType,
PalletInfoAccess, StorageInfoTrait, StorageVersion, TypedGet,
},
weights::{DispatchClass, Pays, Weight},
weights::{DispatchClass, Pays, RefTimeWeight, Weight},
Blake2_128, Blake2_128Concat, Blake2_256, CloneNoBound, DebugNoBound, EqNoBound, Identity,
PartialEqNoBound, RuntimeDebug, RuntimeDebugNoBound, Twox128, Twox256, Twox64Concat,
};
+1 -1
View File
@@ -48,7 +48,7 @@ impl<T: GetStorageVersion + PalletInfoAccess> PalletVersionToStorageVersionHelpe
#[cfg_attr(feature = "tuples-128", impl_for_tuples(128))]
impl PalletVersionToStorageVersionHelper for T {
fn migrate(db_weight: &RuntimeDbWeight) -> Weight {
let mut weight: Weight = 0;
let mut weight = Weight::new();
for_tuples!( #( weight = weight.saturating_add(T::migrate(db_weight)); )* );
+38 -46
View File
@@ -17,8 +17,8 @@
//! Traits for hooking tasks to events in a blockchain's lifecycle.
use crate::weights::Weight;
use impl_trait_for_tuples::impl_for_tuples;
use sp_arithmetic::traits::Saturating;
use sp_runtime::traits::AtLeast32BitUnsigned;
/// The block initialization trait.
@@ -33,8 +33,8 @@ pub trait OnInitialize<BlockNumber> {
/// NOTE: This function is called BEFORE ANY extrinsic in a block is applied,
/// including inherent extrinsics. Hence for instance, if you runtime includes
/// `pallet_timestamp`, the `timestamp` is not yet up to date at this point.
fn on_initialize(_n: BlockNumber) -> crate::weights::Weight {
0
fn on_initialize(_n: BlockNumber) -> Weight {
Weight::new()
}
}
@@ -42,8 +42,8 @@ pub trait OnInitialize<BlockNumber> {
#[cfg_attr(all(feature = "tuples-96", not(feature = "tuples-128")), impl_for_tuples(96))]
#[cfg_attr(feature = "tuples-128", impl_for_tuples(128))]
impl<BlockNumber: Clone> OnInitialize<BlockNumber> for Tuple {
fn on_initialize(n: BlockNumber) -> crate::weights::Weight {
let mut weight = 0;
fn on_initialize(n: BlockNumber) -> Weight {
let mut weight = Weight::new();
for_tuples!( #( weight = weight.saturating_add(Tuple::on_initialize(n.clone())); )* );
weight
}
@@ -75,11 +75,8 @@ pub trait OnIdle<BlockNumber> {
///
/// NOTE: This function is called AFTER ALL extrinsics - including inherent extrinsics -
/// in a block are applied but before `on_finalize` is executed.
fn on_idle(
_n: BlockNumber,
_remaining_weight: crate::weights::Weight,
) -> crate::weights::Weight {
0
fn on_idle(_n: BlockNumber, _remaining_weight: Weight) -> Weight {
Weight::new()
}
}
@@ -87,12 +84,10 @@ pub trait OnIdle<BlockNumber> {
#[cfg_attr(all(feature = "tuples-96", not(feature = "tuples-128")), impl_for_tuples(96))]
#[cfg_attr(feature = "tuples-128", impl_for_tuples(128))]
impl<BlockNumber: Copy + AtLeast32BitUnsigned> OnIdle<BlockNumber> for Tuple {
fn on_idle(n: BlockNumber, remaining_weight: crate::weights::Weight) -> crate::weights::Weight {
let on_idle_functions: &[fn(
BlockNumber,
crate::weights::Weight,
) -> crate::weights::Weight] = &[for_tuples!( #( Tuple::on_idle ),* )];
let mut weight = 0;
fn on_idle(n: BlockNumber, remaining_weight: Weight) -> Weight {
let on_idle_functions: &[fn(BlockNumber, Weight) -> Weight] =
&[for_tuples!( #( Tuple::on_idle ),* )];
let mut weight = Weight::new();
let len = on_idle_functions.len();
let start_index = n % (len as u32).into();
let start_index = start_index.try_into().ok().expect(
@@ -174,8 +169,8 @@ pub trait OnRuntimeUpgrade {
/// block local data are not accessible.
///
/// Return the non-negotiable weight consumed for runtime upgrade.
fn on_runtime_upgrade() -> crate::weights::Weight {
0
fn on_runtime_upgrade() -> Weight {
Weight::new()
}
/// Execute some pre-checks prior to a runtime upgrade.
@@ -199,8 +194,8 @@ pub trait OnRuntimeUpgrade {
#[cfg_attr(all(feature = "tuples-96", not(feature = "tuples-128")), impl_for_tuples(96))]
#[cfg_attr(feature = "tuples-128", impl_for_tuples(128))]
impl OnRuntimeUpgrade for Tuple {
fn on_runtime_upgrade() -> crate::weights::Weight {
let mut weight = 0;
fn on_runtime_upgrade() -> Weight {
let mut weight = Weight::new();
for_tuples!( #( weight = weight.saturating_add(Tuple::on_runtime_upgrade()); )* );
weight
}
@@ -243,18 +238,15 @@ pub trait Hooks<BlockNumber> {
/// Will not fire if the remaining weight is 0.
/// Return the weight used, the hook will subtract it from current weight used
/// and pass the result to the next `on_idle` hook if it exists.
fn on_idle(
_n: BlockNumber,
_remaining_weight: crate::weights::Weight,
) -> crate::weights::Weight {
0
fn on_idle(_n: BlockNumber, _remaining_weight: Weight) -> Weight {
Weight::new()
}
/// The block is being initialized. Implement to have something happen.
///
/// Return the non-negotiable weight consumed in the block.
fn on_initialize(_n: BlockNumber) -> crate::weights::Weight {
0
fn on_initialize(_n: BlockNumber) -> Weight {
Weight::new()
}
/// Perform a module upgrade.
@@ -276,8 +268,8 @@ pub trait Hooks<BlockNumber> {
/// pallet is discouraged and might get deprecated in the future. Alternatively, export the same
/// logic as a free-function from your pallet, and pass it to `type Executive` from the
/// top-level runtime.
fn on_runtime_upgrade() -> crate::weights::Weight {
0
fn on_runtime_upgrade() -> Weight {
Weight::new()
}
/// Execute some pre-checks prior to a runtime upgrade.
@@ -360,18 +352,18 @@ mod tests {
fn on_initialize_and_on_runtime_upgrade_weight_merge_works() {
struct Test;
impl OnInitialize<u8> for Test {
fn on_initialize(_n: u8) -> crate::weights::Weight {
10
fn on_initialize(_n: u8) -> Weight {
Weight::from_ref_time(10)
}
}
impl OnRuntimeUpgrade for Test {
fn on_runtime_upgrade() -> crate::weights::Weight {
20
fn on_runtime_upgrade() -> Weight {
Weight::from_ref_time(20)
}
}
assert_eq!(<(Test, Test)>::on_initialize(0), 20);
assert_eq!(<(Test, Test)>::on_runtime_upgrade(), 40);
assert_eq!(<(Test, Test)>::on_initialize(0), Weight::from_ref_time(20));
assert_eq!(<(Test, Test)>::on_runtime_upgrade(), Weight::from_ref_time(40));
}
#[test]
@@ -383,48 +375,48 @@ mod tests {
struct Test3;
type TestTuple = (Test1, Test2, Test3);
impl OnIdle<u32> for Test1 {
fn on_idle(_n: u32, _weight: crate::weights::Weight) -> crate::weights::Weight {
fn on_idle(_n: u32, _weight: Weight) -> Weight {
unsafe {
ON_IDLE_INVOCATION_ORDER.push("Test1");
}
0
Weight::zero()
}
}
impl OnIdle<u32> for Test2 {
fn on_idle(_n: u32, _weight: crate::weights::Weight) -> crate::weights::Weight {
fn on_idle(_n: u32, _weight: Weight) -> Weight {
unsafe {
ON_IDLE_INVOCATION_ORDER.push("Test2");
}
0
Weight::zero()
}
}
impl OnIdle<u32> for Test3 {
fn on_idle(_n: u32, _weight: crate::weights::Weight) -> crate::weights::Weight {
fn on_idle(_n: u32, _weight: Weight) -> Weight {
unsafe {
ON_IDLE_INVOCATION_ORDER.push("Test3");
}
0
Weight::zero()
}
}
unsafe {
TestTuple::on_idle(0, 0);
TestTuple::on_idle(0, Weight::zero());
assert_eq!(ON_IDLE_INVOCATION_ORDER, ["Test1", "Test2", "Test3"].to_vec());
ON_IDLE_INVOCATION_ORDER.clear();
TestTuple::on_idle(1, 0);
TestTuple::on_idle(1, Weight::zero());
assert_eq!(ON_IDLE_INVOCATION_ORDER, ["Test2", "Test3", "Test1"].to_vec());
ON_IDLE_INVOCATION_ORDER.clear();
TestTuple::on_idle(2, 0);
TestTuple::on_idle(2, Weight::zero());
assert_eq!(ON_IDLE_INVOCATION_ORDER, ["Test3", "Test1", "Test2"].to_vec());
ON_IDLE_INVOCATION_ORDER.clear();
TestTuple::on_idle(3, 0);
TestTuple::on_idle(3, Weight::zero());
assert_eq!(ON_IDLE_INVOCATION_ORDER, ["Test1", "Test2", "Test3"].to_vec());
ON_IDLE_INVOCATION_ORDER.clear();
TestTuple::on_idle(4, 0);
TestTuple::on_idle(4, Weight::zero());
assert_eq!(ON_IDLE_INVOCATION_ORDER, ["Test2", "Test3", "Test1"].to_vec());
ON_IDLE_INVOCATION_ORDER.clear();
}
+106 -149
View File
@@ -123,6 +123,7 @@ mod block_weights;
mod extrinsic_weights;
mod paritydb_weights;
mod rocksdb_weights;
mod weight_v2;
use crate::{
dispatch::{DispatchError, DispatchErrorWithPostInfo, DispatchResultWithPostInfo},
@@ -146,18 +147,17 @@ use sp_runtime::{
/// Re-export priority as type
pub use sp_runtime::transaction_validity::TransactionPriority;
/// Numeric range of a transaction weight.
pub type Weight = u64;
pub use weight_v2::*;
/// 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 = 1_000_000_000_000;
pub const WEIGHT_PER_MILLIS: Weight = WEIGHT_PER_SECOND / 1000; // 1_000_000_000
pub const WEIGHT_PER_MICROS: Weight = WEIGHT_PER_MILLIS / 1000; // 1_000_000
pub const WEIGHT_PER_NANOS: Weight = WEIGHT_PER_MICROS / 1000; // 1_000
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);
// Expose the Block and Extrinsic base weights.
pub use super::{block_weights::BlockExecutionWeight, extrinsic_weights::ExtrinsicBaseWeight};
@@ -204,6 +204,12 @@ impl Default for Pays {
}
}
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
@@ -359,25 +365,6 @@ pub fn extract_actual_pays_fee(result: &DispatchResultWithPostInfo, info: &Dispa
.pays_fee(info)
}
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<Pays> for PostDispatchInfo {
fn from(pays_fee: Pays) -> Self {
Self { actual_weight: None, pays_fee }
}
}
impl From<Option<Weight>> for PostDispatchInfo {
fn from(actual_weight: Option<Weight>) -> Self {
Self { actual_weight, pays_fee: Default::default() }
}
}
impl From<()> for PostDispatchInfo {
fn from(_: ()) -> Self {
Self { actual_weight: None, pays_fee: Default::default() }
@@ -407,7 +394,7 @@ pub trait WithPostDispatchInfo {
/// # Example
///
/// ```ignore
/// let who = ensure_signed(origin).map_err(|e| e.with_weight(100))?;
/// 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;
@@ -428,78 +415,6 @@ where
}
}
impl<T> WeighData<T> for Weight {
fn weigh_data(&self, _: T) -> Weight {
*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> WeighData<T> for (Weight, DispatchClass, Pays) {
fn weigh_data(&self, _: T) -> Weight {
self.0
}
}
impl<T> ClassifyDispatch<T> for (Weight, DispatchClass, Pays) {
fn classify_dispatch(&self, _: T) -> DispatchClass {
self.1
}
}
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, _: T) -> Weight {
self.0
}
}
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, _: T) -> Weight {
self.0
}
}
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
}
}
/// Implementation for unchecked extrinsic.
impl<Address, Call, Signature, Extra> GetDispatchInfo
for UncheckedExtrinsic<Address, Call, Signature, Extra>
@@ -527,30 +442,37 @@ where
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: self.encode().len() as _, pays_fee: Pays::Yes, ..Default::default() }
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: Weight,
pub write: Weight,
pub read: RefTimeWeight,
pub write: RefTimeWeight,
}
impl RuntimeDbWeight {
pub fn reads(self, r: Weight) -> Weight {
self.read.saturating_mul(r)
pub fn reads(self, r: u64) -> Weight {
Weight::from_ref_time(self.read.saturating_mul(r))
}
pub fn writes(self, w: Weight) -> Weight {
self.write.saturating_mul(w)
pub fn writes(self, w: u64) -> Weight {
Weight::from_ref_time(self.write.saturating_mul(w))
}
pub fn reads_writes(self, r: Weight, w: Weight) -> Weight {
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);
read_weight.saturating_add(write_weight)
Weight::from_ref_time(read_weight.saturating_add(write_weight))
}
}
@@ -618,7 +540,8 @@ where
Self::polynomial()
.iter()
.fold(Self::Balance::saturated_from(0u32), |mut acc, args| {
let w = Self::Balance::saturated_from(*weight).saturating_pow(args.degree.into());
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.
@@ -648,7 +571,7 @@ where
type Balance = T;
fn weight_to_fee(weight: &Weight) -> Self::Balance {
Self::Balance::saturated_from(*weight)
Self::Balance::saturated_from(weight.ref_time())
}
}
@@ -671,7 +594,7 @@ where
type Balance = T;
fn weight_to_fee(weight: &Weight) -> Self::Balance {
Self::Balance::saturated_from(*weight).saturating_mul(M::get())
Self::Balance::saturated_from(weight.ref_time()).saturating_mul(M::get())
}
}
@@ -727,7 +650,7 @@ impl<T: Clone> PerDispatchClass<T> {
impl PerDispatchClass<Weight> {
/// Returns the total weight consumed by all extrinsics in the block.
pub fn total(&self) -> Weight {
let mut sum = 0;
let mut sum = Weight::new();
for class in DispatchClass::all() {
sum = sum.saturating_add(*self.get(*class));
}
@@ -744,7 +667,7 @@ impl PerDispatchClass<Weight> {
/// 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(())?;
*value = value.checked_add(&weight).ok_or(())?;
Ok(())
}
@@ -804,16 +727,16 @@ mod tests {
fn f03(_origin) { unimplemented!(); }
// weight = a x 10 + b
#[weight = ((_a * 10 + _eb * 1) as Weight, DispatchClass::Normal, Pays::Yes)]
#[weight = ((_a * 10 + _eb * 1) as RefTimeWeight, 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) + 10_000]
#[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) + 40_000]
#[weight = T::DbWeight::get().reads_writes(6, 5) + Weight::from_ref_time(40_000)]
fn f21(_origin) { unimplemented!(); }
}
@@ -823,80 +746,98 @@ mod tests {
fn weights_are_correct() {
// #[weight = 1000]
let info = Call::<TraitImpl>::f00 {}.get_dispatch_info();
assert_eq!(info.weight, 1000);
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, 1000);
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, 1000);
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, 1000);
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, 150); // 13*10 + 20
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, 0);
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, 12300); // 100*3 + 1000*2 + 10_1000
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, 45600); // 100*6 + 1000*5 + 40_1000
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: 1000, ..Default::default() };
assert_eq!(extract_actual_weight(&Ok(Some(7).into()), &pre), 7);
assert_eq!(extract_actual_weight(&Ok(Some(1000).into()), &pre), 1000);
assert_eq!(extract_actual_weight(&Err(DispatchError::BadOrigin.with_weight(9)), &pre), 9);
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: 1000, ..Default::default() };
assert_eq!(extract_actual_weight(&Ok(Some(1250).into()), &pre), 1000);
let pre = DispatchInfo { weight: Weight::from_ref_time(1000), ..Default::default() };
assert_eq!(
extract_actual_weight(&Err(DispatchError::BadOrigin.with_weight(1300)), &pre),
1000
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: 1000, ..Default::default() };
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(9)), &pre),
extract_actual_pays_fee(
&Err(DispatchError::BadOrigin.with_weight(Weight::from_ref_time(9))),
&pre
),
Pays::Yes
);
assert_eq!(
@@ -910,7 +851,11 @@ mod tests {
Pays::No
);
let pre = DispatchInfo { weight: 1000, pays_fee: Pays::No, ..Default::default() };
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);
@@ -956,40 +901,52 @@ mod tests {
#[test]
fn polynomial_works() {
// 100^3/2=500000 100^2*(2+1/3)=23333 700 -10000
assert_eq!(Poly::weight_to_fee(&100), 514033);
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(&10_123), 518917034928);
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(&0), 0);
assert_eq!(Poly::weight_to_fee(&10), 0);
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_value()), Balance::max_value() - 10_000);
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(&0), 0);
assert_eq!(IdentityFee::<Balance>::weight_to_fee(&50), 50);
assert_eq!(
IdentityFee::<Balance>::weight_to_fee(&Weight::max_value()),
Balance::max_value()
);
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(&0), 0);
assert_eq!(ConstantMultiplier::<u128, ConstU128<10u128>>::weight_to_fee(&50), 500);
assert_eq!(ConstantMultiplier::<u128, ConstU128<1024u128>>::weight_to_fee(&16), 16384);
assert_eq!(
ConstantMultiplier::<u128, ConstU128<{ u128::MAX }>>::weight_to_fee(&2),
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
);
}
@@ -53,7 +53,7 @@ parameter_types! {
/// 99th: 5_489_273
/// 95th: 5_433_314
/// 75th: 5_354_812
pub const BlockExecutionWeight: Weight = 5_346_284 * WEIGHT_PER_NANOS;
pub const BlockExecutionWeight: Weight = WEIGHT_PER_NANOS.scalar_saturating_mul(5_346_284);
}
#[cfg(test)]
@@ -53,7 +53,7 @@ parameter_types! {
/// 99th: 86_924
/// 95th: 86_828
/// 75th: 86_347
pub const ExtrinsicBaseWeight: Weight = 86_298 * WEIGHT_PER_NANOS;
pub const ExtrinsicBaseWeight: Weight = WEIGHT_PER_NANOS.scalar_saturating_mul(86_298);
}
#[cfg(test)]
@@ -25,8 +25,8 @@ pub mod constants {
/// ParityDB can be enabled with a feature flag, but is still experimental. These weights
/// are available for brave runtime engineers who may want to try this out as default.
pub const ParityDbWeight: RuntimeDbWeight = RuntimeDbWeight {
read: 8_000 * constants::WEIGHT_PER_NANOS,
write: 50_000 * constants::WEIGHT_PER_NANOS,
read: 8_000 * constants::WEIGHT_PER_NANOS.ref_time(),
write: 50_000 * constants::WEIGHT_PER_NANOS.ref_time(),
};
}
@@ -25,8 +25,8 @@ pub mod constants {
/// By default, Substrate uses RocksDB, so this will be the weight used throughout
/// the runtime.
pub const RocksDbWeight: RuntimeDbWeight = RuntimeDbWeight {
read: 25_000 * constants::WEIGHT_PER_NANOS,
write: 100_000 * constants::WEIGHT_PER_NANOS,
read: 25_000 * constants::WEIGHT_PER_NANOS.ref_time(),
write: 100_000 * constants::WEIGHT_PER_NANOS.ref_time(),
};
}
@@ -0,0 +1,483 @@
// 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, One, Zero},
Perquintill, RuntimeDebug,
};
use super::*;
/// The unit of measurement for computational time spent when executing runtime logic on reference
/// hardware.
pub type RefTimeWeight = u64;
#[derive(
Encode,
Decode,
MaxEncodedLen,
TypeInfo,
Eq,
PartialEq,
Copy,
Clone,
RuntimeDebug,
Default,
Ord,
PartialOrd,
CompactAs,
)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
pub struct Weight {
/// The weight of computational time used based on some reference hardware.
ref_time: RefTimeWeight,
}
impl Weight {
/// Create a new Weight with zero.
pub const fn new() -> Self {
Self { ref_time: 0 }
}
/// Set the reference time part of the weight.
pub const fn set_ref_time(mut self, c: RefTimeWeight) -> Self {
self.ref_time = c;
self
}
/// Return the reference time part of the weight.
pub const fn ref_time(&self) -> RefTimeWeight {
self.ref_time
}
/// Return a mutable reference time part of the weight.
pub fn ref_time_mut(&mut self) -> &mut RefTimeWeight {
&mut self.ref_time
}
pub const MAX: Self = Self { ref_time: RefTimeWeight::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 with reference time weight.
pub const fn from_ref_time(ref_time: RefTimeWeight) -> Self {
Self { ref_time }
}
pub fn checked_mul(self, rhs: u64) -> Option<Self> {
let ref_time = self.ref_time.checked_mul(rhs)?;
Some(Self { ref_time })
}
pub fn checked_div(self, rhs: u64) -> Option<Self> {
let ref_time = self.ref_time.checked_div(rhs)?;
Some(Self { ref_time })
}
pub const fn scalar_saturating_mul(self, rhs: u64) -> Self {
Self { ref_time: self.ref_time.saturating_mul(rhs) }
}
pub const fn scalar_div(self, rhs: u64) -> Self {
Self { ref_time: self.ref_time / rhs }
}
}
impl Zero for Weight {
fn zero() -> Self {
Self::zero()
}
fn is_zero(&self) -> bool {
self.ref_time == 0
}
}
impl One for Weight {
fn one() -> Self {
Self::one()
}
}
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 Mul for Weight {
type Output = Self;
fn mul(self, b: Self) -> Self {
Self { ref_time: b.ref_time * self.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 }
}
}
impl Mul<Weight> for Perbill {
type Output = Weight;
fn mul(self, b: Weight) -> Weight {
Weight { ref_time: self * b.ref_time }
}
}
impl Mul<Weight> for Perquintill {
type Output = Weight;
fn mul(self, b: Weight) -> Weight {
Weight { ref_time: self * b.ref_time }
}
}
impl Mul<Weight> for u64 {
type Output = Weight;
fn mul(self, b: Weight) -> Weight {
Weight { ref_time: self * b.ref_time }
}
}
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 Saturating for Weight {
fn saturating_add(self, rhs: Self) -> Self {
self.saturating_add(rhs)
}
fn saturating_sub(self, rhs: Self) -> Self {
self.saturating_sub(rhs)
}
fn saturating_mul(self, rhs: Self) -> Self {
self.saturating_mul(rhs)
}
fn saturating_pow(self, exp: usize) -> Self {
self.saturating_pow(exp)
}
}
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()
}
}
// Re-export common functions so you do not need to import trait.
impl Weight {
pub const fn zero() -> Self {
Self { ref_time: 0 }
}
pub const fn one() -> Self {
Self { ref_time: 1 }
}
pub const fn saturating_add(self, rhs: Self) -> Self {
Self { ref_time: self.ref_time.saturating_add(rhs.ref_time) }
}
pub const fn saturating_sub(self, rhs: Self) -> Self {
Self { ref_time: self.ref_time.saturating_sub(rhs.ref_time) }
}
pub const fn saturating_mul(self, rhs: Self) -> Self {
Self { ref_time: self.ref_time.saturating_mul(rhs.ref_time) }
}
pub const fn saturating_pow(self, exp: usize) -> Self {
Self { ref_time: self.ref_time.saturating_pow(exp as u32) }
}
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,
}
}
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,
}
}
}
// TODO: Eventually remove these
impl From<Option<RefTimeWeight>> for PostDispatchInfo {
fn from(maybe_actual_computation: Option<RefTimeWeight>) -> Self {
let actual_weight = match maybe_actual_computation {
Some(actual_computation) => Some(Weight::new().set_ref_time(actual_computation)),
None => None,
};
Self { actual_weight, pays_fee: Default::default() }
}
}
impl From<(Option<RefTimeWeight>, Pays)> for PostDispatchInfo {
fn from(post_weight_info: (Option<RefTimeWeight>, Pays)) -> Self {
let (maybe_actual_time, pays_fee) = post_weight_info;
let actual_weight = match maybe_actual_time {
Some(actual_time) => Some(Weight::new().set_ref_time(actual_time)),
None => None,
};
Self { actual_weight, pays_fee }
}
}
impl<T> WeighData<T> for RefTimeWeight {
fn weigh_data(&self, _: T) -> Weight {
return Weight::new().set_ref_time(*self)
}
}
impl<T> ClassifyDispatch<T> for RefTimeWeight {
fn classify_dispatch(&self, _: T) -> DispatchClass {
DispatchClass::Normal
}
}
impl<T> PaysFee<T> for RefTimeWeight {
fn pays_fee(&self, _: T) -> Pays {
Pays::Yes
}
}
impl<T> WeighData<T> for (RefTimeWeight, DispatchClass, Pays) {
fn weigh_data(&self, args: T) -> Weight {
return self.0.weigh_data(args)
}
}
impl<T> ClassifyDispatch<T> for (RefTimeWeight, DispatchClass, Pays) {
fn classify_dispatch(&self, _: T) -> DispatchClass {
self.1
}
}
impl<T> PaysFee<T> for (RefTimeWeight, DispatchClass, Pays) {
fn pays_fee(&self, _: T) -> Pays {
self.2
}
}
impl<T> WeighData<T> for (RefTimeWeight, DispatchClass) {
fn weigh_data(&self, args: T) -> Weight {
return self.0.weigh_data(args)
}
}
impl<T> ClassifyDispatch<T> for (RefTimeWeight, DispatchClass) {
fn classify_dispatch(&self, _: T) -> DispatchClass {
self.1
}
}
impl<T> PaysFee<T> for (RefTimeWeight, DispatchClass) {
fn pays_fee(&self, _: T) -> Pays {
Pays::Yes
}
}
impl<T> WeighData<T> for (RefTimeWeight, Pays) {
fn weigh_data(&self, args: T) -> Weight {
return self.0.weigh_data(args)
}
}
impl<T> ClassifyDispatch<T> for (RefTimeWeight, Pays) {
fn classify_dispatch(&self, _: T) -> DispatchClass {
DispatchClass::Normal
}
}
impl<T> PaysFee<T> for (RefTimeWeight, Pays) {
fn pays_fee(&self, _: T) -> Pays {
self.1
}
}
// END TODO