Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Implement batch_all and update Utility pallet for weight refunds #7188

Merged
13 commits merged into from
Oct 27, 2020
16 changes: 11 additions & 5 deletions bin/node/runtime/src/weights/pallet_utility.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// This file is part of Substrate.

// Copyright (C) 2017-2020 Parity Technologies (UK) Ltd.
// Copyright (C) 2020 Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0

// Licensed under the Apache License, Version 2.0 (the "License");
Expand All @@ -15,7 +15,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.

//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 2.0.0-rc5
//! Weights for pallet_utility
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 2.0.0
//! DATE: 2020-10-02, STEPS: [50], REPEAT: 20, LOW RANGE: [], HIGH RANGE: []

#![allow(unused_parens)]
#![allow(unused_imports)]
Expand All @@ -26,10 +28,14 @@ use sp_std::marker::PhantomData;
pub struct WeightInfo<T>(PhantomData<T>);
impl<T: frame_system::Trait> pallet_utility::WeightInfo for WeightInfo<T> {
fn batch(c: u32, ) -> Weight {
(16461000 as Weight)
.saturating_add((1982000 as Weight).saturating_mul(c as Weight))
(20_803_000 as Weight)
.saturating_add((1_984_000 as Weight).saturating_mul(c as Weight))
}
fn as_derivative() -> Weight {
(4086000 as Weight)
(5_853_000 as Weight)
}
fn batch_all(c: u32, ) -> Weight {
(21_104_000 as Weight)
.saturating_add((1_509_000 as Weight).saturating_mul(c as Weight))
}
}
14 changes: 14 additions & 0 deletions frame/utility/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,19 @@ benchmarks! {
let caller_key = frame_system::Account::<T>::hashed_key_for(&caller);
frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into());
}: _(RawOrigin::Signed(caller), SEED as u16, call)

batch_all {
let c in 0 .. 1000;
let mut calls: Vec<<T as Trait>::Call> = Vec::new();
for i in 0 .. c {
let call = frame_system::Call::remark(vec![]).into();
calls.push(call);
}
let caller = whitelisted_caller();
}: _(RawOrigin::Signed(caller), calls)
verify {
assert_last_event::<T>(Event::BatchCompleted.into())
}
}

#[cfg(test)]
Expand All @@ -69,6 +82,7 @@ mod tests {
new_test_ext().execute_with(|| {
assert_ok!(test_benchmark_batch::<Test>());
assert_ok!(test_benchmark_as_derivative::<Test>());
assert_ok!(test_benchmark_batch_all::<Test>());
});
}
}
16 changes: 11 additions & 5 deletions frame/utility/src/default_weights.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// This file is part of Substrate.

// Copyright (C) 2019-2020 Parity Technologies (UK) Ltd.
// Copyright (C) 2020 Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0

// Licensed under the Apache License, Version 2.0 (the "License");
Expand All @@ -15,7 +15,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.

//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 2.0.0-rc5
//! Weights for pallet_utility
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 2.0.0
//! DATE: 2020-10-02, STEPS: [50], REPEAT: 20, LOW RANGE: [], HIGH RANGE: []

#![allow(unused_parens)]
#![allow(unused_imports)]
Expand All @@ -24,10 +26,14 @@ use frame_support::weights::{Weight, constants::RocksDbWeight as DbWeight};

impl crate::WeightInfo for () {
fn batch(c: u32, ) -> Weight {
(16461000 as Weight)
.saturating_add((1982000 as Weight).saturating_mul(c as Weight))
(20_803_000 as Weight)
.saturating_add((1_984_000 as Weight).saturating_mul(c as Weight))
}
fn as_derivative() -> Weight {
(4086000 as Weight)
(5_853_000 as Weight)
}
fn batch_all(c: u32, ) -> Weight {
(21_104_000 as Weight)
.saturating_add((1_509_000 as Weight).saturating_mul(c as Weight))
}
}
99 changes: 89 additions & 10 deletions frame/utility/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,13 +59,14 @@ use sp_std::prelude::*;
use codec::{Encode, Decode};
use sp_core::TypeId;
use sp_io::hashing::blake2_256;
use frame_support::{decl_module, decl_event, decl_storage, Parameter};
use frame_support::{decl_module, decl_event, decl_storage, Parameter, transactional};
use frame_support::{
traits::{OriginTrait, UnfilteredDispatchable, Get},
weights::{Weight, GetDispatchInfo, DispatchClass}, dispatch::PostDispatchInfo,
weights::{Weight, GetDispatchInfo, DispatchClass, extract_actual_weight},
dispatch::{PostDispatchInfo, DispatchResultWithPostInfo},
};
use frame_system::{ensure_signed, ensure_root};
use sp_runtime::{DispatchError, DispatchResult, traits::Dispatchable};
use sp_runtime::{DispatchError, traits::Dispatchable};

mod tests;
mod benchmarking;
Expand All @@ -74,6 +75,7 @@ mod default_weights;
pub trait WeightInfo {
fn batch(c: u32, ) -> Weight;
fn as_derivative() -> Weight;
fn batch_all(c: u32, ) -> Weight;
}

/// Configuration trait.
Expand Down Expand Up @@ -128,9 +130,7 @@ decl_module! {
/// bypassing `frame_system::Trait::BaseCallFilter`).
///
/// # <weight>
/// - Base weight: 14.39 + .987 * c µs
/// - Plus the sum of the weights of the `calls`.
/// - Plus one additional event. (repeat read/write)
/// - Complexity: O(C) where C is the number of calls to be batched.
/// # </weight>
///
/// This will return `Ok` in all circumstances. To determine the success of the batch, an
Expand All @@ -154,20 +154,32 @@ decl_module! {
}
},
)]
fn batch(origin, calls: Vec<<T as Trait>::Call>) {
fn batch(origin, calls: Vec<<T as Trait>::Call>) -> DispatchResultWithPostInfo {
let is_root = ensure_root(origin.clone()).is_ok();
let calls_len = calls.len();
// Track the actual weight of each of the batch calls.
let mut weight: Weight = 0;
for (index, call) in calls.into_iter().enumerate() {
let info = call.get_dispatch_info();
// If origin is root, don't apply any dispatch filters; root can call anything.
let result = if is_root {
call.dispatch_bypass_filter(origin.clone())
} else {
call.dispatch(origin.clone())
};
// Add the weight of this call.
weight = weight.saturating_add(extract_actual_weight(&result, &info));
if let Err(e) = result {
Self::deposit_event(Event::BatchInterrupted(index as u32, e.error));
return Ok(());
// Take the weight of this function itself into account.
let base_weight = T::WeightInfo::batch(index.saturating_add(1) as u32);
// Return the actual used weight + base_weight of this call.
return Ok(Some(base_weight + weight).into());
}
}
Self::deposit_event(Event::BatchCompleted);
let base_weight = T::WeightInfo::batch(calls_len as u32);
Ok(Some(base_weight + weight).into())
}

/// Send a call through an indexed pseudonym of the sender.
Expand All @@ -190,12 +202,79 @@ decl_module! {
.saturating_add(T::DbWeight::get().reads_writes(1, 1)),
call.get_dispatch_info().class,
)]
fn as_derivative(origin, index: u16, call: Box<<T as Trait>::Call>) -> DispatchResult {
fn as_derivative(origin, index: u16, call: Box<<T as Trait>::Call>) -> DispatchResultWithPostInfo {
let mut origin = origin;
let who = ensure_signed(origin.clone())?;
let pseudonym = Self::derivative_account_id(who, index);
origin.set_caller_from(frame_system::RawOrigin::Signed(pseudonym));
call.dispatch(origin).map(|_| ()).map_err(|e| e.error)
let info = call.get_dispatch_info();
let result = call.dispatch(origin);
// Always take into account the base weight of this call.
let mut weight = T::WeightInfo::as_derivative().saturating_add(T::DbWeight::get().reads_writes(1, 1));
// Add the real weight of the dispatch.
weight = weight.saturating_add(extract_actual_weight(&result, &info));
result.map_err(|mut err| {
err.post_info = Some(weight).into();
err
}).map(|_| Some(weight).into())
}

/// Send a batch of dispatch calls and atomically execute them.
/// The whole transaction will rollback and fail if any of the calls failed.
///
/// May be called from any origin.
///
/// - `calls`: The calls to be dispatched from the same origin.
///
/// If origin is root then call are dispatch without checking origin filter. (This includes
/// bypassing `frame_system::Trait::BaseCallFilter`).
///
/// # <weight>
/// - Complexity: O(C) where C is the number of calls to be batched.
/// # </weight>
#[weight = (
calls.iter()
.map(|call| call.get_dispatch_info().weight)
.fold(0, |total: Weight, weight: Weight| total.saturating_add(weight))
.saturating_add(T::WeightInfo::batch_all(calls.len() as u32)),
{
let all_operational = calls.iter()
.map(|call| call.get_dispatch_info().class)
.all(|class| class == DispatchClass::Operational);
if all_operational {
DispatchClass::Operational
} else {
DispatchClass::Normal
}
},
)]
#[transactional]
fn batch_all(origin, calls: Vec<<T as Trait>::Call>) -> DispatchResultWithPostInfo {
let is_root = ensure_root(origin.clone()).is_ok();
let calls_len = calls.len();
// Track the actual weight of each of the batch calls.
let mut weight: Weight = 0;
for (index, call) in calls.into_iter().enumerate() {
let info = call.get_dispatch_info();
// If origin is root, bypass any dispatch filter; root can call anything.
let result = if is_root {
call.dispatch_bypass_filter(origin.clone())
} else {
call.dispatch(origin.clone())
};
// Add the weight of this call.
weight = weight.saturating_add(extract_actual_weight(&result, &info));
result.map_err(|mut err| {
// Take the weight of this function itself into account.
let base_weight = T::WeightInfo::batch_all(index.saturating_add(1) as u32);
// Return the actual used weight + base_weight of this call.
err.post_info = Some(base_weight + weight).into();
err
})?;
}
Self::deposit_event(Event::BatchCompleted);
let base_weight = T::WeightInfo::batch_all(calls_len as u32);
Ok(Some(base_weight + weight).into())
}
}
}
Expand Down
Loading