diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_utility.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_utility.rs index 80afbde1b1e0788948ef69bfb0f1238bdde7904b..d70c1947c4e34f3400377cbd452136dd888b2c8c 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_utility.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_utility.rs @@ -99,6 +99,11 @@ impl<T: frame_system::Config> pallet_utility::WeightInfo for WeightInfo<T> { // Standard Error: 1_745 .saturating_add(Weight::from_parts(6_562_902, 0).saturating_mul(c.into())) } + + fn dispatch_as_fallible() -> Weight { + Default::default() + } + fn if_else() -> Weight { // Proof Size summary in bytes: // Measured: `0` diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_utility.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_utility.rs index ef6d9fb4ba945f46689722d363d4b5ec42dad3bc..240779520a0b28b669feaaf1d83936a54afe71e4 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_utility.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_utility.rs @@ -98,6 +98,11 @@ impl<T: frame_system::Config> pallet_utility::WeightInfo for WeightInfo<T> { // Standard Error: 3_765 .saturating_add(Weight::from_parts(6_028_416, 0).saturating_mul(c.into())) } + + fn dispatch_as_fallible() -> Weight { + Default::default() + } + fn if_else() -> Weight { // Proof Size summary in bytes: // Measured: `0` diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_utility.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_utility.rs index 4e531593f4d532fa8b60076e5cce4f7b0c5deb90..0c5a7cf0aeb34a9dba013daadd1ddb00e312af9e 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_utility.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_utility.rs @@ -98,6 +98,11 @@ impl<T: frame_system::Config> pallet_utility::WeightInfo for WeightInfo<T> { // Standard Error: 1_601 .saturating_add(Weight::from_parts(5_138_293, 0).saturating_mul(c.into())) } + + fn dispatch_as_fallible() -> Weight { + Default::default() + } + fn if_else() -> Weight { // Proof Size summary in bytes: // Measured: `0` diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_utility.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_utility.rs index 5d05e89e45932b3e1044d9afe287bf35e6d64632..b81d217f5b0103aa71ba888c6b94dfc6b8ebb522 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_utility.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_utility.rs @@ -99,6 +99,11 @@ impl<T: frame_system::Config> pallet_utility::WeightInfo for WeightInfo<T> { // Standard Error: 1_601 .saturating_add(Weight::from_parts(5_138_293, 0).saturating_mul(c.into())) } + + fn dispatch_as_fallible() -> Weight { + Default::default() + } + fn if_else() -> Weight { // Proof Size summary in bytes: // Measured: `0` diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_utility.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_utility.rs index 6887e41099e350b07f941a42cd93705eb2abf732..d959b11649bbbdf0e06dd51c01e63c1f5a688bb8 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_utility.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_utility.rs @@ -98,6 +98,11 @@ impl<T: frame_system::Config> pallet_utility::WeightInfo for WeightInfo<T> { // Standard Error: 1_395 .saturating_add(Weight::from_parts(5_000_971, 0).saturating_mul(c.into())) } + + fn dispatch_as_fallible() -> Weight { + Default::default() + } + fn if_else() -> Weight { // Proof Size summary in bytes: // Measured: `0` diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_utility.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_utility.rs index 2619a4180bab7d310e24c70e02ccc56bfe72003d..1bfac221c2c8f6126cf46e71950fdcaf613f501e 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_utility.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_utility.rs @@ -99,6 +99,11 @@ impl<T: frame_system::Config> pallet_utility::WeightInfo for WeightInfo<T> { // Standard Error: 1_621 .saturating_add(Weight::from_parts(3_312_302, 0).saturating_mul(c.into())) } + + fn dispatch_as_fallible() -> Weight { + Default::default() + } + fn if_else() -> Weight { // Proof Size summary in bytes: // Measured: `0` diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_utility.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_utility.rs index f2c40f33711859feb6042c0dd15f5328fc3d4641..7ca8e00c2a7ddbed1b0e6b7a82b48ac82edd8cff 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_utility.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_utility.rs @@ -99,6 +99,11 @@ impl<T: frame_system::Config> pallet_utility::WeightInfo for WeightInfo<T> { // Standard Error: 740 .saturating_add(Weight::from_parts(2_800_888, 0).saturating_mul(c.into())) } + + fn dispatch_as_fallible() -> Weight { + Default::default() + } + fn if_else() -> Weight { // Proof Size summary in bytes: // Measured: `0` diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_utility.rs b/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_utility.rs index f30f0776952625dd9c9fa6f5dff2894ab71aa591..0871b257d39c308772e40fe604b61a557bc1d0a8 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_utility.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_utility.rs @@ -96,6 +96,11 @@ impl<T: frame_system::Config> pallet_utility::WeightInfo for WeightInfo<T> { // Standard Error: 3_915 .saturating_add(Weight::from_parts(4_372_646, 0).saturating_mul(c.into())) } + + fn dispatch_as_fallible() -> Weight { + Default::default() + } + fn if_else() -> Weight { // Proof Size summary in bytes: // Measured: `0` diff --git a/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_utility.rs b/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_utility.rs index c7f98f70fdd84bd88565bb9c133db6c2c36f7b4c..d8def37891d4dfe4f41d6a2f71b5ef0afd5a8e1c 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_utility.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_utility.rs @@ -96,6 +96,11 @@ impl<T: frame_system::Config> pallet_utility::WeightInfo for WeightInfo<T> { // Standard Error: 7_605 .saturating_add(Weight::from_parts(4_306_193, 0).saturating_mul(c.into())) } + + fn dispatch_as_fallible() -> Weight { + Default::default() + } + fn if_else() -> Weight { // Proof Size summary in bytes: // Measured: `0` diff --git a/polkadot/runtime/rococo/src/weights/pallet_utility.rs b/polkadot/runtime/rococo/src/weights/pallet_utility.rs index 5e580de6aad54d75381d385f768e12395d65eea6..2b1db130801a437692d7db56884215f0c69d55e2 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_utility.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_utility.rs @@ -99,6 +99,11 @@ impl<T: frame_system::Config> pallet_utility::WeightInfo for WeightInfo<T> { // Standard Error: 460 .saturating_add(Weight::from_parts(3_173_577, 0).saturating_mul(c.into())) } + + fn dispatch_as_fallible() -> Weight { + Default::default() + } + fn if_else() -> Weight { // Proof Size summary in bytes: // Measured: `0` diff --git a/polkadot/runtime/westend/src/weights/pallet_utility.rs b/polkadot/runtime/westend/src/weights/pallet_utility.rs index 84fa0589a58218da02846794b6ced503316c0096..a13c68545526dac2339d935aec284065fa023a92 100644 --- a/polkadot/runtime/westend/src/weights/pallet_utility.rs +++ b/polkadot/runtime/westend/src/weights/pallet_utility.rs @@ -99,6 +99,11 @@ impl<T: frame_system::Config> pallet_utility::WeightInfo for WeightInfo<T> { // Standard Error: 2_817 .saturating_add(Weight::from_parts(5_113_539, 0).saturating_mul(c.into())) } + + fn dispatch_as_fallible() -> Weight { + Default::default() + } + fn if_else() -> Weight { // Proof Size summary in bytes: // Measured: `0` diff --git a/prdoc/pr_7407.prdoc b/prdoc/pr_7407.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..e99e41769184807bae37bd44ee6826d683cb7b98 --- /dev/null +++ b/prdoc/pr_7407.prdoc @@ -0,0 +1,40 @@ +title: 'Fixes #219' +doc: +- audience: Runtime Dev + description: |- + Add a new extrinsic `dispatch_as_fallible`. + + It's almost the same as `dispatch_as` but check the result of the call. + + Closes #219. + + And add more unit tests to cover `dispatch_as` and `dispatch_as_fallible`. + + --- + + Polkadot address: 156HGo9setPcU2qhFMVWLkcmtCEGySLwNqa3DaEiYSWtte4Y +crates: +- name: asset-hub-rococo-runtime + bump: minor +- name: asset-hub-westend-runtime + bump: minor +- name: bridge-hub-rococo-runtime + bump: minor +- name: bridge-hub-westend-runtime + bump: minor +- name: collectives-westend-runtime + bump: minor +- name: coretime-rococo-runtime + bump: minor +- name: coretime-westend-runtime + bump: minor +- name: people-rococo-runtime + bump: minor +- name: people-westend-runtime + bump: minor +- name: rococo-runtime + bump: minor +- name: westend-runtime + bump: minor +- name: pallet-utility + bump: minor diff --git a/substrate/frame/utility/src/benchmarking.rs b/substrate/frame/utility/src/benchmarking.rs index 261d52436889a1033dd4f576c25c070a8944112c..a329815836ba696957c0f0bf9c8b5ab972c3d9f0 100644 --- a/substrate/frame/utility/src/benchmarking.rs +++ b/substrate/frame/utility/src/benchmarking.rs @@ -92,6 +92,18 @@ mod benchmark { assert_last_event::<T>(Event::BatchCompleted.into()); } + #[benchmark] + fn dispatch_as_fallible() { + 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 = origin.caller().clone(); + let pallets_origin = T::PalletsOrigin::from(pallets_origin); + + #[extrinsic_call] + _(RawOrigin::Root, Box::new(pallets_origin), call); + } + #[benchmark] fn if_else() { // Failing main call. diff --git a/substrate/frame/utility/src/lib.rs b/substrate/frame/utility/src/lib.rs index 63a02febb94c51b6c7f2fe1eff07ae0f6f1f767f..03b193052c37add48192096c470b3c1a11e85e12 100644 --- a/substrate/frame/utility/src/lib.rs +++ b/substrate/frame/utility/src/lib.rs @@ -554,6 +554,34 @@ pub mod pallet { post_info: Some(weight).into(), }) } + + /// Dispatches a function call with a provided origin. + /// + /// Almost the same as [`Pallet::dispatch_as`] but forwards any error of the inner call. + /// + /// The dispatch origin for this call must be _Root_. + #[pallet::call_index(7)] + #[pallet::weight({ + let dispatch_info = call.get_dispatch_info(); + ( + T::WeightInfo::dispatch_as_fallible() + .saturating_add(dispatch_info.call_weight), + dispatch_info.class, + ) + })] + pub fn dispatch_as_fallible( + origin: OriginFor<T>, + as_origin: Box<T::PalletsOrigin>, + call: Box<<T as Config>::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(()) + } } impl<T: Config> Pallet<T> { diff --git a/substrate/frame/utility/src/tests.rs b/substrate/frame/utility/src/tests.rs index 759621907dfeda5028298cc2dadee190212dcda5..56e7e3c21ea24853313ab38e3c3a2ff1a3f578bc 100644 --- a/substrate/frame/utility/src/tests.rs +++ b/substrate/frame/utility/src/tests.rs @@ -262,6 +262,14 @@ fn call_foobar(err: bool, start_weight: Weight, end_weight: Option<Weight>) -> R RuntimeCall::Example(ExampleCall::foobar { err, start_weight, end_weight }) } +fn utility_events() -> Vec<Event> { + System::events() + .into_iter() + .map(|r| r.event) + .filter_map(|e| if let RuntimeEvent::Utility(inner) = e { Some(inner) } else { None }) + .collect() +} + #[test] fn as_derivative_works() { new_test_ext().execute_with(|| { @@ -916,6 +924,33 @@ fn with_weight_works() { }) } +#[test] +fn dispatch_as_works() { + new_test_ext().execute_with(|| { + Balances::force_set_balance(RuntimeOrigin::root(), 666, 100).unwrap(); + assert_eq!(Balances::free_balance(666), 100); + assert_eq!(Balances::free_balance(777), 0); + assert_ok!(Utility::dispatch_as( + RuntimeOrigin::root(), + Box::new(OriginCaller::system(frame_system::RawOrigin::Signed(666))), + Box::new(call_transfer(777, 100)) + )); + assert_eq!(Balances::free_balance(666), 0); + assert_eq!(Balances::free_balance(777), 100); + + System::reset_events(); + assert_ok!(Utility::dispatch_as( + RuntimeOrigin::root(), + Box::new(OriginCaller::system(frame_system::RawOrigin::Signed(777))), + Box::new(RuntimeCall::Timestamp(TimestampCall::set { now: 0 })) + )); + assert_eq!( + utility_events(), + vec![Event::DispatchedAs { result: Err(DispatchError::BadOrigin) }] + ); + }) +} + #[test] fn if_else_with_root_works() { new_test_ext().execute_with(|| { @@ -983,6 +1018,31 @@ fn if_else_successful_main_call() { }) } +#[test] +fn dispatch_as_fallible_works() { + new_test_ext().execute_with(|| { + Balances::force_set_balance(RuntimeOrigin::root(), 666, 100).unwrap(); + assert_eq!(Balances::free_balance(666), 100); + assert_eq!(Balances::free_balance(777), 0); + assert_ok!(Utility::dispatch_as_fallible( + RuntimeOrigin::root(), + Box::new(OriginCaller::system(frame_system::RawOrigin::Signed(666))), + Box::new(call_transfer(777, 100)) + )); + assert_eq!(Balances::free_balance(666), 0); + assert_eq!(Balances::free_balance(777), 100); + + assert_noop!( + Utility::dispatch_as_fallible( + RuntimeOrigin::root(), + Box::new(OriginCaller::system(frame_system::RawOrigin::Signed(777))), + Box::new(RuntimeCall::Timestamp(TimestampCall::set { now: 0 })) + ), + DispatchError::BadOrigin, + ); + }) +} + #[test] fn if_else_failing_fallback_call() { new_test_ext().execute_with(|| { diff --git a/substrate/frame/utility/src/weights.rs b/substrate/frame/utility/src/weights.rs index 30922bbb22d5b30cd2f48c2eec667b51c2f8ce15..ce57af72f91424ffe6c1d2ca74700c45b3617664 100644 --- a/substrate/frame/utility/src/weights.rs +++ b/substrate/frame/utility/src/weights.rs @@ -56,6 +56,7 @@ pub trait WeightInfo { fn batch_all(c: u32, ) -> Weight; fn dispatch_as() -> Weight; fn force_batch(c: u32, ) -> Weight; + fn dispatch_as_fallible() -> Weight; fn if_else() -> Weight; } @@ -126,6 +127,10 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> { .saturating_add(Weight::from_parts(4_570_923, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) } + fn dispatch_as_fallible() -> Weight { + Weight::MAX + } + fn if_else() -> Weight { // Proof Size summary in bytes: // Measured: `0` @@ -202,6 +207,11 @@ impl WeightInfo for () { .saturating_add(Weight::from_parts(4_570_923, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) } + + fn dispatch_as_fallible() -> Weight { + Weight::MAX + } + fn if_else() -> Weight { // Proof Size summary in bytes: // Measured: `0`