// Copyright 2021 Parity Technologies (UK) Ltd. // This file is part of Polkadot. // Polkadot 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. // Polkadot 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 Polkadot. If not, see . //! Parachain runtime mock. use codec::{Decode, Encode}; use frame_support::{ construct_runtime, parameter_types, traits::{All, AllowAll}, weights::{constants::WEIGHT_PER_SECOND, Weight}, }; use sp_core::H256; use sp_runtime::{ testing::Header, traits::{Hash, IdentityLookup}, AccountId32, }; use sp_std::{convert::TryFrom, prelude::*}; use pallet_xcm::XcmPassthrough; use polkadot_core_primitives::BlockNumber as RelayBlockNumber; use polkadot_parachain::primitives::{ DmpMessageHandler, Id as ParaId, Sibling, XcmpMessageFormat, XcmpMessageHandler, }; use xcm::{ v0::{ Error as XcmError, ExecuteXcm, Junction::{Parachain, Parent}, MultiAsset, MultiLocation::{self, X1}, NetworkId, Outcome, Xcm, }, VersionedXcm, }; use xcm_builder::{ AccountId32Aliases, AllowUnpaidExecutionFrom, CurrencyAdapter as XcmCurrencyAdapter, EnsureXcmOrigin, FixedRateOfConcreteFungible, FixedWeightBounds, IsConcrete, LocationInverter, NativeAsset, ParentIsDefault, SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, }; use xcm_executor::{Config, XcmExecutor}; pub type AccountId = AccountId32; pub type Balance = u128; parameter_types! { pub const BlockHashCount: u64 = 250; } impl frame_system::Config for Runtime { type Origin = Origin; type Call = Call; type Index = u64; type BlockNumber = u64; type Hash = H256; type Hashing = ::sp_runtime::traits::BlakeTwo256; type AccountId = AccountId; type Lookup = IdentityLookup; type Header = Header; type Event = Event; type BlockHashCount = BlockHashCount; type BlockWeights = (); type BlockLength = (); type Version = (); type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; type OnNewAccount = (); type OnKilledAccount = (); type DbWeight = (); type BaseCallFilter = AllowAll; type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); } parameter_types! { pub ExistentialDeposit: Balance = 1; pub const MaxLocks: u32 = 50; pub const MaxReserves: u32 = 50; } impl pallet_balances::Config for Runtime { type MaxLocks = MaxLocks; type Balance = Balance; type Event = Event; type DustRemoval = (); type ExistentialDeposit = ExistentialDeposit; type AccountStore = System; type WeightInfo = (); type MaxReserves = MaxReserves; type ReserveIdentifier = [u8; 8]; } parameter_types! { pub const ReservedXcmpWeight: Weight = WEIGHT_PER_SECOND / 4; pub const ReservedDmpWeight: Weight = WEIGHT_PER_SECOND / 4; } parameter_types! { pub const KsmLocation: MultiLocation = MultiLocation::X1(Parent); pub const RelayNetwork: NetworkId = NetworkId::Kusama; pub Ancestry: MultiLocation = Parachain(MsgQueue::parachain_id().into()).into(); } pub type LocationToAccountId = ( ParentIsDefault, SiblingParachainConvertsVia, AccountId32Aliases, ); pub type XcmOriginToCallOrigin = ( SovereignSignedViaLocation, SignedAccountId32AsNative, XcmPassthrough, ); parameter_types! { pub const UnitWeightCost: Weight = 1; pub KsmPerSecond: (MultiLocation, u128) = (X1(Parent), 1); } pub type LocalAssetTransactor = XcmCurrencyAdapter, LocationToAccountId, AccountId, ()>; pub type XcmRouter = super::ParachainXcmRouter; pub type Barrier = AllowUnpaidExecutionFrom>; pub struct XcmConfig; impl Config for XcmConfig { type Call = Call; type XcmSender = XcmRouter; type AssetTransactor = LocalAssetTransactor; type OriginConverter = XcmOriginToCallOrigin; type IsReserve = NativeAsset; type IsTeleporter = (); type LocationInverter = LocationInverter; type Barrier = Barrier; type Weigher = FixedWeightBounds; type Trader = FixedRateOfConcreteFungible; type ResponseHandler = (); } #[frame_support::pallet] pub mod mock_msg_queue { use super::*; use frame_support::pallet_prelude::*; #[pallet::config] pub trait Config: frame_system::Config { type Event: From> + IsType<::Event>; type XcmExecutor: ExecuteXcm; } #[pallet::call] impl Pallet {} #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] pub struct Pallet(_); #[pallet::storage] #[pallet::getter(fn parachain_id)] pub(super) type ParachainId = StorageValue<_, ParaId, ValueQuery>; impl Get for Pallet { fn get() -> ParaId { Self::parachain_id() } } pub type MessageId = [u8; 32]; #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { // XCMP /// Some XCM was executed ok. Success(Option), /// Some XCM failed. Fail(Option, XcmError), /// Bad XCM version used. BadVersion(Option), /// Bad XCM format used. BadFormat(Option), // DMP /// Downward message is invalid XCM. InvalidFormat(MessageId), /// Downward message is unsupported version of XCM. UnsupportedVersion(MessageId), /// Downward message executed with the given outcome. ExecutedDownward(MessageId, Outcome), } impl Pallet { pub fn set_para_id(para_id: ParaId) { ParachainId::::put(para_id); } fn handle_xcmp_message( sender: ParaId, _sent_at: RelayBlockNumber, xcm: VersionedXcm, max_weight: Weight, ) -> Result { let hash = Encode::using_encoded(&xcm, T::Hashing::hash); let (result, event) = match Xcm::::try_from(xcm) { Ok(xcm) => { let location = (Parent, Parachain(sender.into())); match T::XcmExecutor::execute_xcm(location.into(), xcm, max_weight) { Outcome::Error(e) => (Err(e.clone()), Event::Fail(Some(hash), e)), Outcome::Complete(w) => (Ok(w), Event::Success(Some(hash))), // As far as the caller is concerned, this was dispatched without error, so // we just report the weight used. Outcome::Incomplete(w, e) => (Ok(w), Event::Fail(Some(hash), e)), } }, Err(()) => (Err(XcmError::UnhandledXcmVersion), Event::BadVersion(Some(hash))), }; Self::deposit_event(event); result } } impl XcmpMessageHandler for Pallet { fn handle_xcmp_messages<'a, I: Iterator>( iter: I, max_weight: Weight, ) -> Weight { for (sender, sent_at, data) in iter { let mut data_ref = data; let _ = XcmpMessageFormat::decode(&mut data_ref) .expect("Simulator encodes with versioned xcm format; qed"); let mut remaining_fragments = &data_ref[..]; while !remaining_fragments.is_empty() { if let Ok(xcm) = VersionedXcm::::decode(&mut remaining_fragments) { let _ = Self::handle_xcmp_message(sender, sent_at, xcm, max_weight); } else { debug_assert!(false, "Invalid incoming XCMP message data"); } } } max_weight } } impl DmpMessageHandler for Pallet { fn handle_dmp_messages( iter: impl Iterator)>, limit: Weight, ) -> Weight { for (_i, (_sent_at, data)) in iter.enumerate() { let id = sp_io::hashing::blake2_256(&data[..]); let maybe_msg = VersionedXcm::::decode(&mut &data[..]).map(Xcm::::try_from); match maybe_msg { Err(_) => { Self::deposit_event(Event::InvalidFormat(id)); }, Ok(Err(())) => { Self::deposit_event(Event::UnsupportedVersion(id)); }, Ok(Ok(x)) => { let outcome = T::XcmExecutor::execute_xcm(Parent.into(), x, limit); Self::deposit_event(Event::ExecutedDownward(id, outcome)); }, } } limit } } } impl mock_msg_queue::Config for Runtime { type Event = Event; type XcmExecutor = XcmExecutor; } pub type LocalOriginToLocation = SignedToAccountId32; impl pallet_xcm::Config for Runtime { type Event = Event; type SendXcmOrigin = EnsureXcmOrigin; type XcmRouter = XcmRouter; type ExecuteXcmOrigin = EnsureXcmOrigin; type XcmExecuteFilter = All<(MultiLocation, Xcm)>; type XcmExecutor = XcmExecutor; type XcmTeleportFilter = (); type XcmReserveTransferFilter = All<(MultiLocation, Vec)>; type Weigher = FixedWeightBounds; } type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; type Block = frame_system::mocking::MockBlock; construct_runtime!( pub enum Runtime where Block = Block, NodeBlock = Block, UncheckedExtrinsic = UncheckedExtrinsic, { System: frame_system::{Pallet, Call, Storage, Config, Event}, Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, MsgQueue: mock_msg_queue::{Pallet, Storage, Event}, PolkadotXcm: pallet_xcm::{Pallet, Call, Event, Origin}, } );