Skip to content

Commit 7b0de49

Browse files
karolk91github-actions[bot]acatangiubkontur
committed
[xcm-builder][origin_conversion] LocationAsSuperuser converter introduced (#8210)
Relates to: polkadot-fellows/runtimes#651 Already used by: polkadot-fellows/runtimes#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 <[email protected]> Co-authored-by: Branislav Kontur <[email protected]> (cherry picked from commit 7755066)
1 parent 2c17894 commit 7b0de49

File tree

3 files changed

+131
-4
lines changed

3 files changed

+131
-4
lines changed

polkadot/xcm/xcm-builder/src/lib.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,9 +115,9 @@ pub use origin_aliases::*;
115115
mod origin_conversion;
116116
pub use origin_conversion::{
117117
BackingToPlurality, ChildParachainAsNative, ChildSystemParachainAsSuperuser, EnsureXcmOrigin,
118-
OriginToPluralityVoice, ParentAsSuperuser, RelayChainAsNative, SiblingParachainAsNative,
119-
SiblingSystemParachainAsSuperuser, SignedAccountId32AsNative, SignedAccountKey20AsNative,
120-
SignedToAccountId32, SovereignSignedViaLocation,
118+
LocationAsSuperuser, OriginToPluralityVoice, ParentAsSuperuser, RelayChainAsNative,
119+
SiblingParachainAsNative, SiblingSystemParachainAsSuperuser, SignedAccountId32AsNative,
120+
SignedAccountKey20AsNative, SignedToAccountId32, SovereignSignedViaLocation,
121121
};
122122

123123
mod pay;

polkadot/xcm/xcm-builder/src/origin_conversion.rs

Lines changed: 120 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
//! Various implementations for `ConvertOrigin`.
1818
1919
use core::marker::PhantomData;
20-
use frame_support::traits::{EnsureOrigin, Get, GetBacking, OriginTrait};
20+
use frame_support::traits::{Contains, EnsureOrigin, Get, GetBacking, OriginTrait};
2121
use frame_system::RawOrigin as SystemRawOrigin;
2222
use polkadot_parachain_primitives::primitives::IsSystem;
2323
use sp_runtime::traits::TryConvert;
@@ -332,3 +332,122 @@ impl<RuntimeOrigin: Clone, EnsureBodyOrigin: EnsureOrigin<RuntimeOrigin>, Body:
332332
}
333333
}
334334
}
335+
336+
/// Converter that allows specific `Location`s to act as a superuser (`RuntimeOrigin::root()`)
337+
/// if it matches the predefined `WhitelistedSuperuserLocations` filter and `OriginKind::Superuser`.
338+
pub struct LocationAsSuperuser<WhitelistedSuperuserLocations, RuntimeOrigin>(
339+
PhantomData<(WhitelistedSuperuserLocations, RuntimeOrigin)>,
340+
);
341+
impl<WhitelistedSuperuserLocations: Contains<Location>, RuntimeOrigin: OriginTrait>
342+
ConvertOrigin<RuntimeOrigin>
343+
for LocationAsSuperuser<WhitelistedSuperuserLocations, RuntimeOrigin>
344+
{
345+
fn convert_origin(
346+
origin: impl Into<Location>,
347+
kind: OriginKind,
348+
) -> Result<RuntimeOrigin, Location> {
349+
let origin = origin.into();
350+
tracing::trace!(
351+
target: "xcm::origin_conversion",
352+
?origin, ?kind,
353+
"LocationAsSuperuser",
354+
);
355+
match (kind, &origin) {
356+
(OriginKind::Superuser, loc) if WhitelistedSuperuserLocations::contains(loc) =>
357+
Ok(RuntimeOrigin::root()),
358+
_ => Err(origin),
359+
}
360+
}
361+
}
362+
363+
#[cfg(test)]
364+
mod tests {
365+
use super::*;
366+
use frame_support::{construct_runtime, derive_impl, parameter_types, traits::Equals};
367+
use xcm::latest::{Junction::*, OriginKind};
368+
369+
type Block = frame_system::mocking::MockBlock<Test>;
370+
371+
construct_runtime!(
372+
pub enum Test
373+
{
374+
System: frame_system,
375+
}
376+
);
377+
378+
#[derive_impl(frame_system::config_preludes::TestDefaultConfig)]
379+
impl frame_system::Config for Test {
380+
type Block = Block;
381+
}
382+
383+
parameter_types! {
384+
pub SuperuserLocation: Location = Location::new(0, Parachain(1));
385+
}
386+
387+
#[test]
388+
fn superuser_location_works() {
389+
let test_conversion = |loc, kind| {
390+
LocationAsSuperuser::<Equals<SuperuserLocation>, RuntimeOrigin>::convert_origin(
391+
loc, kind,
392+
)
393+
};
394+
395+
// Location that was set as SuperUserLocation should result in success conversion to Root
396+
assert!(matches!(test_conversion(SuperuserLocation::get(), OriginKind::Superuser), Ok(..)));
397+
// Same Location as SuperUserLocation::get()
398+
assert!(matches!(
399+
test_conversion(Location::new(0, Parachain(1)), OriginKind::Superuser),
400+
Ok(..)
401+
));
402+
403+
// Same Location but different origin kind
404+
assert!(matches!(test_conversion(SuperuserLocation::get(), OriginKind::Native), Err(..)));
405+
assert!(matches!(
406+
test_conversion(SuperuserLocation::get(), OriginKind::SovereignAccount),
407+
Err(..)
408+
));
409+
assert!(matches!(test_conversion(SuperuserLocation::get(), OriginKind::Xcm), Err(..)));
410+
411+
// No other location should result in successful conversion to Root
412+
// thus expecting Err in all cases below
413+
//
414+
// Non-matching parachain number
415+
assert!(matches!(
416+
test_conversion(Location::new(0, Parachain(2)), OriginKind::Superuser),
417+
Err(..)
418+
));
419+
// Non-matching parents count
420+
assert!(matches!(
421+
test_conversion(Location::new(1, Parachain(1)), OriginKind::Superuser),
422+
Err(..)
423+
));
424+
// Child location of SuperUserLocation
425+
assert!(matches!(
426+
test_conversion(
427+
Location::new(1, [Parachain(1), GeneralIndex(0)]),
428+
OriginKind::Superuser
429+
),
430+
Err(..)
431+
));
432+
// Here
433+
assert!(matches!(test_conversion(Location::new(0, Here), OriginKind::Superuser), Err(..)));
434+
// Parent
435+
assert!(matches!(test_conversion(Location::new(1, Here), OriginKind::Superuser), Err(..)));
436+
// Some random account
437+
assert!(matches!(
438+
test_conversion(
439+
Location::new(0, AccountId32 { network: None, id: [0u8; 32] }),
440+
OriginKind::Superuser
441+
),
442+
Err(..)
443+
));
444+
// Child location of SuperUserLocation
445+
assert!(matches!(
446+
test_conversion(
447+
Location::new(0, [Parachain(1), AccountId32 { network: None, id: [1u8; 32] }]),
448+
OriginKind::Superuser
449+
),
450+
Err(..)
451+
));
452+
}
453+
}

prdoc/pr_8210.prdoc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
title: '[xcm-builder][origin_conversion] LocationAsSuperuser converter introduced'
2+
doc:
3+
- audience: Runtime Dev
4+
description: |-
5+
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.
6+
crates:
7+
- name: staging-xcm-builder
8+
bump: minor

0 commit comments

Comments
 (0)