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

Commit

Permalink
implement batch_all
Browse files Browse the repository at this point in the history
  • Loading branch information
xlc committed Sep 23, 2020
1 parent a200cdb commit 37a1e37
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 5 deletions.
2 changes: 1 addition & 1 deletion frame/support/procedural/src/transactional.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ pub fn transactional(_attr: TokenStream, input: TokenStream) -> Result<TokenStre
#vis #sig {
use #crate_::storage::{with_transaction, TransactionOutcome};
with_transaction(|| {
let r = #block;
let r = (|| { #block })();
if r.is_ok() {
TransactionOutcome::Commit(r)
} else {
Expand Down
57 changes: 55 additions & 2 deletions frame/utility/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,11 @@ 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},
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};
Expand Down Expand Up @@ -195,6 +196,58 @@ decl_module! {
origin.set_caller_from(frame_system::RawOrigin::Signed(pseudonym));
call.dispatch(origin).map(|_| ()).map_err(|e| e.error)
}

/// Send a batch of dispatch calls and atomically execute them.
/// The whole transaction will rollback and fail if any of th ecalls 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>
/// - Base weight: 14.39 + .987 * c µs
/// - Plus the sum of the weights of the `calls`.
/// - Plus one additional event. (repeat read/write)
/// # </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(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 mut weight: Weight = 0;
for call in calls.into_iter() {
let info = call.get_dispatch_info();
let result = if is_root {
call.dispatch_bypass_filter(origin.clone())
} else {
call.dispatch(origin.clone())
};
weight += extract_actual_weight(&result, &info);
result.map_err(|mut err| {
err.post_info = Some(weight).into();
err
})?;
}
Self::deposit_event(Event::BatchCompleted);
Ok(Some(weight).into())
}
}
}

Expand Down
48 changes: 46 additions & 2 deletions frame/utility/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,11 @@
use super::*;

use frame_support::{
assert_ok, assert_noop, impl_outer_origin, parameter_types, impl_outer_dispatch,
weights::Weight, impl_outer_event, dispatch::DispatchError, traits::Filter, storage,
assert_ok, assert_noop, impl_outer_origin, parameter_types, impl_outer_dispatch, impl_outer_event,
weights::{Weight, Pays},
dispatch::{DispatchError, DispatchErrorWithPostInfo},
traits::Filter,
storage,
};
use sp_core::H256;
use sp_runtime::{Perbill, traits::{BlakeTwo256, IdentityLookup}, testing::Header};
Expand Down Expand Up @@ -255,3 +258,44 @@ fn batch_weight_calculation_doesnt_overflow() {
assert_eq!(batch_call.get_dispatch_info().weight, Weight::max_value());
});
}


#[test]
fn batch_all_works() {
new_test_ext().execute_with(|| {
assert_eq!(Balances::free_balance(1), 10);
assert_eq!(Balances::free_balance(2), 10);
assert_ok!(
Utility::batch_all(Origin::signed(1), vec![
Call::Balances(BalancesCall::transfer(2, 5)),
Call::Balances(BalancesCall::transfer(2, 5))
]),
);
assert_eq!(Balances::free_balance(1), 0);
assert_eq!(Balances::free_balance(2), 20);
});
}

#[test]
fn batch_all_revert() {
new_test_ext().execute_with(|| {
assert_eq!(Balances::free_balance(1), 10);
assert_eq!(Balances::free_balance(2), 10);
assert_noop!(
Utility::batch_all(Origin::signed(1), vec![
Call::Balances(BalancesCall::transfer(2, 5)),
Call::Balances(BalancesCall::transfer(2, 10)),
Call::Balances(BalancesCall::transfer(2, 5)),
]),
DispatchErrorWithPostInfo {
post_info: PostDispatchInfo {
actual_weight: Some(381898000),
pays_fee: Pays::Yes
},
error: pallet_balances::Error::<Test, _>::InsufficientBalance.into()
}
);
assert_eq!(Balances::free_balance(1), 10);
assert_eq!(Balances::free_balance(2), 10);
});
}

0 comments on commit 37a1e37

Please sign in to comment.