diff --git a/Cargo.lock b/Cargo.lock index be807feec2144..f734f0499ccd2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13807,6 +13807,7 @@ dependencies = [ "staging-xcm-builder", "staging-xcm-executor", "substrate-wasm-builder", + "testnet-parachains-constants", "xcm-runtime-apis", ] diff --git a/cumulus/parachains/integration-tests/emulated/common/src/macros.rs b/cumulus/parachains/integration-tests/emulated/common/src/macros.rs index 383e6864d788e..de969d665e8fa 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/macros.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/macros.rs @@ -750,9 +750,9 @@ macro_rules! test_xcm_fee_querying_apis_work_for_asset_hub { macro_rules! test_cross_chain_alias { ( vec![$( ($sender_para:ty, $receiver_para:ty, $is_teleport:expr, $expected_success:expr) ),+], $origin:expr, $target:expr, $fees:expr ) => { $crate::macros::paste::paste! { - use xcm::latest::AssetTransferFilter; $( { + use xcm::latest::AssetTransferFilter; let para_destination = <$sender_para>::sibling_location_of(<$receiver_para>::para_id()); let account: AccountId = $origin.clone().into(); $sender_para::fund_accounts(vec![(account.clone(), $fees * 10)]); diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/aliases.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/aliases.rs index 6dbcc1edb5163..7a9ab2638ab52 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/aliases.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/aliases.rs @@ -20,6 +20,7 @@ use emulated_integration_tests_common::{macros::AccountId, test_cross_chain_alia use frame_support::{traits::ContainsPair, BoundedVec}; use xcm::latest::Junctions::*; +const ALLOWED: bool = true; const DENIED: bool = false; const TELEPORT_FEES: bool = true; @@ -32,8 +33,8 @@ fn account_on_sibling_syschain_aliases_into_same_local_account() { let target = origin.clone(); let fees = WESTEND_ED * 10; - PenpalA::mint_foreign_asset( - ::RuntimeOrigin::signed(PenpalAssetOwner::get()), + PenpalB::mint_foreign_asset( + ::RuntimeOrigin::signed(PenpalAssetOwner::get()), Location::parent(), origin.clone(), fees * 10, @@ -55,7 +56,7 @@ fn account_on_sibling_syschain_aliases_into_same_local_account() { // between People and AH: denied (PeopleWestend, AssetHubWestend, TELEPORT_FEES, DENIED), // between Penpal and AH: denied - (PenpalA, AssetHubWestend, RESERVE_TRANSFER_FEES, DENIED) + (PenpalB, AssetHubWestend, RESERVE_TRANSFER_FEES, DENIED) ], origin, target, @@ -70,8 +71,8 @@ fn account_on_sibling_syschain_cannot_alias_into_different_local_account() { let target: AccountId = [2; 32].into(); let fees = WESTEND_ED * 10; - PenpalA::mint_foreign_asset( - ::RuntimeOrigin::signed(PenpalAssetOwner::get()), + PenpalB::mint_foreign_asset( + ::RuntimeOrigin::signed(PenpalAssetOwner::get()), Location::parent(), origin.clone(), fees * 10, @@ -89,7 +90,7 @@ fn account_on_sibling_syschain_cannot_alias_into_different_local_account() { // between People and AH: denied (PeopleWestend, AssetHubWestend, TELEPORT_FEES, DENIED), // between Penpal and AH: denied - (PenpalA, AssetHubWestend, RESERVE_TRANSFER_FEES, DENIED) + (PenpalB, AssetHubWestend, RESERVE_TRANSFER_FEES, DENIED) ], origin, target, @@ -100,82 +101,177 @@ fn account_on_sibling_syschain_cannot_alias_into_different_local_account() { #[test] fn aliasing_child_locations() { use AssetHubWestendXcmConfig as XcmConfig; - // Allows aliasing descendant of origin. - let origin = Location::new(1, X1([PalletInstance(8)].into())); - let target = Location::new(1, X2([PalletInstance(8), GeneralIndex(9)].into())); - assert!(::Aliasers::contains(&origin, &target)); - let origin = Location::new(1, X1([Parachain(8)].into())); - let target = - Location::new(1, X2([Parachain(8), AccountId32 { network: None, id: [1u8; 32] }].into())); - assert!(::Aliasers::contains(&origin, &target)); - let origin = Location::new(1, X1([Parachain(8)].into())); - let target = Location::new(1, X3([Parachain(8), PalletInstance(8), GeneralIndex(9)].into())); - assert!(::Aliasers::contains(&origin, &target)); - - // Does not allow if not descendant. - let origin = Location::new(1, X1([PalletInstance(8)].into())); - let target = Location::new(0, X2([PalletInstance(8), GeneralIndex(9)].into())); - assert!(!::Aliasers::contains(&origin, &target)); - let origin = Location::new(1, X1([Parachain(8)].into())); - let target = - Location::new(0, X2([Parachain(8), AccountId32 { network: None, id: [1u8; 32] }].into())); - assert!(!::Aliasers::contains(&origin, &target)); - let origin = Location::new(1, X1([Parachain(8)].into())); - let target = Location::new(0, X1([AccountId32 { network: None, id: [1u8; 32] }].into())); - assert!(!::Aliasers::contains(&origin, &target)); - let origin = Location::new(1, X1([AccountId32 { network: None, id: [1u8; 32] }].into())); - let target = Location::new(0, X1([AccountId32 { network: None, id: [1u8; 32] }].into())); - assert!(!::Aliasers::contains(&origin, &target)); + AssetHubWestend::execute_with(|| { + // Allows aliasing descendant of origin. + let origin = Location::new(1, X1([PalletInstance(8)].into())); + let target = Location::new(1, X2([PalletInstance(8), GeneralIndex(9)].into())); + assert!(::Aliasers::contains(&origin, &target)); + let origin = Location::new(1, X1([Parachain(8)].into())); + let target = Location::new( + 1, + X2([Parachain(8), AccountId32 { network: None, id: [1u8; 32] }].into()), + ); + assert!(::Aliasers::contains(&origin, &target)); + let origin = Location::new(1, X1([Parachain(8)].into())); + let target = + Location::new(1, X3([Parachain(8), PalletInstance(8), GeneralIndex(9)].into())); + assert!(::Aliasers::contains(&origin, &target)); + + // Does not allow if not descendant. + let origin = Location::new(1, X1([PalletInstance(8)].into())); + let target = Location::new(0, X2([PalletInstance(8), GeneralIndex(9)].into())); + assert!(!::Aliasers::contains(&origin, &target)); + let origin = Location::new(1, X1([Parachain(8)].into())); + let target = Location::new( + 0, + X2([Parachain(8), AccountId32 { network: None, id: [1u8; 32] }].into()), + ); + assert!(!::Aliasers::contains(&origin, &target)); + let origin = Location::new(1, X1([Parachain(8)].into())); + let target = Location::new(0, X1([AccountId32 { network: None, id: [1u8; 32] }].into())); + assert!(!::Aliasers::contains(&origin, &target)); + let origin = Location::new(1, X1([AccountId32 { network: None, id: [1u8; 32] }].into())); + let target = Location::new(0, X1([AccountId32 { network: None, id: [1u8; 32] }].into())); + assert!(!::Aliasers::contains(&origin, &target)); + }); } #[test] fn asset_hub_root_aliases_anything() { use AssetHubWestendXcmConfig as XcmConfig; + AssetHubWestend::execute_with(|| { + // Does not allow local/AH root to alias other (non-descendant) locations. + let origin = Location::new(0, Here); + + let target = Location::new(1, X1([Parachain(2000)].into())); + assert!(!::Aliasers::contains(&origin, &target)); + let target = Location::new(1, X1([AccountId32 { network: None, id: [1u8; 32] }].into())); + assert!(!::Aliasers::contains(&origin, &target)); + let target = Location::new( + 1, + X2([Parachain(8), AccountId32 { network: None, id: [1u8; 32] }].into()), + ); + assert!(!::Aliasers::contains(&origin, &target)); + let target = + Location::new(1, X3([Parachain(42), PalletInstance(8), GeneralIndex(9)].into())); + assert!(!::Aliasers::contains(&origin, &target)); + let target = Location::new(2, X1([GlobalConsensus(Ethereum { chain_id: 1 })].into())); + assert!(!::Aliasers::contains(&origin, &target)); + let target = Location::new(2, X2([GlobalConsensus(Polkadot), Parachain(1000)].into())); + assert!(!::Aliasers::contains(&origin, &target)); + let target = Location::new(1, X2([PalletInstance(8), GeneralIndex(9)].into())); + assert!(!::Aliasers::contains(&origin, &target)); + + // Other AH locations cannot alias anything. + let origin = Location::new(1, X2([Parachain(1000), GeneralIndex(9)].into())); + assert!(!::Aliasers::contains(&origin, &target)); + let origin = Location::new(1, X2([Parachain(1000), PalletInstance(9)].into())); + assert!(!::Aliasers::contains(&origin, &target)); + let origin = Location::new( + 1, + X2([Parachain(1000), AccountId32 { network: None, id: [1u8; 32] }].into()), + ); + assert!(!::Aliasers::contains(&origin, &target)); - // Does not allow local/AH root to alias other locations. - let origin = Location::new(1, X1([Parachain(1000)].into())); - - let target = Location::new(1, X1([Parachain(2000)].into())); - assert!(!::Aliasers::contains(&origin, &target)); - let target = Location::new(1, X1([AccountId32 { network: None, id: [1u8; 32] }].into())); - assert!(!::Aliasers::contains(&origin, &target)); - let target = - Location::new(1, X2([Parachain(8), AccountId32 { network: None, id: [1u8; 32] }].into())); - assert!(!::Aliasers::contains(&origin, &target)); - let target = Location::new(1, X3([Parachain(42), PalletInstance(8), GeneralIndex(9)].into())); - assert!(!::Aliasers::contains(&origin, &target)); - let target = Location::new(2, X1([GlobalConsensus(Ethereum { chain_id: 1 })].into())); - assert!(!::Aliasers::contains(&origin, &target)); - let target = Location::new(2, X2([GlobalConsensus(Polkadot), Parachain(1000)].into())); - assert!(!::Aliasers::contains(&origin, &target)); - let target = Location::new(0, X2([PalletInstance(8), GeneralIndex(9)].into())); - assert!(!::Aliasers::contains(&origin, &target)); - - // Other AH locations cannot alias anything. - let origin = Location::new(1, X2([Parachain(1000), GeneralIndex(9)].into())); - assert!(!::Aliasers::contains(&origin, &target)); - let origin = Location::new(1, X2([Parachain(1000), PalletInstance(9)].into())); - assert!(!::Aliasers::contains(&origin, &target)); - let origin = Location::new( - 1, - X2([Parachain(1000), AccountId32 { network: None, id: [1u8; 32] }].into()), + // Other root locations cannot alias anything. + let origin = Location::new(1, Here); + let target = Location::new(2, X1([GlobalConsensus(Ethereum { chain_id: 1 })].into())); + assert!(!::Aliasers::contains(&origin, &target)); + let target = Location::new(2, X2([GlobalConsensus(Polkadot), Parachain(1000)].into())); + assert!(!::Aliasers::contains(&origin, &target)); + let target = Location::new(0, X2([PalletInstance(8), GeneralIndex(9)].into())); + assert!(!::Aliasers::contains(&origin, &target)); + + let origin = Location::new(0, Here); + let target = Location::new(1, X1([Parachain(2000)].into())); + assert!(!::Aliasers::contains(&origin, &target)); + let origin = Location::new(1, X1([Parachain(1001)].into())); + assert!(!::Aliasers::contains(&origin, &target)); + let origin = Location::new(1, X1([Parachain(1002)].into())); + assert!(!::Aliasers::contains(&origin, &target)); + }); +} + +#[test] +fn authorized_cross_chain_aliases() { + // origin and target are different accounts on different chains + let origin: AccountId = [100; 32].into(); + let bad_origin: AccountId = [150; 32].into(); + let target: AccountId = [200; 32].into(); + let fees = WESTEND_ED * 10; + + let pal_admin = ::RuntimeOrigin::signed(PenpalAssetOwner::get()); + PenpalB::mint_foreign_asset(pal_admin.clone(), Location::parent(), origin.clone(), fees * 10); + PenpalB::mint_foreign_asset(pal_admin, Location::parent(), bad_origin.clone(), fees * 10); + AssetHubWestend::fund_accounts(vec![(target.clone(), fees * 10)]); + + // let's authorize `origin` on Penpal to alias `target` on AssetHub + AssetHubWestend::execute_with(|| { + let penpal_origin = Location::new( + 1, + X2([ + Parachain(PenpalB::para_id().into()), + AccountId32 { + network: Some(ByGenesis(WESTEND_GENESIS_HASH)), + id: origin.clone().into(), + }, + ] + .into()), + ); + // `target` adds `penpal_origin` as authorized alias + assert_ok!(::PolkadotXcm::add_authorized_alias( + ::RuntimeOrigin::signed(target.clone()), + Box::new(penpal_origin.into()), + None + )); + }); + // Verify that unauthorized `bad_origin` cannot alias into `target`, from any chain. + test_cross_chain_alias!( + vec![ + // between BH and AssetHub: denied + (BridgeHubWestend, AssetHubWestend, TELEPORT_FEES, DENIED), + // between Collectives and AssetHub: denied + (CollectivesWestend, AssetHubWestend, TELEPORT_FEES, DENIED), + // between People and AssetHub: denied + (PeopleWestend, AssetHubWestend, TELEPORT_FEES, DENIED), + // between Penpal and AssetHub: denied + (PenpalB, AssetHubWestend, RESERVE_TRANSFER_FEES, DENIED) + ], + bad_origin, + target, + fees + ); + // Verify that only authorized `penpal::origin` can alias into `target`, while `origin` on other + // chains cannot. + test_cross_chain_alias!( + vec![ + // between BH and AssetHub: denied + (BridgeHubWestend, AssetHubWestend, TELEPORT_FEES, DENIED), + // between Collectives and AssetHub: denied + (CollectivesWestend, AssetHubWestend, TELEPORT_FEES, DENIED), + // between People and AssetHub: denied + (PeopleWestend, AssetHubWestend, TELEPORT_FEES, DENIED), + // between Penpal and AssetHub: allowed + (PenpalB, AssetHubWestend, RESERVE_TRANSFER_FEES, ALLOWED) + ], + origin, + target, + fees + ); + // remove authorization for `origin` on Penpal to alias `target` on AssetHub + AssetHubWestend::execute_with(|| { + // `target` removes all authorized aliases + assert_ok!( + ::PolkadotXcm::remove_all_authorized_aliases( + ::RuntimeOrigin::signed(target.clone()) + ) + ); + }); + // Verify `penpal::origin` can no longer alias into `target` on AssetHub. + test_cross_chain_alias!( + vec![(PenpalB, AssetHubWestend, RESERVE_TRANSFER_FEES, DENIED)], + origin, + target, + fees ); - assert!(!::Aliasers::contains(&origin, &target)); - - // Other root locations cannot alias anything. - let origin = Location::new(1, Here); - let target = Location::new(2, X1([GlobalConsensus(Ethereum { chain_id: 1 })].into())); - assert!(!::Aliasers::contains(&origin, &target)); - let target = Location::new(2, X2([GlobalConsensus(Polkadot), Parachain(1000)].into())); - assert!(!::Aliasers::contains(&origin, &target)); - let target = Location::new(0, X2([PalletInstance(8), GeneralIndex(9)].into())); - assert!(!::Aliasers::contains(&origin, &target)); - - let origin = Location::new(0, Here); - let target = Location::new(1, X1([Parachain(2000)].into())); - assert!(!::Aliasers::contains(&origin, &target)); - let origin = Location::new(1, X1([Parachain(1001)].into())); - assert!(!::Aliasers::contains(&origin, &target)); - let origin = Location::new(1, X1([Parachain(1002)].into())); - assert!(!::Aliasers::contains(&origin, &target)); } diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/aliases.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/aliases.rs index 45c72a9ee388f..c3208b09922af 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/aliases.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/aliases.rs @@ -21,6 +21,7 @@ use emulated_integration_tests_common::{macros::AccountId, test_cross_chain_alia use frame_support::{traits::ContainsPair, BoundedVec}; use xcm::latest::Junctions::*; +const ALLOWED: bool = true; const DENIED: bool = false; const TELEPORT_FEES: bool = true; @@ -87,79 +88,169 @@ fn account_on_sibling_syschain_cannot_alias_into_different_local_account() { #[test] fn aliasing_child_locations() { - // Bridge Hub doesn't allow aliasing descendant of origin. - let origin = Location::new(1, X1([PalletInstance(8)].into())); - let target = Location::new(1, X2([PalletInstance(8), GeneralIndex(9)].into())); - assert!(!::Aliasers::contains(&origin, &target)); - let origin = Location::new(1, X1([Parachain(8)].into())); - let target = - Location::new(1, X2([Parachain(8), AccountId32 { network: None, id: [1u8; 32] }].into())); - assert!(!::Aliasers::contains(&origin, &target)); - let origin = Location::new(1, X1([Parachain(8)].into())); - let target = Location::new(1, X3([Parachain(8), PalletInstance(8), GeneralIndex(9)].into())); - assert!(!::Aliasers::contains(&origin, &target)); - // Does not allow if not descendant. - let origin = Location::new(1, X1([PalletInstance(8)].into())); - let target = Location::new(0, X2([PalletInstance(8), GeneralIndex(9)].into())); - assert!(!::Aliasers::contains(&origin, &target)); - let origin = Location::new(1, X1([Parachain(8)].into())); - let target = - Location::new(0, X2([Parachain(8), AccountId32 { network: None, id: [1u8; 32] }].into())); - assert!(!::Aliasers::contains(&origin, &target)); - let origin = Location::new(1, X1([Parachain(8)].into())); - let target = Location::new(0, X1([AccountId32 { network: None, id: [1u8; 32] }].into())); - assert!(!::Aliasers::contains(&origin, &target)); - let origin = Location::new(1, X1([AccountId32 { network: None, id: [1u8; 32] }].into())); - let target = Location::new(0, X1([AccountId32 { network: None, id: [1u8; 32] }].into())); - assert!(!::Aliasers::contains(&origin, &target)); + BridgeHubWestend::execute_with(|| { + // Bridge Hub allows aliasing descendant of origin. + let origin = Location::new(1, X1([PalletInstance(8)].into())); + let target = Location::new(1, X2([PalletInstance(8), GeneralIndex(9)].into())); + assert!(::Aliasers::contains(&origin, &target)); + let origin = Location::new(1, X1([Parachain(8)].into())); + let target = Location::new( + 1, + X2([Parachain(8), AccountId32 { network: None, id: [1u8; 32] }].into()), + ); + assert!(::Aliasers::contains(&origin, &target)); + let origin = Location::new(1, X1([Parachain(8)].into())); + let target = + Location::new(1, X3([Parachain(8), PalletInstance(8), GeneralIndex(9)].into())); + assert!(::Aliasers::contains(&origin, &target)); + // Does not allow if not descendant. + let origin = Location::new(1, X1([PalletInstance(8)].into())); + let target = Location::new(0, X2([PalletInstance(8), GeneralIndex(9)].into())); + assert!(!::Aliasers::contains(&origin, &target)); + let origin = Location::new(1, X1([Parachain(8)].into())); + let target = Location::new( + 0, + X2([Parachain(8), AccountId32 { network: None, id: [1u8; 32] }].into()), + ); + assert!(!::Aliasers::contains(&origin, &target)); + let origin = Location::new(1, X1([Parachain(8)].into())); + let target = Location::new(0, X1([AccountId32 { network: None, id: [1u8; 32] }].into())); + assert!(!::Aliasers::contains(&origin, &target)); + let origin = Location::new(1, X1([AccountId32 { network: None, id: [1u8; 32] }].into())); + let target = Location::new(0, X1([AccountId32 { network: None, id: [1u8; 32] }].into())); + assert!(!::Aliasers::contains(&origin, &target)); + }); } #[test] fn asset_hub_root_aliases_anything() { - // Does not allow AH root to alias other locations. - let origin = Location::new(1, X1([Parachain(1000)].into())); - - let target = Location::new(1, X1([Parachain(2000)].into())); - assert!(!::Aliasers::contains(&origin, &target)); - let target = Location::new(1, X1([AccountId32 { network: None, id: [1u8; 32] }].into())); - assert!(!::Aliasers::contains(&origin, &target)); - let target = - Location::new(1, X2([Parachain(8), AccountId32 { network: None, id: [1u8; 32] }].into())); - assert!(!::Aliasers::contains(&origin, &target)); - let target = Location::new(1, X3([Parachain(42), PalletInstance(8), GeneralIndex(9)].into())); - assert!(!::Aliasers::contains(&origin, &target)); - let target = Location::new(2, X1([GlobalConsensus(Ethereum { chain_id: 1 })].into())); - assert!(!::Aliasers::contains(&origin, &target)); - let target = Location::new(2, X2([GlobalConsensus(Polkadot), Parachain(1000)].into())); - assert!(!::Aliasers::contains(&origin, &target)); - let target = Location::new(0, X2([PalletInstance(8), GeneralIndex(9)].into())); - assert!(!::Aliasers::contains(&origin, &target)); - - // Other AH locations cannot alias anything. - let origin = Location::new(1, X2([Parachain(1000), GeneralIndex(9)].into())); - assert!(!::Aliasers::contains(&origin, &target)); - let origin = Location::new(1, X2([Parachain(1000), PalletInstance(9)].into())); - assert!(!::Aliasers::contains(&origin, &target)); - let origin = Location::new( - 1, - X2([Parachain(1000), AccountId32 { network: None, id: [1u8; 32] }].into()), + BridgeHubWestend::execute_with(|| { + // Does not allow AH root to alias other locations. + let origin = Location::new(1, X1([Parachain(1000)].into())); + + let target = Location::new(1, X1([Parachain(2000)].into())); + assert!(!::Aliasers::contains(&origin, &target)); + let target = Location::new(1, X1([AccountId32 { network: None, id: [1u8; 32] }].into())); + assert!(!::Aliasers::contains(&origin, &target)); + let target = Location::new( + 1, + X2([Parachain(8), AccountId32 { network: None, id: [1u8; 32] }].into()), + ); + assert!(!::Aliasers::contains(&origin, &target)); + let target = + Location::new(1, X3([Parachain(42), PalletInstance(8), GeneralIndex(9)].into())); + assert!(!::Aliasers::contains(&origin, &target)); + let target = Location::new(2, X1([GlobalConsensus(Ethereum { chain_id: 1 })].into())); + assert!(!::Aliasers::contains(&origin, &target)); + let target = Location::new(2, X2([GlobalConsensus(Polkadot), Parachain(1000)].into())); + assert!(!::Aliasers::contains(&origin, &target)); + let target = Location::new(0, X2([PalletInstance(8), GeneralIndex(9)].into())); + assert!(!::Aliasers::contains(&origin, &target)); + + // Other AH locations cannot alias anything. + let origin = Location::new(1, X2([Parachain(1000), GeneralIndex(9)].into())); + assert!(!::Aliasers::contains(&origin, &target)); + let origin = Location::new(1, X2([Parachain(1000), PalletInstance(9)].into())); + assert!(!::Aliasers::contains(&origin, &target)); + let origin = Location::new( + 1, + X2([Parachain(1000), AccountId32 { network: None, id: [1u8; 32] }].into()), + ); + assert!(!::Aliasers::contains(&origin, &target)); + + // Other root locations cannot alias anything. + let origin = Location::new(1, Here); + let target = Location::new(2, X1([GlobalConsensus(Ethereum { chain_id: 1 })].into())); + assert!(!::Aliasers::contains(&origin, &target)); + let target = Location::new(2, X2([GlobalConsensus(Polkadot), Parachain(1000)].into())); + assert!(!::Aliasers::contains(&origin, &target)); + let target = Location::new(0, X2([PalletInstance(8), GeneralIndex(9)].into())); + assert!(!::Aliasers::contains(&origin, &target)); + + let origin = Location::new(0, Here); + let target = Location::new(1, X1([Parachain(2000)].into())); + assert!(!::Aliasers::contains(&origin, &target)); + let origin = Location::new(1, X1([Parachain(1001)].into())); + assert!(!::Aliasers::contains(&origin, &target)); + let origin = Location::new(1, X1([Parachain(1002)].into())); + assert!(!::Aliasers::contains(&origin, &target)); + }); +} + +#[test] +fn authorized_cross_chain_aliases() { + // origin and target are different accounts on different chains + let origin: AccountId = [100; 32].into(); + let bad_origin: AccountId = [150; 32].into(); + let target: AccountId = [200; 32].into(); + let fees = WESTEND_ED * 10; + + let pal_admin = ::RuntimeOrigin::signed(PenpalAssetOwner::get()); + PenpalB::mint_foreign_asset(pal_admin.clone(), Location::parent(), origin.clone(), fees * 10); + PenpalB::mint_foreign_asset(pal_admin, Location::parent(), bad_origin.clone(), fees * 10); + BridgeHubWestend::fund_accounts(vec![(target.clone(), fees * 10)]); + + // let's authorize `origin` on Penpal to alias `target` on BridgeHub + BridgeHubWestend::execute_with(|| { + let penpal_origin = Location::new( + 1, + X2([ + Parachain(PenpalB::para_id().into()), + AccountId32 { + network: Some(ByGenesis(WESTEND_GENESIS_HASH)), + id: origin.clone().into(), + }, + ] + .into()), + ); + // `target` adds `penpal_origin` as authorized alias + assert_ok!( + ::PolkadotXcm::add_authorized_alias( + ::RuntimeOrigin::signed(target.clone()), + Box::new(penpal_origin.into()), + None + ) + ); + }); + // Verify that unauthorized `bad_origin` cannot alias into `target`, from any chain. + test_cross_chain_alias!( + vec![ + // between AH and BridgeHub: denied + (AssetHubWestend, BridgeHubWestend, TELEPORT_FEES, DENIED), + // between Penpal and BridgeHub: denied + (PenpalB, BridgeHubWestend, RESERVE_TRANSFER_FEES, DENIED) + ], + bad_origin, + target, + fees + ); + // Verify that only authorized `penpal::origin` can alias into `target`, while `origin` on other + // chains cannot. + test_cross_chain_alias!( + vec![ + // between AH and BridgeHub: denied + (AssetHubWestend, BridgeHubWestend, TELEPORT_FEES, DENIED), + // between Penpal and BridgeHub: allowed + (PenpalB, BridgeHubWestend, RESERVE_TRANSFER_FEES, ALLOWED) + ], + origin, + target, + fees + ); + // remove authorization for `origin` on Penpal to alias `target` on BridgeHub + BridgeHubWestend::execute_with(|| { + // `target` removes all authorized aliases + assert_ok!( + ::PolkadotXcm::remove_all_authorized_aliases( + ::RuntimeOrigin::signed(target.clone()) + ) + ); + }); + // Verify `penpal::origin` can no longer alias into `target` on BridgeHub. + test_cross_chain_alias!( + vec![(PenpalB, BridgeHubWestend, RESERVE_TRANSFER_FEES, DENIED)], + origin, + target, + fees ); - assert!(!::Aliasers::contains(&origin, &target)); - - // Other root locations cannot alias anything. - let origin = Location::new(1, Here); - let target = Location::new(2, X1([GlobalConsensus(Ethereum { chain_id: 1 })].into())); - assert!(!::Aliasers::contains(&origin, &target)); - let target = Location::new(2, X2([GlobalConsensus(Polkadot), Parachain(1000)].into())); - assert!(!::Aliasers::contains(&origin, &target)); - let target = Location::new(0, X2([PalletInstance(8), GeneralIndex(9)].into())); - assert!(!::Aliasers::contains(&origin, &target)); - - let origin = Location::new(0, Here); - let target = Location::new(1, X1([Parachain(2000)].into())); - assert!(!::Aliasers::contains(&origin, &target)); - let origin = Location::new(1, X1([Parachain(1001)].into())); - assert!(!::Aliasers::contains(&origin, &target)); - let origin = Location::new(1, X1([Parachain(1002)].into())); - assert!(!::Aliasers::contains(&origin, &target)); } diff --git a/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/src/lib.rs index 43f03a7013889..00ad3f9f52a91 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/src/lib.rs @@ -13,7 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -pub use xcm::{prelude::*, v3}; +pub use xcm::{latest::WESTEND_GENESIS_HASH, prelude::*}; pub use emulated_integration_tests_common::{ accounts::ALICE, @@ -43,7 +43,7 @@ pub use westend_system_emulated_network::{ coretime_westend_runtime::ExistentialDeposit as CoretimeWestendExistentialDeposit, CoretimeWestendParaPallet as CoretimeWestendPallet, }, - penpal_emulated_chain::{PenpalAParaPallet as PenpalAPallet, PenpalAssetOwner}, + penpal_emulated_chain::{PenpalAssetOwner, PenpalBParaPallet as PenpalBPallet}, people_westend_emulated_chain::PeopleWestendParaPallet as PeopleWestendPallet, westend_emulated_chain::{ genesis::ED as WESTEND_ED, @@ -58,7 +58,7 @@ pub use westend_system_emulated_network::{ CollectivesWestendPara as CollectivesWestend, CollectivesWestendParaReceiver as CollectivesWestendReceiver, CollectivesWestendParaSender as CollectivesWestendSender, - CoretimeWestendPara as CoretimeWestend, PenpalAPara as PenpalA, + CoretimeWestendPara as CoretimeWestend, PenpalBPara as PenpalB, PeopleWestendPara as PeopleWestend, WestendRelay as Westend, WestendRelayReceiver as WestendReceiver, WestendRelaySender as WestendSender, }; diff --git a/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/src/tests/aliases.rs b/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/src/tests/aliases.rs index 220b7e8f77d49..369208c3b12aa 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/src/tests/aliases.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/src/tests/aliases.rs @@ -33,8 +33,8 @@ fn account_on_sibling_syschain_aliases_into_same_local_account() { let target = origin.clone(); let fees = WESTEND_ED * 10; - PenpalA::mint_foreign_asset( - ::RuntimeOrigin::signed(PenpalAssetOwner::get()), + PenpalB::mint_foreign_asset( + ::RuntimeOrigin::signed(PenpalAssetOwner::get()), Location::parent(), origin.clone(), fees * 10, @@ -52,7 +52,7 @@ fn account_on_sibling_syschain_aliases_into_same_local_account() { // between People and Collectives: allowed (PeopleWestend, CollectivesWestend, TELEPORT_FEES, ALLOWED), // between Penpal and Collectives: denied - (PenpalA, CollectivesWestend, RESERVE_TRANSFER_FEES, DENIED) + (PenpalB, CollectivesWestend, RESERVE_TRANSFER_FEES, DENIED) ], origin, target, @@ -67,8 +67,8 @@ fn account_on_sibling_syschain_cannot_alias_into_different_local_account() { let target: AccountId = [2; 32].into(); let fees = WESTEND_ED * 10; - PenpalA::mint_foreign_asset( - ::RuntimeOrigin::signed(PenpalAssetOwner::get()), + PenpalB::mint_foreign_asset( + ::RuntimeOrigin::signed(PenpalAssetOwner::get()), Location::parent(), origin.clone(), fees * 10, @@ -86,7 +86,7 @@ fn account_on_sibling_syschain_cannot_alias_into_different_local_account() { // between People and Collectives: denied (PeopleWestend, CollectivesWestend, TELEPORT_FEES, DENIED), // between Penpal and Collectives: denied - (PenpalA, CollectivesWestend, RESERVE_TRANSFER_FEES, DENIED) + (PenpalB, CollectivesWestend, RESERVE_TRANSFER_FEES, DENIED) ], origin, target, @@ -97,81 +97,179 @@ fn account_on_sibling_syschain_cannot_alias_into_different_local_account() { #[test] fn aliasing_child_locations() { use CollectivesWestendXcmConfig as XcmConfig; - // Allows aliasing descendant of origin. - let origin = Location::new(1, X1([PalletInstance(8)].into())); - let target = Location::new(1, X2([PalletInstance(8), GeneralIndex(9)].into())); - assert!(::Aliasers::contains(&origin, &target)); - let origin = Location::new(1, X1([Parachain(8)].into())); - let target = - Location::new(1, X2([Parachain(8), AccountId32 { network: None, id: [1u8; 32] }].into())); - assert!(::Aliasers::contains(&origin, &target)); - let origin = Location::new(1, X1([Parachain(8)].into())); - let target = Location::new(1, X3([Parachain(8), PalletInstance(8), GeneralIndex(9)].into())); - assert!(::Aliasers::contains(&origin, &target)); - - // Does not allow if not descendant. - let origin = Location::new(1, X1([PalletInstance(8)].into())); - let target = Location::new(0, X2([PalletInstance(8), GeneralIndex(9)].into())); - assert!(!::Aliasers::contains(&origin, &target)); - let origin = Location::new(1, X1([Parachain(8)].into())); - let target = - Location::new(0, X2([Parachain(8), AccountId32 { network: None, id: [1u8; 32] }].into())); - assert!(!::Aliasers::contains(&origin, &target)); - let origin = Location::new(1, X1([Parachain(8)].into())); - let target = Location::new(0, X1([AccountId32 { network: None, id: [1u8; 32] }].into())); - assert!(!::Aliasers::contains(&origin, &target)); - let origin = Location::new(1, X1([AccountId32 { network: None, id: [1u8; 32] }].into())); - let target = Location::new(0, X1([AccountId32 { network: None, id: [1u8; 32] }].into())); - assert!(!::Aliasers::contains(&origin, &target)); + CollectivesWestend::execute_with(|| { + // Allows aliasing descendant of origin. + let origin = Location::new(1, X1([PalletInstance(8)].into())); + let target = Location::new(1, X2([PalletInstance(8), GeneralIndex(9)].into())); + assert!(::Aliasers::contains(&origin, &target)); + let origin = Location::new(1, X1([Parachain(8)].into())); + let target = Location::new( + 1, + X2([Parachain(8), AccountId32 { network: None, id: [1u8; 32] }].into()), + ); + assert!(::Aliasers::contains(&origin, &target)); + let origin = Location::new(1, X1([Parachain(8)].into())); + let target = + Location::new(1, X3([Parachain(8), PalletInstance(8), GeneralIndex(9)].into())); + assert!(::Aliasers::contains(&origin, &target)); + + // Does not allow if not descendant. + let origin = Location::new(1, X1([PalletInstance(8)].into())); + let target = Location::new(0, X2([PalletInstance(8), GeneralIndex(9)].into())); + assert!(!::Aliasers::contains(&origin, &target)); + let origin = Location::new(1, X1([Parachain(8)].into())); + let target = Location::new( + 0, + X2([Parachain(8), AccountId32 { network: None, id: [1u8; 32] }].into()), + ); + assert!(!::Aliasers::contains(&origin, &target)); + let origin = Location::new(1, X1([Parachain(8)].into())); + let target = Location::new(0, X1([AccountId32 { network: None, id: [1u8; 32] }].into())); + assert!(!::Aliasers::contains(&origin, &target)); + let origin = Location::new(1, X1([AccountId32 { network: None, id: [1u8; 32] }].into())); + let target = Location::new(0, X1([AccountId32 { network: None, id: [1u8; 32] }].into())); + assert!(!::Aliasers::contains(&origin, &target)); + }); } #[test] fn asset_hub_root_aliases_anything() { use CollectivesWestendXcmConfig as XcmConfig; - // Allows AH root to alias anything. - let origin = Location::new(1, X1([Parachain(1000)].into())); - - let target = Location::new(1, X1([Parachain(2000)].into())); - assert!(::Aliasers::contains(&origin, &target)); - let target = Location::new(1, X1([AccountId32 { network: None, id: [1u8; 32] }].into())); - assert!(::Aliasers::contains(&origin, &target)); - let target = - Location::new(1, X2([Parachain(8), AccountId32 { network: None, id: [1u8; 32] }].into())); - assert!(::Aliasers::contains(&origin, &target)); - let target = Location::new(1, X3([Parachain(42), PalletInstance(8), GeneralIndex(9)].into())); - assert!(::Aliasers::contains(&origin, &target)); - let target = Location::new(2, X1([GlobalConsensus(Ethereum { chain_id: 1 })].into())); - assert!(::Aliasers::contains(&origin, &target)); - let target = Location::new(2, X2([GlobalConsensus(Polkadot), Parachain(1000)].into())); - assert!(::Aliasers::contains(&origin, &target)); - let target = Location::new(0, X2([PalletInstance(8), GeneralIndex(9)].into())); - assert!(::Aliasers::contains(&origin, &target)); - - // Other AH locations cannot alias anything. - let origin = Location::new(1, X2([Parachain(1000), GeneralIndex(9)].into())); - assert!(!::Aliasers::contains(&origin, &target)); - let origin = Location::new(1, X2([Parachain(1000), PalletInstance(9)].into())); - assert!(!::Aliasers::contains(&origin, &target)); - let origin = Location::new( - 1, - X2([Parachain(1000), AccountId32 { network: None, id: [1u8; 32] }].into()), + CollectivesWestend::execute_with(|| { + // Allows AH root to alias anything. + let origin = Location::new(1, X1([Parachain(1000)].into())); + + let target = Location::new(1, X1([Parachain(2000)].into())); + assert!(::Aliasers::contains(&origin, &target)); + let target = Location::new(1, X1([AccountId32 { network: None, id: [1u8; 32] }].into())); + assert!(::Aliasers::contains(&origin, &target)); + let target = Location::new( + 1, + X2([Parachain(8), AccountId32 { network: None, id: [1u8; 32] }].into()), + ); + assert!(::Aliasers::contains(&origin, &target)); + let target = + Location::new(1, X3([Parachain(42), PalletInstance(8), GeneralIndex(9)].into())); + assert!(::Aliasers::contains(&origin, &target)); + let target = Location::new(2, X1([GlobalConsensus(Ethereum { chain_id: 1 })].into())); + assert!(::Aliasers::contains(&origin, &target)); + let target = Location::new(2, X2([GlobalConsensus(Polkadot), Parachain(1000)].into())); + assert!(::Aliasers::contains(&origin, &target)); + let target = Location::new(0, X2([PalletInstance(8), GeneralIndex(9)].into())); + assert!(::Aliasers::contains(&origin, &target)); + + // Other AH locations cannot alias anything. + let origin = Location::new(1, X2([Parachain(1000), GeneralIndex(9)].into())); + assert!(!::Aliasers::contains(&origin, &target)); + let origin = Location::new(1, X2([Parachain(1000), PalletInstance(9)].into())); + assert!(!::Aliasers::contains(&origin, &target)); + let origin = Location::new( + 1, + X2([Parachain(1000), AccountId32 { network: None, id: [1u8; 32] }].into()), + ); + assert!(!::Aliasers::contains(&origin, &target)); + + // Other root locations cannot alias anything. + let origin = Location::new(1, Here); + let target = Location::new(2, X1([GlobalConsensus(Ethereum { chain_id: 1 })].into())); + assert!(!::Aliasers::contains(&origin, &target)); + let target = Location::new(2, X2([GlobalConsensus(Polkadot), Parachain(1000)].into())); + assert!(!::Aliasers::contains(&origin, &target)); + let target = Location::new(0, X2([PalletInstance(8), GeneralIndex(9)].into())); + assert!(!::Aliasers::contains(&origin, &target)); + + let origin = Location::new(0, Here); + let target = Location::new(1, X1([Parachain(2000)].into())); + assert!(!::Aliasers::contains(&origin, &target)); + let origin = Location::new(1, X1([Parachain(1001)].into())); + assert!(!::Aliasers::contains(&origin, &target)); + let origin = Location::new(1, X1([Parachain(1002)].into())); + assert!(!::Aliasers::contains(&origin, &target)); + }); +} + +#[test] +fn authorized_cross_chain_aliases() { + // origin and target are different accounts on different chains + let origin: AccountId = [100; 32].into(); + let bad_origin: AccountId = [150; 32].into(); + let target: AccountId = [200; 32].into(); + let fees = WESTEND_ED * 10; + + let pal_admin = ::RuntimeOrigin::signed(PenpalAssetOwner::get()); + PenpalB::mint_foreign_asset(pal_admin.clone(), Location::parent(), origin.clone(), fees * 10); + PenpalB::mint_foreign_asset(pal_admin, Location::parent(), bad_origin.clone(), fees * 10); + CollectivesWestend::fund_accounts(vec![(target.clone(), fees * 10)]); + + // let's authorize `origin` on Penpal to alias `target` on Collectives + CollectivesWestend::execute_with(|| { + let penpal_origin = Location::new( + 1, + X2([ + Parachain(PenpalB::para_id().into()), + AccountId32 { + network: Some(ByGenesis(WESTEND_GENESIS_HASH)), + id: origin.clone().into(), + }, + ] + .into()), + ); + // `target` adds `penpal_origin` as authorized alias + assert_ok!( + ::PolkadotXcm::add_authorized_alias( + ::RuntimeOrigin::signed(target.clone()), + Box::new(penpal_origin.into()), + None + ) + ); + }); + // Verify that unauthorized `bad_origin` cannot alias into `target`, from any chain. + test_cross_chain_alias!( + vec![ + // between AH and Collectives: denied + (AssetHubWestend, CollectivesWestend, TELEPORT_FEES, DENIED), + // between BH and Collectives: denied + (BridgeHubWestend, CollectivesWestend, TELEPORT_FEES, DENIED), + // between People and Collectives: denied + (PeopleWestend, CollectivesWestend, TELEPORT_FEES, DENIED), + // between Penpal and Collectives: denied + (PenpalB, CollectivesWestend, RESERVE_TRANSFER_FEES, DENIED) + ], + bad_origin, + target, + fees + ); + // Verify that only authorized `penpal::origin` can alias into `target`, while `origin` on other + // chains cannot. + test_cross_chain_alias!( + vec![ + // between AH and Collectives: denied + (AssetHubWestend, CollectivesWestend, TELEPORT_FEES, DENIED), + // between BH and Collectives: denied + (BridgeHubWestend, CollectivesWestend, TELEPORT_FEES, DENIED), + // between People and Collectives: denied + (PeopleWestend, CollectivesWestend, TELEPORT_FEES, DENIED), + // between Penpal and Collectives: allowed + (PenpalB, CollectivesWestend, RESERVE_TRANSFER_FEES, ALLOWED) + ], + origin, + target, + fees + ); + // remove authorization for `origin` on Penpal to alias `target` on Collectives + CollectivesWestend::execute_with(|| { + // `target` removes all authorized aliases + assert_ok!( + ::PolkadotXcm::remove_all_authorized_aliases( + ::RuntimeOrigin::signed(target.clone()) + ) + ); + }); + // Verify `penpal::origin` can no longer alias into `target` on Collectives. + test_cross_chain_alias!( + vec![(PenpalB, CollectivesWestend, RESERVE_TRANSFER_FEES, DENIED)], + origin, + target, + fees ); - assert!(!::Aliasers::contains(&origin, &target)); - - // Other root locations cannot alias anything. - let origin = Location::new(1, Here); - let target = Location::new(2, X1([GlobalConsensus(Ethereum { chain_id: 1 })].into())); - assert!(!::Aliasers::contains(&origin, &target)); - let target = Location::new(2, X2([GlobalConsensus(Polkadot), Parachain(1000)].into())); - assert!(!::Aliasers::contains(&origin, &target)); - let target = Location::new(0, X2([PalletInstance(8), GeneralIndex(9)].into())); - assert!(!::Aliasers::contains(&origin, &target)); - - let origin = Location::new(0, Here); - let target = Location::new(1, X1([Parachain(2000)].into())); - assert!(!::Aliasers::contains(&origin, &target)); - let origin = Location::new(1, X1([Parachain(1001)].into())); - assert!(!::Aliasers::contains(&origin, &target)); - let origin = Location::new(1, X1([Parachain(1002)].into())); - assert!(!::Aliasers::contains(&origin, &target)); } diff --git a/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/src/lib.rs index 44efa40e4ea6e..62f332ecb784e 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/src/lib.rs @@ -35,13 +35,13 @@ mod imports { coretime_westend_runtime::ExistentialDeposit as CoretimeWestendExistentialDeposit, CoretimeWestendParaPallet as CoretimeWestendPallet, }, - penpal_emulated_chain::{PenpalAParaPallet as PenpalAPallet, PenpalAssetOwner}, + penpal_emulated_chain::{PenpalAssetOwner, PenpalBParaPallet as PenpalBPallet}, people_westend_emulated_chain::PeopleWestendParaPallet as PeopleWestendPallet, westend_emulated_chain::genesis::ED as WESTEND_ED, AssetHubWestendPara as AssetHubWestend, BridgeHubWestendPara as BridgeHubWestend, CollectivesWestendPara as CollectivesWestend, CoretimeWestendPara as CoretimeWestend, CoretimeWestendParaReceiver as CoretimeWestendReceiver, - CoretimeWestendParaSender as CoretimeWestendSender, PenpalAPara as PenpalA, + CoretimeWestendParaSender as CoretimeWestendSender, PenpalBPara as PenpalB, PeopleWestendPara as PeopleWestend, WestendRelay as Westend, }; } diff --git a/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/src/tests/aliases.rs b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/src/tests/aliases.rs index ccaf53a8d0993..db65d5e4a5cb0 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/src/tests/aliases.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/src/tests/aliases.rs @@ -34,8 +34,8 @@ fn account_on_sibling_syschain_aliases_into_same_local_account() { let target = origin.clone(); let fees = WESTEND_ED * 10; - PenpalA::mint_foreign_asset( - ::RuntimeOrigin::signed(PenpalAssetOwner::get()), + PenpalB::mint_foreign_asset( + ::RuntimeOrigin::signed(PenpalAssetOwner::get()), Location::parent(), origin.clone(), fees * 10, @@ -53,7 +53,7 @@ fn account_on_sibling_syschain_aliases_into_same_local_account() { // between People and Coretime: allowed (PeopleWestend, CoretimeWestend, TELEPORT_FEES, ALLOWED), // between Penpal and Coretime: denied - (PenpalA, CoretimeWestend, RESERVE_TRANSFER_FEES, DENIED) + (PenpalB, CoretimeWestend, RESERVE_TRANSFER_FEES, DENIED) ], origin, target, @@ -68,8 +68,8 @@ fn account_on_sibling_syschain_cannot_alias_into_different_local_account() { let target: AccountId = [2; 32].into(); let fees = WESTEND_ED * 10; - PenpalA::mint_foreign_asset( - ::RuntimeOrigin::signed(PenpalAssetOwner::get()), + PenpalB::mint_foreign_asset( + ::RuntimeOrigin::signed(PenpalAssetOwner::get()), Location::parent(), origin.clone(), fees * 10, @@ -87,7 +87,7 @@ fn account_on_sibling_syschain_cannot_alias_into_different_local_account() { // between People and Coretime: denied (PeopleWestend, CoretimeWestend, TELEPORT_FEES, DENIED), // between Penpal and Coretime: denied - (PenpalA, CoretimeWestend, RESERVE_TRANSFER_FEES, DENIED) + (PenpalB, CoretimeWestend, RESERVE_TRANSFER_FEES, DENIED) ], origin, target, @@ -97,80 +97,176 @@ fn account_on_sibling_syschain_cannot_alias_into_different_local_account() { #[test] fn aliasing_child_locations() { - // Allows aliasing descendant of origin. - let origin = Location::new(1, X1([PalletInstance(8)].into())); - let target = Location::new(1, X2([PalletInstance(8), GeneralIndex(9)].into())); - assert!(::Aliasers::contains(&origin, &target)); - let origin = Location::new(1, X1([Parachain(8)].into())); - let target = - Location::new(1, X2([Parachain(8), AccountId32 { network: None, id: [1u8; 32] }].into())); - assert!(::Aliasers::contains(&origin, &target)); - let origin = Location::new(1, X1([Parachain(8)].into())); - let target = Location::new(1, X3([Parachain(8), PalletInstance(8), GeneralIndex(9)].into())); - assert!(::Aliasers::contains(&origin, &target)); - - // Does not allow if not descendant. - let origin = Location::new(1, X1([PalletInstance(8)].into())); - let target = Location::new(0, X2([PalletInstance(8), GeneralIndex(9)].into())); - assert!(!::Aliasers::contains(&origin, &target)); - let origin = Location::new(1, X1([Parachain(8)].into())); - let target = - Location::new(0, X2([Parachain(8), AccountId32 { network: None, id: [1u8; 32] }].into())); - assert!(!::Aliasers::contains(&origin, &target)); - let origin = Location::new(1, X1([Parachain(8)].into())); - let target = Location::new(0, X1([AccountId32 { network: None, id: [1u8; 32] }].into())); - assert!(!::Aliasers::contains(&origin, &target)); - let origin = Location::new(1, X1([AccountId32 { network: None, id: [1u8; 32] }].into())); - let target = Location::new(0, X1([AccountId32 { network: None, id: [1u8; 32] }].into())); - assert!(!::Aliasers::contains(&origin, &target)); + CoretimeWestend::execute_with(|| { + // Allows aliasing descendant of origin. + let origin = Location::new(1, X1([PalletInstance(8)].into())); + let target = Location::new(1, X2([PalletInstance(8), GeneralIndex(9)].into())); + assert!(::Aliasers::contains(&origin, &target)); + let origin = Location::new(1, X1([Parachain(8)].into())); + let target = Location::new( + 1, + X2([Parachain(8), AccountId32 { network: None, id: [1u8; 32] }].into()), + ); + assert!(::Aliasers::contains(&origin, &target)); + let origin = Location::new(1, X1([Parachain(8)].into())); + let target = + Location::new(1, X3([Parachain(8), PalletInstance(8), GeneralIndex(9)].into())); + assert!(::Aliasers::contains(&origin, &target)); + + // Does not allow if not descendant. + let origin = Location::new(1, X1([PalletInstance(8)].into())); + let target = Location::new(0, X2([PalletInstance(8), GeneralIndex(9)].into())); + assert!(!::Aliasers::contains(&origin, &target)); + let origin = Location::new(1, X1([Parachain(8)].into())); + let target = Location::new( + 0, + X2([Parachain(8), AccountId32 { network: None, id: [1u8; 32] }].into()), + ); + assert!(!::Aliasers::contains(&origin, &target)); + let origin = Location::new(1, X1([Parachain(8)].into())); + let target = Location::new(0, X1([AccountId32 { network: None, id: [1u8; 32] }].into())); + assert!(!::Aliasers::contains(&origin, &target)); + let origin = Location::new(1, X1([AccountId32 { network: None, id: [1u8; 32] }].into())); + let target = Location::new(0, X1([AccountId32 { network: None, id: [1u8; 32] }].into())); + assert!(!::Aliasers::contains(&origin, &target)); + }); } #[test] fn asset_hub_root_aliases_anything() { - // Allows AH root to alias anything. - let origin = Location::new(1, X1([Parachain(1000)].into())); - - let target = Location::new(1, X1([Parachain(2000)].into())); - assert!(::Aliasers::contains(&origin, &target)); - let target = Location::new(1, X1([AccountId32 { network: None, id: [1u8; 32] }].into())); - assert!(::Aliasers::contains(&origin, &target)); - let target = - Location::new(1, X2([Parachain(8), AccountId32 { network: None, id: [1u8; 32] }].into())); - assert!(::Aliasers::contains(&origin, &target)); - let target = Location::new(1, X3([Parachain(42), PalletInstance(8), GeneralIndex(9)].into())); - assert!(::Aliasers::contains(&origin, &target)); - let target = Location::new(2, X1([GlobalConsensus(Ethereum { chain_id: 1 })].into())); - assert!(::Aliasers::contains(&origin, &target)); - let target = Location::new(2, X2([GlobalConsensus(Polkadot), Parachain(1000)].into())); - assert!(::Aliasers::contains(&origin, &target)); - let target = Location::new(0, X2([PalletInstance(8), GeneralIndex(9)].into())); - assert!(::Aliasers::contains(&origin, &target)); - - // Other AH locations cannot alias anything. - let origin = Location::new(1, X2([Parachain(1000), GeneralIndex(9)].into())); - assert!(!::Aliasers::contains(&origin, &target)); - let origin = Location::new(1, X2([Parachain(1000), PalletInstance(9)].into())); - assert!(!::Aliasers::contains(&origin, &target)); - let origin = Location::new( - 1, - X2([Parachain(1000), AccountId32 { network: None, id: [1u8; 32] }].into()), + CoretimeWestend::execute_with(|| { + // Allows AH root to alias anything. + let origin = Location::new(1, X1([Parachain(1000)].into())); + + let target = Location::new(1, X1([Parachain(2000)].into())); + assert!(::Aliasers::contains(&origin, &target)); + let target = Location::new(1, X1([AccountId32 { network: None, id: [1u8; 32] }].into())); + assert!(::Aliasers::contains(&origin, &target)); + let target = Location::new( + 1, + X2([Parachain(8), AccountId32 { network: None, id: [1u8; 32] }].into()), + ); + assert!(::Aliasers::contains(&origin, &target)); + let target = + Location::new(1, X3([Parachain(42), PalletInstance(8), GeneralIndex(9)].into())); + assert!(::Aliasers::contains(&origin, &target)); + let target = Location::new(2, X1([GlobalConsensus(Ethereum { chain_id: 1 })].into())); + assert!(::Aliasers::contains(&origin, &target)); + let target = Location::new(2, X2([GlobalConsensus(Polkadot), Parachain(1000)].into())); + assert!(::Aliasers::contains(&origin, &target)); + let target = Location::new(0, X2([PalletInstance(8), GeneralIndex(9)].into())); + assert!(::Aliasers::contains(&origin, &target)); + + // Other AH locations cannot alias anything. + let origin = Location::new(1, X2([Parachain(1000), GeneralIndex(9)].into())); + assert!(!::Aliasers::contains(&origin, &target)); + let origin = Location::new(1, X2([Parachain(1000), PalletInstance(9)].into())); + assert!(!::Aliasers::contains(&origin, &target)); + let origin = Location::new( + 1, + X2([Parachain(1000), AccountId32 { network: None, id: [1u8; 32] }].into()), + ); + assert!(!::Aliasers::contains(&origin, &target)); + + // Other root locations cannot alias anything. + let origin = Location::new(1, Here); + let target = Location::new(2, X1([GlobalConsensus(Ethereum { chain_id: 1 })].into())); + assert!(!::Aliasers::contains(&origin, &target)); + let target = Location::new(2, X2([GlobalConsensus(Polkadot), Parachain(1000)].into())); + assert!(!::Aliasers::contains(&origin, &target)); + let target = Location::new(0, X2([PalletInstance(8), GeneralIndex(9)].into())); + assert!(!::Aliasers::contains(&origin, &target)); + + let origin = Location::new(0, Here); + let target = Location::new(1, X1([Parachain(2000)].into())); + assert!(!::Aliasers::contains(&origin, &target)); + let origin = Location::new(1, X1([Parachain(1001)].into())); + assert!(!::Aliasers::contains(&origin, &target)); + let origin = Location::new(1, X1([Parachain(1002)].into())); + assert!(!::Aliasers::contains(&origin, &target)); + }); +} + +#[test] +fn authorized_cross_chain_aliases() { + // origin and target are different accounts on different chains + let origin: AccountId = [100; 32].into(); + let bad_origin: AccountId = [150; 32].into(); + let target: AccountId = [200; 32].into(); + let fees = WESTEND_ED * 10; + + let pal_admin = ::RuntimeOrigin::signed(PenpalAssetOwner::get()); + PenpalB::mint_foreign_asset(pal_admin.clone(), Location::parent(), origin.clone(), fees * 10); + PenpalB::mint_foreign_asset(pal_admin, Location::parent(), bad_origin.clone(), fees * 10); + CoretimeWestend::fund_accounts(vec![(target.clone(), fees * 10)]); + + // let's authorize `origin` on Penpal to alias `target` on Coretime + CoretimeWestend::execute_with(|| { + let penpal_origin = Location::new( + 1, + X2([ + Parachain(PenpalB::para_id().into()), + AccountId32 { + network: Some(ByGenesis(WESTEND_GENESIS_HASH)), + id: origin.clone().into(), + }, + ] + .into()), + ); + // `target` adds `penpal_origin` as authorized alias + assert_ok!(::PolkadotXcm::add_authorized_alias( + ::RuntimeOrigin::signed(target.clone()), + Box::new(penpal_origin.into()), + None + )); + }); + // Verify that unauthorized `bad_origin` cannot alias into `target`, from any chain. + test_cross_chain_alias!( + vec![ + // between AH and Coretime: denied + (AssetHubWestend, CoretimeWestend, TELEPORT_FEES, DENIED), + // between BH and Coretime: denied + (BridgeHubWestend, CoretimeWestend, TELEPORT_FEES, DENIED), + // between People and Coretime: denied + (PeopleWestend, CoretimeWestend, TELEPORT_FEES, DENIED), + // between Penpal and Coretime: denied + (PenpalB, CoretimeWestend, RESERVE_TRANSFER_FEES, DENIED) + ], + bad_origin, + target, + fees + ); + // Verify that only authorized `penpal::origin` can alias into `target`, while `origin` on other + // chains cannot. + test_cross_chain_alias!( + vec![ + // between AH and Coretime: denied + (AssetHubWestend, CoretimeWestend, TELEPORT_FEES, DENIED), + // between BH and Coretime: denied + (BridgeHubWestend, CoretimeWestend, TELEPORT_FEES, DENIED), + // between People and Coretime: denied + (PeopleWestend, CoretimeWestend, TELEPORT_FEES, DENIED), + // between Penpal and Coretime: allowed + (PenpalB, CoretimeWestend, RESERVE_TRANSFER_FEES, ALLOWED) + ], + origin, + target, + fees + ); + // remove authorization for `origin` on Penpal to alias `target` on Coretime + CoretimeWestend::execute_with(|| { + // `target` removes all authorized aliases + assert_ok!( + ::PolkadotXcm::remove_all_authorized_aliases( + ::RuntimeOrigin::signed(target.clone()) + ) + ); + }); + // Verify `penpal::origin` can no longer alias into `target` on Coretime. + test_cross_chain_alias!( + vec![(PenpalB, CoretimeWestend, RESERVE_TRANSFER_FEES, DENIED)], + origin, + target, + fees ); - assert!(!::Aliasers::contains(&origin, &target)); - - // Other root locations cannot alias anything. - let origin = Location::new(1, Here); - let target = Location::new(2, X1([GlobalConsensus(Ethereum { chain_id: 1 })].into())); - assert!(!::Aliasers::contains(&origin, &target)); - let target = Location::new(2, X2([GlobalConsensus(Polkadot), Parachain(1000)].into())); - assert!(!::Aliasers::contains(&origin, &target)); - let target = Location::new(0, X2([PalletInstance(8), GeneralIndex(9)].into())); - assert!(!::Aliasers::contains(&origin, &target)); - - let origin = Location::new(0, Here); - let target = Location::new(1, X1([Parachain(2000)].into())); - assert!(!::Aliasers::contains(&origin, &target)); - let origin = Location::new(1, X1([Parachain(1001)].into())); - assert!(!::Aliasers::contains(&origin, &target)); - let origin = Location::new(1, X1([Parachain(1002)].into())); - assert!(!::Aliasers::contains(&origin, &target)); } diff --git a/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/lib.rs index 6223af15b849c..6338f6b0635ce 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/lib.rs @@ -34,7 +34,7 @@ mod imports { bridge_hub_westend_emulated_chain::BridgeHubWestendParaPallet as BridgeHubWestendPallet, collectives_westend_emulated_chain::CollectivesWestendParaPallet as CollectivesWestendPallet, coretime_westend_emulated_chain::CoretimeWestendParaPallet as CoretimeWestendPallet, - penpal_emulated_chain::{PenpalAParaPallet as PenpalAPallet, PenpalAssetOwner}, + penpal_emulated_chain::{PenpalAssetOwner, PenpalBParaPallet as PenpalBPallet}, people_westend_emulated_chain::{ people_westend_runtime::{ self, xcm_config::XcmConfig as PeopleWestendXcmConfig, @@ -48,7 +48,7 @@ mod imports { }, AssetHubWestendPara as AssetHubWestend, BridgeHubWestendPara as BridgeHubWestend, CollectivesWestendPara as CollectivesWestend, CoretimeWestendPara as CoretimeWestend, - PenpalAPara as PenpalA, PeopleWestendPara as PeopleWestend, + PenpalBPara as PenpalB, PeopleWestendPara as PeopleWestend, PeopleWestendParaReceiver as PeopleWestendReceiver, PeopleWestendParaSender as PeopleWestendSender, WestendRelay as Westend, WestendRelayReceiver as WestendReceiver, WestendRelaySender as WestendSender, diff --git a/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/aliases.rs b/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/aliases.rs index 511602ecd9770..6a7da5dd2e3bf 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/aliases.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/aliases.rs @@ -33,8 +33,8 @@ fn account_on_sibling_syschain_aliases_into_same_local_account() { let target = origin.clone(); let fees = WESTEND_ED * 10; - PenpalA::mint_foreign_asset( - ::RuntimeOrigin::signed(PenpalAssetOwner::get()), + PenpalB::mint_foreign_asset( + ::RuntimeOrigin::signed(PenpalAssetOwner::get()), Location::parent(), origin.clone(), fees * 10, @@ -52,7 +52,7 @@ fn account_on_sibling_syschain_aliases_into_same_local_account() { // between Coretime and People: allowed (CoretimeWestend, PeopleWestend, TELEPORT_FEES, ALLOWED), // between Penpal and People: denied - (PenpalA, PeopleWestend, RESERVE_TRANSFER_FEES, DENIED) + (PenpalB, PeopleWestend, RESERVE_TRANSFER_FEES, DENIED) ], origin, target, @@ -67,8 +67,8 @@ fn account_on_sibling_syschain_cannot_alias_into_different_local_account() { let target: AccountId = [2; 32].into(); let fees = WESTEND_ED * 10; - PenpalA::mint_foreign_asset( - ::RuntimeOrigin::signed(PenpalAssetOwner::get()), + PenpalB::mint_foreign_asset( + ::RuntimeOrigin::signed(PenpalAssetOwner::get()), Location::parent(), origin.clone(), fees * 10, @@ -86,7 +86,7 @@ fn account_on_sibling_syschain_cannot_alias_into_different_local_account() { // between Coretime and People: denied (CoretimeWestend, PeopleWestend, TELEPORT_FEES, DENIED), // between Penpal and People: denied - (PenpalA, PeopleWestend, RESERVE_TRANSFER_FEES, DENIED) + (PenpalB, PeopleWestend, RESERVE_TRANSFER_FEES, DENIED) ], origin, target, @@ -97,81 +97,177 @@ fn account_on_sibling_syschain_cannot_alias_into_different_local_account() { #[test] fn aliasing_child_locations() { use PeopleWestendXcmConfig as XcmConfig; - // Allows aliasing descendant of origin. - let origin = Location::new(1, X1([PalletInstance(8)].into())); - let target = Location::new(1, X2([PalletInstance(8), GeneralIndex(9)].into())); - assert!(::Aliasers::contains(&origin, &target)); - let origin = Location::new(1, X1([Parachain(8)].into())); - let target = - Location::new(1, X2([Parachain(8), AccountId32 { network: None, id: [1u8; 32] }].into())); - assert!(::Aliasers::contains(&origin, &target)); - let origin = Location::new(1, X1([Parachain(8)].into())); - let target = Location::new(1, X3([Parachain(8), PalletInstance(8), GeneralIndex(9)].into())); - assert!(::Aliasers::contains(&origin, &target)); - - // Does not allow if not descendant. - let origin = Location::new(1, X1([PalletInstance(8)].into())); - let target = Location::new(0, X2([PalletInstance(8), GeneralIndex(9)].into())); - assert!(!::Aliasers::contains(&origin, &target)); - let origin = Location::new(1, X1([Parachain(8)].into())); - let target = - Location::new(0, X2([Parachain(8), AccountId32 { network: None, id: [1u8; 32] }].into())); - assert!(!::Aliasers::contains(&origin, &target)); - let origin = Location::new(1, X1([Parachain(8)].into())); - let target = Location::new(0, X1([AccountId32 { network: None, id: [1u8; 32] }].into())); - assert!(!::Aliasers::contains(&origin, &target)); - let origin = Location::new(1, X1([AccountId32 { network: None, id: [1u8; 32] }].into())); - let target = Location::new(0, X1([AccountId32 { network: None, id: [1u8; 32] }].into())); - assert!(!::Aliasers::contains(&origin, &target)); + PeopleWestend::execute_with(|| { + // Allows aliasing descendant of origin. + let origin = Location::new(1, X1([PalletInstance(8)].into())); + let target = Location::new(1, X2([PalletInstance(8), GeneralIndex(9)].into())); + assert!(::Aliasers::contains(&origin, &target)); + let origin = Location::new(1, X1([Parachain(8)].into())); + let target = Location::new( + 1, + X2([Parachain(8), AccountId32 { network: None, id: [1u8; 32] }].into()), + ); + assert!(::Aliasers::contains(&origin, &target)); + let origin = Location::new(1, X1([Parachain(8)].into())); + let target = + Location::new(1, X3([Parachain(8), PalletInstance(8), GeneralIndex(9)].into())); + assert!(::Aliasers::contains(&origin, &target)); + + // Does not allow if not descendant. + let origin = Location::new(1, X1([PalletInstance(8)].into())); + let target = Location::new(0, X2([PalletInstance(8), GeneralIndex(9)].into())); + assert!(!::Aliasers::contains(&origin, &target)); + let origin = Location::new(1, X1([Parachain(8)].into())); + let target = Location::new( + 0, + X2([Parachain(8), AccountId32 { network: None, id: [1u8; 32] }].into()), + ); + assert!(!::Aliasers::contains(&origin, &target)); + let origin = Location::new(1, X1([Parachain(8)].into())); + let target = Location::new(0, X1([AccountId32 { network: None, id: [1u8; 32] }].into())); + assert!(!::Aliasers::contains(&origin, &target)); + let origin = Location::new(1, X1([AccountId32 { network: None, id: [1u8; 32] }].into())); + let target = Location::new(0, X1([AccountId32 { network: None, id: [1u8; 32] }].into())); + assert!(!::Aliasers::contains(&origin, &target)); + }); } #[test] fn asset_hub_root_aliases_anything() { use PeopleWestendXcmConfig as XcmConfig; - // Allows AH root to alias anything. - let origin = Location::new(1, X1([Parachain(1000)].into())); - - let target = Location::new(1, X1([Parachain(2000)].into())); - assert!(::Aliasers::contains(&origin, &target)); - let target = Location::new(1, X1([AccountId32 { network: None, id: [1u8; 32] }].into())); - assert!(::Aliasers::contains(&origin, &target)); - let target = - Location::new(1, X2([Parachain(8), AccountId32 { network: None, id: [1u8; 32] }].into())); - assert!(::Aliasers::contains(&origin, &target)); - let target = Location::new(1, X3([Parachain(42), PalletInstance(8), GeneralIndex(9)].into())); - assert!(::Aliasers::contains(&origin, &target)); - let target = Location::new(2, X1([GlobalConsensus(Ethereum { chain_id: 1 })].into())); - assert!(::Aliasers::contains(&origin, &target)); - let target = Location::new(2, X2([GlobalConsensus(Polkadot), Parachain(1000)].into())); - assert!(::Aliasers::contains(&origin, &target)); - let target = Location::new(0, X2([PalletInstance(8), GeneralIndex(9)].into())); - assert!(::Aliasers::contains(&origin, &target)); - - // Other AH locations cannot alias anything. - let origin = Location::new(1, X2([Parachain(1000), GeneralIndex(9)].into())); - assert!(!::Aliasers::contains(&origin, &target)); - let origin = Location::new(1, X2([Parachain(1000), PalletInstance(9)].into())); - assert!(!::Aliasers::contains(&origin, &target)); - let origin = Location::new( - 1, - X2([Parachain(1000), AccountId32 { network: None, id: [1u8; 32] }].into()), + PeopleWestend::execute_with(|| { + // Allows AH root to alias anything. + let origin = Location::new(1, X1([Parachain(1000)].into())); + + let target = Location::new(1, X1([Parachain(2000)].into())); + assert!(::Aliasers::contains(&origin, &target)); + let target = Location::new(1, X1([AccountId32 { network: None, id: [1u8; 32] }].into())); + assert!(::Aliasers::contains(&origin, &target)); + let target = Location::new( + 1, + X2([Parachain(8), AccountId32 { network: None, id: [1u8; 32] }].into()), + ); + assert!(::Aliasers::contains(&origin, &target)); + let target = + Location::new(1, X3([Parachain(42), PalletInstance(8), GeneralIndex(9)].into())); + assert!(::Aliasers::contains(&origin, &target)); + let target = Location::new(2, X1([GlobalConsensus(Ethereum { chain_id: 1 })].into())); + assert!(::Aliasers::contains(&origin, &target)); + let target = Location::new(2, X2([GlobalConsensus(Polkadot), Parachain(1000)].into())); + assert!(::Aliasers::contains(&origin, &target)); + let target = Location::new(0, X2([PalletInstance(8), GeneralIndex(9)].into())); + assert!(::Aliasers::contains(&origin, &target)); + + // Other AH locations cannot alias anything. + let origin = Location::new(1, X2([Parachain(1000), GeneralIndex(9)].into())); + assert!(!::Aliasers::contains(&origin, &target)); + let origin = Location::new(1, X2([Parachain(1000), PalletInstance(9)].into())); + assert!(!::Aliasers::contains(&origin, &target)); + let origin = Location::new( + 1, + X2([Parachain(1000), AccountId32 { network: None, id: [1u8; 32] }].into()), + ); + assert!(!::Aliasers::contains(&origin, &target)); + + // Other root locations cannot alias anything. + let origin = Location::new(1, Here); + let target = Location::new(2, X1([GlobalConsensus(Ethereum { chain_id: 1 })].into())); + assert!(!::Aliasers::contains(&origin, &target)); + let target = Location::new(2, X2([GlobalConsensus(Polkadot), Parachain(1000)].into())); + assert!(!::Aliasers::contains(&origin, &target)); + let target = Location::new(0, X2([PalletInstance(8), GeneralIndex(9)].into())); + assert!(!::Aliasers::contains(&origin, &target)); + + let origin = Location::new(0, Here); + let target = Location::new(1, X1([Parachain(2000)].into())); + assert!(!::Aliasers::contains(&origin, &target)); + let origin = Location::new(1, X1([Parachain(1001)].into())); + assert!(!::Aliasers::contains(&origin, &target)); + let origin = Location::new(1, X1([Parachain(1002)].into())); + assert!(!::Aliasers::contains(&origin, &target)); + }); +} + +#[test] +fn authorized_cross_chain_aliases() { + // origin and target are different accounts on different chains + let origin: AccountId = [100; 32].into(); + let bad_origin: AccountId = [150; 32].into(); + let target: AccountId = [200; 32].into(); + let fees = WESTEND_ED * 10; + + let pal_admin = ::RuntimeOrigin::signed(PenpalAssetOwner::get()); + PenpalB::mint_foreign_asset(pal_admin.clone(), Location::parent(), origin.clone(), fees * 10); + PenpalB::mint_foreign_asset(pal_admin, Location::parent(), bad_origin.clone(), fees * 10); + PeopleWestend::fund_accounts(vec![(target.clone(), fees * 10)]); + + // let's authorize `origin` on Penpal to alias `target` on People + PeopleWestend::execute_with(|| { + let penpal_origin = Location::new( + 1, + X2([ + Parachain(PenpalB::para_id().into()), + AccountId32 { + network: Some(ByGenesis(WESTEND_GENESIS_HASH)), + id: origin.clone().into(), + }, + ] + .into()), + ); + // `target` adds `penpal_origin` as authorized alias + assert_ok!(::PolkadotXcm::add_authorized_alias( + ::RuntimeOrigin::signed(target.clone()), + Box::new(penpal_origin.into()), + None + )); + }); + // Verify that unauthorized `bad_origin` cannot alias into `target`, from any chain. + test_cross_chain_alias!( + vec![ + // between AH and People: denied + (AssetHubWestend, PeopleWestend, TELEPORT_FEES, DENIED), + // between BH and People: denied + (BridgeHubWestend, PeopleWestend, TELEPORT_FEES, DENIED), + // between Collectives and People: denied + (CollectivesWestend, PeopleWestend, TELEPORT_FEES, DENIED), + // between Penpal and People: denied + (PenpalB, PeopleWestend, RESERVE_TRANSFER_FEES, DENIED) + ], + bad_origin, + target, + fees + ); + // Verify that only authorized `penpal::origin` can alias into `target`, while `origin` on other + // chains cannot. + test_cross_chain_alias!( + vec![ + // between AH and People: denied + (AssetHubWestend, PeopleWestend, TELEPORT_FEES, DENIED), + // between BH and People: denied + (BridgeHubWestend, PeopleWestend, TELEPORT_FEES, DENIED), + // between Collectives and People: denied + (CollectivesWestend, PeopleWestend, TELEPORT_FEES, DENIED), + // between Penpal and People: allowed + (PenpalB, PeopleWestend, RESERVE_TRANSFER_FEES, ALLOWED) + ], + origin, + target, + fees + ); + // remove authorization for `origin` on Penpal to alias `target` on People + PeopleWestend::execute_with(|| { + // `target` removes all authorized aliases + assert_ok!( + ::PolkadotXcm::remove_all_authorized_aliases( + ::RuntimeOrigin::signed(target.clone()) + ) + ); + }); + // Verify `penpal::origin` can no longer alias into `target` on People. + test_cross_chain_alias!( + vec![(PenpalB, PeopleWestend, RESERVE_TRANSFER_FEES, DENIED)], + origin, + target, + fees ); - assert!(!::Aliasers::contains(&origin, &target)); - - // Other root locations cannot alias anything. - let origin = Location::new(1, Here); - let target = Location::new(2, X1([GlobalConsensus(Ethereum { chain_id: 1 })].into())); - assert!(!::Aliasers::contains(&origin, &target)); - let target = Location::new(2, X2([GlobalConsensus(Polkadot), Parachain(1000)].into())); - assert!(!::Aliasers::contains(&origin, &target)); - let target = Location::new(0, X2([PalletInstance(8), GeneralIndex(9)].into())); - assert!(!::Aliasers::contains(&origin, &target)); - - let origin = Location::new(0, Here); - let target = Location::new(1, X1([Parachain(2000)].into())); - assert!(!::Aliasers::contains(&origin, &target)); - let origin = Location::new(1, X1([Parachain(1001)].into())); - assert!(!::Aliasers::contains(&origin, &target)); - let origin = Location::new(1, X1([Parachain(1002)].into())); - assert!(!::Aliasers::contains(&origin, &target)); } 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 caf269f7984cc..f8237f18fd50a 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs @@ -2057,6 +2057,21 @@ impl_runtime_apis! { PolkadotXcm::is_trusted_teleporter(asset, location) } } + + impl xcm_runtime_apis::authorized_aliases::AuthorizedAliasersApi for Runtime { + fn authorized_aliasers(target: VersionedLocation) -> Result< + Vec, + xcm_runtime_apis::authorized_aliases::Error + > { + PolkadotXcm::authorized_aliasers(target) + } + fn is_authorized_alias(origin: VersionedLocation, target: VersionedLocation) -> Result< + bool, + xcm_runtime_apis::authorized_aliases::Error + > { + PolkadotXcm::is_authorized_alias(origin, target) + } + } } cumulus_pallet_parachain_system::register_validate_block! { diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm.rs index 210337e4b5623..0ec2e938b6adc 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm.rs @@ -50,6 +50,28 @@ use core::marker::PhantomData; /// Weight functions for `pallet_xcm`. pub struct WeightInfo(PhantomData); impl pallet_xcm::WeightInfo for WeightInfo { + /// Storage: `PolkadotXcm::AuthorizedAliases` (r:1 w:1) + /// Proof: `PolkadotXcm::AuthorizedAliases` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn add_authorized_alias() -> Weight { + // Proof Size summary in bytes: + // Measured: `498` + // Estimated: `3963` + // Minimum execution time: 19_789_000 picoseconds. + Weight::from_parts(20_317_000, 3963) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `PolkadotXcm::AuthorizedAliases` (r:1 w:1) + /// Proof: `PolkadotXcm::AuthorizedAliases` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn remove_authorized_alias() -> Weight { + // Proof Size summary in bytes: + // Measured: `537` + // Estimated: `4002` + // Minimum execution time: 20_805_000 picoseconds. + Weight::from_parts(21_481_000, 4002) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs index 1a7ca90b05998..9d2444f76df58 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs @@ -16,9 +16,9 @@ use super::{ AccountId, AllPalletsWithSystem, Assets, Authorship, Balance, Balances, BaseDeliveryFee, CollatorSelection, FeeAssetId, ForeignAssets, ForeignAssetsInstance, ParachainInfo, - ParachainSystem, PolkadotXcm, PoolAssets, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, - ToWestendXcmRouter, TransactionByteFee, TrustBackedAssetsInstance, Uniques, WeightToFee, - XcmpQueue, + ParachainSystem, PolkadotXcm, PoolAssets, Runtime, RuntimeCall, RuntimeEvent, + RuntimeHoldReason, RuntimeOrigin, ToWestendXcmRouter, TransactionByteFee, + TrustBackedAssetsInstance, Uniques, WeightToFee, XcmpQueue, }; use assets_common::{ matching::{FromNetwork, FromSiblingParachain, IsForeignConcreteAsset, ParentLocation}, @@ -27,12 +27,13 @@ use assets_common::{ use frame_support::{ parameter_types, traits::{ + fungible::HoldConsideration, tokens::imbalance::{ResolveAssetTo, ResolveTo}, - ConstU32, Contains, Equals, Everything, PalletInfoAccess, + ConstU32, Contains, Equals, Everything, LinearStoragePrice, PalletInfoAccess, }, }; use frame_system::EnsureRoot; -use pallet_xcm::XcmPassthrough; +use pallet_xcm::{AuthorizedAliasers, XcmPassthrough}; use parachains_common::{ xcm_config::{ AllSiblingSystemParachains, AssetFeeAsExistentialDepositMultiplier, @@ -328,6 +329,12 @@ pub type TrustedTeleporters = ( IsForeignConcreteAsset>>, ); +/// Defines origin aliasing rules for this chain. +/// +/// - Allow any origin to alias into a child sub-location (equivalent to DescendOrigin), +/// - Allow origins explicitly authorized by the alias target location. +pub type TrustedAliasers = (AliasChildLocation, AuthorizedAliasers); + /// Asset converter for pool assets. /// Used to convert one asset to another, when there is a pool available between the two. /// This type thus allows paying fees with any asset as long as there is a pool between said @@ -443,7 +450,7 @@ impl xcm_executor::Config for XcmConfig { type CallDispatcher = RuntimeCall; type SafeCallFilter = Everything; // We allow any origin to alias into a child sub-location (equivalent to DescendOrigin). - type Aliasers = AliasChildLocation; + type Aliasers = TrustedAliasers; type TransactionalProcessor = FrameTransactionalProcessor; type HrmpNewChannelOpenRequestHandler = (); type HrmpChannelAcceptedHandler = (); @@ -451,8 +458,8 @@ impl xcm_executor::Config for XcmConfig { type XcmRecorder = PolkadotXcm; } -/// Converts a local signed origin into an XCM location. -/// Forms the basis for local origins sending/executing XCMs. +/// Converts a local signed origin into an XCM location. Forms the basis for local origins +/// sending/executing XCMs. pub type LocalOriginToLocation = SignedToAccountId32; pub type PriceForParentDelivery = @@ -478,6 +485,12 @@ pub type XcmRouter = WithUniqueTopic<( SovereignPaidRemoteExporter, )>; +parameter_types! { + pub const DepositPerItem: Balance = crate::deposit(1, 0); + pub const DepositPerByte: Balance = crate::deposit(0, 1); + pub const AuthorizeAliasHoldReason: RuntimeHoldReason = RuntimeHoldReason::PolkadotXcm(pallet_xcm::HoldReason::AuthorizeAlias); +} + impl pallet_xcm::Config for Runtime { type RuntimeEvent = RuntimeEvent; // We want to disallow users sending (arbitrary) XCMs from this chain. @@ -508,6 +521,13 @@ impl pallet_xcm::Config for Runtime { type AdminOrigin = EnsureRoot; type MaxRemoteLockConsumers = ConstU32<0>; type RemoteLockConsumerIdentifier = (); + // xcm_executor::Config::Aliasers also uses pallet_xcm::AuthorizedAliasers. + type AuthorizedAliasConsideration = HoldConsideration< + AccountId, + Balances, + AuthorizeAliasHoldReason, + LinearStoragePrice, + >; } impl cumulus_pallet_xcm::Config for Runtime { 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 6d1beced292d2..e1a9b7faf67a0 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs @@ -1752,6 +1752,30 @@ impl_runtime_apis! { } } + impl xcm_runtime_apis::trusted_query::TrustedQueryApi for Runtime { + fn is_trusted_reserve(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { + PolkadotXcm::is_trusted_reserve(asset, location) + } + fn is_trusted_teleporter(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { + PolkadotXcm::is_trusted_teleporter(asset, location) + } + } + + impl xcm_runtime_apis::authorized_aliases::AuthorizedAliasersApi for Runtime { + fn authorized_aliasers(target: VersionedLocation) -> Result< + Vec, + xcm_runtime_apis::authorized_aliases::Error + > { + PolkadotXcm::authorized_aliasers(target) + } + fn is_authorized_alias(origin: VersionedLocation, target: VersionedLocation) -> Result< + bool, + xcm_runtime_apis::authorized_aliases::Error + > { + PolkadotXcm::is_authorized_alias(origin, target) + } + } + impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentCallApi for Runtime { @@ -2296,15 +2320,6 @@ impl_runtime_apis! { } } - impl xcm_runtime_apis::trusted_query::TrustedQueryApi for Runtime { - fn is_trusted_reserve(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { - PolkadotXcm::is_trusted_reserve(asset, location) - } - fn is_trusted_teleporter(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { - PolkadotXcm::is_trusted_teleporter(asset, location) - } - } - impl pallet_revive::ReviveApi for Runtime { fn balance(address: H160) -> U256 { diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm.rs index 38c6cd18c57ee..4670eac3331d4 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm.rs @@ -50,6 +50,28 @@ use core::marker::PhantomData; /// Weight functions for `pallet_xcm`. pub struct WeightInfo(PhantomData); impl pallet_xcm::WeightInfo for WeightInfo { + /// Storage: `PolkadotXcm::AuthorizedAliases` (r:1 w:1) + /// Proof: `PolkadotXcm::AuthorizedAliases` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn add_authorized_alias() -> Weight { + // Proof Size summary in bytes: + // Measured: `498` + // Estimated: `3963` + // Minimum execution time: 19_789_000 picoseconds. + Weight::from_parts(20_317_000, 3963) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `PolkadotXcm::AuthorizedAliases` (r:1 w:1) + /// Proof: `PolkadotXcm::AuthorizedAliases` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn remove_authorized_alias() -> Weight { + // Proof Size summary in bytes: + // Measured: `537` + // Estimated: `4002` + // Minimum execution time: 20_805_000 picoseconds. + Weight::from_parts(21_481_000, 4002) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs index a29c94ff06f1c..388fecde57d1b 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs @@ -15,10 +15,10 @@ use super::{ AccountId, AllPalletsWithSystem, Assets, Authorship, Balance, Balances, BaseDeliveryFee, - CollatorSelection, FeeAssetId, ForeignAssets, ForeignAssetsInstance, ParachainInfo, - ParachainSystem, PolkadotXcm, PoolAssets, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, - ToRococoXcmRouter, TransactionByteFee, TrustBackedAssetsInstance, Uniques, WeightToFee, - XcmpQueue, + CollatorSelection, DepositPerByte, DepositPerItem, FeeAssetId, ForeignAssets, + ForeignAssetsInstance, ParachainInfo, ParachainSystem, PolkadotXcm, PoolAssets, Runtime, + RuntimeCall, RuntimeEvent, RuntimeHoldReason, RuntimeOrigin, ToRococoXcmRouter, + TransactionByteFee, TrustBackedAssetsInstance, Uniques, WeightToFee, XcmpQueue, }; use assets_common::{ matching::{FromSiblingParachain, IsForeignConcreteAsset, ParentLocation}, @@ -27,12 +27,13 @@ use assets_common::{ use frame_support::{ parameter_types, traits::{ + fungible::HoldConsideration, tokens::imbalance::{ResolveAssetTo, ResolveTo}, - ConstU32, Contains, Equals, Everything, PalletInfoAccess, + ConstU32, Contains, Equals, Everything, LinearStoragePrice, PalletInfoAccess, }, }; use frame_system::EnsureRoot; -use pallet_xcm::XcmPassthrough; +use pallet_xcm::{AuthorizedAliasers, XcmPassthrough}; use parachains_common::{ xcm_config::{ AllSiblingSystemParachains, AssetFeeAsExistentialDepositMultiplier, @@ -350,6 +351,12 @@ pub type TrustedTeleporters = ( IsForeignConcreteAsset>>, ); +/// Defines origin aliasing rules for this chain. +/// +/// - Allow any origin to alias into a child sub-location (equivalent to DescendOrigin), +/// - Allow origins explicitly authorized by the alias target location. +pub type TrustedAliasers = (AliasChildLocation, AuthorizedAliasers); + /// Asset converter for pool assets. /// Used to convert one asset to another, when there is a pool available between the two. /// This type thus allows paying fees with any asset as long as there is a pool between said @@ -463,8 +470,7 @@ impl xcm_executor::Config for XcmConfig { (bridging::to_rococo::UniversalAliases, bridging::to_ethereum::UniversalAliases); type CallDispatcher = RuntimeCall; type SafeCallFilter = Everything; - // We allow any origin to alias into a child sub-location (equivalent to DescendOrigin). - type Aliasers = AliasChildLocation; + type Aliasers = TrustedAliasers; type TransactionalProcessor = FrameTransactionalProcessor; type HrmpNewChannelOpenRequestHandler = (); type HrmpChannelAcceptedHandler = (); @@ -472,7 +478,8 @@ impl xcm_executor::Config for XcmConfig { type XcmRecorder = PolkadotXcm; } -/// Local origins on this chain are allowed to dispatch XCM sends/executions. +/// Converts a local signed origin into an XCM location. Forms the basis for local origins +/// sending/executing XCMs. pub type LocalOriginToLocation = SignedToAccountId32; pub type PriceForParentDelivery = @@ -508,6 +515,10 @@ pub type XcmRouter = WithUniqueTopic<( >, )>; +parameter_types! { + pub const AuthorizeAliasHoldReason: RuntimeHoldReason = RuntimeHoldReason::PolkadotXcm(pallet_xcm::HoldReason::AuthorizeAlias); +} + impl pallet_xcm::Config for Runtime { type RuntimeEvent = RuntimeEvent; type SendXcmOrigin = EnsureXcmOrigin; @@ -536,6 +547,13 @@ impl pallet_xcm::Config for Runtime { type AdminOrigin = EnsureRoot; type MaxRemoteLockConsumers = ConstU32<0>; type RemoteLockConsumerIdentifier = (); + // xcm_executor::Config::Aliasers also uses pallet_xcm::AuthorizedAliasers. + type AuthorizedAliasConsideration = HoldConsideration< + AccountId, + Balances, + AuthorizeAliasHoldReason, + LinearStoragePrice, + >; } impl cumulus_pallet_xcm::Config for Runtime { diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs index 58d4fe9b14023..564228d307476 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs @@ -44,6 +44,7 @@ use frame_support::{ fungibles::{ Create, Inspect as FungiblesInspect, InspectEnumerable, Mutate as FungiblesMutate, }, + ContainsPair, }, weights::{Weight, WeightToFee as WeightToFeeT}, }; @@ -142,6 +143,7 @@ fn setup_pool_for_paying_fees_with_foreign_assets( #[test] fn test_buy_and_refund_weight_in_native() { ExtBuilder::::default() + .with_tracing() .with_collators(vec![AccountId::from(ALICE)]) .with_session_keys(vec![( AccountId::from(ALICE), @@ -200,6 +202,7 @@ fn test_buy_and_refund_weight_in_native() { #[test] fn test_buy_and_refund_weight_with_swap_local_asset_xcm_trader() { ExtBuilder::::default() + .with_tracing() .with_collators(vec![AccountId::from(ALICE)]) .with_session_keys(vec![( AccountId::from(ALICE), @@ -309,6 +312,7 @@ fn test_buy_and_refund_weight_with_swap_local_asset_xcm_trader() { #[test] fn test_buy_and_refund_weight_with_swap_foreign_asset_xcm_trader() { ExtBuilder::::default() + .with_tracing() .with_collators(vec![AccountId::from(ALICE)]) .with_session_keys(vec![( AccountId::from(ALICE), @@ -419,6 +423,7 @@ fn test_buy_and_refund_weight_with_swap_foreign_asset_xcm_trader() { #[test] fn test_asset_xcm_take_first_trader() { ExtBuilder::::default() + .with_tracing() .with_collators(vec![AccountId::from(ALICE)]) .with_session_keys(vec![( AccountId::from(ALICE), @@ -497,6 +502,7 @@ fn test_asset_xcm_take_first_trader() { #[test] fn test_foreign_asset_xcm_take_first_trader() { ExtBuilder::::default() + .with_tracing() .with_collators(vec![AccountId::from(ALICE)]) .with_session_keys(vec![( AccountId::from(ALICE), @@ -578,6 +584,7 @@ fn test_foreign_asset_xcm_take_first_trader() { #[test] fn test_asset_xcm_take_first_trader_with_refund() { ExtBuilder::::default() + .with_tracing() .with_collators(vec![AccountId::from(ALICE)]) .with_session_keys(vec![( AccountId::from(ALICE), @@ -657,6 +664,7 @@ fn test_asset_xcm_take_first_trader_with_refund() { #[test] fn test_asset_xcm_take_first_trader_refund_not_possible_since_amount_less_than_ed() { ExtBuilder::::default() + .with_tracing() .with_collators(vec![AccountId::from(ALICE)]) .with_session_keys(vec![( AccountId::from(ALICE), @@ -709,6 +717,7 @@ fn test_asset_xcm_take_first_trader_refund_not_possible_since_amount_less_than_e #[test] fn test_that_buying_ed_refund_does_not_refund_for_take_first_trader() { ExtBuilder::::default() + .with_tracing() .with_collators(vec![AccountId::from(ALICE)]) .with_session_keys(vec![( AccountId::from(ALICE), @@ -773,6 +782,7 @@ fn test_that_buying_ed_refund_does_not_refund_for_take_first_trader() { #[test] fn test_asset_xcm_take_first_trader_not_possible_for_non_sufficient_assets() { ExtBuilder::::default() + .with_tracing() .with_collators(vec![AccountId::from(ALICE)]) .with_session_keys(vec![( AccountId::from(ALICE), @@ -834,6 +844,7 @@ fn test_assets_balances_api_works() { use assets_common::runtime_api::runtime_decl_for_fungibles_api::FungiblesApi; ExtBuilder::::default() + .with_tracing() .with_collators(vec![AccountId::from(ALICE)]) .with_session_keys(vec![( AccountId::from(ALICE), @@ -948,6 +959,91 @@ fn test_assets_balances_api_works() { }); } +#[test] +fn authorized_aliases_work() { + ExtBuilder::::default() + .with_tracing() + .with_collators(vec![AccountId::from(ALICE)]) + .with_session_keys(vec![( + AccountId::from(ALICE), + AccountId::from(ALICE), + SessionKeys { aura: AuraId::from(sp_core::sr25519::Public::from_raw(ALICE)) }, + )]) + .build() + .execute_with(|| { + let alice: AccountId = ALICE.into(); + let local_alice = Location::new(0, AccountId32 { network: None, id: ALICE }); + let alice_on_sibling_para = + Location::new(1, [Parachain(42), AccountId32 { network: None, id: ALICE }]); + let alice_on_relay = Location::new(1, AccountId32 { network: None, id: ALICE }); + let bob_on_relay = Location::new(1, AccountId32 { network: None, id: [42_u8; 32] }); + + assert_ok!(Balances::mint_into(&alice, 2 * UNITS)); + + // neither `alice_on_sibling_para`, `alice_on_relay`, `bob_on_relay` are allowed to + // alias into `local_alice` + for aliaser in [&alice_on_sibling_para, &alice_on_relay, &bob_on_relay] { + assert!(!::Aliasers::contains( + aliaser, + &local_alice + )); + } + + // Alice explicitly authorizes `alice_on_sibling_para` to alias her local account + assert_ok!(PolkadotXcm::add_authorized_alias( + RuntimeHelper::origin_of(alice.clone()), + Box::new(alice_on_sibling_para.clone().into()), + None + )); + + // `alice_on_sibling_para` now explicitly allowed to alias into `local_alice` + assert!(::Aliasers::contains( + &alice_on_sibling_para, + &local_alice + )); + // as expected, `alice_on_relay` and `bob_on_relay` still can't alias into `local_alice` + for aliaser in [&alice_on_relay, &bob_on_relay] { + assert!(!::Aliasers::contains( + aliaser, + &local_alice + )); + } + + // Alice explicitly authorizes `alice_on_relay` to alias her local account + assert_ok!(PolkadotXcm::add_authorized_alias( + RuntimeHelper::origin_of(alice.clone()), + Box::new(alice_on_relay.clone().into()), + None + )); + // Now both `alice_on_relay` and `alice_on_sibling_para` can alias into her local + // account + for aliaser in [&alice_on_relay, &alice_on_sibling_para] { + assert!(::Aliasers::contains( + aliaser, + &local_alice + )); + } + + // Alice removes authorization for `alice_on_relay` to alias her local account + assert_ok!(PolkadotXcm::remove_authorized_alias( + RuntimeHelper::origin_of(alice.clone()), + Box::new(alice_on_relay.clone().into()) + )); + + // `alice_on_relay` no longer allowed to alias into `local_alice` + assert!(!::Aliasers::contains( + &alice_on_relay, + &local_alice + )); + + // `alice_on_sibling_para` still allowed to alias into `local_alice` + assert!(::Aliasers::contains( + &alice_on_sibling_para, + &local_alice + )); + }) +} + asset_test_utils::include_teleports_for_native_asset_works!( Runtime, AllPalletsWithoutSystem, diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_xcm.rs index 3cebe053b9663..872cd1ad31d6f 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_xcm.rs @@ -50,6 +50,28 @@ use core::marker::PhantomData; /// Weight functions for `pallet_xcm`. pub struct WeightInfo(PhantomData); impl pallet_xcm::WeightInfo for WeightInfo { + /// Storage: `PolkadotXcm::AuthorizedAliases` (r:1 w:1) + /// Proof: `PolkadotXcm::AuthorizedAliases` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn add_authorized_alias() -> Weight { + // Proof Size summary in bytes: + // Measured: `498` + // Estimated: `3963` + // Minimum execution time: 19_789_000 picoseconds. + Weight::from_parts(20_317_000, 3963) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `PolkadotXcm::AuthorizedAliases` (r:1 w:1) + /// Proof: `PolkadotXcm::AuthorizedAliases` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn remove_authorized_alias() -> Weight { + // Proof Size summary in bytes: + // Measured: `537` + // Estimated: `4002` + // Minimum execution time: 20_805_000 picoseconds. + Weight::from_parts(21_481_000, 4002) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs index 376e751299c50..dab4ff8b7779c 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs @@ -15,19 +15,23 @@ // limitations under the License. use super::{ - AccountId, AllPalletsWithSystem, Balances, BaseDeliveryFee, FeeAssetId, ParachainInfo, - ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, - TransactionByteFee, WeightToFee, XcmOverBridgeHubWestend, XcmOverRococoBulletin, XcmpQueue, + AccountId, AllPalletsWithSystem, Balance, Balances, BaseDeliveryFee, FeeAssetId, ParachainInfo, + ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeHoldReason, + RuntimeOrigin, TransactionByteFee, WeightToFee, XcmOverBridgeHubWestend, XcmOverRococoBulletin, + XcmpQueue, }; use core::marker::PhantomData; use frame_support::{ parameter_types, - traits::{tokens::imbalance::ResolveTo, ConstU32, Contains, Equals, Everything, Nothing}, + traits::{ + fungible::HoldConsideration, tokens::imbalance::ResolveTo, ConstU32, Contains, Equals, + Everything, LinearStoragePrice, Nothing, + }, }; use frame_system::EnsureRoot; use pallet_collator_selection::StakingPotAccountId; -use pallet_xcm::XcmPassthrough; +use pallet_xcm::{AuthorizedAliasers, XcmPassthrough}; use parachains_common::{ xcm_config::{ AllSiblingSystemParachains, ConcreteAssetFromSystem, ParentRelayOrSiblingParachains, @@ -42,10 +46,10 @@ use sp_runtime::traits::AccountIdConversion; use testnet_parachains_constants::rococo::snowbridge::EthereumNetwork; use xcm::latest::{prelude::*, ROCOCO_GENESIS_HASH}; use xcm_builder::{ - AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowHrmpNotificationsFromRelayChain, - AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, - DenyRecursively, DenyReserveTransferToRelayChain, DenyThenTry, DescribeAllTerminal, - DescribeFamily, EnsureXcmOrigin, ExternalConsensusLocationsConverterFor, + AccountId32Aliases, AliasChildLocation, AllowExplicitUnpaidExecutionFrom, + AllowHrmpNotificationsFromRelayChain, AllowKnownQueryResponses, AllowSubscriptionsFrom, + AllowTopLevelPaidExecutionFrom, DenyRecursively, DenyReserveTransferToRelayChain, DenyThenTry, + DescribeAllTerminal, DescribeFamily, EnsureXcmOrigin, ExternalConsensusLocationsConverterFor, FrameTransactionalProcessor, FungibleAdapter, HandleFee, HashedDescription, IsConcrete, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SendXcmFeeToAccount, SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, @@ -177,6 +181,12 @@ pub type WaivedLocations = ( /// - NativeToken with the parent Relay Chain and sibling parachains. pub type TrustedTeleporters = ConcreteAssetFromSystem; +/// Defines origin aliasing rules for this chain. +/// +/// - Allow any origin to alias into a child sub-location (equivalent to DescendOrigin), +/// - Allow origins explicitly authorized by the alias target location. +pub type TrustedAliasers = (AliasChildLocation, AuthorizedAliasers); + pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; @@ -232,7 +242,7 @@ impl xcm_executor::Config for XcmConfig { type UniversalAliases = Nothing; type CallDispatcher = RuntimeCall; type SafeCallFilter = Everything; - type Aliasers = Nothing; + type Aliasers = TrustedAliasers; type TransactionalProcessor = FrameTransactionalProcessor; type HrmpNewChannelOpenRequestHandler = (); type HrmpChannelAcceptedHandler = (); @@ -243,8 +253,8 @@ impl xcm_executor::Config for XcmConfig { pub type PriceForParentDelivery = ExponentialPrice; -/// Converts a local signed origin into an XCM location. -/// Forms the basis for local origins sending/executing XCMs. +/// Converts a local signed origin into an XCM location. Forms the basis for local origins +/// sending/executing XCMs. pub type LocalOriginToLocation = SignedToAccountId32; /// The means for routing XCM messages which are not for local execution into the right message @@ -256,6 +266,12 @@ pub type XcmRouter = WithUniqueTopic<( XcmpQueue, )>; +parameter_types! { + pub const DepositPerItem: Balance = crate::deposit(1, 0); + pub const DepositPerByte: Balance = crate::deposit(0, 1); + pub const AuthorizeAliasHoldReason: RuntimeHoldReason = RuntimeHoldReason::PolkadotXcm(pallet_xcm::HoldReason::AuthorizeAlias); +} + impl pallet_xcm::Config for Runtime { type RuntimeEvent = RuntimeEvent; type XcmRouter = XcmRouter; @@ -286,6 +302,13 @@ impl pallet_xcm::Config for Runtime { type AdminOrigin = EnsureRoot; type MaxRemoteLockConsumers = ConstU32<0>; type RemoteLockConsumerIdentifier = (); + // xcm_executor::Config::Aliasers also uses pallet_xcm::AuthorizedAliasers. + type AuthorizedAliasConsideration = HoldConsideration< + AccountId, + Balances, + AuthorizeAliasHoldReason, + LinearStoragePrice, + >; } impl cumulus_pallet_xcm::Config for Runtime { 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 699e403e179d9..b7ce33c794268 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 @@ -861,6 +861,30 @@ impl_runtime_apis! { } } + impl xcm_runtime_apis::trusted_query::TrustedQueryApi for Runtime { + fn is_trusted_reserve(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { + PolkadotXcm::is_trusted_reserve(asset, location) + } + fn is_trusted_teleporter(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { + PolkadotXcm::is_trusted_teleporter(asset, location) + } + } + + impl xcm_runtime_apis::authorized_aliases::AuthorizedAliasersApi for Runtime { + fn authorized_aliasers(target: VersionedLocation) -> Result< + Vec, + xcm_runtime_apis::authorized_aliases::Error + > { + PolkadotXcm::authorized_aliasers(target) + } + fn is_authorized_alias(origin: VersionedLocation, target: VersionedLocation) -> Result< + bool, + xcm_runtime_apis::authorized_aliases::Error + > { + PolkadotXcm::is_authorized_alias(origin, target) + } + } + impl cumulus_primitives_core::CollectCollationInfo for Runtime { fn collect_collation_info(header: &::Header) -> cumulus_primitives_core::CollationInfo { ParachainSystem::collect_collation_info(header) @@ -1406,15 +1430,6 @@ impl_runtime_apis! { genesis_config_presets::preset_names() } } - - impl xcm_runtime_apis::trusted_query::TrustedQueryApi for Runtime { - fn is_trusted_reserve(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { - PolkadotXcm::is_trusted_reserve(asset, location) - } - fn is_trusted_teleporter(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { - PolkadotXcm::is_trusted_teleporter(asset, location) - } - } } cumulus_pallet_parachain_system::register_validate_block! { diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_xcm.rs index 4223d8fba64bf..61c552ee3e142 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_xcm.rs @@ -50,6 +50,28 @@ use core::marker::PhantomData; /// Weight functions for `pallet_xcm`. pub struct WeightInfo(PhantomData); impl pallet_xcm::WeightInfo for WeightInfo { + /// Storage: `PolkadotXcm::AuthorizedAliases` (r:1 w:1) + /// Proof: `PolkadotXcm::AuthorizedAliases` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn add_authorized_alias() -> Weight { + // Proof Size summary in bytes: + // Measured: `498` + // Estimated: `3963` + // Minimum execution time: 19_789_000 picoseconds. + Weight::from_parts(20_317_000, 3963) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `PolkadotXcm::AuthorizedAliases` (r:1 w:1) + /// Proof: `PolkadotXcm::AuthorizedAliases` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn remove_authorized_alias() -> Weight { + // Proof Size summary in bytes: + // Measured: `537` + // Estimated: `4002` + // Minimum execution time: 20_805_000 picoseconds. + Weight::from_parts(21_481_000, 4002) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs index 97816a7f60a90..5a00ae852886b 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs @@ -15,22 +15,22 @@ // limitations under the License. use super::{ - AccountId, AllPalletsWithSystem, Balances, BaseDeliveryFee, FeeAssetId, ParachainInfo, - ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, - TransactionByteFee, WeightToFee, XcmOverBridgeHubRococo, XcmpQueue, + AccountId, AllPalletsWithSystem, Balance, Balances, BaseDeliveryFee, FeeAssetId, ParachainInfo, + ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeHoldReason, + RuntimeOrigin, TransactionByteFee, WeightToFee, XcmOverBridgeHubRococo, XcmpQueue, }; use crate::bridge_to_ethereum_config::{AssetHubLocation, SnowbridgeFrontendLocation}; use bridge_hub_common::DenyExportMessageFrom; use frame_support::{ parameter_types, traits::{ - tokens::imbalance::ResolveTo, ConstU32, Contains, Equals, Everything, EverythingBut, - Nothing, + fungible::HoldConsideration, tokens::imbalance::ResolveTo, ConstU32, Contains, Equals, + Everything, EverythingBut, LinearStoragePrice, Nothing, }, }; use frame_system::EnsureRoot; use pallet_collator_selection::StakingPotAccountId; -use pallet_xcm::XcmPassthrough; +use pallet_xcm::{AuthorizedAliasers, XcmPassthrough}; use parachains_common::{ xcm_config::{ AllSiblingSystemParachains, ConcreteAssetFromSystem, ParentRelayOrSiblingParachains, @@ -46,10 +46,10 @@ use sp_std::marker::PhantomData; use testnet_parachains_constants::westend::snowbridge::EthereumNetwork; use xcm::latest::{prelude::*, WESTEND_GENESIS_HASH}; use xcm_builder::{ - AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowHrmpNotificationsFromRelayChain, - AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, - DenyRecursively, DenyReserveTransferToRelayChain, DenyThenTry, DescribeAllTerminal, - DescribeFamily, EnsureXcmOrigin, ExternalConsensusLocationsConverterFor, + AccountId32Aliases, AliasChildLocation, AllowExplicitUnpaidExecutionFrom, + AllowHrmpNotificationsFromRelayChain, AllowKnownQueryResponses, AllowSubscriptionsFrom, + AllowTopLevelPaidExecutionFrom, DenyRecursively, DenyReserveTransferToRelayChain, DenyThenTry, + DescribeAllTerminal, DescribeFamily, EnsureXcmOrigin, ExternalConsensusLocationsConverterFor, FrameTransactionalProcessor, FungibleAdapter, HandleFee, HashedDescription, IsConcrete, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SendXcmFeeToAccount, SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, @@ -191,6 +191,12 @@ pub type WaivedLocations = ( /// - NativeToken with the parent Relay Chain and sibling parachains. pub type TrustedTeleporters = ConcreteAssetFromSystem; +/// Defines origin aliasing rules for this chain. +/// +/// - Allow any origin to alias into a child sub-location (equivalent to DescendOrigin), +/// - Allow origins explicitly authorized by the alias target location. +pub type TrustedAliasers = (AliasChildLocation, AuthorizedAliasers); + pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; @@ -246,7 +252,7 @@ impl xcm_executor::Config for XcmConfig { type UniversalAliases = Nothing; type CallDispatcher = RuntimeCall; type SafeCallFilter = Everything; - type Aliasers = Nothing; + type Aliasers = TrustedAliasers; type TransactionalProcessor = FrameTransactionalProcessor; type HrmpNewChannelOpenRequestHandler = (); type HrmpChannelAcceptedHandler = (); @@ -257,8 +263,8 @@ impl xcm_executor::Config for XcmConfig { pub type PriceForParentDelivery = ExponentialPrice; -/// Converts a local signed origin into an XCM location. -/// Forms the basis for local origins sending/executing XCMs. +/// Converts a local signed origin into an XCM location. Forms the basis for local origins +/// sending/executing XCMs. pub type LocalOriginToLocation = SignedToAccountId32; /// The means for routing XCM messages which are not for local execution into the right message @@ -270,6 +276,12 @@ pub type XcmRouter = WithUniqueTopic<( XcmpQueue, )>; +parameter_types! { + pub const DepositPerItem: Balance = crate::deposit(1, 0); + pub const DepositPerByte: Balance = crate::deposit(0, 1); + pub const AuthorizeAliasHoldReason: RuntimeHoldReason = RuntimeHoldReason::PolkadotXcm(pallet_xcm::HoldReason::AuthorizeAlias); +} + impl pallet_xcm::Config for Runtime { type RuntimeEvent = RuntimeEvent; type XcmRouter = XcmRouter; @@ -300,6 +312,13 @@ impl pallet_xcm::Config for Runtime { type AdminOrigin = EnsureRoot; type MaxRemoteLockConsumers = ConstU32<0>; type RemoteLockConsumerIdentifier = (); + // xcm_executor::Config::Aliasers also uses pallet_xcm::AuthorizedAliasers. + type AuthorizedAliasConsideration = HoldConsideration< + AccountId, + Balances, + AuthorizeAliasHoldReason, + LinearStoragePrice, + >; } impl cumulus_pallet_xcm::Config for Runtime { diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs index c001dae0804f9..475e885173b46 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs @@ -1032,6 +1032,30 @@ impl_runtime_apis! { } } + impl xcm_runtime_apis::trusted_query::TrustedQueryApi for Runtime { + fn is_trusted_reserve(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { + PolkadotXcm::is_trusted_reserve(asset, location) + } + fn is_trusted_teleporter(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { + PolkadotXcm::is_trusted_teleporter(asset, location) + } + } + + impl xcm_runtime_apis::authorized_aliases::AuthorizedAliasersApi for Runtime { + fn authorized_aliasers(target: VersionedLocation) -> Result< + Vec, + xcm_runtime_apis::authorized_aliases::Error + > { + PolkadotXcm::authorized_aliasers(target) + } + fn is_authorized_alias(origin: VersionedLocation, target: VersionedLocation) -> Result< + bool, + xcm_runtime_apis::authorized_aliases::Error + > { + PolkadotXcm::is_authorized_alias(origin, target) + } + } + impl cumulus_primitives_core::CollectCollationInfo for Runtime { fn collect_collation_info(header: &::Header) -> cumulus_primitives_core::CollationInfo { ParachainSystem::collect_collation_info(header) @@ -1298,15 +1322,6 @@ impl_runtime_apis! { genesis_config_presets::preset_names() } } - - impl xcm_runtime_apis::trusted_query::TrustedQueryApi for Runtime { - fn is_trusted_reserve(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { - PolkadotXcm::is_trusted_reserve(asset, location) - } - fn is_trusted_teleporter(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { - PolkadotXcm::is_trusted_teleporter(asset, location) - } - } } cumulus_pallet_parachain_system::register_validate_block! { diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_xcm.rs index 88d396d0f0f1f..4ee3f92f1f981 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_xcm.rs @@ -50,6 +50,28 @@ use core::marker::PhantomData; /// Weight functions for `pallet_xcm`. pub struct WeightInfo(PhantomData); impl pallet_xcm::WeightInfo for WeightInfo { + /// Storage: `PolkadotXcm::AuthorizedAliases` (r:1 w:1) + /// Proof: `PolkadotXcm::AuthorizedAliases` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn add_authorized_alias() -> Weight { + // Proof Size summary in bytes: + // Measured: `498` + // Estimated: `3963` + // Minimum execution time: 19_789_000 picoseconds. + Weight::from_parts(20_317_000, 3963) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `PolkadotXcm::AuthorizedAliases` (r:1 w:1) + /// Proof: `PolkadotXcm::AuthorizedAliases` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn remove_authorized_alias() -> Weight { + // Proof Size summary in bytes: + // Measured: `537` + // Estimated: `4002` + // Minimum execution time: 20_805_000 picoseconds. + Weight::from_parts(21_481_000, 4002) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/xcm_config.rs index 112c1740d7d31..21d76113eb842 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/xcm_config.rs @@ -14,17 +14,21 @@ // limitations under the License. use super::{ - AccountId, AllPalletsWithSystem, Balances, BaseDeliveryFee, FeeAssetId, Fellows, ParachainInfo, - ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, - TransactionByteFee, WeightToFee, WestendTreasuryAccount, XcmpQueue, + AccountId, AllPalletsWithSystem, Balance, Balances, BaseDeliveryFee, FeeAssetId, Fellows, + ParachainInfo, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, + RuntimeHoldReason, RuntimeOrigin, TransactionByteFee, WeightToFee, WestendTreasuryAccount, + XcmpQueue, }; use frame_support::{ parameter_types, - traits::{tokens::imbalance::ResolveTo, ConstU32, Contains, Equals, Everything, Nothing}, + traits::{ + fungible::HoldConsideration, tokens::imbalance::ResolveTo, ConstU32, Contains, Equals, + Everything, LinearStoragePrice, Nothing, + }, }; use frame_system::EnsureRoot; use pallet_collator_selection::StakingPotAccountId; -use pallet_xcm::XcmPassthrough; +use pallet_xcm::{AuthorizedAliasers, XcmPassthrough}; use parachains_common::xcm_config::{ AliasAccountId32FromSiblingSystemChain, AllSiblingSystemParachains, ConcreteAssetFromSystem, ParentRelayOrSiblingParachains, RelayOrOtherSystemParachains, @@ -183,15 +187,20 @@ pub type WaivedLocations = ( ); /// Cases where a remote origin is accepted as trusted Teleporter for a given asset: -/// - DOT with the parent Relay Chain and sibling parachains. +/// - WND with the parent Relay Chain and sibling parachains. pub type TrustedTeleporters = ConcreteAssetFromSystem; -/// We allow locations to alias into their own child locations, allow AssetHub root to alias into -/// anything, and allow same accounts to alias into each other across system chains. -pub type Aliasers = ( +/// Defines origin aliasing rules for this chain. +/// +/// - Allow any origin to alias into a child sub-location (equivalent to DescendOrigin), +/// - Allow same accounts to alias into each other across system chains, +/// - Allow AssetHub root to alias into anything, +/// - Allow origins explicitly authorized to alias into target location. +pub type TrustedAliasers = ( AliasChildLocation, - AliasOriginRootUsingFilter, AliasAccountId32FromSiblingSystemChain, + AliasOriginRootUsingFilter, + AuthorizedAliasers, ); pub struct XcmConfig; @@ -235,7 +244,7 @@ impl xcm_executor::Config for XcmConfig { type UniversalAliases = Nothing; type CallDispatcher = RuntimeCall; type SafeCallFilter = Everything; - type Aliasers = Aliasers; + type Aliasers = TrustedAliasers; type TransactionalProcessor = FrameTransactionalProcessor; type HrmpNewChannelOpenRequestHandler = (); type HrmpChannelAcceptedHandler = (); @@ -243,8 +252,8 @@ impl xcm_executor::Config for XcmConfig { type XcmRecorder = PolkadotXcm; } -/// Converts a local signed origin into an XCM location. -/// Forms the basis for local origins sending/executing XCMs. +/// Converts a local signed origin into an XCM location. Forms the basis for local origins +/// sending/executing XCMs. pub type LocalOriginToLocation = SignedToAccountId32; pub type PriceForParentDelivery = @@ -267,6 +276,12 @@ parameter_types! { /// Type to convert the Fellows origin to a Plurality `Location` value. pub type FellowsToPlurality = OriginToPluralityVoice; +parameter_types! { + pub const DepositPerItem: Balance = crate::deposit(1, 0); + pub const DepositPerByte: Balance = crate::deposit(0, 1); + pub const AuthorizeAliasHoldReason: RuntimeHoldReason = RuntimeHoldReason::PolkadotXcm(pallet_xcm::HoldReason::AuthorizeAlias); +} + impl pallet_xcm::Config for Runtime { type RuntimeEvent = RuntimeEvent; // We only allow the Fellows to send messages. @@ -297,6 +312,13 @@ impl pallet_xcm::Config for Runtime { type AdminOrigin = EnsureRoot; type MaxRemoteLockConsumers = ConstU32<0>; type RemoteLockConsumerIdentifier = (); + // xcm_executor::Config::Aliasers also uses pallet_xcm::AuthorizedAliasers. + type AuthorizedAliasConsideration = HoldConsideration< + AccountId, + Balances, + AuthorizeAliasHoldReason, + LinearStoragePrice, + >; } impl cumulus_pallet_xcm::Config for Runtime { diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_xcm.rs index 9287792f8c77c..2fe827c0cf952 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_xcm.rs @@ -50,6 +50,28 @@ use core::marker::PhantomData; /// Weight functions for `pallet_xcm`. pub struct WeightInfo(PhantomData); impl pallet_xcm::WeightInfo for WeightInfo { + /// Storage: `PolkadotXcm::AuthorizedAliases` (r:1 w:1) + /// Proof: `PolkadotXcm::AuthorizedAliases` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn add_authorized_alias() -> Weight { + // Proof Size summary in bytes: + // Measured: `498` + // Estimated: `3963` + // Minimum execution time: 19_789_000 picoseconds. + Weight::from_parts(20_317_000, 3963) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `PolkadotXcm::AuthorizedAliases` (r:1 w:1) + /// Proof: `PolkadotXcm::AuthorizedAliases` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn remove_authorized_alias() -> Weight { + // Proof Size summary in bytes: + // Measured: `537` + // Estimated: `4002` + // Minimum execution time: 20_805_000 picoseconds. + Weight::from_parts(21_481_000, 4002) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/xcm_config.rs index 66d5267d91565..3dcc258abb654 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/xcm_config.rs @@ -22,7 +22,9 @@ use super::{ use frame_support::{ pallet_prelude::PalletInfoAccess, parameter_types, - traits::{tokens::imbalance::ResolveTo, ConstU32, Contains, Equals, Everything, Nothing}, + traits::{ + tokens::imbalance::ResolveTo, ConstU32, Contains, Disabled, Equals, Everything, Nothing, + }, }; use frame_system::EnsureRoot; use pallet_collator_selection::StakingPotAccountId; @@ -183,6 +185,10 @@ pub type WaivedLocations = ( Equals, ); +/// Cases where a remote origin is accepted as trusted Teleporter for a given asset: +/// - ROC with the parent Relay Chain and sibling parachains. +pub type TrustedTeleporters = ConcreteAssetFromSystem; + pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; @@ -193,8 +199,7 @@ impl xcm_executor::Config for XcmConfig { // Coretime chain does not recognize a reserve location for any asset. Users must teleport ROC // where allowed (e.g. with the Relay Chain). type IsReserve = (); - /// Only allow teleportation of ROC. - type IsTeleporter = ConcreteAssetFromSystem; + type IsTeleporter = TrustedTeleporters; type UniversalLocation = UniversalLocation; type Barrier = Barrier; type Weigher = WeightInfoBounds< @@ -279,6 +284,8 @@ impl pallet_xcm::Config for Runtime { type AdminOrigin = EnsureRoot; type MaxRemoteLockConsumers = ConstU32<0>; type RemoteLockConsumerIdentifier = (); + // Aliasing is disabled: xcm_executor::Config::Aliasers is set to `Nothing`. + type AuthorizedAliasConsideration = Disabled; } impl cumulus_pallet_xcm::Config for Runtime { diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs index 8c9caa46128eb..4f555dec39c65 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs @@ -900,6 +900,30 @@ impl_runtime_apis! { } } + impl xcm_runtime_apis::trusted_query::TrustedQueryApi for Runtime { + fn is_trusted_reserve(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { + PolkadotXcm::is_trusted_reserve(asset, location) + } + fn is_trusted_teleporter(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { + PolkadotXcm::is_trusted_teleporter(asset, location) + } + } + + impl xcm_runtime_apis::authorized_aliases::AuthorizedAliasersApi for Runtime { + fn authorized_aliasers(target: VersionedLocation) -> Result< + Vec, + xcm_runtime_apis::authorized_aliases::Error + > { + PolkadotXcm::authorized_aliasers(target) + } + fn is_authorized_alias(origin: VersionedLocation, target: VersionedLocation) -> Result< + bool, + xcm_runtime_apis::authorized_aliases::Error + > { + PolkadotXcm::is_authorized_alias(origin, target) + } + } + impl cumulus_primitives_core::CollectCollationInfo for Runtime { fn collect_collation_info(header: &::Header) -> cumulus_primitives_core::CollationInfo { ParachainSystem::collect_collation_info(header) @@ -1185,15 +1209,6 @@ impl_runtime_apis! { genesis_config_presets::preset_names() } } - - impl xcm_runtime_apis::trusted_query::TrustedQueryApi for Runtime { - fn is_trusted_reserve(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { - PolkadotXcm::is_trusted_reserve(asset, location) - } - fn is_trusted_teleporter(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { - PolkadotXcm::is_trusted_teleporter(asset, location) - } - } } cumulus_pallet_parachain_system::register_validate_block! { diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_xcm.rs index c065ae1b2c03a..5cf5a7097153b 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_xcm.rs @@ -50,6 +50,28 @@ use core::marker::PhantomData; /// Weight functions for `pallet_xcm`. pub struct WeightInfo(PhantomData); impl pallet_xcm::WeightInfo for WeightInfo { + /// Storage: `PolkadotXcm::AuthorizedAliases` (r:1 w:1) + /// Proof: `PolkadotXcm::AuthorizedAliases` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn add_authorized_alias() -> Weight { + // Proof Size summary in bytes: + // Measured: `498` + // Estimated: `3963` + // Minimum execution time: 19_789_000 picoseconds. + Weight::from_parts(20_317_000, 3963) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `PolkadotXcm::AuthorizedAliases` (r:1 w:1) + /// Proof: `PolkadotXcm::AuthorizedAliases` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn remove_authorized_alias() -> Weight { + // Proof Size summary in bytes: + // Measured: `537` + // Estimated: `4002` + // Minimum execution time: 20_805_000 picoseconds. + Weight::from_parts(21_481_000, 4002) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/xcm_config.rs index 6b88669f18f62..0c5d1ef47907c 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/xcm_config.rs @@ -15,18 +15,21 @@ // limitations under the License. use super::{ - AccountId, AllPalletsWithSystem, Balances, BaseDeliveryFee, Broker, FeeAssetId, ParachainInfo, - ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, - TransactionByteFee, WeightToFee, XcmpQueue, + AccountId, AllPalletsWithSystem, Balance, Balances, BaseDeliveryFee, Broker, FeeAssetId, + ParachainInfo, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, + RuntimeHoldReason, RuntimeOrigin, TransactionByteFee, WeightToFee, XcmpQueue, }; use frame_support::{ pallet_prelude::PalletInfoAccess, parameter_types, - traits::{tokens::imbalance::ResolveTo, ConstU32, Contains, Equals, Everything, Nothing}, + traits::{ + fungible::HoldConsideration, tokens::imbalance::ResolveTo, ConstU32, Contains, Equals, + Everything, LinearStoragePrice, Nothing, + }, }; use frame_system::EnsureRoot; use pallet_collator_selection::StakingPotAccountId; -use pallet_xcm::XcmPassthrough; +use pallet_xcm::{AuthorizedAliasers, XcmPassthrough}; use parachains_common::{ xcm_config::{ AliasAccountId32FromSiblingSystemChain, AllSiblingSystemParachains, @@ -197,12 +200,21 @@ pub type WaivedLocations = ( Equals, ); -/// We allow locations to alias into their own child locations, allow AssetHub root to alias into -/// anything, and allow same accounts to alias into each other across system chains. -pub type Aliasers = ( +/// Cases where a remote origin is accepted as trusted Teleporter for a given asset: +/// - WND with the parent Relay Chain and sibling parachains. +pub type TrustedTeleporters = ConcreteAssetFromSystem; + +/// Defines origin aliasing rules for this chain. +/// +/// - Allow any origin to alias into a child sub-location (equivalent to DescendOrigin), +/// - Allow same accounts to alias into each other across system chains, +/// - Allow AssetHub root to alias into anything, +/// - Allow origins explicitly authorized to alias into target location. +pub type TrustedAliasers = ( AliasChildLocation, - AliasOriginRootUsingFilter, AliasAccountId32FromSiblingSystemChain, + AliasOriginRootUsingFilter, + AuthorizedAliasers, ); pub struct XcmConfig; @@ -215,8 +227,7 @@ impl xcm_executor::Config for XcmConfig { // Coretime chain does not recognize a reserve location for any asset. Users must teleport ROC // where allowed (e.g. with the Relay Chain). type IsReserve = (); - /// Only allow teleportation of WND. - type IsTeleporter = ConcreteAssetFromSystem; + type IsTeleporter = TrustedTeleporters; type UniversalLocation = UniversalLocation; type Barrier = Barrier; type Weigher = WeightInfoBounds< @@ -247,7 +258,7 @@ impl xcm_executor::Config for XcmConfig { type UniversalAliases = Nothing; type CallDispatcher = RuntimeCall; type SafeCallFilter = Everything; - type Aliasers = Aliasers; + type Aliasers = TrustedAliasers; type TransactionalProcessor = FrameTransactionalProcessor; type HrmpNewChannelOpenRequestHandler = (); type HrmpChannelAcceptedHandler = (); @@ -271,6 +282,12 @@ pub type XcmRouter = WithUniqueTopic<( XcmpQueue, )>; +parameter_types! { + pub const DepositPerItem: Balance = crate::deposit(1, 0); + pub const DepositPerByte: Balance = crate::deposit(0, 1); + pub const AuthorizeAliasHoldReason: RuntimeHoldReason = RuntimeHoldReason::PolkadotXcm(pallet_xcm::HoldReason::AuthorizeAlias); +} + impl pallet_xcm::Config for Runtime { type RuntimeEvent = RuntimeEvent; // We want to disallow users sending (arbitrary) XCM programs from this chain. @@ -301,6 +318,13 @@ impl pallet_xcm::Config for Runtime { type AdminOrigin = EnsureRoot; type MaxRemoteLockConsumers = ConstU32<0>; type RemoteLockConsumerIdentifier = (); + // xcm_executor::Config::Aliasers also uses pallet_xcm::AuthorizedAliasers. + type AuthorizedAliasConsideration = HoldConsideration< + AccountId, + Balances, + AuthorizeAliasHoldReason, + LinearStoragePrice, + >; } impl cumulus_pallet_xcm::Config for Runtime { diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_xcm.rs index 3f396a5df461f..31234cba71bd3 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_xcm.rs @@ -50,6 +50,28 @@ use core::marker::PhantomData; /// Weight functions for `pallet_xcm`. pub struct WeightInfo(PhantomData); impl pallet_xcm::WeightInfo for WeightInfo { + /// Storage: `PolkadotXcm::AuthorizedAliases` (r:1 w:1) + /// Proof: `PolkadotXcm::AuthorizedAliases` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn add_authorized_alias() -> Weight { + // Proof Size summary in bytes: + // Measured: `498` + // Estimated: `3963` + // Minimum execution time: 19_789_000 picoseconds. + Weight::from_parts(20_317_000, 3963) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `PolkadotXcm::AuthorizedAliases` (r:1 w:1) + /// Proof: `PolkadotXcm::AuthorizedAliases` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn remove_authorized_alias() -> Weight { + // Proof Size summary in bytes: + // Measured: `537` + // Estimated: `4002` + // Minimum execution time: 20_805_000 picoseconds. + Weight::from_parts(21_481_000, 4002) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/people/people-rococo/src/xcm_config.rs index d2d5c8c85bcb3..4adbf02d9e586 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/xcm_config.rs @@ -20,7 +20,9 @@ use super::{ use crate::{TransactionByteFee, CENTS}; use frame_support::{ parameter_types, - traits::{tokens::imbalance::ResolveTo, ConstU32, Contains, Equals, Everything, Nothing}, + traits::{ + tokens::imbalance::ResolveTo, ConstU32, Contains, Disabled, Equals, Everything, Nothing, + }, }; use frame_system::EnsureRoot; use pallet_collator_selection::StakingPotAccountId; @@ -280,6 +282,8 @@ impl pallet_xcm::Config for Runtime { type AdminOrigin = EnsureRoot; type MaxRemoteLockConsumers = ConstU32<0>; type RemoteLockConsumerIdentifier = (); + // Aliasing is disabled: xcm_executor::Config::Aliasers is set to `Nothing`. + type AuthorizedAliasConsideration = Disabled; } impl cumulus_pallet_xcm::Config for Runtime { diff --git a/cumulus/parachains/runtimes/people/people-westend/src/lib.rs b/cumulus/parachains/runtimes/people/people-westend/src/lib.rs index 83e405bcaebe3..548dc1509efa9 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/lib.rs @@ -845,6 +845,30 @@ impl_runtime_apis! { } } + impl xcm_runtime_apis::trusted_query::TrustedQueryApi for Runtime { + fn is_trusted_reserve(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { + PolkadotXcm::is_trusted_reserve(asset, location) + } + fn is_trusted_teleporter(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { + PolkadotXcm::is_trusted_teleporter(asset, location) + } + } + + impl xcm_runtime_apis::authorized_aliases::AuthorizedAliasersApi for Runtime { + fn authorized_aliasers(target: VersionedLocation) -> Result< + Vec, + xcm_runtime_apis::authorized_aliases::Error + > { + PolkadotXcm::authorized_aliasers(target) + } + fn is_authorized_alias(origin: VersionedLocation, target: VersionedLocation) -> Result< + bool, + xcm_runtime_apis::authorized_aliases::Error + > { + PolkadotXcm::is_authorized_alias(origin, target) + } + } + impl cumulus_primitives_core::CollectCollationInfo for Runtime { fn collect_collation_info(header: &::Header) -> cumulus_primitives_core::CollationInfo { ParachainSystem::collect_collation_info(header) @@ -1096,15 +1120,6 @@ impl_runtime_apis! { genesis_config_presets::preset_names() } } - - impl xcm_runtime_apis::trusted_query::TrustedQueryApi for Runtime { - fn is_trusted_reserve(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { - PolkadotXcm::is_trusted_reserve(asset, location) - } - fn is_trusted_teleporter(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { - PolkadotXcm::is_trusted_teleporter(asset, location) - } - } } cumulus_pallet_parachain_system::register_validate_block! { diff --git a/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_xcm.rs index d895f0277545e..b4507c3c50218 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_xcm.rs @@ -50,6 +50,28 @@ use core::marker::PhantomData; /// Weight functions for `pallet_xcm`. pub struct WeightInfo(PhantomData); impl pallet_xcm::WeightInfo for WeightInfo { + /// Storage: `PolkadotXcm::AuthorizedAliases` (r:1 w:1) + /// Proof: `PolkadotXcm::AuthorizedAliases` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn add_authorized_alias() -> Weight { + // Proof Size summary in bytes: + // Measured: `498` + // Estimated: `3963` + // Minimum execution time: 19_789_000 picoseconds. + Weight::from_parts(20_317_000, 3963) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `PolkadotXcm::AuthorizedAliases` (r:1 w:1) + /// Proof: `PolkadotXcm::AuthorizedAliases` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn remove_authorized_alias() -> Weight { + // Proof Size summary in bytes: + // Measured: `537` + // Estimated: `4002` + // Minimum execution time: 20_805_000 picoseconds. + Weight::from_parts(21_481_000, 4002) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) diff --git a/cumulus/parachains/runtimes/people/people-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/people/people-westend/src/xcm_config.rs index 7a07153aa8fd7..62a84d5f2d858 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/xcm_config.rs @@ -14,17 +14,21 @@ // limitations under the License. use super::{ - AccountId, AllPalletsWithSystem, Balances, ParachainInfo, ParachainSystem, PolkadotXcm, - Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, WeightToFee, XcmpQueue, + AccountId, AllPalletsWithSystem, Balance, Balances, ParachainInfo, ParachainSystem, + PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeHoldReason, RuntimeOrigin, WeightToFee, + XcmpQueue, }; use crate::{TransactionByteFee, CENTS}; use frame_support::{ parameter_types, - traits::{tokens::imbalance::ResolveTo, ConstU32, Contains, Equals, Everything, Nothing}, + traits::{ + fungible::HoldConsideration, tokens::imbalance::ResolveTo, ConstU32, Contains, Equals, + Everything, LinearStoragePrice, Nothing, + }, }; use frame_system::EnsureRoot; use pallet_collator_selection::StakingPotAccountId; -use pallet_xcm::XcmPassthrough; +use pallet_xcm::{AuthorizedAliasers, XcmPassthrough}; use parachains_common::{ xcm_config::{ AliasAccountId32FromSiblingSystemChain, AllSiblingSystemParachains, @@ -201,12 +205,21 @@ pub type WaivedLocations = ( LocalPlurality, ); -/// We allow locations to alias into their own child locations, allow AssetHub root to alias into -/// anything, and allow same accounts to alias into each other across system chains. -pub type Aliasers = ( +/// Cases where a remote origin is accepted as trusted Teleporter for a given asset: +/// - WND with the parent Relay Chain and sibling parachains. +pub type TrustedTeleporters = ConcreteAssetFromSystem; + +/// Defines origin aliasing rules for this chain. +/// +/// - Allow any origin to alias into a child sub-location (equivalent to DescendOrigin), +/// - Allow same accounts to alias into each other across system chains, +/// - Allow AssetHub root to alias into anything, +/// - Allow origins explicitly authorized to alias into target location. +pub type TrustedAliasers = ( AliasChildLocation, - AliasOriginRootUsingFilter, AliasAccountId32FromSiblingSystemChain, + AliasOriginRootUsingFilter, + AuthorizedAliasers, ); pub struct XcmConfig; @@ -219,8 +232,7 @@ impl xcm_executor::Config for XcmConfig { // People does not recognize a reserve location for any asset. Users must teleport WND // where allowed (e.g. with the Relay Chain). type IsReserve = (); - /// Only allow teleportation of WND amongst the system. - type IsTeleporter = ConcreteAssetFromSystem; + type IsTeleporter = TrustedTeleporters; type UniversalLocation = UniversalLocation; type Barrier = Barrier; type Weigher = WeightInfoBounds< @@ -251,7 +263,7 @@ impl xcm_executor::Config for XcmConfig { type UniversalAliases = Nothing; type CallDispatcher = RuntimeCall; type SafeCallFilter = Everything; - type Aliasers = Aliasers; + type Aliasers = TrustedAliasers; type TransactionalProcessor = FrameTransactionalProcessor; type HrmpNewChannelOpenRequestHandler = (); type HrmpChannelAcceptedHandler = (); @@ -272,6 +284,12 @@ pub type XcmRouter = WithUniqueTopic<( XcmpQueue, )>; +parameter_types! { + pub const DepositPerItem: Balance = crate::deposit(1, 0); + pub const DepositPerByte: Balance = crate::deposit(0, 1); + pub const AuthorizeAliasHoldReason: RuntimeHoldReason = RuntimeHoldReason::PolkadotXcm(pallet_xcm::HoldReason::AuthorizeAlias); +} + impl pallet_xcm::Config for Runtime { type RuntimeEvent = RuntimeEvent; // We want to disallow users sending (arbitrary) XCMs from this chain. @@ -302,6 +320,13 @@ impl pallet_xcm::Config for Runtime { type AdminOrigin = EnsureRoot; type MaxRemoteLockConsumers = ConstU32<0>; type RemoteLockConsumerIdentifier = (); + // xcm_executor::Config::Aliasers also uses pallet_xcm::AuthorizedAliasers. + type AuthorizedAliasConsideration = HoldConsideration< + AccountId, + Balances, + AuthorizeAliasHoldReason, + LinearStoragePrice, + >; } impl cumulus_pallet_xcm::Config for Runtime { diff --git a/cumulus/parachains/runtimes/testing/penpal/Cargo.toml b/cumulus/parachains/runtimes/testing/penpal/Cargo.toml index d6dce4f5026f3..2b8560fe994be 100644 --- a/cumulus/parachains/runtimes/testing/penpal/Cargo.toml +++ b/cumulus/parachains/runtimes/testing/penpal/Cargo.toml @@ -81,6 +81,7 @@ pallet-message-queue = { workspace = true } parachain-info = { workspace = true } parachains-common = { workspace = true } snowbridge-inbound-queue-primitives = { workspace = true } +testnet-parachains-constants = { features = ["westend"], workspace = true } primitive-types = { workspace = true, default-features = false, features = [ "codec", @@ -144,6 +145,7 @@ std = [ "sp-transaction-pool/std", "sp-version/std", "substrate-wasm-builder", + "testnet-parachains-constants/std", "xcm-builder/std", "xcm-executor/std", "xcm-runtime-apis/std", diff --git a/cumulus/parachains/runtimes/testing/penpal/src/lib.rs b/cumulus/parachains/runtimes/testing/penpal/src/lib.rs index 82da5764744b6..78b59562772ee 100644 --- a/cumulus/parachains/runtimes/testing/penpal/src/lib.rs +++ b/cumulus/parachains/runtimes/testing/penpal/src/lib.rs @@ -1123,6 +1123,42 @@ impl_runtime_apis! { } } + impl xcm_runtime_apis::conversions::LocationToAccountApi for Runtime { + fn convert_location(location: VersionedLocation) -> Result< + AccountId, + xcm_runtime_apis::conversions::Error + > { + xcm_runtime_apis::conversions::LocationToAccountHelper::< + AccountId, + xcm_config::LocationToAccountId, + >::convert_location(location) + } + } + + impl xcm_runtime_apis::trusted_query::TrustedQueryApi for Runtime { + fn is_trusted_reserve(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { + PolkadotXcm::is_trusted_reserve(asset, location) + } + fn is_trusted_teleporter(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { + PolkadotXcm::is_trusted_teleporter(asset, location) + } + } + + impl xcm_runtime_apis::authorized_aliases::AuthorizedAliasersApi for Runtime { + fn authorized_aliasers(target: VersionedLocation) -> Result< + Vec, + xcm_runtime_apis::authorized_aliases::Error + > { + PolkadotXcm::authorized_aliasers(target) + } + fn is_authorized_alias(origin: VersionedLocation, target: VersionedLocation) -> Result< + bool, + xcm_runtime_apis::authorized_aliases::Error + > { + PolkadotXcm::is_authorized_alias(origin, target) + } + } + #[cfg(feature = "try-runtime")] impl frame_try_runtime::TryRuntime for Runtime { fn on_runtime_upgrade(checks: frame_try_runtime::UpgradeCheckSelect) -> (Weight, Weight) { @@ -1200,15 +1236,6 @@ impl_runtime_apis! { vec![] } } - - impl xcm_runtime_apis::trusted_query::TrustedQueryApi for Runtime { - fn is_trusted_reserve(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { - PolkadotXcm::is_trusted_reserve(asset, location) - } - fn is_trusted_teleporter(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { - PolkadotXcm::is_trusted_teleporter(asset, location) - } - } } cumulus_pallet_parachain_system::register_validate_block! { diff --git a/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs b/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs index 0718a82b158d1..2f41c118d7a89 100644 --- a/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs @@ -37,8 +37,8 @@ use super::{ AccountId, AllPalletsWithSystem, AssetId as AssetIdPalletAssets, Assets, Authorship, Balance, Balances, CollatorSelection, ForeignAssets, ForeignAssetsInstance, NonZeroIssuance, - ParachainInfo, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, - WeightToFee, XcmpQueue, + ParachainInfo, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, + RuntimeHoldReason, RuntimeOrigin, WeightToFee, XcmpQueue, }; use crate::{BaseDeliveryFee, FeeAssetId, TransactionByteFee}; use assets_common::TrustBackedAssetsAsLocation; @@ -46,13 +46,14 @@ use core::marker::PhantomData; use frame_support::{ parameter_types, traits::{ - tokens::imbalance::ResolveAssetTo, ConstU32, Contains, ContainsPair, Equals, Everything, - EverythingBut, Get, Nothing, PalletInfoAccess, + fungible::HoldConsideration, tokens::imbalance::ResolveAssetTo, ConstU32, Contains, + ContainsPair, Equals, Everything, EverythingBut, Get, LinearStoragePrice, Nothing, + PalletInfoAccess, }, weights::Weight, }; use frame_system::EnsureRoot; -use pallet_xcm::XcmPassthrough; +use pallet_xcm::{AuthorizedAliasers, XcmPassthrough}; use parachains_common::{ xcm_config::{AssetFeeAsExistentialDepositMultiplier, ConcreteAssetFromSystem}, TREASURY_PALLET_ID, @@ -60,18 +61,20 @@ use parachains_common::{ use polkadot_parachain_primitives::primitives::Sibling; use polkadot_runtime_common::{impls::ToAuthor, xcm_sender::ExponentialPrice}; use sp_runtime::traits::{AccountIdConversion, ConvertInto, Identity, TryConvertInto}; +use testnet_parachains_constants::westend::currency::deposit; use xcm::latest::{prelude::*, WESTEND_GENESIS_HASH}; use xcm_builder::{ - AccountId32Aliases, AliasOriginRootUsingFilter, AllowHrmpNotificationsFromRelayChain, - AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, - AsPrefixedGeneralIndex, ConvertedConcreteId, DescribeAllTerminal, DescribeFamily, - DescribeTerminus, EnsureXcmOrigin, ExternalConsensusLocationsConverterFor, FixedWeightBounds, - FrameTransactionalProcessor, FungibleAdapter, FungiblesAdapter, HashedDescription, IsConcrete, - LocalMint, NativeAsset, NoChecking, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, - SendXcmFeeToAccount, SiblingParachainAsNative, SiblingParachainConvertsVia, - SignedAccountId32AsNative, SignedToAccountId32, SingleAssetExchangeAdapter, - SovereignSignedViaLocation, StartsWith, TakeWeightCredit, TrailingSetTopicAsId, - UsingComponents, WithComputedOrigin, WithUniqueTopic, XcmFeeManagerFromComponents, + AccountId32Aliases, AliasChildLocation, AliasOriginRootUsingFilter, + AllowHrmpNotificationsFromRelayChain, AllowKnownQueryResponses, AllowSubscriptionsFrom, + AllowTopLevelPaidExecutionFrom, AsPrefixedGeneralIndex, ConvertedConcreteId, + DescribeAllTerminal, DescribeFamily, DescribeTerminus, EnsureXcmOrigin, + ExternalConsensusLocationsConverterFor, FixedWeightBounds, FrameTransactionalProcessor, + FungibleAdapter, FungiblesAdapter, HashedDescription, IsConcrete, LocalMint, NativeAsset, + NoChecking, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SendXcmFeeToAccount, + SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, + SignedToAccountId32, SingleAssetExchangeAdapter, SovereignSignedViaLocation, StartsWith, + TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, WithComputedOrigin, WithUniqueTopic, + XcmFeeManagerFromComponents, }; use xcm_executor::{traits::JustTry, XcmExecutor}; @@ -336,6 +339,17 @@ pub type TrustedReserves = ( pub type TrustedTeleporters = (AssetFromChain,); +/// Defines origin aliasing rules for this chain. +/// +/// - Allow any origin to alias into a child sub-location (equivalent to DescendOrigin), +/// - Allow AssetHub root to alias into anything, +/// - Allow origins explicitly authorized by the alias target location. +pub type TrustedAliasers = ( + AliasChildLocation, + AliasOriginRootUsingFilter, + AuthorizedAliasers, +); + pub type WaivedLocations = Equals; /// `AssetId`/`Balance` converter for `TrustBackedAssets`. pub type TrustBackedAssetsConvertedConcreteId = @@ -408,8 +422,7 @@ impl xcm_executor::Config for XcmConfig { type UniversalAliases = Nothing; type CallDispatcher = RuntimeCall; type SafeCallFilter = Everything; - // We allow trusted Asset Hub root to alias other locations. - type Aliasers = AliasOriginRootUsingFilter; + type Aliasers = TrustedAliasers; type TransactionalProcessor = FrameTransactionalProcessor; type HrmpNewChannelOpenRequestHandler = (); type HrmpChannelAcceptedHandler = (); @@ -426,7 +439,8 @@ pub type ForeignAssetFeeAsExistentialDepositMultiplierFeeCharger = ForeignAssetsInstance, >; -/// No local origins on this chain are allowed to dispatch XCM sends/executions. +/// Converts a local signed origin into an XCM location. Forms the basis for local origins +/// sending/executing XCMs. pub type LocalOriginToLocation = SignedToAccountId32; pub type PriceForParentDelivery = @@ -441,6 +455,12 @@ pub type XcmRouter = WithUniqueTopic<( XcmpQueue, )>; +parameter_types! { + pub const DepositPerItem: Balance = deposit(1, 0); + pub const DepositPerByte: Balance = deposit(0, 1); + pub const AuthorizeAliasHoldReason: RuntimeHoldReason = RuntimeHoldReason::PolkadotXcm(pallet_xcm::HoldReason::AuthorizeAlias); +} + impl pallet_xcm::Config for Runtime { type RuntimeEvent = RuntimeEvent; type SendXcmOrigin = EnsureXcmOrigin; @@ -467,6 +487,13 @@ impl pallet_xcm::Config for Runtime { type AdminOrigin = EnsureRoot; type MaxRemoteLockConsumers = ConstU32<0>; type RemoteLockConsumerIdentifier = (); + // xcm_executor::Config::Aliasers also uses pallet_xcm::AuthorizedAliasers. + type AuthorizedAliasConsideration = HoldConsideration< + AccountId, + Balances, + AuthorizeAliasHoldReason, + LinearStoragePrice, + >; } impl cumulus_pallet_xcm::Config for Runtime { diff --git a/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs b/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs index 45708fdf29dbb..78a3df8349bc0 100644 --- a/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs +++ b/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs @@ -69,7 +69,7 @@ pub use sp_runtime::BuildStorage; pub use sp_runtime::{Perbill, Permill}; use cumulus_primitives_core::{AggregateMessageOrigin, ClaimQueueOffset, CoreSelector, ParaId}; -use frame_support::traits::TransformOrigin; +use frame_support::traits::{Disabled, TransformOrigin}; use parachains_common::{ impls::{AssetsFrom, NonZeroIssuance}, message_queue::{NarrowOriginToSibling, ParaIdToSibling}, @@ -503,7 +503,8 @@ impl xcm_executor::Config for XcmConfig { type XcmRecorder = PolkadotXcm; } -/// Local origins on this chain are allowed to dispatch XCM sends/executions. +/// Converts a local signed origin into an XCM location. Forms the basis for local origins +/// sending/executing XCMs. pub type LocalOriginToLocation = SignedToAccountId32; /// The means for routing XCM messages which are not for local execution into the right message @@ -539,6 +540,8 @@ impl pallet_xcm::Config for Runtime { type AdminOrigin = EnsureRoot; type MaxRemoteLockConsumers = ConstU32<0>; type RemoteLockConsumerIdentifier = (); + // Aliasing is disabled: xcm_executor::Config::Aliasers is set to `Nothing`. + type AuthorizedAliasConsideration = Disabled; } impl cumulus_pallet_xcm::Config for Runtime { diff --git a/polkadot/runtime/rococo/src/weights/pallet_xcm.rs b/polkadot/runtime/rococo/src/weights/pallet_xcm.rs index de508d0ac5e73..846e812ac68fe 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_xcm.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_xcm.rs @@ -372,4 +372,26 @@ impl pallet_xcm::WeightInfo for WeightInfo { .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } + /// Storage: `XcmPallet::AuthorizedAliases` (r:1 w:1) + /// Proof: `XcmPallet::AuthorizedAliases` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn add_authorized_alias() -> Weight { + // Proof Size summary in bytes: + // Measured: `361` + // Estimated: `3826` + // Minimum execution time: 15_975_000 picoseconds. + Weight::from_parts(16_398_000, 3826) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `XcmPallet::AuthorizedAliases` (r:1 w:1) + /// Proof: `XcmPallet::AuthorizedAliases` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn remove_authorized_alias() -> Weight { + // Proof Size summary in bytes: + // Measured: `400` + // Estimated: `3865` + // Minimum execution time: 17_326_000 picoseconds. + Weight::from_parts(17_622_000, 3865) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } } diff --git a/polkadot/runtime/rococo/src/xcm_config.rs b/polkadot/runtime/rococo/src/xcm_config.rs index af486db12f426..87fc99eb32ad7 100644 --- a/polkadot/runtime/rococo/src/xcm_config.rs +++ b/polkadot/runtime/rococo/src/xcm_config.rs @@ -26,7 +26,7 @@ use crate::governance::StakingAdmin; use frame_support::{ parameter_types, - traits::{Contains, Equals, Everything, Nothing}, + traits::{Contains, Disabled, Equals, Everything, Nothing}, weights::Weight, }; use frame_system::EnsureRoot; @@ -300,4 +300,6 @@ impl pallet_xcm::Config for Runtime { type RemoteLockConsumerIdentifier = (); type WeightInfo = crate::weights::pallet_xcm::WeightInfo; type AdminOrigin = EnsureRoot; + // Aliasing is disabled: xcm_executor::Config::Aliasers is set to `Nothing`. + type AuthorizedAliasConsideration = Disabled; } diff --git a/polkadot/runtime/test-runtime/src/xcm_config.rs b/polkadot/runtime/test-runtime/src/xcm_config.rs index 304c1d52e9ef5..8d7e351d0d5be 100644 --- a/polkadot/runtime/test-runtime/src/xcm_config.rs +++ b/polkadot/runtime/test-runtime/src/xcm_config.rs @@ -16,7 +16,7 @@ use frame_support::{ parameter_types, - traits::{Everything, Get, Nothing}, + traits::{Disabled, Everything, Get, Nothing}, weights::Weight, }; use frame_system::EnsureRoot; @@ -186,4 +186,6 @@ impl pallet_xcm::Config for crate::Runtime { type RemoteLockConsumerIdentifier = (); type WeightInfo = pallet_xcm::TestWeightInfo; type AdminOrigin = EnsureRoot; + // Aliasing is disabled: xcm_executor::Config::Aliasers is set to `Nothing`. + type AuthorizedAliasConsideration = Disabled; } diff --git a/polkadot/runtime/westend/src/weights/pallet_xcm.rs b/polkadot/runtime/westend/src/weights/pallet_xcm.rs index 1133012941fd2..d0c652f79f114 100644 --- a/polkadot/runtime/westend/src/weights/pallet_xcm.rs +++ b/polkadot/runtime/westend/src/weights/pallet_xcm.rs @@ -372,4 +372,26 @@ impl pallet_xcm::WeightInfo for WeightInfo { .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } + /// Storage: `XcmPallet::AuthorizedAliases` (r:1 w:1) + /// Proof: `XcmPallet::AuthorizedAliases` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn add_authorized_alias() -> Weight { + // Proof Size summary in bytes: + // Measured: `361` + // Estimated: `3826` + // Minimum execution time: 15_975_000 picoseconds. + Weight::from_parts(16_398_000, 3826) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `XcmPallet::AuthorizedAliases` (r:1 w:1) + /// Proof: `XcmPallet::AuthorizedAliases` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn remove_authorized_alias() -> Weight { + // Proof Size summary in bytes: + // Measured: `400` + // Estimated: `3865` + // Minimum execution time: 17_326_000 picoseconds. + Weight::from_parts(17_622_000, 3865) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } } diff --git a/polkadot/runtime/westend/src/xcm_config.rs b/polkadot/runtime/westend/src/xcm_config.rs index c5a3cc1bde736..e93da33b204f2 100644 --- a/polkadot/runtime/westend/src/xcm_config.rs +++ b/polkadot/runtime/westend/src/xcm_config.rs @@ -24,7 +24,7 @@ use super::{ use crate::governance::pallet_custom_origins::Treasurer; use frame_support::{ parameter_types, - traits::{Contains, Equals, Everything, Nothing}, + traits::{Contains, Disabled, Equals, Everything, Nothing}, }; use frame_system::EnsureRoot; use pallet_xcm::XcmPassthrough; @@ -249,7 +249,8 @@ parameter_types! { pub type GeneralAdminToPlurality = OriginToPluralityVoice; -/// location of this chain. +/// Converts a local signed origin into an XCM location. Forms the basis for local origins +/// sending/executing XCMs. pub type LocalOriginToLocation = ( GeneralAdminToPlurality, // And a usual Signed origin to be used in XCM as a corresponding AccountId32 @@ -314,4 +315,6 @@ impl pallet_xcm::Config for Runtime { type RemoteLockConsumerIdentifier = (); type WeightInfo = crate::weights::pallet_xcm::WeightInfo; type AdminOrigin = EnsureRoot; + // Aliasing is disabled: xcm_executor::Config::Aliasers only allows `AliasChildLocation`. + type AuthorizedAliasConsideration = Disabled; } diff --git a/polkadot/xcm/docs/src/cookbook/relay_token_transactor/parachain/xcm_config.rs b/polkadot/xcm/docs/src/cookbook/relay_token_transactor/parachain/xcm_config.rs index 17bef935a2fa0..a2e73fbbb597e 100644 --- a/polkadot/xcm/docs/src/cookbook/relay_token_transactor/parachain/xcm_config.rs +++ b/polkadot/xcm/docs/src/cookbook/relay_token_transactor/parachain/xcm_config.rs @@ -20,7 +20,7 @@ use frame::{ deps::frame_system, runtime::prelude::*, - traits::{Everything, Nothing}, + traits::{Disabled, Everything, Nothing}, }; use xcm::latest::prelude::*; use xcm_builder::{ @@ -148,6 +148,8 @@ impl xcm_executor::Config for XcmConfig { type XcmRecorder = (); } +/// Converts a local signed origin into an XCM location. Forms the basis for local origins +/// sending/executing XCMs. pub type LocalOriginToLocation = SignedToAccountId32; impl pallet_xcm::Config for Runtime { @@ -188,4 +190,6 @@ impl pallet_xcm::Config for Runtime { type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; type RuntimeEvent = RuntimeEvent; + // Aliasing is disabled: xcm_executor::Config::Aliasers is set to `Nothing`. + type AuthorizedAliasConsideration = Disabled; } diff --git a/polkadot/xcm/docs/src/cookbook/relay_token_transactor/relay_chain/xcm_config.rs b/polkadot/xcm/docs/src/cookbook/relay_token_transactor/relay_chain/xcm_config.rs index 445e8f950acdd..ed4427a1bfc8b 100644 --- a/polkadot/xcm/docs/src/cookbook/relay_token_transactor/relay_chain/xcm_config.rs +++ b/polkadot/xcm/docs/src/cookbook/relay_token_transactor/relay_chain/xcm_config.rs @@ -20,7 +20,7 @@ use frame::{ deps::frame_system, runtime::prelude::*, - traits::{Everything, Nothing}, + traits::{Disabled, Everything, Nothing}, }; use xcm::latest::prelude::*; use xcm_builder::{ @@ -121,6 +121,8 @@ impl xcm_executor::Config for XcmConfig { type XcmRecorder = (); } +/// Converts a local signed origin into an XCM location. Forms the basis for local origins +/// sending/executing XCMs. pub type LocalOriginToLocation = SignedToAccountId32; impl pallet_xcm::Config for Runtime { @@ -162,4 +164,6 @@ impl pallet_xcm::Config for Runtime { type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; type RuntimeEvent = RuntimeEvent; + // Aliasing is disabled: xcm_executor::Config::Aliasers is set to `Nothing`. + type AuthorizedAliasConsideration = Disabled; } diff --git a/polkadot/xcm/pallet-xcm/src/benchmarking.rs b/polkadot/xcm/pallet-xcm/src/benchmarking.rs index 3ca048057ee49..e3a3b610ac032 100644 --- a/polkadot/xcm/pallet-xcm/src/benchmarking.rs +++ b/polkadot/xcm/pallet-xcm/src/benchmarking.rs @@ -28,7 +28,7 @@ type RuntimeOrigin = ::RuntimeOrigin; pub struct Pallet(crate::Pallet); /// Trait that must be implemented by runtime to be able to benchmark pallet properly. -pub trait Config: crate::Config { +pub trait Config: crate::Config + pallet_balances::Config { /// Helper that ensures successful delivery for extrinsics/benchmarks which need `SendXcm`. type DeliveryHelper: EnsureDelivery; @@ -396,7 +396,7 @@ mod benchmarks { #[block] { - crate::Pallet::::check_xcm_version_change( + crate::Pallet::::lazy_migration( VersionMigrationStage::MigrateSupportedVersion, Weight::zero(), ); @@ -411,7 +411,7 @@ mod benchmarks { #[block] { - crate::Pallet::::check_xcm_version_change( + crate::Pallet::::lazy_migration( VersionMigrationStage::MigrateVersionNotifiers, Weight::zero(), ); @@ -433,7 +433,7 @@ mod benchmarks { #[block] { - crate::Pallet::::check_xcm_version_change( + crate::Pallet::::lazy_migration( VersionMigrationStage::NotifyCurrentTargets(None), Weight::zero(), ); @@ -454,7 +454,7 @@ mod benchmarks { #[block] { - crate::Pallet::::check_xcm_version_change( + crate::Pallet::::lazy_migration( VersionMigrationStage::NotifyCurrentTargets(None), Weight::zero(), ); @@ -480,7 +480,7 @@ mod benchmarks { #[block] { - crate::Pallet::::check_xcm_version_change( + crate::Pallet::::lazy_migration( VersionMigrationStage::MigrateAndNotifyOldTargets, Weight::zero(), ); @@ -496,7 +496,7 @@ mod benchmarks { #[block] { - crate::Pallet::::check_xcm_version_change( + crate::Pallet::::lazy_migration( VersionMigrationStage::MigrateAndNotifyOldTargets, Weight::zero(), ); @@ -514,7 +514,7 @@ mod benchmarks { #[block] { - crate::Pallet::::check_xcm_version_change( + crate::Pallet::::lazy_migration( VersionMigrationStage::MigrateAndNotifyOldTargets, Weight::zero(), ); @@ -597,6 +597,89 @@ mod benchmarks { Ok(()) } + #[benchmark] + fn add_authorized_alias() -> Result<(), BenchmarkError> { + let who: T::AccountId = whitelisted_caller(); + let origin = RawOrigin::Signed(who.clone()); + let origin_location: VersionedLocation = + T::ExecuteXcmOrigin::try_origin(origin.clone().into()) + .map_err(|_| BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))? + .into(); + + // Give some multiple of ED + let balance = T::ExistentialDeposit::get() * 1000u32.into(); + let _ = + as frame_support::traits::Currency<_>>::make_free_balance_be(&who, balance); + + let mut existing_aliases = BoundedVec::::new(); + // prepopulate list with `max-1` aliases to benchmark worst case + for i in 1..MaxAuthorizedAliases::get() { + let alias = + Location::new(1, [Parachain(i), AccountId32 { network: None, id: [42_u8; 32] }]) + .into(); + let aliaser = OriginAliaser { location: alias, expiry: None }; + existing_aliases.try_push(aliaser).unwrap() + } + let ticket = TicketOf::::new(&who, aliasers_footprint(existing_aliases.len())) + .map_err(|_| BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))?; + let entry = AuthorizedAliasesEntry { aliasers: existing_aliases, ticket }; + AuthorizedAliases::::insert(&origin_location, entry); + + // now benchmark adding new alias + let aliaser: VersionedLocation = + Location::new(1, [Parachain(1234), AccountId32 { network: None, id: [42_u8; 32] }]) + .into(); + + #[extrinsic_call] + _(origin, Box::new(aliaser), None); + + Ok(()) + } + + #[benchmark] + fn remove_authorized_alias() -> Result<(), BenchmarkError> { + let who: T::AccountId = whitelisted_caller(); + let origin = RawOrigin::Signed(who.clone()); + let error = BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)); + let origin_location = + T::ExecuteXcmOrigin::try_origin(origin.clone().into()).map_err(|_| error.clone())?; + // remove `network` from inner `AccountId32` for easier matching of automatic AccountId -> + // Location conversions. + let origin_location: VersionedLocation = match origin_location.unpack() { + (0, [AccountId32 { network: _, id }]) => + Location::new(0, [AccountId32 { network: None, id: *id }]).into(), + _ => return Err(error.clone()), + }; + + // Give some multiple of ED + let balance = T::ExistentialDeposit::get() * 1000u32.into(); + let _ = + as frame_support::traits::Currency<_>>::make_free_balance_be(&who, balance); + + let mut existing_aliases = BoundedVec::::new(); + // prepopulate list with `max` aliases to benchmark worst case + for i in 1..MaxAuthorizedAliases::get() + 1 { + let alias = + Location::new(1, [Parachain(i), AccountId32 { network: None, id: [42_u8; 32] }]) + .into(); + let aliaser = OriginAliaser { location: alias, expiry: None }; + existing_aliases.try_push(aliaser).unwrap() + } + let ticket = TicketOf::::new(&who, aliasers_footprint(existing_aliases.len())) + .map_err(|_| error)?; + let entry = AuthorizedAliasesEntry { aliasers: existing_aliases, ticket }; + AuthorizedAliases::::insert(&origin_location, entry); + + // now benchmark removing an alias + let aliaser_to_remove: VersionedLocation = + Location::new(1, [Parachain(1), AccountId32 { network: None, id: [42_u8; 32] }]).into(); + + #[extrinsic_call] + _(origin, Box::new(aliaser_to_remove)); + + Ok(()) + } + impl_benchmark_test_suite!( Pallet, crate::mock::new_test_ext_with_balances(Vec::new()), diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index 1cf97f00d7d4a..ae4d0e3097eb6 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -38,8 +38,8 @@ use frame_support::{ }, pallet_prelude::*, traits::{ - Contains, ContainsPair, Currency, Defensive, EnsureOrigin, Get, LockableCurrency, - OriginTrait, WithdrawReasons, + Consideration, Contains, ContainsPair, Currency, Defensive, EnsureOrigin, Footprint, Get, + LockableCurrency, OriginTrait, WithdrawReasons, }, PalletId, }; @@ -52,7 +52,7 @@ use sp_runtime::{ AccountIdConversion, BadOrigin, BlakeTwo256, BlockNumberProvider, Dispatchable, Hash, Saturating, Zero, }, - Either, RuntimeDebug, + Either, RuntimeDebug, SaturatedConversion, }; use xcm::{latest::QueryResponseInfo, prelude::*}; use xcm_builder::{ @@ -62,13 +62,14 @@ use xcm_builder::{ use xcm_executor::{ traits::{ AssetTransferError, CheckSuspension, ClaimAssets, ConvertLocation, ConvertOrigin, - DropAssets, EventEmitter, MatchesFungible, OnResponse, Properties, QueryHandler, - QueryResponseStatus, RecordXcm, TransactAsset, TransferType, VersionChangeNotifier, - WeightBounds, XcmAssetTransfers, + DropAssets, EventEmitter, FeeManager, FeeReason, MatchesFungible, OnResponse, Properties, + QueryHandler, QueryResponseStatus, RecordXcm, TransactAsset, TransferType, + VersionChangeNotifier, WeightBounds, XcmAssetTransfers, }, AssetsInHolding, }; use xcm_runtime_apis::{ + authorized_aliases::{Error as AuthorizedAliasersApiError, OriginAliaser}, dry_run::{CallDryRunEffects, Error as XcmDryRunApiError, XcmDryRunEffects}, fees::Error as XcmPaymentApiError, trusted_query::Error as TrustedQueryApiError, @@ -76,7 +77,6 @@ use xcm_runtime_apis::{ #[cfg(any(feature = "try-runtime", test))] use sp_runtime::TryRuntimeError; -use xcm_executor::traits::{FeeManager, FeeReason}; pub trait WeightInfo { fn send() -> Weight; @@ -99,6 +99,8 @@ pub trait WeightInfo { fn new_query() -> Weight; fn take_response() -> Weight; fn claim_assets() -> Weight; + fn add_authorized_alias() -> Weight; + fn remove_authorized_alias() -> Weight; } /// fallback implementation @@ -183,6 +185,24 @@ impl WeightInfo for TestWeightInfo { fn claim_assets() -> Weight { Weight::from_parts(100_000_000, 0) } + + fn add_authorized_alias() -> Weight { + Weight::from_parts(100_000, 0) + } + + fn remove_authorized_alias() -> Weight { + Weight::from_parts(100_000, 0) + } +} + +#[derive(Clone, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)] +pub struct AuthorizedAliasesEntry> { + pub aliasers: BoundedVec, + pub ticket: Ticket, +} + +pub fn aliasers_footprint(aliasers_count: usize) -> Footprint { + Footprint::from_parts(aliasers_count, OriginAliaser::max_encoded_len()) } #[frame_support::pallet] @@ -200,6 +220,10 @@ pub mod pallet { /// An implementation of `Get` which just returns the latest XCM version which we can /// support. pub const CurrentXcmVersion: u32 = XCM_VERSION; + + #[derive(Debug, TypeInfo)] + /// The maximum number of distinct locations allowed as authorized aliases for a local origin. + pub const MaxAuthorizedAliases: u32 = 10; } const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); @@ -211,6 +235,7 @@ pub mod pallet { pub type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; + pub type TicketOf = ::AuthorizedAliasConsideration; #[pallet::config] /// The module configuration trait. @@ -225,6 +250,9 @@ pub mod pallet { /// The `Asset` matcher for `Currency`. type CurrencyMatcher: MatchesFungible>; + /// A means of providing some cost while Authorized Aliasers data is stored on-chain. + type AuthorizedAliasConsideration: Consideration; + /// Required origin for sending XCM messages. If successful, it resolves to `Location` /// which exists as an interior location within this chain's XCM context. type SendXcmOrigin: EnsureOrigin<::RuntimeOrigin, Success = Location>; @@ -543,6 +571,13 @@ pub mod pallet { AssetsClaimed { hash: H256, origin: Location, assets: VersionedAssets }, /// A XCM version migration finished. VersionMigrationFinished { version: XcmVersion }, + /// An `aliaser` location was authorized by `target` to alias it, authorization valid until + /// `expiry` block number. + AliasAuthorized { aliaser: Location, target: Location, expiry: Option }, + /// `target` removed alias authorization for `aliaser`. + AliasAuthorizationRemoved { aliaser: Location, target: Location }, + /// `target` removed all alias authorizations. + AliasesAuthorizationsRemoved { target: Location }, } #[pallet::origin] @@ -569,6 +604,13 @@ pub mod pallet { } } + /// A reason for this pallet placing a hold on funds. + #[pallet::composite_enum] + pub enum HoldReason { + /// The funds are held as storage deposit for an authorized alias. + AuthorizeAlias, + } + #[pallet::error] pub enum Error { /// The desired destination was unreachable, generally because there is a no way of routing @@ -626,6 +668,15 @@ pub mod pallet { /// Local XCM execution incomplete. #[codec(index = 24)] LocalExecutionIncomplete, + /// Too many locations authorized to alias origin. + #[codec(index = 25)] + TooManyAuthorizedAliases, + /// Expiry block number is in the past. + #[codec(index = 26)] + ExpiresInPast, + /// The alias to remove authorization for was not found. + #[codec(index = 27)] + AliasNotFound, } impl From for Error { @@ -647,7 +698,7 @@ pub mod pallet { } /// The status of a query. - #[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)] + #[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub enum QueryStatus { /// The query was sent but no response has yet been received. Pending { @@ -843,6 +894,18 @@ pub mod pallet { #[pallet::storage] pub(crate) type RecordedXcm = StorageValue<_, Xcm<()>>; + /// Map of authorized aliasers of local origins. Each local location can authorize a list of + /// other locations to alias into it. Each aliaser is only valid until its inner `expiry` + /// block number. + #[pallet::storage] + pub(super) type AuthorizedAliases = StorageMap< + _, + Blake2_128Concat, + VersionedLocation, + AuthorizedAliasesEntry, MaxAuthorizedAliases>, + OptionQuery, + >; + #[pallet::genesis_config] pub struct GenesisConfig { #[serde(skip)] @@ -871,7 +934,7 @@ pub mod pallet { if let Some(migration) = CurrentMigration::::get() { // Consume 10% of block at most let max_weight = T::BlockWeights::get().max_block / 10; - let (w, maybe_migration) = Self::check_xcm_version_change(migration, max_weight); + let (w, maybe_migration) = Self::lazy_migration(migration, max_weight); if maybe_migration.is_none() { Self::deposit_event(Event::VersionMigrationFinished { version: XCM_VERSION }); } @@ -1475,6 +1538,164 @@ pub mod pallet { weight_limit, ) } + + /// Authorize another `aliaser` location to alias into the local `origin` making this call. + /// The `aliaser` is only authorized until the provided `expiry` block number. + /// The call can also be used for a previously authorized alias in order to update its + /// `expiry` block number. + /// + /// Usually useful to allow your local account to be aliased into from a remote location + /// also under your control (like your account on another chain). + /// + /// WARNING: make sure the caller `origin` (you) trusts the `aliaser` location to act in + /// their/your name. Once authorized using this call, the `aliaser` can freely impersonate + /// `origin` in XCM programs executed on the local chain. + #[pallet::call_index(14)] + pub fn add_authorized_alias( + origin: OriginFor, + aliaser: Box, + expires: Option, + ) -> DispatchResult { + let signed_origin = ensure_signed(origin.clone())?; + let origin_location: Location = T::ExecuteXcmOrigin::ensure_origin(origin)?; + let new_aliaser: Location = + (*aliaser).try_into().map_err(|()| Error::::BadVersion)?; + ensure!(origin_location != new_aliaser, Error::::BadLocation); + // remove `network` from inner `AccountId32` for easier matching + let origin_location = match origin_location.unpack() { + (0, [AccountId32 { network: _, id }]) => + Location::new(0, [AccountId32 { network: None, id: *id }]), + _ => return Err(Error::::InvalidOrigin.into()), + }; + tracing::debug!(target: "xcm::pallet_xcm::add_authorized_alias", ?origin_location, ?new_aliaser, ?expires); + ensure!(origin_location != new_aliaser, Error::::BadLocation); + if let Some(expiry) = expires { + ensure!( + expiry > + frame_system::Pallet::::current_block_number().saturated_into::(), + Error::::ExpiresInPast + ); + } + let versioned_origin = VersionedLocation::from(origin_location.clone()); + let versioned_aliaser = VersionedLocation::from(new_aliaser.clone()); + let entry = if let Some(entry) = AuthorizedAliases::::get(&versioned_origin) { + // entry already exists, update it + let (mut aliasers, mut ticket) = (entry.aliasers, entry.ticket); + if let Some(aliaser) = + aliasers.iter_mut().find(|aliaser| aliaser.location == versioned_aliaser) + { + // if the aliaser already exists, just update its expiry block + aliaser.expiry = expires; + } else { + // if it doesn't, we try to add it + let aliaser = + OriginAliaser { location: versioned_aliaser.clone(), expiry: expires }; + aliasers.try_push(aliaser).map_err(|_| Error::::TooManyAuthorizedAliases)?; + // we try to update the ticket (the storage deposit) + ticket = ticket.update(&signed_origin, aliasers_footprint(aliasers.len()))?; + } + AuthorizedAliasesEntry { aliasers, ticket } + } else { + // add new entry with its first alias + let ticket = TicketOf::::new(&signed_origin, aliasers_footprint(1))?; + let aliaser = + OriginAliaser { location: versioned_aliaser.clone(), expiry: expires }; + let mut aliasers = BoundedVec::::new(); + aliasers.try_push(aliaser).map_err(|_| Error::::TooManyAuthorizedAliases)?; + AuthorizedAliasesEntry { aliasers, ticket } + }; + // write to storage + AuthorizedAliases::::insert(&versioned_origin, entry); + Self::deposit_event(Event::AliasAuthorized { + aliaser: new_aliaser, + target: origin_location, + expiry: expires, + }); + Ok(()) + } + + /// Remove a previously authorized `aliaser` from the list of locations that can alias into + /// the local `origin` making this call. + #[pallet::call_index(15)] + pub fn remove_authorized_alias( + origin: OriginFor, + aliaser: Box, + ) -> DispatchResult { + let signed_origin = ensure_signed(origin.clone())?; + let origin_location: Location = T::ExecuteXcmOrigin::ensure_origin(origin)?; + let to_remove: Location = (*aliaser).try_into().map_err(|()| Error::::BadVersion)?; + ensure!(origin_location != to_remove, Error::::BadLocation); + // remove `network` from inner `AccountId32` for easier matching + let origin_location = match origin_location.unpack() { + (0, [AccountId32 { network: _, id }]) => + Location::new(0, [AccountId32 { network: None, id: *id }]), + _ => return Err(Error::::InvalidOrigin.into()), + }; + tracing::debug!(target: "xcm::pallet_xcm::remove_authorized_alias", ?origin_location, ?to_remove); + ensure!(origin_location != to_remove, Error::::BadLocation); + // convert to latest versioned + let versioned_origin = VersionedLocation::from(origin_location.clone()); + let versioned_to_remove = VersionedLocation::from(to_remove.clone()); + AuthorizedAliases::::get(&versioned_origin) + .ok_or(Error::::AliasNotFound.into()) + .and_then(|entry| { + let (mut aliasers, mut ticket) = (entry.aliasers, entry.ticket); + let old_len = aliasers.len(); + aliasers.retain(|alias| versioned_to_remove.ne(&alias.location)); + let new_len = aliasers.len(); + if aliasers.is_empty() { + // remove entry altogether and return all storage deposit + ticket.drop(&signed_origin)?; + AuthorizedAliases::::remove(&versioned_origin); + Self::deposit_event(Event::AliasAuthorizationRemoved { + aliaser: to_remove, + target: origin_location, + }); + Ok(()) + } else if old_len != new_len { + // update aliasers and storage deposit + ticket = ticket.update(&signed_origin, aliasers_footprint(new_len))?; + let entry = AuthorizedAliasesEntry { aliasers, ticket }; + AuthorizedAliases::::insert(&versioned_origin, entry); + Self::deposit_event(Event::AliasAuthorizationRemoved { + aliaser: to_remove, + target: origin_location, + }); + Ok(()) + } else { + Err(Error::::AliasNotFound.into()) + } + }) + } + + /// Remove all previously authorized `aliaser`s that can alias into the local `origin` + /// making this call. + #[pallet::call_index(16)] + #[pallet::weight(T::WeightInfo::remove_authorized_alias())] + pub fn remove_all_authorized_aliases(origin: OriginFor) -> DispatchResult { + let signed_origin = ensure_signed(origin.clone())?; + let origin_location: Location = T::ExecuteXcmOrigin::ensure_origin(origin)?; + // remove `network` from inner `AccountId32` for easier matching + let origin_location = match origin_location.unpack() { + (0, [AccountId32 { network: _, id }]) => + Location::new(0, [AccountId32 { network: None, id: *id }]), + _ => return Err(Error::::InvalidOrigin.into()), + }; + tracing::debug!(target: "xcm::pallet_xcm::remove_all_authorized_aliases", ?origin_location); + // convert to latest versioned + let versioned_origin = VersionedLocation::from(origin_location.clone()); + if let Some(entry) = AuthorizedAliases::::get(&versioned_origin) { + // remove entry altogether and return all storage deposit + entry.ticket.drop(&signed_origin)?; + AuthorizedAliases::::remove(&versioned_origin); + Self::deposit_event(Event::AliasesAuthorizationsRemoved { + target: origin_location, + }); + Ok(()) + } else { + Err(Error::::AliasNotFound.into()) + } + } } } @@ -1557,7 +1778,7 @@ impl QueryHandler for Pallet { let response = response.into(); Queries::::insert( id, - QueryStatus::Ready { response, at: frame_system::Pallet::::block_number() }, + QueryStatus::Ready { response, at: frame_system::Pallet::::current_block_number() }, ); } } @@ -2334,7 +2555,7 @@ impl Pallet { /// Will always make progress, and will do its best not to use much more than `weight_cutoff` /// in doing so. - pub(crate) fn check_xcm_version_change( + pub(crate) fn lazy_migration( mut stage: VersionMigrationStage, weight_cutoff: Weight, ) -> (Weight, Option) { @@ -2731,6 +2952,40 @@ impl Pallet { }) } + /// Given a `destination` and XCM `message`, return assets to be charged as XCM delivery fees. + pub fn query_delivery_fees( + destination: VersionedLocation, + message: VersionedXcm<()>, + ) -> Result { + let result_version = destination.identify_version().max(message.identify_version()); + + let destination: Location = destination + .clone() + .try_into() + .map_err(|e| { + tracing::error!(target: "xcm::pallet_xcm::query_delivery_fees", ?e, ?destination, "Failed to convert versioned destination"); + XcmPaymentApiError::VersionedConversionFailed + })?; + + let message: Xcm<()> = + message.clone().try_into().map_err(|e| { + tracing::error!(target: "xcm::pallet_xcm::query_delivery_fees", ?e, ?message, "Failed to convert versioned message"); + XcmPaymentApiError::VersionedConversionFailed + })?; + + let (_, fees) = validate_send::(destination.clone(), message.clone()).map_err(|error| { + tracing::error!(target: "xcm::pallet_xcm::query_delivery_fees", ?error, ?destination, ?message, "Failed to validate send to destination"); + XcmPaymentApiError::Unroutable + })?; + + VersionedAssets::from(fees) + .into_version(result_version) + .map_err(|e| { + tracing::error!(target: "xcm::pallet_xcm::query_delivery_fees", ?e, ?result_version, "Failed to convert fees into version"); + XcmPaymentApiError::VersionedConversionFailed + }) + } + /// Given an Asset and a Location, returns if the provided location is a trusted reserve for the /// given asset. pub fn is_trusted_reserve( @@ -2740,8 +2995,7 @@ impl Pallet { let location: Location = location.try_into().map_err(|e| { tracing::debug!( target: "xcm::pallet_xcm::is_trusted_reserve", - "Asset version conversion failed with error: {:?}", - e, + ?e, "Failed to convert versioned location", ); TrustedQueryApiError::VersionedLocationConversionFailed })?; @@ -2749,8 +3003,7 @@ impl Pallet { let a: Asset = asset.try_into().map_err(|e| { tracing::debug!( target: "xcm::pallet_xcm::is_trusted_reserve", - "Location version conversion failed with error: {:?}", - e, + ?e, "Failed to convert versioned asset", ); TrustedQueryApiError::VersionedAssetConversionFailed })?; @@ -2766,53 +3019,78 @@ impl Pallet { let location: Location = location.try_into().map_err(|e| { tracing::debug!( target: "xcm::pallet_xcm::is_trusted_teleporter", - "Asset version conversion failed with error: {:?}", - e, + ?e, "Failed to convert versioned location", ); TrustedQueryApiError::VersionedLocationConversionFailed })?; let a: Asset = asset.try_into().map_err(|e| { tracing::debug!( target: "xcm::pallet_xcm::is_trusted_teleporter", - "Location version conversion failed with error: {:?}", - e, + ?e, "Failed to convert versioned asset", ); TrustedQueryApiError::VersionedAssetConversionFailed })?; Ok(::IsTeleporter::contains(&a, &location)) } - pub fn query_delivery_fees( - destination: VersionedLocation, - message: VersionedXcm<()>, - ) -> Result { - let result_version = destination.identify_version().max(message.identify_version()); - - let destination: Location = destination - .clone() - .try_into() - .map_err(|e| { - tracing::error!(target: "xcm::pallet_xcm::query_delivery_fees", ?e, ?destination, "Failed to convert versioned destination"); - XcmPaymentApiError::VersionedConversionFailed - })?; - - let message: Xcm<()> = - message.clone().try_into().map_err(|e| { - tracing::error!(target: "xcm::pallet_xcm::query_delivery_fees", ?e, ?message, "Failed to convert versioned message"); - XcmPaymentApiError::VersionedConversionFailed - })?; - - let (_, fees) = validate_send::(destination.clone(), message.clone()).map_err(|error| { - tracing::error!(target: "xcm::pallet_xcm::query_delivery_fees", ?error, ?destination, ?message, "Failed to validate send to destination"); - XcmPaymentApiError::Unroutable + /// Returns locations allowed to alias into and act as `target`. + pub fn authorized_aliasers( + target: VersionedLocation, + ) -> Result, AuthorizedAliasersApiError> { + let desired_version = target.identify_version(); + // storage entries are always latest version + let target: VersionedLocation = target.into_version(XCM_VERSION).map_err(|e| { + tracing::debug!( + target: "xcm::pallet_xcm::authorized_aliasers", + ?e, "Failed to convert versioned location", + ); + AuthorizedAliasersApiError::LocationVersionConversionFailed })?; - - VersionedAssets::from(fees) - .into_version(result_version) - .map_err(|e| { - tracing::error!(target: "xcm::pallet_xcm::query_delivery_fees", ?e, ?result_version, "Failed to convert fees into version"); - XcmPaymentApiError::VersionedConversionFailed + Ok(AuthorizedAliases::::get(&target) + .map(|authorized| { + authorized + .aliasers + .into_iter() + .filter_map(|aliaser| { + let OriginAliaser { location, expiry } = aliaser; + location + .into_version(desired_version) + .map(|location| OriginAliaser { location, expiry }) + .ok() + }) + .collect() }) + .unwrap_or_default()) + } + + /// Given an `origin` and a `target`, returns if the `origin` location was added by `target` as + /// an authorized aliaser. + /// + /// Effectively says whether `origin` is allowed to alias into and act as `target`. + pub fn is_authorized_alias( + origin: VersionedLocation, + target: VersionedLocation, + ) -> Result { + let desired_version = target.identify_version(); + let origin = origin.into_version(desired_version).map_err(|e| { + tracing::debug!( + target: "xcm::pallet_xcm::is_authorized_alias", + ?e, "mismatching origin and target versions", + ); + AuthorizedAliasersApiError::LocationVersionConversionFailed + })?; + Ok(Self::authorized_aliasers(target)?.into_iter().any(|aliaser| { + // `aliasers` and `origin` have already been transformed to `desired_version`, we + // can just directly compare them. + aliaser.location == origin && + aliaser + .expiry + .map(|expiry| { + frame_system::Pallet::::current_block_number().saturated_into::() < + expiry + }) + .unwrap_or(true) + })) } /// Create a new expectation of a query response with the querier being here. @@ -3556,6 +3834,23 @@ where } } +/// Filter for `(origin: Location, target: Location)` to find whether `target` has explicitly +/// authorized `origin` to alias it. +/// +/// Note: users can authorize other locations to alias them by using +/// `pallet_xcm::add_authorized_alias()`. +pub struct AuthorizedAliasers(PhantomData); +impl + Clone, T: Config> ContainsPair for AuthorizedAliasers { + fn contains(origin: &L, target: &L) -> bool { + let origin: VersionedLocation = origin.clone().into(); + let target: VersionedLocation = target.clone().into(); + tracing::trace!(target: "xcm::pallet_xcm::AuthorizedAliasers::contains", ?origin, ?target); + // return true if the `origin` has been explicitly authorized by `target` as aliaser, and + // the authorization has not expired + Pallet::::is_authorized_alias(origin, target).unwrap_or(false) + } +} + /// Filter for `Location` to find those which represent a strict majority approval of an /// identified plurality. /// diff --git a/polkadot/xcm/pallet-xcm/src/migration.rs b/polkadot/xcm/pallet-xcm/src/migration.rs index 80154f57ddfbf..194bb1680ec4d 100644 --- a/polkadot/xcm/pallet-xcm/src/migration.rs +++ b/polkadot/xcm/pallet-xcm/src/migration.rs @@ -170,6 +170,51 @@ pub mod data { } } + /// Implementation of `NeedsMigration` for `AuthorizedAliases` data. + impl, T: Config> NeedsMigration + for (&VersionedLocation, AuthorizedAliasesEntry, M>, PhantomData) + { + type MigratedData = (VersionedLocation, AuthorizedAliasesEntry, M>); + + fn needs_migration(&self, required_version: XcmVersion) -> bool { + self.0.identify_version() != required_version || + self.1 + .aliasers + .iter() + .any(|alias| alias.location.identify_version() != required_version) + } + + fn try_migrate( + self, + required_version: XcmVersion, + ) -> Result, ()> { + if !self.needs_migration(required_version) { + return Ok(None) + } + + let key = if self.0.identify_version() != required_version { + let Ok(converted_key) = self.0.clone().into_version(required_version) else { + return Err(()) + }; + converted_key + } else { + self.0.clone() + }; + + let mut new_aliases = BoundedVec::::new(); + let (aliasers, ticket) = (self.1.aliasers, self.1.ticket); + for alias in aliasers { + let OriginAliaser { mut location, expiry } = alias.clone(); + if location.identify_version() != required_version { + location = location.into_version(required_version)?; + } + new_aliases.try_push(OriginAliaser { location, expiry }).map_err(|_| ())?; + } + + Ok(Some((key, AuthorizedAliasesEntry { aliasers: new_aliases, ticket }))) + } + } + impl Pallet { /// Migrates relevant data to the `required_xcm_version`. pub(crate) fn migrate_data_to_xcm_version( @@ -323,6 +368,38 @@ pub mod data { >(&old_key, &new_key); weight.saturating_add(T::DbWeight::get().writes(1)); } + + // check and migrate `AuthorizedAliases` + let aliases_to_migrate = AuthorizedAliases::::iter().filter_map(|(id, data)| { + weight.saturating_add(T::DbWeight::get().reads(1)); + match (&id, data, PhantomData::).try_migrate(required_xcm_version) { + Ok(Some((new_id, new_data))) => Some((id, new_id, new_data)), + Ok(None) => None, + Err(_) => { + tracing::error!( + target: LOG_TARGET, + ?id, + ?required_xcm_version, + "`AuthorizedAliases` cannot be migrated!" + ); + None + }, + } + }); + let mut count = 0; + for (old_id, new_id, new_data) in aliases_to_migrate { + tracing::info!( + target: LOG_TARGET, + ?new_id, + ?new_data, + "Migrating `AuthorizedAliases`" + ); + AuthorizedAliases::::remove(old_id); + AuthorizedAliases::::insert(new_id, new_data); + count = count + 1; + } + // two writes per key, one to remove old entry, one to write new entry + weight.saturating_add(T::DbWeight::get().writes(count * 2)); } } } diff --git a/polkadot/xcm/pallet-xcm/src/mock.rs b/polkadot/xcm/pallet-xcm/src/mock.rs index a3062964627da..f7ba2cdc91d4a 100644 --- a/polkadot/xcm/pallet-xcm/src/mock.rs +++ b/polkadot/xcm/pallet-xcm/src/mock.rs @@ -19,8 +19,8 @@ pub use core::cell::RefCell; use frame_support::{ construct_runtime, derive_impl, parameter_types, traits::{ - AsEnsureOriginWithArg, ConstU128, ConstU32, Contains, Equals, Everything, EverythingBut, - Nothing, + fungible::HoldConsideration, AsEnsureOriginWithArg, ConstU128, ConstU32, Contains, Equals, + Everything, EverythingBut, Footprint, Nothing, }, weights::Weight, }; @@ -28,7 +28,10 @@ use frame_system::EnsureRoot; use polkadot_parachain_primitives::primitives::Id as ParaId; use polkadot_runtime_parachains::origin; use sp_core::H256; -use sp_runtime::{traits::IdentityLookup, AccountId32, BuildStorage}; +use sp_runtime::{ + traits::{Convert, IdentityLookup}, + AccountId32, BuildStorage, +}; use xcm::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom, @@ -527,10 +530,20 @@ impl xcm_executor::Config for XcmConfig { type XcmRecorder = XcmPallet; } +/// Converts a local signed origin into an XCM location. Forms the basis for local origins +/// sending/executing XCMs. pub type LocalOriginToLocation = SignedToAccountId32; parameter_types! { pub static AdvertisedXcmVersion: pallet_xcm::XcmVersion = 4; + pub const AuthorizeAliasHoldReason: RuntimeHoldReason = RuntimeHoldReason::XcmPallet(pallet_xcm::HoldReason::AuthorizeAlias); +} + +pub struct ConvertDeposit; +impl Convert for ConvertDeposit { + fn convert(a: Footprint) -> u128 { + (a.count * 2 + a.size) as u128 + } } pub struct XcmTeleportFiltered; @@ -565,6 +578,8 @@ impl pallet_xcm::Config for Test { type MaxRemoteLockConsumers = frame_support::traits::ConstU32<0>; type RemoteLockConsumerIdentifier = (); type WeightInfo = TestWeightInfo; + type AuthorizedAliasConsideration = + HoldConsideration; } impl origin::Config for Test {} diff --git a/polkadot/xcm/pallet-xcm/src/tests/mod.rs b/polkadot/xcm/pallet-xcm/src/tests/mod.rs index b215425cefdab..a49f6345375ed 100644 --- a/polkadot/xcm/pallet-xcm/src/tests/mod.rs +++ b/polkadot/xcm/pallet-xcm/src/tests/mod.rs @@ -19,22 +19,26 @@ pub(crate) mod assets_transfer; use crate::{ + aliasers_footprint, migration::data::NeedsMigration, mock::*, pallet::{LockedFungibles, RemoteLockedFungibles, SupportedVersion}, - AssetTraps, Config, CurrentMigration, Error, ExecuteControllerWeightInfo, - LatestVersionedLocation, Pallet, Queries, QueryStatus, RecordedXcm, RemoteLockedFungibleRecord, - ShouldRecordXcm, VersionDiscoveryQueue, VersionMigrationStage, VersionNotifiers, - VersionNotifyTargets, WeightInfo, + AssetTraps, AuthorizedAliasers, Config, CurrentMigration, Error, ExecuteControllerWeightInfo, + LatestVersionedLocation, MaxAuthorizedAliases, Pallet, Queries, QueryStatus, RecordedXcm, + RemoteLockedFungibleRecord, ShouldRecordXcm, VersionDiscoveryQueue, VersionMigrationStage, + VersionNotifiers, VersionNotifyTargets, WeightInfo, }; use bounded_collections::BoundedVec; use frame_support::{ assert_err_ignore_postinfo, assert_noop, assert_ok, - traits::{Currency, Hooks}, + traits::{ContainsPair, Currency, Hooks}, weights::Weight, }; use polkadot_parachain_primitives::primitives::Id as ParaId; -use sp_runtime::traits::{AccountIdConversion, BlakeTwo256, Hash}; +use sp_runtime::{ + traits::{AccountIdConversion, BlakeTwo256, BlockNumberProvider, Hash}, + SaturatedConversion, TokenError, +}; use xcm::{latest::QueryResponseInfo, prelude::*}; use xcm_builder::AllowKnownQueryResponses; use xcm_executor::{ @@ -44,7 +48,7 @@ use xcm_executor::{ const ALICE: AccountId = AccountId::new([0u8; 32]); const BOB: AccountId = AccountId::new([1u8; 32]); -const INITIAL_BALANCE: u128 = 100; +const INITIAL_BALANCE: u128 = 1000; const SEND_AMOUNT: u128 = 10; const FEE_AMOUNT: u128 = 2; @@ -403,6 +407,184 @@ fn execute_withdraw_to_deposit_works() { }); } +/// Test XCM authorized aliases. +#[test] +fn authorized_aliases_work() { + let balances = vec![(ALICE, INITIAL_BALANCE)]; + new_test_ext_with_balances(balances).execute_with(|| { + // --- alias is same as origin + let alias: Location = AccountId32 { network: None, id: BOB.into() }.into(); + assert_eq!( + XcmPallet::add_authorized_alias( + RuntimeOrigin::signed(BOB), + Box::new(alias.into()), + None + ), + Err(Error::::BadLocation.into()) + ); + + // --- alias already expired + let alias = Location::here(); + let expires = Some(System::current_block_number().saturated_into::()); + assert_eq!( + XcmPallet::add_authorized_alias( + RuntimeOrigin::signed(BOB), + Box::new(alias.clone().into()), + expires + ), + Err(Error::::ExpiresInPast.into()) + ); + + // --- storage deposit not covered (BOB has no funds) + assert_eq!( + XcmPallet::add_authorized_alias( + RuntimeOrigin::signed(BOB), + Box::new(alias.clone().into()), + None + ), + Err(sp_runtime::DispatchError::Token(TokenError::FundsUnavailable)) + ); + + // --- setting single alias works + let who = ALICE; + let first_alias: Location = AccountId32 { network: Some(Polkadot), id: BOB.into() }.into(); + let total_balance_before = >::total_balance(&who); + let free_balance = >::free_balance(&who); + assert_eq!(free_balance, total_balance_before); + assert_ok!(XcmPallet::add_authorized_alias( + RuntimeOrigin::signed(who.clone()), + Box::new(first_alias.clone().into()), + None + )); + let footprint = aliasers_footprint(1); + let deposit = footprint.size + 2 * footprint.count; + let free_balance = >::free_balance(&who); + let total_balance = >::total_balance(&who); + assert_eq!(total_balance, total_balance_before); + assert_eq!(total_balance, free_balance + deposit as u128); + + // --- setting same alias again only updates its expiry + assert_ok!(XcmPallet::add_authorized_alias( + RuntimeOrigin::signed(who.clone()), + Box::new(first_alias.clone().into()), + Some(100) + )); + // deposit is unchanged + assert_eq!(total_balance - deposit as u128, >::free_balance(&who)); + + // --- setting max number of aliases works + let mut aliases = vec![]; + for i in 1..MaxAuthorizedAliases::get() { + let alias = Location::new(0, [Parachain(OTHER_PARA_ID), GeneralIndex(i as u128)]); + assert_ok!(XcmPallet::add_authorized_alias( + RuntimeOrigin::signed(who.clone()), + Box::new(alias.clone().into()), + None + )); + let footprint = aliasers_footprint(i as usize + 1); + let deposit = (footprint.size + 2 * footprint.count) as u128; + assert_eq!(total_balance - deposit, >::free_balance(&who)); + aliases.push(alias); + } + + // deposit held for MaxAliases + let footprint = aliasers_footprint(MaxAuthorizedAliases::get() as usize); + let deposit = (footprint.size + 2 * footprint.count) as u128; + assert_eq!(total_balance - deposit, >::free_balance(&who)); + + // --- adding more than max aliases is not allowed + let alias = Location::new( + 0, + [Parachain(OTHER_PARA_ID), GeneralIndex(MaxAuthorizedAliases::get() as u128 + 100)], + ); + assert_eq!( + XcmPallet::add_authorized_alias( + RuntimeOrigin::signed(who.clone()), + Box::new(alias.clone().into()), + None + ), + Err(Error::::TooManyAuthorizedAliases.into()) + ); + + // --- remove one alias + let target: Location = AccountId32 { network: None, id: who.clone().into() }.into(); + assert_ok!(XcmPallet::remove_authorized_alias( + RuntimeOrigin::signed(who.clone()), + Box::new(first_alias.clone().into()), + )); + // deposit held for MaxAliases - 1 + let footprint = aliasers_footprint(MaxAuthorizedAliases::get() as usize - 1); + let deposit = (footprint.size + 2 * footprint.count) as u128; + assert_eq!(total_balance - deposit, >::free_balance(&who)); + // de-authorization event + assert_eq!( + last_events(1), + vec![RuntimeEvent::XcmPallet(crate::Event::AliasAuthorizationRemoved { + aliaser: first_alias.into(), + target: target.clone().into(), + })] + ); + + // --- adding one more is now allowed + assert_ok!(XcmPallet::add_authorized_alias( + RuntimeOrigin::signed(who.clone()), + Box::new(alias.clone().into()), + None + )); + assert_eq!( + last_events(1), + vec![RuntimeEvent::XcmPallet(crate::Event::AliasAuthorized { + aliaser: alias.clone().into(), + target: target.clone().into(), + expiry: None, + })] + ); + + // --- un-authorized alias is correctly filtered/denied + assert!(!AuthorizedAliasers::::contains(&Location::here(), &target)); + // --- authorized aliases are correctly allowed + for i in 1..MaxAuthorizedAliases::get() { + assert!(AuthorizedAliasers::::contains(&aliases[i as usize - 1], &target)); + } + // --- remove alias then verify no longer allowed + assert_ok!(XcmPallet::remove_authorized_alias( + RuntimeOrigin::signed(who.clone()), + Box::new(aliases[0].clone().into()), + )); + assert!(!AuthorizedAliasers::::contains(&aliases[0], &target)); + + // --- remove nonexistent alias + assert_eq!( + XcmPallet::remove_authorized_alias( + RuntimeOrigin::signed(ALICE), + Box::new(Location::parent().into()) + ), + Err(Error::::AliasNotFound.into()) + ); + + // --- remove nonexistent alias (BOB has no registered aliases) + assert_eq!( + XcmPallet::remove_authorized_alias( + RuntimeOrigin::signed(BOB), + Box::new(Location::parent().into()), + ), + Err(Error::::AliasNotFound.into()) + ); + + // --- remove all aliases then verify all deposit is returned + assert_ok!(XcmPallet::remove_all_authorized_aliases(RuntimeOrigin::signed(who.clone()))); + // de-authorization event + assert_eq!( + last_events(1), + vec![RuntimeEvent::XcmPallet(crate::Event::AliasesAuthorizationsRemoved { + target: target.clone().into(), + })] + ); + // all deposit is returned + assert_eq!(total_balance_before, >::free_balance(&who)); + }); +} + /// Test drop/claim assets. #[test] fn trapped_assets_can_be_claimed() { @@ -1066,7 +1248,7 @@ fn subscription_side_upgrades_work_with_multistage_notify() { let mut counter = 0; while let Some(migration) = maybe_migration.take() { counter += 1; - let (_, m) = XcmPallet::check_xcm_version_change(migration, Weight::zero()); + let (_, m) = XcmPallet::lazy_migration(migration, Weight::zero()); maybe_migration = m; } assert_eq!(counter, 4); @@ -1219,7 +1401,7 @@ fn multistage_migration_works() { let mut weight_used = Weight::zero(); while let Some(migration) = maybe_migration.take() { counter += 1; - let (w, m) = XcmPallet::check_xcm_version_change(migration, Weight::zero()); + let (w, m) = XcmPallet::lazy_migration(migration, Weight::zero()); maybe_migration = m; weight_used.saturating_accrue(w); } diff --git a/polkadot/xcm/src/lib.rs b/polkadot/xcm/src/lib.rs index 7f5d12b10ab77..76dc45fb2fe30 100644 --- a/polkadot/xcm/src/lib.rs +++ b/polkadot/xcm/src/lib.rs @@ -140,12 +140,17 @@ macro_rules! versioned_type { } impl IntoVersion for $n { fn into_version(self, n: Version) -> Result { - Ok(match n { - 3 => Self::V3(self.try_into()?), - 4 => Self::V4(self.try_into()?), - 5 => Self::V5(self.try_into()?), - _ => return Err(()), - }) + let version = self.identify_version(); + if version == n { + Ok(self) + } else { + Ok(match n { + 3 => Self::V3(self.try_into()?), + 4 => Self::V4(self.try_into()?), + 5 => Self::V5(self.try_into()?), + _ => return Err(()), + }) + } } } impl From<$v3> for $n { diff --git a/polkadot/xcm/xcm-builder/src/asset_exchange/single_asset_adapter/mock.rs b/polkadot/xcm/xcm-builder/src/asset_exchange/single_asset_adapter/mock.rs index 1184aba6ea43f..30136b004a480 100644 --- a/polkadot/xcm/xcm-builder/src/asset_exchange/single_asset_adapter/mock.rs +++ b/polkadot/xcm/xcm-builder/src/asset_exchange/single_asset_adapter/mock.rs @@ -23,7 +23,8 @@ use frame_support::{ fungible::{self, NativeFromLeft, NativeOrWithId}, fungibles::Mutate, tokens::imbalance::ResolveAssetTo, - AsEnsureOriginWithArg, Equals, Everything, Nothing, OriginTrait, PalletInfoAccess, + AsEnsureOriginWithArg, Disabled, Equals, Everything, Nothing, OriginTrait, + PalletInfoAccess, }, PalletId, }; @@ -293,6 +294,8 @@ parameter_types! { pub const NoNetwork: Option = None; } +/// Converts a local signed origin into an XCM location. Forms the basis for local origins +/// sending/executing XCMs. pub type LocalOriginToLocation = SignedToAccountIndex64; impl pallet_xcm::Config for Runtime { @@ -333,6 +336,8 @@ impl pallet_xcm::Config for Runtime { type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; type RuntimeEvent = RuntimeEvent; + // Aliasing is disabled: xcm_executor::Config::Aliasers is set to `Nothing`. + type AuthorizedAliasConsideration = Disabled; } pub const INITIAL_BALANCE: Balance = 1_000_000_000; diff --git a/polkadot/xcm/xcm-builder/src/tests/pay/mock.rs b/polkadot/xcm/xcm-builder/src/tests/pay/mock.rs index 3a0e17b97dced..c578e7667864f 100644 --- a/polkadot/xcm/xcm-builder/src/tests/pay/mock.rs +++ b/polkadot/xcm/xcm-builder/src/tests/pay/mock.rs @@ -16,7 +16,7 @@ use super::*; -use frame_support::traits::{AsEnsureOriginWithArg, Nothing}; +use frame_support::traits::{AsEnsureOriginWithArg, Disabled, Nothing}; use frame_support::derive_impl; @@ -162,6 +162,8 @@ impl MaybeEquivalence } } +/// Converts a local signed origin into an XCM location. Forms the basis for local origins +/// sending/executing XCMs. pub type LocalOriginToLocation = SignedToAccountId32; pub type LocalAssetsTransactor = FungiblesAdapter< Assets, @@ -279,6 +281,7 @@ impl pallet_xcm::Config for Test { type RemoteLockConsumerIdentifier = (); type WeightInfo = pallet_xcm::TestWeightInfo; type AdminOrigin = EnsureRoot; + type AuthorizedAliasConsideration = Disabled; } pub const UNITS: Balance = 1_000_000_000_000; diff --git a/polkadot/xcm/xcm-builder/tests/mock/mod.rs b/polkadot/xcm/xcm-builder/tests/mock/mod.rs index 76656e3214789..4a12ea257d2ef 100644 --- a/polkadot/xcm/xcm-builder/tests/mock/mod.rs +++ b/polkadot/xcm/xcm-builder/tests/mock/mod.rs @@ -18,7 +18,7 @@ use codec::Encode; use core::cell::RefCell; use frame_support::{ construct_runtime, derive_impl, parameter_types, - traits::{Everything, Nothing}, + traits::{Disabled, Everything, Nothing}, weights::Weight, }; use frame_system::EnsureRoot; @@ -198,6 +198,8 @@ impl xcm_executor::Config for XcmConfig { type XcmRecorder = XcmPallet; } +/// Converts a local signed origin into an XCM location. Forms the basis for local origins +/// sending/executing XCMs. pub type LocalOriginToLocation = SignedToAccountId32; impl pallet_xcm::Config for Runtime { @@ -225,6 +227,8 @@ impl pallet_xcm::Config for Runtime { type RemoteLockConsumerIdentifier = (); type WeightInfo = pallet_xcm::TestWeightInfo; type AdminOrigin = EnsureRoot; + // Aliasing is disabled: xcm_executor::Config::Aliasers is set to `Nothing`. + type AuthorizedAliasConsideration = Disabled; } impl origin::Config for Runtime {} diff --git a/polkadot/xcm/xcm-runtime-apis/src/authorized_aliases.rs b/polkadot/xcm/xcm-runtime-apis/src/authorized_aliases.rs new file mode 100644 index 0000000000000..61bdba3caa237 --- /dev/null +++ b/polkadot/xcm/xcm-runtime-apis/src/authorized_aliases.rs @@ -0,0 +1,49 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Contains runtime APIs for querying XCM authorized aliases. + +use alloc::vec::Vec; +use codec::{Decode, Encode}; +use frame_support::pallet_prelude::{MaxEncodedLen, TypeInfo}; +use xcm::VersionedLocation; + +/// Entry of an authorized aliaser for a local origin. The aliaser `location` is only authorized +/// until its inner `expiry` block number. +#[derive(Clone, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)] +pub struct OriginAliaser { + pub location: VersionedLocation, + pub expiry: Option, +} + +sp_api::decl_runtime_apis! { + /// API for querying XCM authorized aliases + pub trait AuthorizedAliasersApi { + /// Returns locations allowed to alias into and act as `target`. + fn authorized_aliasers(target: VersionedLocation) -> Result, Error>; + /// Returns whether `origin` is allowed to alias into and act as `target`. + fn is_authorized_alias(origin: VersionedLocation, target: VersionedLocation) -> Result; + } +} + +/// `AuthorizedAliasersApi` Runtime APIs errors. +#[derive(Copy, Clone, Encode, Decode, Eq, PartialEq, Debug, TypeInfo)] +pub enum Error { + /// Converting a location from one version to another failed. + #[codec(index = 0)] + LocationVersionConversionFailed, +} diff --git a/polkadot/xcm/xcm-runtime-apis/src/lib.rs b/polkadot/xcm/xcm-runtime-apis/src/lib.rs index c6754ffb2d0cf..7b42b01e716d7 100644 --- a/polkadot/xcm/xcm-runtime-apis/src/lib.rs +++ b/polkadot/xcm/xcm-runtime-apis/src/lib.rs @@ -20,17 +20,16 @@ extern crate alloc; +/// Runtime APIs for querying XCM authorized aliases. +pub mod authorized_aliases; /// Exposes runtime APIs for various XCM-related conversions. pub mod conversions; - /// Dry-run API. /// Given an extrinsic or an XCM program, it returns the outcome of its execution. pub mod dry_run; - /// Fee estimation API. /// Given an XCM program, it will return the fees needed to execute it properly or send it. pub mod fees; - -// Exposes runtime API for querying whether a Location is trusted as a reserve or teleporter for a -// given Asset. +/// Exposes runtime API for querying whether a Location is trusted as a reserve or teleporter for a +/// given Asset. pub mod trusted_query; diff --git a/polkadot/xcm/xcm-runtime-apis/src/trusted_query.rs b/polkadot/xcm/xcm-runtime-apis/src/trusted_query.rs index be3e0492f8d5f..1aad361173db6 100644 --- a/polkadot/xcm/xcm-runtime-apis/src/trusted_query.rs +++ b/polkadot/xcm/xcm-runtime-apis/src/trusted_query.rs @@ -25,7 +25,7 @@ use xcm::{VersionedAsset, VersionedLocation}; pub type XcmTrustedQueryResult = Result; sp_api::decl_runtime_apis! { - // API for querying trusted reserves and trusted teleporters. + /// API for querying trusted reserves and trusted teleporters. pub trait TrustedQueryApi { /// Returns if the location is a trusted reserve for the asset. /// @@ -45,7 +45,9 @@ sp_api::decl_runtime_apis! { #[derive(Copy, Clone, Encode, Decode, Eq, PartialEq, Debug, TypeInfo)] pub enum Error { /// Converting a versioned Asset structure from one version to another failed. + #[codec(index = 0)] VersionedAssetConversionFailed, /// Converting a versioned Location structure from one version to another failed. + #[codec(index = 1)] VersionedLocationConversionFailed, } diff --git a/polkadot/xcm/xcm-runtime-apis/tests/mock.rs b/polkadot/xcm/xcm-runtime-apis/tests/mock.rs index 9c5be8a563404..05c5dcbbef251 100644 --- a/polkadot/xcm/xcm-runtime-apis/tests/mock.rs +++ b/polkadot/xcm/xcm-runtime-apis/tests/mock.rs @@ -26,8 +26,8 @@ use frame_support::{ BuildStorage, SaturatedConversion, }, traits::{ - AsEnsureOriginWithArg, ConstU128, ConstU32, Contains, ContainsPair, Everything, Nothing, - OriginTrait, + AsEnsureOriginWithArg, ConstU128, ConstU32, Contains, ContainsPair, Disabled, Everything, + Nothing, OriginTrait, }, weights::WeightToFee as WeightToFeeT, }; @@ -351,6 +351,8 @@ where } } +/// Converts a local signed origin into an XCM location. Forms the basis for local origins +/// sending/executing XCMs. pub type LocalOriginToLocation = SignedToAccountIndex64; impl pallet_xcm::Config for TestRuntime { @@ -377,6 +379,7 @@ impl pallet_xcm::Config for TestRuntime { type MaxRemoteLockConsumers = ConstU32<0>; type RemoteLockConsumerIdentifier = (); type WeightInfo = TestWeightInfo; + type AuthorizedAliasConsideration = Disabled; } #[allow(dead_code)] diff --git a/polkadot/xcm/xcm-simulator/example/src/parachain/mod.rs b/polkadot/xcm/xcm-simulator/example/src/parachain/mod.rs index bfb455aba3f93..ed7870163d7d8 100644 --- a/polkadot/xcm/xcm-simulator/example/src/parachain/mod.rs +++ b/polkadot/xcm/xcm-simulator/example/src/parachain/mod.rs @@ -22,7 +22,9 @@ pub use xcm_config::*; use core::marker::PhantomData; use frame_support::{ construct_runtime, derive_impl, parameter_types, - traits::{ConstU128, ContainsPair, EnsureOrigin, EnsureOriginWithArg, Everything, Nothing}, + traits::{ + ConstU128, ContainsPair, Disabled, EnsureOrigin, EnsureOriginWithArg, Everything, Nothing, + }, weights::{constants::WEIGHT_REF_TIME_PER_SECOND, Weight}, }; use frame_system::EnsureRoot; @@ -166,6 +168,7 @@ impl pallet_xcm::Config for Runtime { type RemoteLockConsumerIdentifier = (); type WeightInfo = pallet_xcm::TestWeightInfo; type AdminOrigin = EnsureRoot; + type AuthorizedAliasConsideration = Disabled; } type Block = frame_system::mocking::MockBlock; diff --git a/polkadot/xcm/xcm-simulator/example/src/relay_chain/mod.rs b/polkadot/xcm/xcm-simulator/example/src/relay_chain/mod.rs index c843f52d41a97..5b09a27e4e744 100644 --- a/polkadot/xcm/xcm-simulator/example/src/relay_chain/mod.rs +++ b/polkadot/xcm/xcm-simulator/example/src/relay_chain/mod.rs @@ -22,7 +22,8 @@ pub use xcm_config::*; use frame_support::{ construct_runtime, derive_impl, parameter_types, traits::{ - AsEnsureOriginWithArg, ConstU128, Everything, Nothing, ProcessMessage, ProcessMessageError, + AsEnsureOriginWithArg, ConstU128, Disabled, Everything, Nothing, ProcessMessage, + ProcessMessageError, }, weights::{Weight, WeightMeter}, }; @@ -119,6 +120,7 @@ impl pallet_xcm::Config for Runtime { type RemoteLockConsumerIdentifier = (); type WeightInfo = pallet_xcm::TestWeightInfo; type AdminOrigin = EnsureRoot; + type AuthorizedAliasConsideration = Disabled; } impl origin::Config for Runtime {} diff --git a/polkadot/xcm/xcm-simulator/fuzzer/src/parachain.rs b/polkadot/xcm/xcm-simulator/fuzzer/src/parachain.rs index 7e29a843ebaba..ee3853cf27c05 100644 --- a/polkadot/xcm/xcm-simulator/fuzzer/src/parachain.rs +++ b/polkadot/xcm/xcm-simulator/fuzzer/src/parachain.rs @@ -19,7 +19,7 @@ use codec::{Decode, Encode}; use frame_support::{ construct_runtime, derive_impl, parameter_types, - traits::{Everything, Nothing}, + traits::{Disabled, Everything, Nothing}, weights::{constants::WEIGHT_REF_TIME_PER_SECOND, Weight}, }; @@ -341,6 +341,7 @@ impl pallet_xcm::Config for Runtime { type RemoteLockConsumerIdentifier = (); type WeightInfo = pallet_xcm::TestWeightInfo; type AdminOrigin = EnsureRoot; + type AuthorizedAliasConsideration = Disabled; } construct_runtime!( diff --git a/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs b/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs index e5c37531fb10a..2eec1a79b4a45 100644 --- a/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs +++ b/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs @@ -18,7 +18,7 @@ use frame_support::{ construct_runtime, derive_impl, parameter_types, - traits::{Everything, Nothing, ProcessMessage, ProcessMessageError}, + traits::{Disabled, Everything, Nothing, ProcessMessage, ProcessMessageError}, weights::{Weight, WeightMeter}, }; @@ -180,6 +180,7 @@ impl pallet_xcm::Config for Runtime { type RemoteLockConsumerIdentifier = (); type WeightInfo = pallet_xcm::TestWeightInfo; type AdminOrigin = EnsureRoot; + type AuthorizedAliasConsideration = Disabled; } impl origin::Config for Runtime {} diff --git a/prdoc/pr_6336.prdoc b/prdoc/pr_6336.prdoc new file mode 100644 index 0000000000000..4858f59805b05 --- /dev/null +++ b/prdoc/pr_6336.prdoc @@ -0,0 +1,66 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: "pallet-xcm: add support to authorize aliases" + +doc: + - audience: Runtime User + description: | + Added new `add_authorized_alias()` and `remove_authorized_alias()` calls to `pallet-xcm`. + These can be used by a "caller" to explicitly authorize another location to alias into the "caller" origin. + Usually useful to allow one's local account to be aliased into from a remote location also under + one's control (one's account on another chain). + WARNING: make sure that you as the caller `origin` trust the `aliaser` location to act in your name on this + chain. Once authorized using this call, the `aliaser` can freely impersonate `origin` in XCM programs + executed on the local chain. + + - audience: Runtime Dev + description: | + Added `AuthorizedAliasers` type exposed by `pallet-xcm`, that acts as a filter for explicitly authorized + aliases using `pallet-xcm::add_authorized_alias()` and `pallet-xcm::remove_authorized_alias()`. + Runtime developers can simply plug this `pallet-xcm::AuthorizedAliasers` type in their runtime's `XcmConfig`, + specifically in `::Aliasers`. + +crates: + - name: frame-support + bump: minor + - name: pallet-xcm + bump: major + - name: staging-xcm + bump: patch + - name: xcm-runtime-apis + bump: minor + - name: staging-xcm-builder + bump: major + - name: westend-runtime + bump: major + - name: rococo-runtime + bump: major + - name: asset-hub-rococo-runtime + bump: major + - name: asset-hub-westend-runtime + bump: major + - name: bridge-hub-rococo-runtime + bump: major + - name: bridge-hub-westend-runtime + bump: major + - name: collectives-westend-runtime + bump: major + - name: coretime-rococo-runtime + bump: major + - name: coretime-westend-runtime + bump: major + - name: people-rococo-runtime + bump: major + - name: people-westend-runtime + bump: major + - name: penpal-runtime + bump: major + - name: rococo-parachain-runtime + bump: major + - name: pallet-contracts-mock-network + bump: major + - name: pallet-revive-mock-network + bump: major + - name: xcm-simulator-example + bump: major diff --git a/substrate/frame/contracts/mock-network/src/parachain.rs b/substrate/frame/contracts/mock-network/src/parachain.rs index 2c24682ae91d9..01dc1ff7eacbb 100644 --- a/substrate/frame/contracts/mock-network/src/parachain.rs +++ b/substrate/frame/contracts/mock-network/src/parachain.rs @@ -24,7 +24,9 @@ use crate::{ use core::marker::PhantomData; use frame_support::{ construct_runtime, derive_impl, parameter_types, - traits::{AsEnsureOriginWithArg, Contains, ContainsPair, Everything, EverythingBut, Nothing}, + traits::{ + AsEnsureOriginWithArg, Contains, ContainsPair, Disabled, Everything, EverythingBut, Nothing, + }, weights::{ constants::{WEIGHT_PROOF_SIZE_PER_MB, WEIGHT_REF_TIME_PER_SECOND}, Weight, @@ -324,6 +326,8 @@ impl pallet_xcm::Config for Runtime { type RemoteLockConsumerIdentifier = (); type WeightInfo = pallet_xcm::TestWeightInfo; type AdminOrigin = EnsureRoot; + // Aliasing is disabled: xcm_executor::Config::Aliasers is set to `Nothing`. + type AuthorizedAliasConsideration = Disabled; } type Block = frame_system::mocking::MockBlock; diff --git a/substrate/frame/contracts/mock-network/src/relay_chain.rs b/substrate/frame/contracts/mock-network/src/relay_chain.rs index d6c092d4c8343..0e60e3df6e19d 100644 --- a/substrate/frame/contracts/mock-network/src/relay_chain.rs +++ b/substrate/frame/contracts/mock-network/src/relay_chain.rs @@ -18,7 +18,7 @@ use frame_support::{ construct_runtime, derive_impl, parameter_types, - traits::{Contains, Everything, Nothing}, + traits::{Contains, Disabled, Everything, Nothing}, weights::Weight, }; @@ -211,6 +211,8 @@ impl pallet_xcm::Config for Runtime { type RemoteLockConsumerIdentifier = (); type WeightInfo = pallet_xcm::TestWeightInfo; type AdminOrigin = EnsureRoot; + // Aliasing is disabled: xcm_executor::Config::Aliasers is set to `Nothing`. + type AuthorizedAliasConsideration = Disabled; } impl origin::Config for Runtime {} diff --git a/substrate/frame/revive/mock-network/src/parachain.rs b/substrate/frame/revive/mock-network/src/parachain.rs index fcb6beabce353..9a07517588f31 100644 --- a/substrate/frame/revive/mock-network/src/parachain.rs +++ b/substrate/frame/revive/mock-network/src/parachain.rs @@ -24,7 +24,9 @@ use crate::{ use core::marker::PhantomData; use frame_support::{ construct_runtime, derive_impl, parameter_types, - traits::{AsEnsureOriginWithArg, Contains, ContainsPair, Everything, EverythingBut, Nothing}, + traits::{ + AsEnsureOriginWithArg, Contains, ContainsPair, Disabled, Everything, EverythingBut, Nothing, + }, weights::{ constants::{WEIGHT_PROOF_SIZE_PER_MB, WEIGHT_REF_TIME_PER_SECOND}, Weight, @@ -324,6 +326,8 @@ impl pallet_xcm::Config for Runtime { type RemoteLockConsumerIdentifier = (); type WeightInfo = pallet_xcm::TestWeightInfo; type AdminOrigin = EnsureRoot; + // Aliasing is disabled: xcm_executor::Config::Aliasers is set to `Nothing`. + type AuthorizedAliasConsideration = Disabled; } type Block = frame_system::mocking::MockBlock; diff --git a/substrate/frame/revive/mock-network/src/relay_chain.rs b/substrate/frame/revive/mock-network/src/relay_chain.rs index d6c092d4c8343..0e60e3df6e19d 100644 --- a/substrate/frame/revive/mock-network/src/relay_chain.rs +++ b/substrate/frame/revive/mock-network/src/relay_chain.rs @@ -18,7 +18,7 @@ use frame_support::{ construct_runtime, derive_impl, parameter_types, - traits::{Contains, Everything, Nothing}, + traits::{Contains, Disabled, Everything, Nothing}, weights::Weight, }; @@ -211,6 +211,8 @@ impl pallet_xcm::Config for Runtime { type RemoteLockConsumerIdentifier = (); type WeightInfo = pallet_xcm::TestWeightInfo; type AdminOrigin = EnsureRoot; + // Aliasing is disabled: xcm_executor::Config::Aliasers is set to `Nothing`. + type AuthorizedAliasConsideration = Disabled; } impl origin::Config for Runtime {} diff --git a/substrate/frame/support/src/traits.rs b/substrate/frame/support/src/traits.rs index 4a83c809a6a5e..f95f73c27ab5e 100644 --- a/substrate/frame/support/src/traits.rs +++ b/substrate/frame/support/src/traits.rs @@ -96,9 +96,9 @@ mod storage; #[cfg(feature = "experimental")] pub use storage::MaybeConsideration; pub use storage::{ - Consideration, ConstantStoragePrice, Footprint, Incrementable, Instance, LinearStoragePrice, - PartialStorageInfoTrait, StorageInfo, StorageInfoTrait, StorageInstance, TrackedStorageKey, - WhitelistedStorageKeys, + Consideration, ConstantStoragePrice, Disabled, Footprint, Incrementable, Instance, + LinearStoragePrice, PartialStorageInfoTrait, StorageInfo, StorageInfoTrait, StorageInstance, + TrackedStorageKey, WhitelistedStorageKeys, }; mod dispatch; diff --git a/substrate/frame/support/src/traits/storage.rs b/substrate/frame/support/src/traits/storage.rs index 3dc9639dec2fd..4f0e8607a0239 100644 --- a/substrate/frame/support/src/traits/storage.rs +++ b/substrate/frame/support/src/traits/storage.rs @@ -18,8 +18,9 @@ //! Traits for encoding data related to pallet's storage items. use alloc::{collections::btree_set::BTreeSet, vec, vec::Vec}; -use codec::{Encode, FullCodec, MaxEncodedLen}; +use codec::{Decode, Encode, FullCodec, MaxEncodedLen}; use core::marker::PhantomData; +use frame_support::CloneNoBound; use impl_trait_for_tuples::impl_for_tuples; use scale_info::TypeInfo; pub use sp_core::storage::TrackedStorageKey; @@ -212,6 +213,23 @@ where } } +/// Placeholder marking functionality disabled. Useful for disabling various (sub)features. +#[derive(CloneNoBound, Debug, Encode, Eq, Decode, TypeInfo, MaxEncodedLen, PartialEq)] +pub struct Disabled; +impl Consideration for Disabled { + fn new(_: &A, _: F) -> Result { + Err(DispatchError::Other("Disabled")) + } + fn update(self, _: &A, _: F) -> Result { + Err(DispatchError::Other("Disabled")) + } + fn drop(self, _: &A) -> Result<(), DispatchError> { + Ok(()) + } + #[cfg(feature = "runtime-benchmarks")] + fn ensure_successful(_: &A, _: F) {} +} + /// Some sort of cost taken from account temporarily in order to offset the cost to the chain of /// holding some data [`Footprint`] in state. /// diff --git a/templates/parachain/runtime/src/configs/xcm_config.rs b/templates/parachain/runtime/src/configs/xcm_config.rs index 7328b3d163f0b..d56f130b8c0a1 100644 --- a/templates/parachain/runtime/src/configs/xcm_config.rs +++ b/templates/parachain/runtime/src/configs/xcm_config.rs @@ -16,7 +16,10 @@ use frame_system::EnsureRoot; use pallet_xcm::XcmPassthrough; use polkadot_parachain_primitives::primitives::Sibling; use polkadot_runtime_common::impls::ToAuthor; -use polkadot_sdk::staging_xcm_builder::{DenyRecursively, DenyThenTry}; +use polkadot_sdk::{ + polkadot_sdk_frame::traits::Disabled, + staging_xcm_builder::{DenyRecursively, DenyThenTry}, +}; use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowTopLevelPaidExecutionFrom, @@ -152,7 +155,8 @@ impl xcm_executor::Config for XcmConfig { type XcmRecorder = PolkadotXcm; } -/// No local origins on this chain are allowed to dispatch XCM sends/executions. +/// Converts a local signed origin into an XCM location. Forms the basis for local origins +/// sending/executing XCMs. pub type LocalOriginToLocation = SignedToAccountId32; /// The means for routing XCM messages which are not for local execution into the right message @@ -192,6 +196,8 @@ impl pallet_xcm::Config for Runtime { type AdminOrigin = EnsureRoot; type MaxRemoteLockConsumers = ConstU32<0>; type RemoteLockConsumerIdentifier = (); + // Aliasing is disabled: xcm_executor::Config::Aliasers is set to `Nothing`. + type AuthorizedAliasConsideration = Disabled; } impl cumulus_pallet_xcm::Config for Runtime {