referrerpolicy=no-referrer-when-downgrade

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}