Implement batch_all and update Utility pallet for weight refunds (#7188)

* implement batch_all

* bump version

* updates

* Better weight story for utility

* small fixes

* weights

* assert_noop_ignore_postinfo doesnt make sense

* Apply suggestions from code review

Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com>

Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com>
Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com>
This commit is contained in:
Xiliang Chen
2020-10-28 08:08:51 +13:00
committed by GitHub
parent f373ecbcf0
commit f14809779d
5 changed files with 414 additions and 24 deletions
+89 -10
View File
@@ -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;
@@ -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.
@@ -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
@@ -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.
@@ -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())
}
}
}