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

            
17
//! Support data structures for `MultiLocation`, primarily the `Junction` datatype.
18

            
19
use super::{BodyId, BodyPart, Junctions, MultiLocation, NetworkId};
20
use crate::v3::Junction as NewJunction;
21
use bounded_collections::{ConstU32, WeakBoundedVec};
22
use codec::{Decode, Encode, MaxEncodedLen};
23
use scale_info::TypeInfo;
24

            
25
/// A single item in a path to describe the relative location of a consensus system.
26
///
27
/// Each item assumes a pre-existing location as its context and is defined in terms of it.
28
201
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug, TypeInfo, MaxEncodedLen)]
29
#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
30
#[scale_info(replace_segment("staging_xcm", "xcm"))]
31
pub enum Junction {
32
17325
	/// An indexed parachain belonging to and operated by the context.
33
	///
34
	/// Generally used when the context is a Polkadot Relay-chain.
35
17325
	Parachain(#[codec(compact)] u32),
36
2748
	/// A 32-byte identifier for an account of a specific network that is respected as a sovereign
37
	/// endpoint within the context.
38
	///
39
	/// Generally used when the context is a Substrate-based chain.
40
2748
	AccountId32 { network: NetworkId, id: [u8; 32] },
41
2055
	/// An 8-byte index for an account of a specific network that is respected as a sovereign
42
	/// endpoint within the context.
43
	///
44
	/// May be used when the context is a Frame-based chain and includes e.g. an indices pallet.
45
	AccountIndex64 {
46
21
		network: NetworkId,
47
15
		#[codec(compact)]
48
15
		index: u64,
49
2055
	},
50
912
	/// A 20-byte identifier for an account of a specific network that is respected as a sovereign
51
	/// endpoint within the context.
52
	///
53
	/// May be used when the context is an Ethereum or Bitcoin chain or smart-contract.
54
912
	AccountKey20 { network: NetworkId, key: [u8; 20] },
55
3396
	/// An instanced, indexed pallet that forms a constituent part of the context.
56
	///
57
	/// Generally used when the context is a Frame-based chain.
58
3396
	PalletInstance(u8),
59
1356
	/// A non-descript index within the context location.
60
	///
61
	/// Usage will vary widely owing to its generality.
62
	///
63
	/// NOTE: Try to avoid using this and instead use a more specific item.
64
1356
	GeneralIndex(#[codec(compact)] u128),
65
576
	/// A nondescript datum acting as a key within the context location.
66
	///
67
	/// Usage will vary widely owing to its generality.
68
	///
69
	/// NOTE: Try to avoid using this and instead use a more specific item.
70
576
	GeneralKey(WeakBoundedVec<u8, ConstU32<32>>),
71
699
	/// The unambiguous child.
72
699
	///
73
699
	/// Not currently used except as a fallback when deriving ancestry.
74
699
	OnlyChild,
75
1800
	/// A pluralistic body existing within consensus.
76
	///
77
	/// Typical to be used to represent a governance origin of a chain, but could in principle be
78
	/// used to represent things such as multisigs also.
79
1800
	Plurality { id: BodyId, part: BodyPart },
80
}
81

            
82
impl TryFrom<NewJunction> for Junction {
83
	type Error = ();
84

            
85
	fn try_from(value: NewJunction) -> Result<Self, Self::Error> {
86
		use NewJunction::*;
87
		Ok(match value {
88
			Parachain(id) => Self::Parachain(id),
89
			AccountId32 { network, id } => Self::AccountId32 { network: network.try_into()?, id },
90
			AccountIndex64 { network, index } =>
91
				Self::AccountIndex64 { network: network.try_into()?, index },
92
			AccountKey20 { network, key } =>
93
				Self::AccountKey20 { network: network.try_into()?, key },
94
			PalletInstance(index) => Self::PalletInstance(index),
95
			GeneralIndex(id) => Self::GeneralIndex(id),
96
			GeneralKey { length, data } => Self::GeneralKey(
97
				data[0..data.len().min(length as usize)]
98
					.to_vec()
99
					.try_into()
100
					.expect("key is bounded to 32 and so will never be out of bounds; qed"),
101
			),
102
			OnlyChild => Self::OnlyChild,
103
			Plurality { id, part } => Self::Plurality { id: id.into(), part: part.into() },
104
			_ => return Err(()),
105
		})
106
	}
107
}
108

            
109
impl Junction {
110
	/// Convert `self` into a `MultiLocation` containing 0 parents.
111
	///
112
	/// Similar to `Into::into`, except that this method can be used in a const evaluation context.
113
	pub const fn into(self) -> MultiLocation {
114
		MultiLocation { parents: 0, interior: Junctions::X1(self) }
115
	}
116

            
117
	/// Convert `self` into a `MultiLocation` containing `n` parents.
118
	///
119
	/// Similar to `Self::into`, with the added ability to specify the number of parent junctions.
120
	pub const fn into_exterior(self, n: u8) -> MultiLocation {
121
		MultiLocation { parents: n, interior: Junctions::X1(self) }
122
	}
123
}