mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-30 17:31:03 +00:00
XCM Revamp Continued (#2865)
* Introduce plurality XCM locations * Add RelayedFrom * DMP dispatch weight handling. * Add pallet for XCM sending, add routing logic. * Update error types & doc * Fix warnings. * Fixes * Fixes * Fixes * Bump Substrate * Fixes * Docs * Docs * Docs * Fixes * Fixes * Fixes * Update xcm/pallet-xcm/src/lib.rs Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com> * Docs * Fixes * Update lib.rs * Fixes Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com>
This commit is contained in:
@@ -0,0 +1,182 @@
|
||||
// Copyright 2020-2021 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Pallet to handle XCM messages.
|
||||
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
use sp_std::{marker::PhantomData, convert::TryInto, boxed::Box};
|
||||
use codec::{Encode, Decode};
|
||||
use xcm::v0::{BodyId, MultiLocation::{self, X1}, Junction::Plurality};
|
||||
use sp_runtime::{RuntimeDebug, traits::BadOrigin};
|
||||
use frame_support::traits::{EnsureOrigin, OriginTrait, Filter, Get};
|
||||
|
||||
pub use pallet::*;
|
||||
|
||||
#[frame_support::pallet]
|
||||
pub mod pallet {
|
||||
use super::*;
|
||||
use frame_support::pallet_prelude::*;
|
||||
use frame_system::pallet_prelude::*;
|
||||
use xcm::v0::{Xcm, MultiLocation, Error as XcmError, SendXcm, ExecuteXcm};
|
||||
|
||||
#[pallet::pallet]
|
||||
#[pallet::generate_store(pub(super) trait Store)]
|
||||
pub struct Pallet<T>(_);
|
||||
|
||||
#[pallet::config]
|
||||
/// The module configuration trait.
|
||||
pub trait Config: frame_system::Config {
|
||||
/// The overarching event type.
|
||||
type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event>;
|
||||
|
||||
/// Required origin for sending XCM messages. If successful, the it resolves to `MultiLocation`
|
||||
/// which exists as an interior location within this chain's XCM context.
|
||||
type SendXcmOrigin: EnsureOrigin<Self::Origin, Success=MultiLocation>;
|
||||
|
||||
/// The type used to actually dispatch an XCM to its destination.
|
||||
type XcmRouter: SendXcm;
|
||||
|
||||
/// Required origin for executing XCM messages. If successful, the it resolves to `MultiLocation`
|
||||
/// which exists as an interior location within this chain's XCM context.
|
||||
type ExecuteXcmOrigin: EnsureOrigin<Self::Origin, Success=MultiLocation>;
|
||||
|
||||
/// Something to execute an XCM message.
|
||||
type XcmExecutor: ExecuteXcm<Self::Call>;
|
||||
}
|
||||
|
||||
#[pallet::event]
|
||||
#[pallet::generate_deposit(pub(super) fn deposit_event)]
|
||||
pub enum Event<T: Config> {
|
||||
Attempted(xcm::v0::Outcome),
|
||||
}
|
||||
|
||||
#[pallet::error]
|
||||
pub enum Error<T> {
|
||||
Unreachable,
|
||||
SendFailure,
|
||||
}
|
||||
|
||||
#[pallet::hooks]
|
||||
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {}
|
||||
|
||||
#[pallet::call]
|
||||
impl<T: Config> Pallet<T> {
|
||||
#[pallet::weight(1_000)]
|
||||
fn send(origin: OriginFor<T>, dest: MultiLocation, message: Xcm<()>) -> DispatchResult {
|
||||
let origin_location = T::SendXcmOrigin::ensure_origin(origin)?;
|
||||
Self::send_xcm(origin_location, dest, message)
|
||||
.map_err(|e| match e {
|
||||
XcmError::CannotReachDestination(..) => Error::<T>::Unreachable,
|
||||
_ => Error::<T>::SendFailure,
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Execute an XCM message from a local, signed, origin.
|
||||
///
|
||||
/// An event is deposited indicating whether `msg` could be executed completely or only
|
||||
/// partially.
|
||||
///
|
||||
/// No more than `max_weight` will be used in its attempted execution. If this is less than the
|
||||
/// maximum amount of weight that the message could take to be executed, then no execution
|
||||
/// attempt will be made.
|
||||
///
|
||||
/// NOTE: A successful return to this does *not* imply that the `msg` was executed successfully
|
||||
/// to completion; only that *some* of it was executed.
|
||||
#[pallet::weight(max_weight.saturating_add(1_000u64))]
|
||||
fn execute(origin: OriginFor<T>, message: Box<Xcm<T::Call>>, max_weight: Weight)
|
||||
-> DispatchResult
|
||||
{
|
||||
let origin_location = T::ExecuteXcmOrigin::ensure_origin(origin)?;
|
||||
let outcome = T::XcmExecutor::execute_xcm(origin_location, *message, max_weight);
|
||||
Self::deposit_event(Event::Attempted(outcome));
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Config> Pallet<T> {
|
||||
/// Relay an XCM `message` from a given `interior` location in this context to a given `dest`
|
||||
/// location. A null `dest` is not handled.
|
||||
pub fn send_xcm(interior: MultiLocation, dest: MultiLocation, message: Xcm<()>) -> Result<(), XcmError> {
|
||||
let message = match interior {
|
||||
MultiLocation::Null => message,
|
||||
who => Xcm::<()>::RelayedFrom { who, message: Box::new(message) },
|
||||
};
|
||||
T::XcmRouter::send_xcm(dest, message)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Origin for the parachains module.
|
||||
#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug)]
|
||||
pub enum Origin {
|
||||
/// It comes from somewhere in the XCM space.
|
||||
Xcm(MultiLocation),
|
||||
}
|
||||
|
||||
impl From<MultiLocation> for Origin {
|
||||
fn from(location: MultiLocation) -> Origin {
|
||||
Origin::Xcm(location)
|
||||
}
|
||||
}
|
||||
|
||||
/// Ensure that the origin `o` represents a sibling parachain.
|
||||
/// Returns `Ok` with the parachain ID of the sibling or an `Err` otherwise.
|
||||
pub fn ensure_xcm<OuterOrigin>(o: OuterOrigin) -> Result<MultiLocation, BadOrigin>
|
||||
where OuterOrigin: Into<Result<Origin, OuterOrigin>>
|
||||
{
|
||||
match o.into() {
|
||||
Ok(Origin::Xcm(location)) => Ok(location),
|
||||
_ => Err(BadOrigin),
|
||||
}
|
||||
}
|
||||
|
||||
/// Filter for `MultiLocation` to find those which represent a strict majority approval of an identified
|
||||
/// plurality.
|
||||
///
|
||||
/// May reasonably be used with `EnsureXcm`.
|
||||
pub struct IsMajorityOfBody<Body>(PhantomData<Body>);
|
||||
impl<Body: Get<BodyId>> Filter<MultiLocation> for IsMajorityOfBody<Body> {
|
||||
fn filter(l: &MultiLocation) -> bool {
|
||||
matches!(l, X1(Plurality { id, part }) if id == &Body::get() && part.is_majority())
|
||||
}
|
||||
}
|
||||
|
||||
/// `EnsureOrigin` implementation succeeding with a `MultiLocation` value to recognise and filter the
|
||||
/// `Origin::Xcm` item.
|
||||
pub struct EnsureXcm<F>(PhantomData<F>);
|
||||
impl<O: OriginTrait + From<Origin>, F: Filter<MultiLocation>> EnsureOrigin<O> for EnsureXcm<F>
|
||||
where O::PalletsOrigin: From<Origin> + TryInto<Origin, Error=O::PalletsOrigin>
|
||||
{
|
||||
type Success = MultiLocation;
|
||||
|
||||
fn try_origin(outer: O) -> Result<Self::Success, O> {
|
||||
outer.try_with_caller(|caller| caller.try_into()
|
||||
.and_then(|Origin::Xcm(location)|
|
||||
if F::filter(&location) {
|
||||
Ok(location)
|
||||
} else {
|
||||
Err(Origin::Xcm(location).into())
|
||||
}
|
||||
))
|
||||
}
|
||||
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
fn successful_origin() -> O {
|
||||
O::from(Origin::Xcm(MultiLocation::Null))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user