// 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) } }