diff --git a/Cargo.lock b/Cargo.lock index c848d2bc2ded..be4c4a79b6e5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11756,6 +11756,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", + "impl-trait-for-tuples", "pallet-balances", "pallet-collective", "pallet-root-testing", diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs index 60470cc44950..6b2a9a2dbae0 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs @@ -437,6 +437,7 @@ impl pallet_utility::Config for Runtime { type RuntimeEvent = RuntimeEvent; type RuntimeCall = RuntimeCall; type PalletsOrigin = OriginCaller; + type BatchHook = (); type WeightInfo = weights::pallet_utility::WeightInfo; } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs index 3dc396d0344a..fe4ab818805c 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs @@ -430,6 +430,7 @@ impl pallet_utility::Config for Runtime { type RuntimeEvent = RuntimeEvent; type RuntimeCall = RuntimeCall; type PalletsOrigin = OriginCaller; + type BatchHook = (); type WeightInfo = weights::pallet_utility::WeightInfo; } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs index 8a095d62cc21..c48e2fcefe17 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs @@ -491,6 +491,7 @@ impl pallet_utility::Config for Runtime { type RuntimeEvent = RuntimeEvent; type RuntimeCall = RuntimeCall; type PalletsOrigin = OriginCaller; + type BatchHook = (); type WeightInfo = weights::pallet_utility::WeightInfo; } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs index f714b4719c0c..44eee33265a8 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs @@ -453,6 +453,7 @@ impl pallet_utility::Config for Runtime { type RuntimeEvent = RuntimeEvent; type RuntimeCall = RuntimeCall; type PalletsOrigin = OriginCaller; + type BatchHook = (); type WeightInfo = weights::pallet_utility::WeightInfo; } diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs index 953d6d885975..ec5bc367a5b4 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs @@ -251,6 +251,7 @@ impl pallet_utility::Config for Runtime { type RuntimeEvent = RuntimeEvent; type RuntimeCall = RuntimeCall; type PalletsOrigin = OriginCaller; + type BatchHook = (); type WeightInfo = weights::pallet_utility::WeightInfo; } diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs index a272ec0d71b5..046cec8745f6 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs @@ -263,6 +263,7 @@ impl pallet_utility::Config for Runtime { type RuntimeEvent = RuntimeEvent; type RuntimeCall = RuntimeCall; type PalletsOrigin = OriginCaller; + type BatchHook = (); type WeightInfo = pallet_utility::weights::SubstrateWeight; } diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs index a01f575e52dc..46c174d1026c 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs @@ -423,6 +423,7 @@ impl pallet_utility::Config for Runtime { type RuntimeEvent = RuntimeEvent; type RuntimeCall = RuntimeCall; type PalletsOrigin = OriginCaller; + type BatchHook = (); type WeightInfo = weights::pallet_utility::WeightInfo; } diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs index a74874992326..d9baa8954387 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs @@ -424,6 +424,7 @@ impl pallet_utility::Config for Runtime { type RuntimeEvent = RuntimeEvent; type RuntimeCall = RuntimeCall; type PalletsOrigin = OriginCaller; + type BatchHook = (); type WeightInfo = weights::pallet_utility::WeightInfo; } diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs b/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs index 027fee752634..b5868b0f7e77 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs @@ -390,6 +390,7 @@ impl pallet_utility::Config for Runtime { type RuntimeEvent = RuntimeEvent; type RuntimeCall = RuntimeCall; type PalletsOrigin = OriginCaller; + type BatchHook = (); type WeightInfo = weights::pallet_utility::WeightInfo; } diff --git a/cumulus/parachains/runtimes/people/people-westend/src/lib.rs b/cumulus/parachains/runtimes/people/people-westend/src/lib.rs index 56ae1ee238be..f6fb3b6b12a6 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/lib.rs @@ -390,6 +390,7 @@ impl pallet_utility::Config for Runtime { type RuntimeEvent = RuntimeEvent; type RuntimeCall = RuntimeCall; type PalletsOrigin = OriginCaller; + type BatchHook = (); type WeightInfo = weights::pallet_utility::WeightInfo; } diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index 508dff479636..2495e5a9a145 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -714,6 +714,7 @@ impl pallet_utility::Config for Runtime { type RuntimeEvent = RuntimeEvent; type RuntimeCall = RuntimeCall; type PalletsOrigin = OriginCaller; + type BatchHook = (); type WeightInfo = weights::pallet_utility::WeightInfo; } diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 97b1b1e70d7c..39f663700c5c 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -856,6 +856,7 @@ impl pallet_utility::Config for Runtime { type RuntimeEvent = RuntimeEvent; type RuntimeCall = RuntimeCall; type PalletsOrigin = OriginCaller; + type BatchHook = (); type WeightInfo = weights::pallet_utility::WeightInfo; } diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index 2f1c4b31eba5..51909a22e0fc 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -329,6 +329,7 @@ impl pallet_utility::Config for Runtime { type RuntimeEvent = RuntimeEvent; type RuntimeCall = RuntimeCall; type PalletsOrigin = OriginCaller; + type BatchHook = (); type WeightInfo = pallet_utility::weights::SubstrateWeight; } diff --git a/substrate/frame/utility/Cargo.toml b/substrate/frame/utility/Cargo.toml index 2ad575ed51ff..3bab1c158200 100644 --- a/substrate/frame/utility/Cargo.toml +++ b/substrate/frame/utility/Cargo.toml @@ -26,6 +26,8 @@ sp-io = { path = "../../primitives/io", default-features = false } sp-runtime = { path = "../../primitives/runtime", default-features = false } sp-std = { path = "../../primitives/std", default-features = false } +impl-trait-for-tuples = "0.2.2" + [dev-dependencies] pallet-balances = { path = "../balances" } pallet-root-testing = { path = "../root-testing" } diff --git a/substrate/frame/utility/README.md b/substrate/frame/utility/README.md index 0a6769ae1c7c..a3e8d546bbbe 100644 --- a/substrate/frame/utility/README.md +++ b/substrate/frame/utility/README.md @@ -22,6 +22,10 @@ This module contains two basic pieces of functionality: Since proxy filters are respected in all dispatches of this module, it should never need to be filtered by any proxy. +Pre- and post-hooks can be configured via `BatchHook` associated type. +They are triggered for each batch call: `batch`, `batch_all`, and `force_batch`. Use the unit type `()` if no behavior is required. + + ## Interface ### Dispatchable Functions diff --git a/substrate/frame/utility/src/lib.rs b/substrate/frame/utility/src/lib.rs index 7f963e3637d6..fba173eafde9 100644 --- a/substrate/frame/utility/src/lib.rs +++ b/substrate/frame/utility/src/lib.rs @@ -69,6 +69,28 @@ pub use weights::WeightInfo; pub use pallet::*; +/// Hooks that will be called for `batch` calls. +pub trait BatchHook { + /// Will be called before a batch is executed. + fn on_batch_start() -> sp_runtime::DispatchResult; + /// Will be called after the batch was executed. + /// + /// Depending on the exact batch call used, it may not be called when a batch item failed. + fn on_batch_end() -> sp_runtime::DispatchResult; +} + +impl BatchHook for () { + fn on_batch_start() -> sp_runtime::DispatchResult { + Ok(()) + } + + fn on_batch_end() -> sp_runtime::DispatchResult { + Ok(()) + } + +} + + #[frame_support::pallet] pub mod pallet { use super::*; @@ -98,6 +120,10 @@ pub mod pallet { Into<::RuntimeOrigin> + IsType<<::RuntimeOrigin as frame_support::traits::OriginTrait>::PalletsOrigin>; + + /// Hook to be called before any batch operation. + type BatchHook: BatchHook; + /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; } @@ -207,6 +233,8 @@ pub mod pallet { return Err(BadOrigin.into()) } + T::BatchHook::on_batch_start()?; + let is_root = ensure_root(origin.clone()).is_ok(); let calls_len = calls.len(); ensure!(calls_len <= Self::batched_calls_limit() as usize, Error::::TooManyCalls); @@ -236,6 +264,9 @@ pub mod pallet { Self::deposit_event(Event::ItemCompleted); } Self::deposit_event(Event::BatchCompleted); + + T::BatchHook::on_batch_end()?; + let base_weight = T::WeightInfo::batch(calls_len as u32); Ok(Some(base_weight + weight).into()) } @@ -329,6 +360,8 @@ pub mod pallet { return Err(BadOrigin.into()) } + T::BatchHook::on_batch_start()?; + let is_root = ensure_root(origin.clone()).is_ok(); let calls_len = calls.len(); ensure!(calls_len <= Self::batched_calls_limit() as usize, Error::::TooManyCalls); @@ -363,6 +396,9 @@ pub mod pallet { Self::deposit_event(Event::ItemCompleted); } Self::deposit_event(Event::BatchCompleted); + + T::BatchHook::on_batch_end()?; + let base_weight = T::WeightInfo::batch_all(calls_len as u32); Ok(Some(base_weight.saturating_add(weight)).into()) } @@ -438,6 +474,8 @@ pub mod pallet { return Err(BadOrigin.into()) } + T::BatchHook::on_batch_start()?; + let is_root = ensure_root(origin.clone()).is_ok(); let calls_len = calls.len(); ensure!(calls_len <= Self::batched_calls_limit() as usize, Error::::TooManyCalls); @@ -468,6 +506,9 @@ pub mod pallet { } else { Self::deposit_event(Event::BatchCompleted); } + + T::BatchHook::on_batch_end()?; + let base_weight = T::WeightInfo::batch(calls_len as u32); Ok(Some(base_weight.saturating_add(weight)).into()) } diff --git a/substrate/frame/utility/src/tests.rs b/substrate/frame/utility/src/tests.rs index 9bcbec99f3b4..c96df09dc599 100644 --- a/substrate/frame/utility/src/tests.rs +++ b/substrate/frame/utility/src/tests.rs @@ -230,6 +230,7 @@ impl Config for Test { type RuntimeEvent = RuntimeEvent; type RuntimeCall = RuntimeCall; type PalletsOrigin = OriginCaller; + type BatchHook = (); type WeightInfo = (); }