From 7b0de49b74137d53b253ca7f9e6fd8c45ff8c3ba Mon Sep 17 00:00:00 2001 From: Karol Kokoszka Date: Thu, 10 Apr 2025 14:44:59 +0200 Subject: [PATCH 1/2] [xcm-builder][origin_conversion] LocationAsSuperuser converter introduced (#8210) Relates to: https://github.com/polkadot-fellows/runtimes/issues/651 Already used by: https://github.com/polkadot-fellows/runtimes/pull/626 # Description This PR introduces a `LocationAsSuperuser` struct that implements `ConvertOrigin` to allow some `Location` chosen by the XCM configuration to act as Root on the local chain. Implementation is generic over `Location` but was created for purposes of allowing AssetHub system chain (by other system chains and relay chains) to execute Root level extrinsics like `authorize_upgrade` on them. ## TODO * [ ] backport to stable2412 * [ ] backport to stable2503 --------- Co-authored-by: cmd[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Adrian Catangiu Co-authored-by: Branislav Kontur (cherry picked from commit 7755066e348aaea5d8ebb5febe5e38db1c29f141) --- polkadot/xcm/xcm-builder/src/lib.rs | 6 +- .../xcm/xcm-builder/src/origin_conversion.rs | 121 +++++++++++++++++- prdoc/pr_8210.prdoc | 8 ++ 3 files changed, 131 insertions(+), 4 deletions(-) create mode 100644 prdoc/pr_8210.prdoc diff --git a/polkadot/xcm/xcm-builder/src/lib.rs b/polkadot/xcm/xcm-builder/src/lib.rs index 8f6eb9d642962..27d0efe115508 100644 --- a/polkadot/xcm/xcm-builder/src/lib.rs +++ b/polkadot/xcm/xcm-builder/src/lib.rs @@ -115,9 +115,9 @@ pub use origin_aliases::*; mod origin_conversion; pub use origin_conversion::{ BackingToPlurality, ChildParachainAsNative, ChildSystemParachainAsSuperuser, EnsureXcmOrigin, - OriginToPluralityVoice, ParentAsSuperuser, RelayChainAsNative, SiblingParachainAsNative, - SiblingSystemParachainAsSuperuser, SignedAccountId32AsNative, SignedAccountKey20AsNative, - SignedToAccountId32, SovereignSignedViaLocation, + LocationAsSuperuser, OriginToPluralityVoice, ParentAsSuperuser, RelayChainAsNative, + SiblingParachainAsNative, SiblingSystemParachainAsSuperuser, SignedAccountId32AsNative, + SignedAccountKey20AsNative, SignedToAccountId32, SovereignSignedViaLocation, }; mod pay; diff --git a/polkadot/xcm/xcm-builder/src/origin_conversion.rs b/polkadot/xcm/xcm-builder/src/origin_conversion.rs index 20dbc9bba0a50..2071fcd1652f6 100644 --- a/polkadot/xcm/xcm-builder/src/origin_conversion.rs +++ b/polkadot/xcm/xcm-builder/src/origin_conversion.rs @@ -17,7 +17,7 @@ //! Various implementations for `ConvertOrigin`. use core::marker::PhantomData; -use frame_support::traits::{EnsureOrigin, Get, GetBacking, OriginTrait}; +use frame_support::traits::{Contains, EnsureOrigin, Get, GetBacking, OriginTrait}; use frame_system::RawOrigin as SystemRawOrigin; use polkadot_parachain_primitives::primitives::IsSystem; use sp_runtime::traits::TryConvert; @@ -332,3 +332,122 @@ impl, Body: } } } + +/// Converter that allows specific `Location`s to act as a superuser (`RuntimeOrigin::root()`) +/// if it matches the predefined `WhitelistedSuperuserLocations` filter and `OriginKind::Superuser`. +pub struct LocationAsSuperuser( + PhantomData<(WhitelistedSuperuserLocations, RuntimeOrigin)>, +); +impl, RuntimeOrigin: OriginTrait> + ConvertOrigin + for LocationAsSuperuser +{ + fn convert_origin( + origin: impl Into, + kind: OriginKind, + ) -> Result { + let origin = origin.into(); + tracing::trace!( + target: "xcm::origin_conversion", + ?origin, ?kind, + "LocationAsSuperuser", + ); + match (kind, &origin) { + (OriginKind::Superuser, loc) if WhitelistedSuperuserLocations::contains(loc) => + Ok(RuntimeOrigin::root()), + _ => Err(origin), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use frame_support::{construct_runtime, derive_impl, parameter_types, traits::Equals}; + use xcm::latest::{Junction::*, OriginKind}; + + type Block = frame_system::mocking::MockBlock; + + construct_runtime!( + pub enum Test + { + System: frame_system, + } + ); + + #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] + impl frame_system::Config for Test { + type Block = Block; + } + + parameter_types! { + pub SuperuserLocation: Location = Location::new(0, Parachain(1)); + } + + #[test] + fn superuser_location_works() { + let test_conversion = |loc, kind| { + LocationAsSuperuser::, RuntimeOrigin>::convert_origin( + loc, kind, + ) + }; + + // Location that was set as SuperUserLocation should result in success conversion to Root + assert!(matches!(test_conversion(SuperuserLocation::get(), OriginKind::Superuser), Ok(..))); + // Same Location as SuperUserLocation::get() + assert!(matches!( + test_conversion(Location::new(0, Parachain(1)), OriginKind::Superuser), + Ok(..) + )); + + // Same Location but different origin kind + assert!(matches!(test_conversion(SuperuserLocation::get(), OriginKind::Native), Err(..))); + assert!(matches!( + test_conversion(SuperuserLocation::get(), OriginKind::SovereignAccount), + Err(..) + )); + assert!(matches!(test_conversion(SuperuserLocation::get(), OriginKind::Xcm), Err(..))); + + // No other location should result in successful conversion to Root + // thus expecting Err in all cases below + // + // Non-matching parachain number + assert!(matches!( + test_conversion(Location::new(0, Parachain(2)), OriginKind::Superuser), + Err(..) + )); + // Non-matching parents count + assert!(matches!( + test_conversion(Location::new(1, Parachain(1)), OriginKind::Superuser), + Err(..) + )); + // Child location of SuperUserLocation + assert!(matches!( + test_conversion( + Location::new(1, [Parachain(1), GeneralIndex(0)]), + OriginKind::Superuser + ), + Err(..) + )); + // Here + assert!(matches!(test_conversion(Location::new(0, Here), OriginKind::Superuser), Err(..))); + // Parent + assert!(matches!(test_conversion(Location::new(1, Here), OriginKind::Superuser), Err(..))); + // Some random account + assert!(matches!( + test_conversion( + Location::new(0, AccountId32 { network: None, id: [0u8; 32] }), + OriginKind::Superuser + ), + Err(..) + )); + // Child location of SuperUserLocation + assert!(matches!( + test_conversion( + Location::new(0, [Parachain(1), AccountId32 { network: None, id: [1u8; 32] }]), + OriginKind::Superuser + ), + Err(..) + )); + } +} diff --git a/prdoc/pr_8210.prdoc b/prdoc/pr_8210.prdoc new file mode 100644 index 0000000000000..03f08f8d80796 --- /dev/null +++ b/prdoc/pr_8210.prdoc @@ -0,0 +1,8 @@ +title: '[xcm-builder][origin_conversion] LocationAsSuperuser converter introduced' +doc: +- audience: Runtime Dev + description: |- + Introduces a `LocationAsSuperuser` struct that implements `ConvertOrigin` to allow specific `Location`s defined through XCM configuration to act as Root on the local chain. Implementation is generic over `Location` but was created for purposes of allowing AssetHub system chain (by other system chains and relay chains) to execute Root level extrinsics like `authorize_upgrade` on them. +crates: +- name: staging-xcm-builder + bump: minor From b07be1f847b5cd2a7a05f7c2eeaab41cc32281bd Mon Sep 17 00:00:00 2001 From: Karol Kokoszka Date: Tue, 15 Apr 2025 16:02:41 +0200 Subject: [PATCH 2/2] Rename prdoc 8210 -> 8218 --- prdoc/{pr_8210.prdoc => pr_8218.prdoc} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename prdoc/{pr_8210.prdoc => pr_8218.prdoc} (100%) diff --git a/prdoc/pr_8210.prdoc b/prdoc/pr_8218.prdoc similarity index 100% rename from prdoc/pr_8210.prdoc rename to prdoc/pr_8218.prdoc