barriers.rs 4.48 KB
Newer Older
Gavin Wood's avatar
Gavin Wood committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 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 <http://www.gnu.org/licenses/>.

Alexander Popiak's avatar
Alexander Popiak committed
17
18
//! Various implementations for `ShouldExecute`.

Gavin Wood's avatar
Gavin Wood committed
19
use frame_support::{ensure, traits::Contains, weights::Weight};
20
use polkadot_parachain::primitives::IsSystem;
Shawn Tabrizi's avatar
Shawn Tabrizi committed
21
use sp_std::{marker::PhantomData, result::Result};
22
use xcm::latest::{Instruction::*, Junction, Junctions, MultiLocation, WeightLimit::*, Xcm};
Shawn Tabrizi's avatar
Shawn Tabrizi committed
23
use xcm_executor::traits::{OnResponse, ShouldExecute};
Gavin Wood's avatar
Gavin Wood committed
24

25
/// Execution barrier that just takes `max_weight` from `weight_credit`.
26
27
28
29
///
/// Useful to allow XCM execution by local chain users via extrinsics.
/// E.g. `pallet_xcm::reserve_asset_transfer` to transfer a reserve asset
/// out of the local chain to another one.
Gavin Wood's avatar
Gavin Wood committed
30
31
32
pub struct TakeWeightCredit;
impl ShouldExecute for TakeWeightCredit {
	fn should_execute<Call>(
33
		_origin: &MultiLocation,
Gavin Wood's avatar
Gavin Wood committed
34
		_top_level: bool,
35
36
		_message: &mut Xcm<Call>,
		max_weight: Weight,
Gavin Wood's avatar
Gavin Wood committed
37
38
		weight_credit: &mut Weight,
	) -> Result<(), ()> {
39
		*weight_credit = weight_credit.checked_sub(max_weight).ok_or(())?;
Gavin Wood's avatar
Gavin Wood committed
40
41
42
43
		Ok(())
	}
}

44
45
/// Allows execution from `origin` if it is contained in `T` (i.e. `T::Contains(origin)`) taking
/// payments into account.
46
///
47
48
/// Only allows for `TeleportAsset`, `WithdrawAsset` and `ReserveAssetDeposit` XCMs because they are
/// the only ones that place assets in the Holding Register to pay for execution.
Gavin Wood's avatar
Gavin Wood committed
49
50
51
pub struct AllowTopLevelPaidExecutionFrom<T>(PhantomData<T>);
impl<T: Contains<MultiLocation>> ShouldExecute for AllowTopLevelPaidExecutionFrom<T> {
	fn should_execute<Call>(
52
		origin: &MultiLocation,
Gavin Wood's avatar
Gavin Wood committed
53
		top_level: bool,
54
55
		message: &mut Xcm<Call>,
		max_weight: Weight,
Gavin Wood's avatar
Gavin Wood committed
56
57
58
59
		_weight_credit: &mut Weight,
	) -> Result<(), ()> {
		ensure!(T::contains(origin), ());
		ensure!(top_level, ());
60
61
62
		let mut iter = message.0.iter_mut();
		let i = iter.next().ok_or(())?;
		match i {
63
64
65
66
			ReceiveTeleportedAsset(..) |
			WithdrawAsset(..) |
			ReserveAssetDeposited(..) |
			ClaimAsset { .. } => (),
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
			_ => return Err(()),
		}
		let mut i = iter.next().ok_or(())?;
		while let ClearOrigin = i {
			i = iter.next().ok_or(())?;
		}
		match i {
			BuyExecution { weight_limit: Limited(ref mut weight), .. } if *weight >= max_weight => {
				*weight = max_weight;
				Ok(())
			},
			BuyExecution { ref mut weight_limit, .. } if weight_limit == &Unlimited => {
				*weight_limit = Limited(max_weight);
				Ok(())
			},
Gavin Wood's avatar
Gavin Wood committed
82
83
84
85
86
			_ => Err(()),
		}
	}
}

Alexander Popiak's avatar
Alexander Popiak committed
87
88
/// Allows execution from any origin that is contained in `T` (i.e. `T::Contains(origin)`) without any payments.
/// Use only for executions from trusted origin groups.
Gavin Wood's avatar
Gavin Wood committed
89
90
91
pub struct AllowUnpaidExecutionFrom<T>(PhantomData<T>);
impl<T: Contains<MultiLocation>> ShouldExecute for AllowUnpaidExecutionFrom<T> {
	fn should_execute<Call>(
92
		origin: &MultiLocation,
Gavin Wood's avatar
Gavin Wood committed
93
		_top_level: bool,
94
95
		_message: &mut Xcm<Call>,
		_max_weight: Weight,
Gavin Wood's avatar
Gavin Wood committed
96
97
98
99
100
101
102
		_weight_credit: &mut Weight,
	) -> Result<(), ()> {
		ensure!(T::contains(origin), ());
		Ok(())
	}
}

Alexander Popiak's avatar
Alexander Popiak committed
103
/// Allows a message only if it is from a system-level child parachain.
104
pub struct IsChildSystemParachain<ParaId>(PhantomData<ParaId>);
Shawn Tabrizi's avatar
Shawn Tabrizi committed
105
impl<ParaId: IsSystem + From<u32>> Contains<MultiLocation> for IsChildSystemParachain<ParaId> {
106
	fn contains(l: &MultiLocation) -> bool {
107
108
109
110
111
		matches!(
			l.interior(),
			Junctions::X1(Junction::Parachain(id))
				if ParaId::from(*id).is_system() && l.parent_count() == 0,
		)
112
113
114
	}
}

Alexander Popiak's avatar
Alexander Popiak committed
115
/// Allows only messages if the generic `ResponseHandler` expects them via `expecting_response`.
Gavin Wood's avatar
Gavin Wood committed
116
117
118
pub struct AllowKnownQueryResponses<ResponseHandler>(PhantomData<ResponseHandler>);
impl<ResponseHandler: OnResponse> ShouldExecute for AllowKnownQueryResponses<ResponseHandler> {
	fn should_execute<Call>(
119
		origin: &MultiLocation,
Gavin Wood's avatar
Gavin Wood committed
120
		_top_level: bool,
121
122
		message: &mut Xcm<Call>,
		_max_weight: Weight,
Gavin Wood's avatar
Gavin Wood committed
123
124
		_weight_credit: &mut Weight,
	) -> Result<(), ()> {
125
126
		match message.0.first() {
			Some(QueryResponse { query_id, .. })
Shawn Tabrizi's avatar
Shawn Tabrizi committed
127
128
				if ResponseHandler::expecting_response(origin, *query_id) =>
				Ok(()),
Gavin Wood's avatar
Gavin Wood committed
129
130
131
132
			_ => Err(()),
		}
	}
}