staging_xcm_executor/traits/conversion.rs
1// Copyright (C) Parity Technologies (UK) Ltd.
2// This file is part of Polkadot.
3
4// Polkadot is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// Polkadot is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
16
17use core::{marker::PhantomData, result::Result};
18use frame_support::traits::{Contains, OriginTrait};
19use sp_runtime::{traits::Dispatchable, DispatchErrorWithPostInfo};
20use xcm::latest::prelude::*;
21
22/// Means of converting a location into an account identifier.
23pub trait ConvertLocation<AccountId> {
24 /// Convert the `location` into `Some` account ID, or `None` if not possible.
25 fn convert_location(location: &Location) -> Option<AccountId>;
26}
27
28#[impl_trait_for_tuples::impl_for_tuples(30)]
29impl<AccountId> ConvertLocation<AccountId> for Tuple {
30 fn convert_location(l: &Location) -> Option<AccountId> {
31 for_tuples!( #(
32 match Tuple::convert_location(l) {
33 Some(result) => return Some(result),
34 None => {},
35 }
36 )* );
37 None
38 }
39}
40
41/// A converter `trait` for origin types.
42///
43/// Can be amalgamated into tuples. If any of the tuple elements returns `Ok(_)`, it short circuits.
44/// Else, the `Err(_)` of the last tuple item is returned. Each intermediate `Err(_)` might return a
45/// different `origin` of type `Origin` which is passed to the next convert item.
46///
47/// ```rust
48/// # use xcm::latest::{Location, Junctions, Junction, OriginKind};
49/// # use staging_xcm_executor::traits::ConvertOrigin;
50/// // A convertor that will bump the para id and pass it to the next one.
51/// struct BumpParaId;
52/// impl ConvertOrigin<u32> for BumpParaId {
53/// fn convert_origin(origin: impl Into<Location>, _: OriginKind) -> Result<u32, Location> {
54/// match origin.into().unpack() {
55/// (0, [Junction::Parachain(id)]) => {
56/// Err([Junction::Parachain(id + 1)].into())
57/// }
58/// _ => unreachable!()
59/// }
60/// }
61/// }
62///
63/// struct AcceptPara7;
64/// impl ConvertOrigin<u32> for AcceptPara7 {
65/// fn convert_origin(origin: impl Into<Location>, _: OriginKind) -> Result<u32, Location> {
66/// let origin = origin.into();
67/// match origin.unpack() {
68/// (0, [Junction::Parachain(id)]) if *id == 7 => {
69/// Ok(7)
70/// }
71/// _ => Err(origin)
72/// }
73/// }
74/// }
75/// # fn main() {
76/// let origin: Location = [Junction::Parachain(6)].into();
77/// assert!(
78/// <(BumpParaId, AcceptPara7) as ConvertOrigin<u32>>::convert_origin(origin, OriginKind::Native)
79/// .is_ok()
80/// );
81/// # }
82/// ```
83pub trait ConvertOrigin<Origin> {
84 /// Attempt to convert `origin` to the generic `Origin` whilst consuming it.
85 fn convert_origin(origin: impl Into<Location>, kind: OriginKind) -> Result<Origin, Location>;
86}
87
88#[impl_trait_for_tuples::impl_for_tuples(30)]
89impl<O> ConvertOrigin<O> for Tuple {
90 fn convert_origin(origin: impl Into<Location>, kind: OriginKind) -> Result<O, Location> {
91 let origin = origin.into();
92
93 tracing::trace!(
94 target: "xcm::convert_origin",
95 ?origin,
96 ?kind,
97 "Converting origin",
98 );
99
100 for_tuples!( #(
101 let convert_origin = core::any::type_name::<Tuple>();
102
103 let origin = match Tuple::convert_origin(origin, kind) {
104 Err(o) => {
105 tracing::trace!(
106 target: "xcm::convert_origin",
107 %convert_origin,
108 "Convert origin step failed",
109 );
110
111 o
112 },
113 Ok(o) => {
114 tracing::trace!(
115 target: "xcm::convert_origin",
116 %convert_origin,
117 "Convert origin step succeeded",
118 );
119
120 return Ok(o)
121 }
122 };
123 )* );
124
125 tracing::trace!(
126 target: "xcm::convert_origin",
127 "Converting origin failed",
128 );
129
130 Err(origin)
131 }
132}
133
134/// Defines how a call is dispatched with given origin.
135/// Allows to customize call dispatch, such as adapting the origin based on the call
136/// or modifying the call.
137pub trait CallDispatcher<Call: Dispatchable> {
138 fn dispatch(
139 call: Call,
140 origin: Call::RuntimeOrigin,
141 ) -> Result<Call::PostInfo, DispatchErrorWithPostInfo<Call::PostInfo>>;
142}
143
144pub struct WithOriginFilter<Filter>(PhantomData<Filter>);
145impl<Call, Filter> CallDispatcher<Call> for WithOriginFilter<Filter>
146where
147 Call: Dispatchable,
148 Call::RuntimeOrigin: OriginTrait,
149 <<Call as Dispatchable>::RuntimeOrigin as OriginTrait>::Call: 'static,
150 Filter: Contains<<<Call as Dispatchable>::RuntimeOrigin as OriginTrait>::Call> + 'static,
151{
152 fn dispatch(
153 call: Call,
154 mut origin: <Call as Dispatchable>::RuntimeOrigin,
155 ) -> Result<
156 <Call as Dispatchable>::PostInfo,
157 DispatchErrorWithPostInfo<<Call as Dispatchable>::PostInfo>,
158 > {
159 origin.add_filter(Filter::contains);
160 call.dispatch(origin)
161 }
162}
163
164// We implement it for every calls so they can dispatch themselves
165// (without any change).
166impl<Call: Dispatchable> CallDispatcher<Call> for Call {
167 fn dispatch(
168 call: Call,
169 origin: Call::RuntimeOrigin,
170 ) -> Result<Call::PostInfo, DispatchErrorWithPostInfo<Call::PostInfo>> {
171 call.dispatch(origin)
172 }
173}