diff --git a/frame/utility/src/benchmarking.rs b/frame/utility/src/benchmarking.rs index f381b1e5f9e61..5c355f52d902f 100644 --- a/frame/utility/src/benchmarking.rs +++ b/frame/utility/src/benchmarking.rs @@ -86,5 +86,13 @@ benchmarks! { assert_last_event::(Event::BatchCompleted.into()) } + ensure_dispatch_as { + let caller = account("caller", SEED, SEED); + let call = Box::new(frame_system::Call::remark { remark: vec![] }.into()); + let origin: T::RuntimeOrigin = RawOrigin::Signed(caller).into(); + let pallets_origin: ::PalletsOrigin = origin.caller().clone(); + let pallets_origin = Into::::into(pallets_origin); + }: _(RawOrigin::Root, Box::new(pallets_origin), call) + impl_benchmark_test_suite!(Pallet, crate::tests::new_test_ext(), crate::tests::Test); } diff --git a/frame/utility/src/lib.rs b/frame/utility/src/lib.rs index a28dd4994dfa6..345e7afdf62ed 100644 --- a/frame/utility/src/lib.rs +++ b/frame/utility/src/lib.rs @@ -490,6 +490,35 @@ pub mod pallet { let res = call.dispatch_bypass_filter(frame_system::RawOrigin::Root.into()); res.map(|_| ()).map_err(|e| e.error) } + + /// Dispatches a function call with a provided origin. Unlike `dispatch_as`, this + /// function propagates errors returned by the wrapped `call`. + /// + /// The dispatch origin for this call must be _Root_. + /// + /// ## Complexity + /// - O(1). + #[pallet::call_index(6)] + #[pallet::weight({ + let dispatch_info = call.get_dispatch_info(); + ( + T::WeightInfo::ensure_dispatch_as() + .saturating_add(dispatch_info.weight), + dispatch_info.class, + ) + })] + pub fn ensure_dispatch_as( + origin: OriginFor, + as_origin: Box, + call: Box<::RuntimeCall>, + ) -> DispatchResult { + ensure_root(origin)?; + + call.dispatch_bypass_filter((*as_origin).into()).map_err(|e| e.error)?; + + Self::deposit_event(Event::DispatchedAs { result: Ok(()) }); + Ok(()) + } } } diff --git a/frame/utility/src/weights.rs b/frame/utility/src/weights.rs index 7b8c261d1db8b..4d4cb649e9390 100644 --- a/frame/utility/src/weights.rs +++ b/frame/utility/src/weights.rs @@ -53,6 +53,7 @@ pub trait WeightInfo { fn batch_all(c: u32, ) -> Weight; fn dispatch_as() -> Weight; fn force_batch(c: u32, ) -> Weight; + fn ensure_dispatch_as() -> Weight; } /// Weights for pallet_utility using the Substrate node and recommended hardware. @@ -102,6 +103,13 @@ impl WeightInfo for SubstrateWeight { // Standard Error: 1_803 .saturating_add(Weight::from_ref_time(3_645_950).saturating_mul(c.into())) } + fn ensure_dispatch_as() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 8_840 nanoseconds. + Weight::from_ref_time(9_280_000) + } } // For backwards compatibility and tests @@ -150,4 +158,11 @@ impl WeightInfo for () { // Standard Error: 1_803 .saturating_add(Weight::from_ref_time(3_645_950).saturating_mul(c.into())) } + fn ensure_dispatch_as() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 8_840 nanoseconds. + Weight::from_ref_time(9_280_000) + } }