Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor XCM Simulator Example #4220

Merged
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
3533b09
refactor xcm simulator example
shawntabrizi Apr 19, 2024
6ab85f7
clean up imports
shawntabrizi Apr 19, 2024
4efe047
clean up stray changes
shawntabrizi Apr 19, 2024
85d0b2b
Merge branch 'master' into shawntabrizi-xcm-simulator-refactor
shawntabrizi Apr 19, 2024
a5ad22d
Create pr_4220.prdoc
shawntabrizi Apr 19, 2024
26f5794
constants, weigher, location_converter
shawntabrizi Apr 19, 2024
9b8e3e2
fixes
shawntabrizi Apr 19, 2024
89bd53f
derive_impl
shawntabrizi Apr 19, 2024
26fa6ce
expose public types matching the file and config
shawntabrizi Apr 19, 2024
8518b05
remove `SovereignAccountOf`
shawntabrizi Apr 19, 2024
b22b75a
more explicit imports
shawntabrizi Apr 19, 2024
e83b830
Merge branch 'master' into shawntabrizi-xcm-simulator-refactor
shawntabrizi Apr 20, 2024
74ea394
feat(location-converter): use HashedDescription
franciscoaguirre Apr 22, 2024
6196c04
Merge pull request #1 from paritytech/pr4220
shawntabrizi Apr 22, 2024
a2ccd63
Merge branch 'master' into shawntabrizi-xcm-simulator-refactor
franciscoaguirre Apr 22, 2024
7acbe30
Merge remote-tracking branch 'upstream/master' into shawntabrizi-xcm-…
shawntabrizi Apr 28, 2024
62f89dc
add EnsureDecodableXcm
shawntabrizi Apr 28, 2024
21493b5
Sanitize UniversalLocation witth GlobalConsensus #4238
shawntabrizi Apr 28, 2024
2393966
Apply suggestions from code review
shawntabrizi Apr 28, 2024
f8cb627
Merge remote-tracking branch 'upstream/master' into shawntabrizi-xcm-…
shawntabrizi Apr 28, 2024
e5776e0
add getters
shawntabrizi Apr 28, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
519 changes: 4 additions & 515 deletions polkadot/xcm/xcm-simulator/example/src/lib.rs

Large diffs are not rendered by default.

470 changes: 0 additions & 470 deletions polkadot/xcm/xcm-simulator/example/src/parachain.rs

This file was deleted.

177 changes: 177 additions & 0 deletions polkadot/xcm/xcm-simulator/example/src/parachain/mock_msg_queue.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
// Copyright (C) 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 <http://www.gnu.org/licenses/>.

use polkadot_core_primitives::BlockNumber as RelayBlockNumber;
use polkadot_parachain_primitives::primitives::{
DmpMessageHandler, Id as ParaId, XcmpMessageFormat, XcmpMessageHandler,
};
use sp_runtime::traits::{Get, Hash};
use xcm::{latest::prelude::*, VersionedXcm};

pub use pallet::*;

#[frame_support::pallet]
pub mod pallet {
use super::*;
use frame_support::pallet_prelude::*;

#[pallet::config]
pub trait Config: frame_system::Config {
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
type XcmExecutor: ExecuteXcm<Self::RuntimeCall>;
}

#[pallet::call]
impl<T: Config> Pallet<T> {}

#[pallet::pallet]
#[pallet::without_storage_info]
pub struct Pallet<T>(_);

#[pallet::storage]
#[pallet::getter(fn parachain_id)]
shawntabrizi marked this conversation as resolved.
Show resolved Hide resolved
pub(super) type ParachainId<T: Config> = StorageValue<_, ParaId, ValueQuery>;

#[pallet::storage]
#[pallet::getter(fn received_dmp)]
shawntabrizi marked this conversation as resolved.
Show resolved Hide resolved
/// A queue of received DMP messages
pub(super) type ReceivedDmp<T: Config> = StorageValue<_, Vec<Xcm<T::RuntimeCall>>, ValueQuery>;

impl<T: Config> Get<ParaId> for Pallet<T> {
fn get() -> ParaId {
Self::parachain_id()
}
}

pub type MessageId = [u8; 32];

#[pallet::event]
#[pallet::generate_deposit(pub(super) fn deposit_event)]
pub enum Event<T: Config> {
// XCMP
/// Some XCM was executed OK.
Success(Option<T::Hash>),
/// Some XCM failed.
Fail(Option<T::Hash>, XcmError),
/// Bad XCM version used.
BadVersion(Option<T::Hash>),
/// Bad XCM format used.
BadFormat(Option<T::Hash>),

// 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<T: Config> Pallet<T> {
pub fn set_para_id(para_id: ParaId) {
ParachainId::<T>::put(para_id);
}

fn handle_xcmp_message(
sender: ParaId,
_sent_at: RelayBlockNumber,
xcm: VersionedXcm<T::RuntimeCall>,
max_weight: Weight,
) -> Result<Weight, XcmError> {
let hash = Encode::using_encoded(&xcm, T::Hashing::hash);
let mut message_hash = Encode::using_encoded(&xcm, sp_io::hashing::blake2_256);
let (result, event) = match Xcm::<T::RuntimeCall>::try_from(xcm) {
Ok(xcm) => {
let location = (Parent, Parachain(sender.into()));
match T::XcmExecutor::prepare_and_execute(
location,
xcm,
&mut message_hash,
max_weight,
Weight::zero(),
) {
Outcome::Error { error } => (Err(error), Event::Fail(Some(hash), error)),
Outcome::Complete { used } => (Ok(used), 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 { used, error } =>
(Ok(used), Event::Fail(Some(hash), error)),
}
},
Err(()) => (Err(XcmError::UnhandledXcmVersion), Event::BadVersion(Some(hash))),
};
Self::deposit_event(event);
result
}
}

impl<T: Config> XcmpMessageHandler for Pallet<T> {
fn handle_xcmp_messages<'a, I: Iterator<Item = (ParaId, RelayBlockNumber, &'a [u8])>>(
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::<T::RuntimeCall>::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<T: Config> DmpMessageHandler for Pallet<T> {
fn handle_dmp_messages(
iter: impl Iterator<Item = (RelayBlockNumber, Vec<u8>)>,
limit: Weight,
) -> Weight {
for (_i, (_sent_at, data)) in iter.enumerate() {
let mut id = sp_io::hashing::blake2_256(&data[..]);
let maybe_versioned = VersionedXcm::<T::RuntimeCall>::decode(&mut &data[..]);
match maybe_versioned {
Err(_) => {
Self::deposit_event(Event::InvalidFormat(id));
},
Ok(versioned) => match Xcm::try_from(versioned) {
Err(()) => Self::deposit_event(Event::UnsupportedVersion(id)),
Ok(x) => {
let outcome = T::XcmExecutor::prepare_and_execute(
Parent,
x.clone(),
&mut id,
limit,
Weight::zero(),
);
<ReceivedDmp<T>>::append(x);
Self::deposit_event(Event::ExecutedDownward(id, outcome));
},
},
}
}
limit
}
}
}
217 changes: 217 additions & 0 deletions polkadot/xcm/xcm-simulator/example/src/parachain/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
// Copyright (C) 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 <http://www.gnu.org/licenses/>.

//! Parachain runtime mock.

mod mock_msg_queue;
mod xcm_config;
pub use xcm_config::*;

use core::marker::PhantomData;
use frame_support::{
construct_runtime, derive_impl, parameter_types,
traits::{ContainsPair, EnsureOrigin, EnsureOriginWithArg, Everything, Nothing},
weights::{constants::WEIGHT_REF_TIME_PER_SECOND, Weight},
};

use frame_system::EnsureRoot;
use sp_core::{ConstU32, H256};
use sp_runtime::{
traits::{Get, IdentityLookup},
AccountId32,
};
use sp_std::prelude::*;

use xcm::latest::prelude::*;
use xcm_builder::{EnsureXcmOrigin, SignedToAccountId32};
use xcm_executor::{traits::ConvertLocation, XcmExecutor};

pub type AccountId = AccountId32;
pub type Balance = u128;

parameter_types! {
pub const BlockHashCount: u64 = 250;
}

#[derive_impl(frame_system::config_preludes::TestDefaultConfig)]
impl frame_system::Config for Runtime {
shawntabrizi marked this conversation as resolved.
Show resolved Hide resolved
type RuntimeOrigin = RuntimeOrigin;
type RuntimeCall = RuntimeCall;
type Nonce = u64;
type Hash = H256;
type Hashing = ::sp_runtime::traits::BlakeTwo256;
type AccountId = AccountId;
type Lookup = IdentityLookup<Self::AccountId>;
type Block = Block;
type RuntimeEvent = RuntimeEvent;
type BlockHashCount = BlockHashCount;
type BlockWeights = ();
type BlockLength = ();
type Version = ();
type PalletInfo = PalletInfo;
type AccountData = pallet_balances::AccountData<Balance>;
type OnNewAccount = ();
type OnKilledAccount = ();
type DbWeight = ();
type BaseCallFilter = Everything;
type SystemWeightInfo = ();
type SS58Prefix = ();
type OnSetCode = ();
type MaxConsumers = ConstU32<16>;
}

parameter_types! {
pub ExistentialDeposit: Balance = 1;
pub const MaxLocks: u32 = 50;
pub const MaxReserves: u32 = 50;
}

impl pallet_balances::Config for Runtime {
franciscoaguirre marked this conversation as resolved.
Show resolved Hide resolved
type MaxLocks = MaxLocks;
type Balance = Balance;
type RuntimeEvent = RuntimeEvent;
type DustRemoval = ();
type ExistentialDeposit = ExistentialDeposit;
type AccountStore = System;
type WeightInfo = ();
type MaxReserves = MaxReserves;
type ReserveIdentifier = [u8; 8];
type RuntimeHoldReason = RuntimeHoldReason;
type RuntimeFreezeReason = RuntimeFreezeReason;
type FreezeIdentifier = ();
type MaxFreezes = ConstU32<0>;
}

#[cfg(feature = "runtime-benchmarks")]
pub struct UniquesHelper;
#[cfg(feature = "runtime-benchmarks")]
impl pallet_uniques::BenchmarkHelper<Location, AssetInstance> for UniquesHelper {
fn collection(i: u16) -> Location {
GeneralIndex(i as u128).into()
}
fn item(i: u16) -> AssetInstance {
AssetInstance::Index(i as u128)
}
}

impl pallet_uniques::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type CollectionId = Location;
type ItemId = AssetInstance;
type Currency = Balances;
type CreateOrigin = ForeignCreators;
type ForceOrigin = frame_system::EnsureRoot<AccountId>;
type CollectionDeposit = frame_support::traits::ConstU128<1_000>;
type ItemDeposit = frame_support::traits::ConstU128<1_000>;
type MetadataDepositBase = frame_support::traits::ConstU128<1_000>;
type AttributeDepositBase = frame_support::traits::ConstU128<1_000>;
type DepositPerByte = frame_support::traits::ConstU128<1>;
type StringLimit = ConstU32<64>;
type KeyLimit = ConstU32<64>;
type ValueLimit = ConstU32<128>;
type Locker = ();
type WeightInfo = ();
#[cfg(feature = "runtime-benchmarks")]
type Helper = UniquesHelper;
}

// `EnsureOriginWithArg` impl for `CreateOrigin` which allows only XCM origins
// which are locations containing the class location.
pub struct ForeignCreators;
impl EnsureOriginWithArg<RuntimeOrigin, Location> for ForeignCreators {
type Success = AccountId;

fn try_origin(
o: RuntimeOrigin,
a: &Location,
) -> sp_std::result::Result<Self::Success, RuntimeOrigin> {
let origin_location = pallet_xcm::EnsureXcm::<Everything>::try_origin(o.clone())?;
if !a.starts_with(&origin_location) {
return Err(o);
}
xcm_config::SovereignAccountOf::convert_location(&origin_location).ok_or(o)
}

#[cfg(feature = "runtime-benchmarks")]
fn try_successful_origin(a: &Location) -> Result<RuntimeOrigin, ()> {
Ok(pallet_xcm::Origin::Xcm(a.clone()).into())
}
}

parameter_types! {
pub const ReservedXcmpWeight: Weight = Weight::from_parts(WEIGHT_REF_TIME_PER_SECOND.saturating_div(4), 0);
pub const ReservedDmpWeight: Weight = Weight::from_parts(WEIGHT_REF_TIME_PER_SECOND.saturating_div(4), 0);
}

impl mock_msg_queue::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type XcmExecutor = XcmExecutor<XcmConfig>;
}

pub type LocalOriginToLocation = SignedToAccountId32<RuntimeOrigin, AccountId, RelayNetwork>;

pub struct TrustedLockerCase<T>(PhantomData<T>);
impl<T: Get<(Location, AssetFilter)>> ContainsPair<Location, Asset> for TrustedLockerCase<T> {
fn contains(origin: &Location, asset: &Asset) -> bool {
let (o, a) = T::get();
a.matches(asset) && &o == origin
}
}

parameter_types! {
pub RelayTokenForRelay: (Location, AssetFilter) = (Parent.into(), Wild(AllOf { id: AssetId(Parent.into()), fun: WildFungible }));
}

pub type TrustedLockers = TrustedLockerCase<RelayTokenForRelay>;

impl pallet_xcm::Config for Runtime {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would give you a dinner and a hug in Singapore if as a part of the XCM tutorials, we can have an simple version of TestDefaultConfig for this as well.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Although, #1959

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i will take a look for sure

type RuntimeEvent = RuntimeEvent;
type SendXcmOrigin = EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>;
type XcmRouter = XcmRouter;
type ExecuteXcmOrigin = EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>;
type XcmExecuteFilter = Everything;
type XcmExecutor = XcmExecutor<XcmConfig>;
type XcmTeleportFilter = Nothing;
type XcmReserveTransferFilter = Everything;
type Weigher = xcm_config::Weigher;
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 = TrustedLockers;
type SovereignAccountOf = xcm_config::LocationToAccountId;
type MaxLockers = ConstU32<8>;
type MaxRemoteLockConsumers = ConstU32<0>;
type RemoteLockConsumerIdentifier = ();
type WeightInfo = pallet_xcm::TestWeightInfo;
type AdminOrigin = EnsureRoot<AccountId>;
}

type Block = frame_system::mocking::MockBlock<Runtime>;

construct_runtime!(
pub enum Runtime
{
shawntabrizi marked this conversation as resolved.
Show resolved Hide resolved
System: frame_system,
Balances: pallet_balances,
MsgQueue: mock_msg_queue,
PolkadotXcm: pallet_xcm,
ForeignUniques: pallet_uniques,
}
);
Loading
Loading