diff --git a/Cargo.lock b/Cargo.lock index b3e18c9d4b3b..621e9072befd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6771,6 +6771,7 @@ dependencies = [ "pallet-treasury", "pallet-utility", "pallet-vesting", + "pallet-xcm", "parity-scale-codec", "polkadot-primitives", "polkadot-runtime-common", @@ -6803,6 +6804,9 @@ dependencies = [ "substrate-wasm-builder", "tiny-keccak", "trie-db", + "xcm", + "xcm-builder", + "xcm-executor", ] [[package]] diff --git a/node/service/src/chain_spec.rs b/node/service/src/chain_spec.rs index 3c4c24eab332..df17c5f0ac92 100644 --- a/node/service/src/chain_spec.rs +++ b/node/service/src/chain_spec.rs @@ -365,6 +365,7 @@ fn polkadot_staging_testnet_config_genesis(wasm_binary: &[u8]) -> polkadot::Gene config: default_parachains_host_configuration(), }, paras: Default::default(), + xcm_pallet: polkadot::XcmPalletConfig { safe_xcm_version: Some(2) }, } } @@ -1306,6 +1307,7 @@ pub fn polkadot_testnet_genesis( config: default_parachains_host_configuration(), }, paras: Default::default(), + xcm_pallet: polkadot::XcmPalletConfig { safe_xcm_version: Some(2) }, } } diff --git a/runtime/polkadot/Cargo.toml b/runtime/polkadot/Cargo.toml index d4abf5b6ef3f..0436a347be08 100644 --- a/runtime/polkadot/Cargo.toml +++ b/runtime/polkadot/Cargo.toml @@ -69,6 +69,7 @@ pallet-treasury = { git = "https://github.com/paritytech/substrate", default-fea pallet-vesting = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "polkadot-v0.9.13" } pallet-utility = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "polkadot-v0.9.13" } frame-election-provider-support = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "polkadot-v0.9.13" } +pallet-xcm = { path = "../../xcm/pallet-xcm", default-features = false } frame-benchmarking = { git = "https://github.com/paritytech/substrate", default-features = false, optional = true , branch = "polkadot-v0.9.13" } frame-try-runtime = { git = "https://github.com/paritytech/substrate", default-features = false, optional = true , branch = "polkadot-v0.9.13" } @@ -81,6 +82,10 @@ runtime-common = { package = "polkadot-runtime-common", path = "../common", defa runtime-parachains = { package = "polkadot-runtime-parachains", path = "../parachains", default-features = false } primitives = { package = "polkadot-primitives", path = "../../primitives", default-features = false } +xcm = { package = "xcm", path = "../../xcm", default-features = false } +xcm-executor = { package = "xcm-executor", path = "../../xcm/xcm-executor", default-features = false } +xcm-builder = { package = "xcm-builder", path = "../../xcm/xcm-builder", default-features = false } + [dev-dependencies] hex-literal = "0.3.4" tiny-keccak = "2.0.2" @@ -158,6 +163,10 @@ std = [ "beefy-primitives/std", "pallet-mmr-primitives/std", "frame-election-provider-support/std", + "pallet-xcm/std", + "xcm/std", + "xcm-executor/std", + "xcm-builder/std", ] runtime-benchmarks = [ "runtime-common/runtime-benchmarks", @@ -187,10 +196,12 @@ runtime-benchmarks = [ "pallet-tips/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "pallet-vesting/runtime-benchmarks", + "pallet-xcm/runtime-benchmarks", "pallet-offences-benchmarking", "pallet-session-benchmarking", "frame-system-benchmarking", "hex-literal", + "xcm-builder/runtime-benchmarks", "frame-election-provider-support/runtime-benchmarks", "runtime-parachains/runtime-benchmarks", ] diff --git a/runtime/polkadot/src/lib.rs b/runtime/polkadot/src/lib.rs index b235c3463633..182e9158f03a 100644 --- a/runtime/polkadot/src/lib.rs +++ b/runtime/polkadot/src/lib.rs @@ -22,9 +22,9 @@ use pallet_transaction_payment::CurrencyAdapter; use runtime_common::{ - auctions, claims, crowdloan, impls::DealWithFees, paras_registrar, slots, BlockHashCount, - BlockLength, BlockWeights, CurrencyToVote, OffchainSolutionLengthLimit, - OffchainSolutionWeightLimit, RocksDbWeight, SlowAdjustingFeeUpdate, + auctions, claims, crowdloan, impls::DealWithFees, paras_registrar, slots, xcm_sender, + BlockHashCount, BlockLength, BlockWeights, CurrencyToVote, OffchainSolutionLengthLimit, + OffchainSolutionWeightLimit, RocksDbWeight, SlowAdjustingFeeUpdate, ToAuthor, }; use runtime_parachains::{ @@ -39,8 +39,11 @@ use runtime_parachains::{ use authority_discovery_primitives::AuthorityId as AuthorityDiscoveryId; use beefy_primitives::crypto::AuthorityId as BeefyId; use frame_support::{ - construct_runtime, parameter_types, - traits::{Contains, KeyOwnerProofSystem, LockIdentifier, OnRuntimeUpgrade, PrivilegeCmp}, + construct_runtime, match_type, parameter_types, + traits::{ + Contains, Everything, InstanceFilter, KeyOwnerProofSystem, LockIdentifier, Nothing, + OnRuntimeUpgrade, PrivilegeCmp, + }, weights::Weight, PalletId, RuntimeDebug, }; @@ -78,6 +81,15 @@ use sp_std::{cmp::Ordering, collections::btree_map::BTreeMap, prelude::*}; use sp_version::NativeVersion; use sp_version::RuntimeVersion; use static_assertions::const_assert; +use xcm::latest::prelude::*; +use xcm_builder::{ + AccountId32Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom, + AllowTopLevelPaidExecutionFrom, BackingToPlurality, ChildParachainAsNative, + ChildParachainConvertsVia, CurrencyAdapter as XcmCurrencyAdapter, FixedWeightBounds, + IsConcrete, LocationInverter, SignedAccountId32AsNative, SignedToAccountId32, + SovereignSignedViaLocation, TakeWeightCredit, UsingComponents, +}; +use xcm_executor::XcmExecutor; pub use pallet_balances::Call as BalancesCall; pub use pallet_election_provider_multi_phase::Call as EPMCall; @@ -90,7 +102,6 @@ pub use sp_runtime::BuildStorage; /// Constant values used within the runtime. pub mod constants; use constants::{currency::*, fee::*, time::*}; -use frame_support::traits::InstanceFilter; // Weights used in the runtime. mod weights; @@ -173,7 +184,8 @@ impl Contains for BaseFilter { Call::Registrar(_) | Call::Auctions(_) | Call::Crowdloan(_) | - Call::BagsList(_) => true, + Call::BagsList(_) | + Call::XcmPallet(_) => true, // All pallets are allowed, but exhaustive match is defensive // in the case of adding new pallets. } @@ -1280,6 +1292,154 @@ impl auctions::Config for Runtime { type WeightInfo = weights::runtime_common_auctions::WeightInfo; } +parameter_types! { + /// The location of the DOT token, from the context of this chain. Since this token is native to this + /// chain, we make it synonymous with it and thus it is the `Here` location, which means "equivalent to + /// the context". + pub const DotLocation: MultiLocation = Here.into(); + /// The Polkadot network ID. This is named. + pub const PolkadotNetwork: NetworkId = NetworkId::Polkadot; + /// Our XCM location ancestry - i.e. what, if anything, `Parent` means evaluated in our context. Since + /// Polkadot is a top-level relay-chain, there is no ancestry. + pub const Ancestry: MultiLocation = Here.into(); + /// The check account, which holds any native assets that have been teleported out and not back in (yet). + pub CheckAccount: AccountId = XcmPallet::check_account(); +} + +/// The canonical means of converting a `MultiLocation` into an `AccountId`, used when we want to determine +/// the sovereign account controlled by a location. +pub type SovereignAccountOf = ( + // We can convert a child parachain using the standard `AccountId` conversion. + ChildParachainConvertsVia, + // We can directly alias an `AccountId32` into a local account. + AccountId32Aliases, +); + +/// Our asset transactor. This is what allows us to interest with the runtime facilities from the point of +/// view of XCM-only concepts like `MultiLocation` and `MultiAsset`. +/// +/// Ours is only aware of the Balances pallet, which is mapped to `DotLocation`. +pub type LocalAssetTransactor = XcmCurrencyAdapter< + // Use this currency: + Balances, + // Use this currency when it is a fungible asset matching the given location or name: + IsConcrete, + // We can convert the MultiLocations with our converter above: + SovereignAccountOf, + // Our chain's account ID type (we can't get away without mentioning it explicitly): + AccountId, + // We track our teleports in/out to keep total issuance correct. + CheckAccount, +>; + +/// The means that we convert an the XCM message origin location into a local dispatch origin. +type LocalOriginConverter = ( + // A `Signed` origin of the sovereign account that the original location controls. + SovereignSignedViaLocation, + // A child parachain, natively expressed, has the `Parachain` origin. + ChildParachainAsNative, + // The AccountId32 location type can be expressed natively as a `Signed` origin. + SignedAccountId32AsNative, +); + +parameter_types! { + /// The amount of weight an XCM operation takes. This is a safe overestimate. + pub const BaseXcmWeight: Weight = 1_000_000_000; + /// Maximum number of instructions in a single XCM fragment. A sanity check against weight + /// calculations getting too crazy. + pub const MaxInstructions: u32 = 100; +} + +/// The XCM router. When we want to send an XCM message, we use this type. It amalgamates all of our +/// individual routers. +pub type XcmRouter = ( + // Only one router so far - use DMP to communicate with child parachains. + xcm_sender::ChildParachainRouter, +); + +parameter_types! { + pub const Polkadot: MultiAssetFilter = Wild(AllOf { fun: WildFungible, id: Concrete(DotLocation::get()) }); + pub const PolkadotForStatemint: (MultiAssetFilter, MultiLocation) = (Polkadot::get(), Parachain(1000).into()); +} + +pub type TrustedTeleporters = (xcm_builder::Case,); + +match_type! { + pub type OnlyParachains: impl Contains = { + MultiLocation { parents: 0, interior: X1(Parachain(_)) } + }; +} + +/// The barriers one of which must be passed for an XCM message to be executed. +pub type Barrier = ( + // Weight that is paid for may be consumed. + TakeWeightCredit, + // If the message is one that immediately attemps to pay for execution, then allow it. + AllowTopLevelPaidExecutionFrom, + // Expected responses are OK. + AllowKnownQueryResponses, + // Subscriptions for version tracking are OK. + AllowSubscriptionsFrom, +); + +pub struct XcmConfig; +impl xcm_executor::Config for XcmConfig { + type Call = Call; + type XcmSender = XcmRouter; + type AssetTransactor = LocalAssetTransactor; + type OriginConverter = LocalOriginConverter; + type IsReserve = (); + type IsTeleporter = TrustedTeleporters; + type LocationInverter = LocationInverter; + type Barrier = Barrier; + type Weigher = FixedWeightBounds; + // The weight trader piggybacks on the existing transaction-fee conversion logic. + type Trader = UsingComponents>; + type ResponseHandler = XcmPallet; + type AssetTrap = XcmPallet; + type AssetClaims = XcmPallet; + type SubscriptionService = XcmPallet; +} + +parameter_types! { + pub const CouncilBodyId: BodyId = BodyId::Executive; + // We are conservative with the XCM version we advertize. + pub const AdvertisedXcmVersion: u32 = 2; +} + +/// Type to convert an `Origin` type value into a `MultiLocation` value which represents an interior location +/// of this chain. +pub type LocalOriginToLocation = ( + // We allow an origin from the Collective pallet to be used in XCM as a corresponding Plurality of the + // `Unit` body. + BackingToPlurality< + Origin, + pallet_collective::Origin, + CouncilBodyId, + >, + // And a usual Signed origin to be used in XCM as a corresponding AccountId32 + SignedToAccountId32, +); + +impl pallet_xcm::Config for Runtime { + type Event = Event; + type SendXcmOrigin = xcm_builder::EnsureXcmOrigin; + type XcmRouter = XcmRouter; + // Anyone can execute XCM messages locally... + type ExecuteXcmOrigin = xcm_builder::EnsureXcmOrigin; + // ...but they must match our filter, which rejects all. + type XcmExecuteFilter = Nothing; + type XcmExecutor = XcmExecutor; + type XcmTeleportFilter = Everything; + type XcmReserveTransferFilter = Everything; + type Weigher = FixedWeightBounds; + type LocationInverter = LocationInverter; + type Origin = Origin; + type Call = Call; + const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; + type AdvertisedXcmVersion = AdvertisedXcmVersion; +} + construct_runtime! { pub enum Runtime where Block = Block, @@ -1363,6 +1523,9 @@ construct_runtime! { Slots: slots::{Pallet, Call, Storage, Event} = 71, Auctions: auctions::{Pallet, Call, Storage, Event} = 72, Crowdloan: crowdloan::{Pallet, Call, Storage, Event} = 73, + + // Pallet for sending XCM. + XcmPallet: pallet_xcm::{Pallet, Call, Storage, Event, Origin, Config} = 99, } } @@ -1884,6 +2047,7 @@ mod test_fees { MaxNominatorRewardedPerValidator::get(), ) as f64; let block_weight = BlockWeights::get().max_block as f64; + println!( "a full payout takes {:.2} of the block weight [{} / {}]", payout_weight / block_weight,