#![cfg_attr(not(feature = "std"), no_std)]
use codec::{Decode, DecodeLimit, Encode};
use cumulus_primitives_core::{
relay_chain::BlockNumber as RelayBlockNumber, DmpMessageHandler, ParaId,
};
use frame_support::dispatch::Weight;
pub use pallet::*;
use scale_info::TypeInfo;
use sp_runtime::{traits::BadOrigin, RuntimeDebug};
use sp_std::{convert::TryFrom, prelude::*};
use xcm::{
latest::{ExecuteXcm, Outcome, Parent, Xcm},
VersionedXcm, MAX_XCM_DECODE_DEPTH,
};
#[frame_support::pallet]
pub mod pallet {
use super::*;
use frame_support::pallet_prelude::*;
use frame_system::pallet_prelude::*;
#[pallet::pallet]
#[pallet::generate_store(pub(super) trait Store)]
pub struct Pallet<T>(_);
#[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::error]
pub enum Error<T> {}
#[pallet::hooks]
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {}
#[pallet::call]
impl<T: Config> Pallet<T> {}
#[pallet::event]
#[pallet::generate_deposit(pub(super) fn deposit_event)]
pub enum Event<T: Config> {
InvalidFormat([u8; 8]),
UnsupportedVersion([u8; 8]),
ExecutedDownward([u8; 8], Outcome),
}
#[derive(PartialEq, Eq, Clone, Encode, Decode, TypeInfo, RuntimeDebug, MaxEncodedLen)]
#[pallet::origin]
pub enum Origin {
Relay,
SiblingParachain(ParaId),
}
impl From<ParaId> for Origin {
fn from(id: ParaId) -> Origin {
Origin::SiblingParachain(id)
}
}
impl From<u32> for Origin {
fn from(id: u32) -> Origin {
Origin::SiblingParachain(id.into())
}
}
}
pub struct UnlimitedDmpExecution<T>(sp_std::marker::PhantomData<T>);
impl<T: Config> DmpMessageHandler for UnlimitedDmpExecution<T> {
fn handle_dmp_messages(
iter: impl Iterator<Item = (RelayBlockNumber, Vec<u8>)>,
limit: Weight,
) -> Weight {
let mut used = Weight::zero();
for (_sent_at, data) in iter {
let id = sp_io::hashing::twox_64(&data[..]);
let msg = VersionedXcm::<T::RuntimeCall>::decode_all_with_depth_limit(
MAX_XCM_DECODE_DEPTH,
&mut data.as_slice(),
)
.map(Xcm::<T::RuntimeCall>::try_from);
match msg {
Err(_) => Pallet::<T>::deposit_event(Event::InvalidFormat(id)),
Ok(Err(())) => Pallet::<T>::deposit_event(Event::UnsupportedVersion(id)),
Ok(Ok(x)) => {
let outcome = T::XcmExecutor::execute_xcm(Parent, x, limit.ref_time());
used += Weight::from_ref_time(outcome.weight_used());
Pallet::<T>::deposit_event(Event::ExecutedDownward(id, outcome));
},
}
}
used
}
}
pub struct LimitAndDropDmpExecution<T>(sp_std::marker::PhantomData<T>);
impl<T: Config> DmpMessageHandler for LimitAndDropDmpExecution<T> {
fn handle_dmp_messages(
iter: impl Iterator<Item = (RelayBlockNumber, Vec<u8>)>,
limit: Weight,
) -> Weight {
let mut used = Weight::zero();
for (_sent_at, data) in iter {
let id = sp_io::hashing::twox_64(&data[..]);
let msg = VersionedXcm::<T::RuntimeCall>::decode_all_with_depth_limit(
MAX_XCM_DECODE_DEPTH,
&mut data.as_slice(),
)
.map(Xcm::<T::RuntimeCall>::try_from);
match msg {
Err(_) => Pallet::<T>::deposit_event(Event::InvalidFormat(id)),
Ok(Err(())) => Pallet::<T>::deposit_event(Event::UnsupportedVersion(id)),
Ok(Ok(x)) => {
let weight_limit = limit.saturating_sub(used);
let outcome = T::XcmExecutor::execute_xcm(Parent, x, weight_limit.ref_time());
used += Weight::from_ref_time(outcome.weight_used());
Pallet::<T>::deposit_event(Event::ExecutedDownward(id, outcome));
},
}
}
used
}
}
pub fn ensure_sibling_para<OuterOrigin>(o: OuterOrigin) -> Result<ParaId, BadOrigin>
where
OuterOrigin: Into<Result<Origin, OuterOrigin>>,
{
match o.into() {
Ok(Origin::SiblingParachain(id)) => Ok(id),
_ => Err(BadOrigin),
}
}
pub fn ensure_relay<OuterOrigin>(o: OuterOrigin) -> Result<(), BadOrigin>
where
OuterOrigin: Into<Result<Origin, OuterOrigin>>,
{
match o.into() {
Ok(Origin::Relay) => Ok(()),
_ => Err(BadOrigin),
}
}