// Copyright 2020 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 .
use frame_support::traits::{Contains, OriginTrait};
use parity_scale_codec::{Decode, Encode};
use sp_runtime::{traits::Dispatchable, DispatchErrorWithPostInfo};
use sp_std::{borrow::Borrow, marker::PhantomData, prelude::*, result::Result};
use xcm::latest::prelude::*;
/// Generic third-party conversion trait. Use this when you don't want to force the user to use default
/// implementations of `From` and `Into` for the types you wish to convert between.
///
/// One of `convert`/`convert_ref` and `reverse`/`reverse_ref` MUST be implemented. If possible, implement
/// `convert_ref`, since this will never result in a clone. Use `convert` when you definitely need to consume
/// the source value.
///
/// Can be amalgamated into tuples. If any of the tuple elements converts into `Ok(_)` it short circuits. Otherwise returns
/// the `Err(_)` of the last failing conversion (or `Err(())` for ref conversions).
pub trait Convert {
/// Convert from `value` (of type `A`) into an equivalent value of type `B`, `Err` if not possible.
fn convert(value: A) -> Result {
Self::convert_ref(&value).map_err(|_| value)
}
fn convert_ref(value: impl Borrow) -> Result {
Self::convert(value.borrow().clone()).map_err(|_| ())
}
/// Convert from `value` (of type `B`) into an equivalent value of type `A`, `Err` if not possible.
fn reverse(value: B) -> Result {
Self::reverse_ref(&value).map_err(|_| value)
}
fn reverse_ref(value: impl Borrow) -> Result {
Self::reverse(value.borrow().clone()).map_err(|_| ())
}
}
#[impl_trait_for_tuples::impl_for_tuples(30)]
impl Convert for Tuple {
fn convert(value: A) -> Result {
for_tuples!( #(
let value = match Tuple::convert(value) {
Ok(result) => return Ok(result),
Err(v) => v,
};
)* );
Err(value)
}
fn reverse(value: B) -> Result {
for_tuples!( #(
let value = match Tuple::reverse(value) {
Ok(result) => return Ok(result),
Err(v) => v,
};
)* );
Err(value)
}
fn convert_ref(value: impl Borrow) -> Result {
let value = value.borrow();
for_tuples!( #(
match Tuple::convert_ref(value) {
Ok(result) => return Ok(result),
Err(_) => (),
}
)* );
Err(())
}
fn reverse_ref(value: impl Borrow) -> Result {
let value = value.borrow();
for_tuples!( #(
match Tuple::reverse_ref(value.clone()) {
Ok(result) => return Ok(result),
Err(_) => (),
}
)* );
Err(())
}
}
/// Simple pass-through which implements `BytesConversion` while not doing any conversion.
pub struct Identity;
impl Convert for Identity {
fn convert(value: T) -> Result {
Ok(value)
}
fn reverse(value: T) -> Result {
Ok(value)
}
}
/// Implementation of `Convert` trait using `TryFrom`.
pub struct JustTry;
impl + Clone, Dest: TryFrom + Clone> Convert
for JustTry
{
fn convert(value: Source) -> Result {
Dest::try_from(value.clone()).map_err(|_| value)
}
fn reverse(value: Dest) -> Result {
Source::try_from(value.clone()).map_err(|_| value)
}
}
/// Implementation of `Convert<_, Vec>` using the parity scale codec.
pub struct Encoded;
impl Convert> for Encoded {
fn convert_ref(value: impl Borrow) -> Result, ()> {
Ok(value.borrow().encode())
}
fn reverse_ref(bytes: impl Borrow>) -> Result {
T::decode(&mut &bytes.borrow()[..]).map_err(|_| ())
}
}
/// Implementation of `Convert, _>` using the parity scale codec.
pub struct Decoded;
impl Convert, T> for Decoded {
fn convert_ref(bytes: impl Borrow>) -> Result {
T::decode(&mut &bytes.borrow()[..]).map_err(|_| ())
}
fn reverse_ref(value: impl Borrow) -> Result, ()> {
Ok(value.borrow().encode())
}
}
/// A converter `trait` for origin types.
///
/// Can be amalgamated into tuples. If any of the tuple elements returns `Ok(_)`, it short circuits. Else, the `Err(_)`
/// of the last tuple item is returned. Each intermediate `Err(_)` might return a different `origin` of type `Origin`
/// which is passed to the next convert item.
///
/// ```rust
/// # use xcm::latest::{MultiLocation, Junctions, Junction, OriginKind};
/// # use xcm_executor::traits::ConvertOrigin;
/// // A convertor that will bump the para id and pass it to the next one.
/// struct BumpParaId;
/// impl ConvertOrigin for BumpParaId {
/// fn convert_origin(origin: impl Into, _: OriginKind) -> Result {
/// match origin.into() {
/// MultiLocation { parents: 0, interior: Junctions::X1(Junction::Parachain(id)) } => {
/// Err(Junctions::X1(Junction::Parachain(id + 1)).into())
/// }
/// _ => unreachable!()
/// }
/// }
/// }
///
/// struct AcceptPara7;
/// impl ConvertOrigin for AcceptPara7 {
/// fn convert_origin(origin: impl Into, _: OriginKind) -> Result {
/// match origin.into() {
/// MultiLocation { parents: 0, interior: Junctions::X1(Junction::Parachain(id)) } if id == 7 => {
/// Ok(7)
/// }
/// o => Err(o)
/// }
/// }
/// }
/// # fn main() {
/// let origin: MultiLocation = Junctions::X1(Junction::Parachain(6)).into();
/// assert!(
/// <(BumpParaId, AcceptPara7) as ConvertOrigin>::convert_origin(origin, OriginKind::Native)
/// .is_ok()
/// );
/// # }
/// ```
pub trait ConvertOrigin {
/// Attempt to convert `origin` to the generic `Origin` whilst consuming it.
fn convert_origin(
origin: impl Into,
kind: OriginKind,
) -> Result;
}
#[impl_trait_for_tuples::impl_for_tuples(30)]
impl ConvertOrigin for Tuple {
fn convert_origin(
origin: impl Into,
kind: OriginKind,
) -> Result {
for_tuples!( #(
let origin = match Tuple::convert_origin(origin, kind) {
Err(o) => o,
r => return r
};
)* );
let origin = origin.into();
log::trace!(
target: "xcm::convert_origin",
"could not convert: origin: {:?}, kind: {:?}",
origin,
kind,
);
Err(origin)
}
}
/// Defines how a call is dispatched with given origin.
/// Allows to customize call dispatch, such as adapting the origin based on the call
/// or modifying the call.
pub trait CallDispatcher {
fn dispatch(
call: Call,
origin: Call::RuntimeOrigin,
) -> Result>;
}
pub struct WithOriginFilter(PhantomData);
impl CallDispatcher for WithOriginFilter
where
Call: Dispatchable,
Call::RuntimeOrigin: OriginTrait,
<::RuntimeOrigin as OriginTrait>::Call: 'static,
Filter: Contains<<::RuntimeOrigin as OriginTrait>::Call> + 'static,
{
fn dispatch(
call: Call,
mut origin: ::RuntimeOrigin,
) -> Result<
::PostInfo,
DispatchErrorWithPostInfo<::PostInfo>,
> {
origin.add_filter(Filter::contains);
call.dispatch(origin)
}
}
// We implement it for every calls so they can dispatch themselves
// (without any change).
impl CallDispatcher for Call {
fn dispatch(
call: Call,
origin: Call::RuntimeOrigin,
) -> Result> {
call.dispatch(origin)
}
}