// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // Cumulus is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . use super::{ AccountId, AllPalletsWithSystem, Balances, BridgeGrandpaRococoInstance, BridgeGrandpaWococoInstance, DeliveryRewardInBalance, ParachainInfo, ParachainSystem, PolkadotXcm, RequiredStakeForStakeAndSlash, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, WeightToFee, XcmpQueue, }; use crate::{ bridge_hub_rococo_config::ToBridgeHubWococoHaulBlobExporter, bridge_hub_wococo_config::ToBridgeHubRococoHaulBlobExporter, }; use frame_support::{ match_types, parameter_types, traits::{ConstU32, Contains, Everything, Nothing}, }; use frame_system::EnsureRoot; use pallet_xcm::XcmPassthrough; use parachains_common::{impls::ToStakingPot, xcm_config::ConcreteNativeAssetFrom}; use polkadot_parachain::primitives::Sibling; use sp_core::Get; use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, CurrencyAdapter, DenyReserveTransferToRelayChain, DenyThenTry, EnsureXcmOrigin, IsConcrete, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, }; use xcm_executor::{ traits::{ExportXcm, WithOriginFilter}, XcmExecutor, }; parameter_types! { pub const RelayLocation: MultiLocation = MultiLocation::parent(); pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); pub UniversalLocation: InteriorMultiLocation = X2(GlobalConsensus(RelayNetwork::get()), Parachain(ParachainInfo::parachain_id().into())); pub const MaxInstructions: u32 = 100; pub const MaxAssetsIntoHolding: u32 = 64; } pub struct RelayNetwork; impl Get> for RelayNetwork { fn get() -> Option { Some(Self::get()) } } impl Get for RelayNetwork { fn get() -> NetworkId { match u32::from(ParachainInfo::parachain_id()) { bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID => NetworkId::Rococo, bp_bridge_hub_wococo::BRIDGE_HUB_WOCOCO_PARACHAIN_ID => NetworkId::Wococo, para_id => unreachable!("Not supported for para_id: {}", para_id), } } } /// Type for specifying how a `MultiLocation` can be converted into an `AccountId`. This is used /// when determining ownership of accounts for asset transacting and when attempting to use XCM /// `Transact` in order to determine the dispatch Origin. pub type LocationToAccountId = ( // The parent (Relay-chain) origin converts to the parent `AccountId`. ParentIsPreset, // Sibling parachain origins convert to AccountId via the `ParaId::into`. SiblingParachainConvertsVia, // Straight up local `AccountId32` origins just alias directly to `AccountId`. AccountId32Aliases, ); /// Means for transacting the native currency on this chain. pub type CurrencyTransactor = CurrencyAdapter< // Use this currency: Balances, // Use this currency when it is a fungible asset matching the given location or name: IsConcrete, // Do a simple punn to convert an AccountId32 MultiLocation into a native chain account ID: LocationToAccountId, // Our chain's account ID type (we can't get away without mentioning it explicitly): AccountId, // We don't track any teleports of `Balances`. (), >; /// This is the type we use to convert an (incoming) XCM origin into a local `Origin` instance, /// ready for dispatching a transaction with Xcm's `Transact`. There is an `OriginKind` which can /// biases the kind of local `Origin` it will become. pub type XcmOriginToTransactDispatchOrigin = ( // Sovereign account converter; this attempts to derive an `AccountId` from the origin location // using `LocationToAccountId` and then turn that into the usual `Signed` origin. Useful for // foreign chains who want to have a local sovereign account on this chain which they control. SovereignSignedViaLocation, // Native converter for Relay-chain (Parent) location; will convert to a `Relay` origin when // recognized. RelayChainAsNative, // Native converter for sibling Parachains; will convert to a `SiblingPara` origin when // recognized. SiblingParachainAsNative, // Superuser converter for the Relay-chain (Parent) location. This will allow it to issue a // transaction from the Root origin. ParentAsSuperuser, // Native signed account converter; this just converts an `AccountId32` origin into a normal // `RuntimeOrigin::Signed` origin of the same 32-byte value. SignedAccountId32AsNative, // Xcm origins can be represented natively under the Xcm pallet's Xcm origin. XcmPassthrough, ); match_types! { pub type ParentOrParentsPlurality: impl Contains = { MultiLocation { parents: 1, interior: Here } | MultiLocation { parents: 1, interior: X1(Plurality { .. }) } }; pub type ParentOrSiblings: impl Contains = { MultiLocation { parents: 1, interior: Here } | MultiLocation { parents: 1, interior: X1(_) } }; } /// A call filter for the XCM Transact instruction. This is a temporary measure until we properly /// account for proof size weights. /// /// Calls that are allowed through this filter must: /// 1. Have a fixed weight; /// 2. Cannot lead to another call being made; /// 3. Have a defined proof size weight, e.g. no unbounded vecs in call parameters. pub struct SafeCallFilter; impl Contains for SafeCallFilter { fn contains(call: &RuntimeCall) -> bool { #[cfg(feature = "runtime-benchmarks")] { if matches!(call, RuntimeCall::System(frame_system::Call::remark_with_event { .. })) { return true } } // Allow to change dedicated storage items (called by governance-like) match call { RuntimeCall::System(frame_system::Call::set_storage { items }) if items.iter().any(|(k, _)| { k.eq(&DeliveryRewardInBalance::key()) | k.eq(&RequiredStakeForStakeAndSlash::key()) }) => return true, _ => (), }; matches!( call, RuntimeCall::PolkadotXcm(pallet_xcm::Call::force_xcm_version { .. }) | RuntimeCall::System( frame_system::Call::set_heap_pages { .. } | frame_system::Call::set_code { .. } | frame_system::Call::set_code_without_checks { .. } | frame_system::Call::kill_prefix { .. }, ) | RuntimeCall::ParachainSystem(..) | RuntimeCall::Timestamp(..) | RuntimeCall::Balances(..) | RuntimeCall::CollatorSelection( pallet_collator_selection::Call::set_desired_candidates { .. } | pallet_collator_selection::Call::set_candidacy_bond { .. } | pallet_collator_selection::Call::register_as_candidate { .. } | pallet_collator_selection::Call::leave_intent { .. } | pallet_collator_selection::Call::set_invulnerables { .. } | pallet_collator_selection::Call::add_invulnerable { .. } | pallet_collator_selection::Call::remove_invulnerable { .. }, ) | RuntimeCall::Session(pallet_session::Call::purge_keys { .. }) | RuntimeCall::XcmpQueue(..) | RuntimeCall::DmpQueue(..) | RuntimeCall::BridgeRococoGrandpa(pallet_bridge_grandpa::Call::< Runtime, BridgeGrandpaRococoInstance, >::initialize { .. }) | RuntimeCall::BridgeWococoGrandpa(pallet_bridge_grandpa::Call::< Runtime, BridgeGrandpaWococoInstance, >::initialize { .. }) ) } } pub type Barrier = TrailingSetTopicAsId< DenyThenTry< DenyReserveTransferToRelayChain, ( // Allow local users to buy weight credit. TakeWeightCredit, // Expected responses are OK. AllowKnownQueryResponses, WithComputedOrigin< ( // If the message is one that immediately attemps to pay for execution, then // allow it. AllowTopLevelPaidExecutionFrom, // Parent and its pluralities (i.e. governance bodies) get free execution. AllowExplicitUnpaidExecutionFrom, // Subscriptions for version tracking are OK. AllowSubscriptionsFrom, ), UniversalLocation, ConstU32<8>, >, // TODO:check-parameter - (https://github.com/paritytech/parity-bridges-common/issues/2084) // remove this and extend `AllowExplicitUnpaidExecutionFrom` with "or SystemParachains" once merged https://github.com/paritytech/polkadot/pull/7005 AllowUnpaidExecutionFrom, ), >, >; pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = XcmRouter; type AssetTransactor = CurrencyTransactor; type OriginConverter = XcmOriginToTransactDispatchOrigin; // BridgeHub does not recognize a reserve location for any asset. Users must teleport Native // token where allowed (e.g. with the Relay Chain). type IsReserve = (); /// Only allow teleportation of NativeToken of relay chain. type IsTeleporter = ConcreteNativeAssetFrom; type UniversalLocation = UniversalLocation; type Barrier = Barrier; type Weigher = WeightInfoBounds< crate::weights::xcm::BridgeHubRococoXcmWeight, RuntimeCall, MaxInstructions, >; type Trader = UsingComponents>; type ResponseHandler = PolkadotXcm; type AssetTrap = PolkadotXcm; type AssetLocker = (); type AssetExchanger = (); type AssetClaims = PolkadotXcm; type SubscriptionService = PolkadotXcm; type PalletInstancesInfo = AllPalletsWithSystem; type MaxAssetsIntoHolding = MaxAssetsIntoHolding; type FeeManager = (); type MessageExporter = BridgeHubRococoOrBridgeHubWococoSwitchExporter; type UniversalAliases = Nothing; type CallDispatcher = WithOriginFilter; type SafeCallFilter = SafeCallFilter; type Aliasers = Nothing; } /// Converts a local signed origin into an XCM multilocation. /// 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 /// queues. pub type XcmRouter = WithUniqueTopic<( // Two routers - use UMP to communicate with the relay chain: cumulus_primitives_utility::ParentAsUmp, // ..and XCMP to communicate with the sibling chains. XcmpQueue, )>; #[cfg(feature = "runtime-benchmarks")] parameter_types! { pub ReachableDest: Option = Some(Parent.into()); } impl pallet_xcm::Config for Runtime { type RuntimeEvent = RuntimeEvent; type XcmRouter = XcmRouter; // We want to disallow users sending (arbitrary) XCMs from this chain. type SendXcmOrigin = EnsureXcmOrigin; // We support local origins dispatching XCM executions in principle... type ExecuteXcmOrigin = EnsureXcmOrigin; type XcmExecuteFilter = Nothing; type XcmExecutor = XcmExecutor; type XcmTeleportFilter = Everything; type XcmReserveTransferFilter = Nothing; // This parachain is not meant as a reserve location. type Weigher = WeightInfoBounds< crate::weights::xcm::BridgeHubRococoXcmWeight, RuntimeCall, MaxInstructions, >; type UniversalLocation = UniversalLocation; type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion; type Currency = Balances; type CurrencyMatcher = (); type TrustedLockers = (); type SovereignAccountOf = LocationToAccountId; type MaxLockers = ConstU32<8>; type WeightInfo = crate::weights::pallet_xcm::WeightInfo; #[cfg(feature = "runtime-benchmarks")] type ReachableDest = ReachableDest; type AdminOrigin = EnsureRoot; type MaxRemoteLockConsumers = ConstU32<0>; type RemoteLockConsumerIdentifier = (); } impl cumulus_pallet_xcm::Config for Runtime { type RuntimeEvent = RuntimeEvent; type XcmExecutor = XcmExecutor; } /// Hacky switch implementation, because we have just one runtime for Rococo and Wococo BridgeHub, /// so it means we have just one XcmConfig pub struct BridgeHubRococoOrBridgeHubWococoSwitchExporter; impl ExportXcm for BridgeHubRococoOrBridgeHubWococoSwitchExporter { type Ticket = (NetworkId, (sp_std::prelude::Vec, XcmHash)); fn validate( network: NetworkId, channel: u32, universal_source: &mut Option, destination: &mut Option, message: &mut Option>, ) -> SendResult { match network { Rococo => ToBridgeHubRococoHaulBlobExporter::validate( network, channel, universal_source, destination, message, ) .map(|result| ((Rococo, result.0), result.1)), Wococo => ToBridgeHubWococoHaulBlobExporter::validate( network, channel, universal_source, destination, message, ) .map(|result| ((Wococo, result.0), result.1)), _ => unimplemented!("Unsupported network: {:?}", network), } } fn deliver(ticket: Self::Ticket) -> Result { let (network, ticket) = ticket; match network { Rococo => ToBridgeHubRococoHaulBlobExporter::deliver(ticket), Wococo => ToBridgeHubWococoHaulBlobExporter::deliver(ticket), _ => unimplemented!("Unsupported network: {:?}", network), } } }