staging_xcm/v2/
multilocation.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
17//! Cross-Consensus Message format data structures.
18
19use super::Junction;
20use crate::v3::MultiLocation as NewMultiLocation;
21use codec::{Decode, Encode, MaxEncodedLen};
22use core::{mem, result};
23use scale_info::TypeInfo;
24
25/// A relative path between state-bearing consensus systems.
26///
27/// A location in a consensus system is defined as an *isolatable state machine* held within global
28/// consensus. The location in question need not have a sophisticated consensus algorithm of its
29/// own; a single account within Ethereum, for example, could be considered a location.
30///
31/// A very-much non-exhaustive list of types of location include:
32/// - A (normal, layer-1) block chain, e.g. the Bitcoin mainnet or a parachain.
33/// - A layer-0 super-chain, e.g. the Polkadot Relay chain.
34/// - A layer-2 smart contract, e.g. an ERC-20 on Ethereum.
35/// - A logical functional component of a chain, e.g. a single instance of a pallet on a Frame-based
36///   Substrate chain.
37/// - An account.
38///
39/// A `MultiLocation` is a *relative identifier*, meaning that it can only be used to define the
40/// relative path between two locations, and cannot generally be used to refer to a location
41/// universally. It is comprised of an integer number of parents specifying the number of times to
42/// "escape" upwards into the containing consensus system and then a number of *junctions*, each
43/// diving down and specifying some interior portion of state (which may be considered a
44/// "sub-consensus" system).
45///
46/// This specific `MultiLocation` implementation uses a `Junctions` datatype which is a Rust `enum`
47/// in order to make pattern matching easier. There are occasions where it is important to ensure
48/// that a value is strictly an interior location, in those cases, `Junctions` may be used.
49///
50/// The `MultiLocation` value of `Null` simply refers to the interpreting consensus system.
51#[derive(Clone, Decode, Encode, Eq, PartialEq, Ord, PartialOrd, Debug, TypeInfo, MaxEncodedLen)]
52#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
53#[scale_info(replace_segment("staging_xcm", "xcm"))]
54pub struct MultiLocation {
55	/// The number of parent junctions at the beginning of this `MultiLocation`.
56	pub parents: u8,
57	/// The interior (i.e. non-parent) junctions that this `MultiLocation` contains.
58	pub interior: Junctions,
59}
60
61impl Default for MultiLocation {
62	fn default() -> Self {
63		Self { parents: 0, interior: Junctions::Here }
64	}
65}
66
67/// A relative location which is constrained to be an interior location of the context.
68///
69/// See also `MultiLocation`.
70pub type InteriorMultiLocation = Junctions;
71
72impl MultiLocation {
73	/// Creates a new `MultiLocation` with the given number of parents and interior junctions.
74	pub fn new(parents: u8, junctions: Junctions) -> MultiLocation {
75		MultiLocation { parents, interior: junctions }
76	}
77
78	/// Consume `self` and return the equivalent `VersionedLocation` value.
79	pub fn versioned(self) -> crate::VersionedLocation {
80		self.into()
81	}
82
83	/// Creates a new `MultiLocation` with 0 parents and a `Here` interior.
84	///
85	/// The resulting `MultiLocation` can be interpreted as the "current consensus system".
86	pub const fn here() -> MultiLocation {
87		MultiLocation { parents: 0, interior: Junctions::Here }
88	}
89
90	/// Creates a new `MultiLocation` which evaluates to the parent context.
91	pub const fn parent() -> MultiLocation {
92		MultiLocation { parents: 1, interior: Junctions::Here }
93	}
94
95	/// Creates a new `MultiLocation` which evaluates to the grand parent context.
96	pub const fn grandparent() -> MultiLocation {
97		MultiLocation { parents: 2, interior: Junctions::Here }
98	}
99
100	/// Creates a new `MultiLocation` with `parents` and an empty (`Here`) interior.
101	pub const fn ancestor(parents: u8) -> MultiLocation {
102		MultiLocation { parents, interior: Junctions::Here }
103	}
104
105	/// Whether the `MultiLocation` has no parents and has a `Here` interior.
106	pub const fn is_here(&self) -> bool {
107		self.parents == 0 && self.interior.len() == 0
108	}
109
110	/// Return a reference to the interior field.
111	pub fn interior(&self) -> &Junctions {
112		&self.interior
113	}
114
115	/// Return a mutable reference to the interior field.
116	pub fn interior_mut(&mut self) -> &mut Junctions {
117		&mut self.interior
118	}
119
120	/// Returns the number of `Parent` junctions at the beginning of `self`.
121	pub const fn parent_count(&self) -> u8 {
122		self.parents
123	}
124
125	/// Returns boolean indicating whether `self` contains only the specified amount of
126	/// parents and no interior junctions.
127	pub const fn contains_parents_only(&self, count: u8) -> bool {
128		matches!(self.interior, Junctions::Here) && self.parents == count
129	}
130
131	/// Returns the number of parents and junctions in `self`.
132	pub const fn len(&self) -> usize {
133		self.parent_count() as usize + self.interior.len()
134	}
135
136	/// Returns the first interior junction, or `None` if the location is empty or contains only
137	/// parents.
138	pub fn first_interior(&self) -> Option<&Junction> {
139		self.interior.first()
140	}
141
142	/// Returns last junction, or `None` if the location is empty or contains only parents.
143	pub fn last(&self) -> Option<&Junction> {
144		self.interior.last()
145	}
146
147	/// Splits off the first interior junction, returning the remaining suffix (first item in tuple)
148	/// and the first element (second item in tuple) or `None` if it was empty.
149	pub fn split_first_interior(self) -> (MultiLocation, Option<Junction>) {
150		let MultiLocation { parents, interior: junctions } = self;
151		let (suffix, first) = junctions.split_first();
152		let multilocation = MultiLocation { parents, interior: suffix };
153		(multilocation, first)
154	}
155
156	/// Splits off the last interior junction, returning the remaining prefix (first item in tuple)
157	/// and the last element (second item in tuple) or `None` if it was empty or if `self` only
158	/// contains parents.
159	pub fn split_last_interior(self) -> (MultiLocation, Option<Junction>) {
160		let MultiLocation { parents, interior: junctions } = self;
161		let (prefix, last) = junctions.split_last();
162		let multilocation = MultiLocation { parents, interior: prefix };
163		(multilocation, last)
164	}
165
166	/// Mutates `self`, suffixing its interior junctions with `new`. Returns `Err` with `new` in
167	/// case of overflow.
168	pub fn push_interior(&mut self, new: Junction) -> result::Result<(), Junction> {
169		self.interior.push(new)
170	}
171
172	/// Mutates `self`, prefixing its interior junctions with `new`. Returns `Err` with `new` in
173	/// case of overflow.
174	pub fn push_front_interior(&mut self, new: Junction) -> result::Result<(), Junction> {
175		self.interior.push_front(new)
176	}
177
178	/// Consumes `self` and returns a `MultiLocation` suffixed with `new`, or an `Err` with
179	/// the original value of `self` in case of overflow.
180	pub fn pushed_with_interior(self, new: Junction) -> result::Result<Self, (Self, Junction)> {
181		match self.interior.pushed_with(new) {
182			Ok(i) => Ok(MultiLocation { interior: i, parents: self.parents }),
183			Err((i, j)) => Err((MultiLocation { interior: i, parents: self.parents }, j)),
184		}
185	}
186
187	/// Consumes `self` and returns a `MultiLocation` prefixed with `new`, or an `Err` with the
188	/// original value of `self` in case of overflow.
189	pub fn pushed_front_with_interior(
190		self,
191		new: Junction,
192	) -> result::Result<Self, (Self, Junction)> {
193		match self.interior.pushed_front_with(new) {
194			Ok(i) => Ok(MultiLocation { interior: i, parents: self.parents }),
195			Err((i, j)) => Err((MultiLocation { interior: i, parents: self.parents }, j)),
196		}
197	}
198
199	/// Returns the junction at index `i`, or `None` if the location is a parent or if the location
200	/// does not contain that many elements.
201	pub fn at(&self, i: usize) -> Option<&Junction> {
202		let num_parents = self.parents as usize;
203		if i < num_parents {
204			return None
205		}
206		self.interior.at(i - num_parents)
207	}
208
209	/// Returns a mutable reference to the junction at index `i`, or `None` if the location is a
210	/// parent or if it doesn't contain that many elements.
211	pub fn at_mut(&mut self, i: usize) -> Option<&mut Junction> {
212		let num_parents = self.parents as usize;
213		if i < num_parents {
214			return None
215		}
216		self.interior.at_mut(i - num_parents)
217	}
218
219	/// Decrements the parent count by 1.
220	pub fn dec_parent(&mut self) {
221		self.parents = self.parents.saturating_sub(1);
222	}
223
224	/// Removes the first interior junction from `self`, returning it
225	/// (or `None` if it was empty or if `self` contains only parents).
226	pub fn take_first_interior(&mut self) -> Option<Junction> {
227		self.interior.take_first()
228	}
229
230	/// Removes the last element from `interior`, returning it (or `None` if it was empty or if
231	/// `self` only contains parents).
232	pub fn take_last(&mut self) -> Option<Junction> {
233		self.interior.take_last()
234	}
235
236	/// Ensures that `self` has the same number of parents as `prefix`, its junctions begins with
237	/// the junctions of `prefix` and that it has a single `Junction` item following.
238	/// If so, returns a reference to this `Junction` item.
239	///
240	/// # Example
241	/// ```rust
242	/// # use staging_xcm::v2::{Junctions::*, Junction::*, MultiLocation};
243	/// let mut m = MultiLocation::new(1, [PalletInstance(3), OnlyChild].into());
244	/// assert_eq!(
245	///     m.match_and_split(&MultiLocation::new(1, [PalletInstance(3)].into())),
246	///     Some(&OnlyChild),
247	/// );
248	/// assert_eq!(m.match_and_split(&MultiLocation::new(1, Here)), None);
249	/// ```
250	pub fn match_and_split(&self, prefix: &MultiLocation) -> Option<&Junction> {
251		if self.parents != prefix.parents {
252			return None
253		}
254		self.interior.match_and_split(&prefix.interior)
255	}
256
257	/// Returns whether `self` has the same number of parents as `prefix` and its junctions begins
258	/// with the junctions of `prefix`.
259	///
260	/// # Example
261	/// ```rust
262	/// # use staging_xcm::v2::{Junctions::*, Junction::*, MultiLocation};
263	/// let m = MultiLocation::new(1, [PalletInstance(3), OnlyChild, OnlyChild].into());
264	/// assert!(m.starts_with(&MultiLocation::new(1, [PalletInstance(3)].into())));
265	/// assert!(!m.starts_with(&MultiLocation::new(1, [GeneralIndex(99)].into())));
266	/// assert!(!m.starts_with(&MultiLocation::new(0, [PalletInstance(3)].into())));
267	/// ```
268	pub fn starts_with(&self, prefix: &MultiLocation) -> bool {
269		if self.parents != prefix.parents {
270			return false
271		}
272		self.interior.starts_with(&prefix.interior)
273	}
274
275	/// Mutate `self` so that it is suffixed with `suffix`.
276	///
277	/// Does not modify `self` and returns `Err` with `suffix` in case of overflow.
278	///
279	/// # Example
280	/// ```rust
281	/// # use staging_xcm::v2::{Junctions::*, Junction::*, MultiLocation};
282	/// let mut m = MultiLocation::new(1, [Parachain(21)].into());
283	/// assert_eq!(m.append_with([PalletInstance(3)].into()), Ok(()));
284	/// assert_eq!(m, MultiLocation::new(1, [Parachain(21), PalletInstance(3)].into()));
285	/// ```
286	pub fn append_with(&mut self, suffix: Junctions) -> Result<(), Junctions> {
287		if self.interior.len().saturating_add(suffix.len()) > MAX_JUNCTIONS {
288			return Err(suffix)
289		}
290		for j in suffix.into_iter() {
291			self.interior.push(j).expect("Already checked the sum of the len()s; qed")
292		}
293		Ok(())
294	}
295
296	/// Mutate `self` so that it is prefixed with `prefix`.
297	///
298	/// Does not modify `self` and returns `Err` with `prefix` in case of overflow.
299	///
300	/// # Example
301	/// ```rust
302	/// # use staging_xcm::v2::{Junctions::*, Junction::*, MultiLocation};
303	/// let mut m = MultiLocation::new(2, [PalletInstance(3)].into());
304	/// assert_eq!(m.prepend_with(MultiLocation::new(1, [Parachain(21), OnlyChild].into())), Ok(()));
305	/// assert_eq!(m, MultiLocation::new(1, [PalletInstance(3)].into()));
306	/// ```
307	pub fn prepend_with(&mut self, mut prefix: MultiLocation) -> Result<(), MultiLocation> {
308		//     prefix     self (suffix)
309		// P .. P I .. I  p .. p i .. i
310		let prepend_interior = prefix.interior.len().saturating_sub(self.parents as usize);
311		let final_interior = self.interior.len().saturating_add(prepend_interior);
312		if final_interior > MAX_JUNCTIONS {
313			return Err(prefix)
314		}
315		let suffix_parents = (self.parents as usize).saturating_sub(prefix.interior.len());
316		let final_parents = (prefix.parents as usize).saturating_add(suffix_parents);
317		if final_parents > 255 {
318			return Err(prefix)
319		}
320
321		// cancel out the final item on the prefix interior for one of the suffix's parents.
322		while self.parents > 0 && prefix.take_last().is_some() {
323			self.dec_parent();
324		}
325
326		// now we have either removed all suffix's parents or prefix interior.
327		// this means we can combine the prefix's and suffix's remaining parents/interior since
328		// we know that with at least one empty, the overall order will be respected:
329		//     prefix     self (suffix)
330		// P .. P   (I)   p .. p i .. i => P + p .. (no I) i
331		//  -- or --
332		// P .. P I .. I    (p)  i .. i => P (no p) .. I + i
333
334		self.parents = self.parents.saturating_add(prefix.parents);
335		for j in prefix.interior.into_iter().rev() {
336			self.push_front_interior(j)
337				.expect("final_interior no greater than MAX_JUNCTIONS; qed");
338		}
339		Ok(())
340	}
341
342	/// Consume `self` and return the value representing the same location from the point of view
343	/// of `target`. The context of `self` is provided as `ancestry`.
344	///
345	/// Returns an `Err` with the unmodified `self` in the case of error.
346	pub fn reanchored(
347		mut self,
348		target: &MultiLocation,
349		ancestry: &MultiLocation,
350	) -> Result<Self, Self> {
351		match self.reanchor(target, ancestry) {
352			Ok(()) => Ok(self),
353			Err(()) => Err(self),
354		}
355	}
356
357	/// Mutate `self` so that it represents the same location from the point of view of `target`.
358	/// The context of `self` is provided as `ancestry`.
359	///
360	/// Does not modify `self` in case of overflow.
361	pub fn reanchor(&mut self, target: &MultiLocation, ancestry: &MultiLocation) -> Result<(), ()> {
362		// TODO: https://github.com/paritytech/polkadot/issues/4489 Optimize this.
363
364		// 1. Use our `ancestry` to figure out how the `target` would address us.
365		let inverted_target = ancestry.inverted(target)?;
366
367		// 2. Prepend `inverted_target` to `self` to get self's location from the perspective of
368		// `target`.
369		self.prepend_with(inverted_target).map_err(|_| ())?;
370
371		// 3. Given that we know some of `target` ancestry, ensure that any parents in `self` are
372		// strictly needed.
373		self.simplify(target.interior());
374
375		Ok(())
376	}
377
378	/// Treating `self` as a context, determine how it would be referenced by a `target` location.
379	pub fn inverted(&self, target: &MultiLocation) -> Result<MultiLocation, ()> {
380		use Junction::OnlyChild;
381		let mut ancestry = self.clone();
382		let mut junctions = Junctions::Here;
383		for _ in 0..target.parent_count() {
384			junctions = junctions
385				.pushed_front_with(ancestry.interior.take_last().unwrap_or(OnlyChild))
386				.map_err(|_| ())?;
387		}
388		let parents = target.interior().len() as u8;
389		Ok(MultiLocation::new(parents, junctions))
390	}
391
392	/// Remove any unneeded parents/junctions in `self` based on the given context it will be
393	/// interpreted in.
394	pub fn simplify(&mut self, context: &Junctions) {
395		if context.len() < self.parents as usize {
396			// Not enough context
397			return
398		}
399		while self.parents > 0 {
400			let maybe = context.at(context.len() - (self.parents as usize));
401			match (self.interior.first(), maybe) {
402				(Some(i), Some(j)) if i == j => {
403					self.interior.take_first();
404					self.parents -= 1;
405				},
406				_ => break,
407			}
408		}
409	}
410}
411
412impl TryFrom<NewMultiLocation> for MultiLocation {
413	type Error = ();
414	fn try_from(x: NewMultiLocation) -> result::Result<Self, ()> {
415		Ok(MultiLocation { parents: x.parents, interior: x.interior.try_into()? })
416	}
417}
418
419/// A unit struct which can be converted into a `MultiLocation` of `parents` value 1.
420#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
421pub struct Parent;
422impl From<Parent> for MultiLocation {
423	fn from(_: Parent) -> Self {
424		MultiLocation { parents: 1, interior: Junctions::Here }
425	}
426}
427
428/// A tuple struct which can be converted into a `MultiLocation` of `parents` value 1 with the inner
429/// interior.
430#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
431pub struct ParentThen(pub Junctions);
432impl From<ParentThen> for MultiLocation {
433	fn from(ParentThen(interior): ParentThen) -> Self {
434		MultiLocation { parents: 1, interior }
435	}
436}
437
438/// A unit struct which can be converted into a `MultiLocation` of the inner `parents` value.
439#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
440pub struct Ancestor(pub u8);
441impl From<Ancestor> for MultiLocation {
442	fn from(Ancestor(parents): Ancestor) -> Self {
443		MultiLocation { parents, interior: Junctions::Here }
444	}
445}
446
447/// A unit struct which can be converted into a `MultiLocation` of the inner `parents` value and the
448/// inner interior.
449#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
450pub struct AncestorThen<Interior>(pub u8, pub Interior);
451impl<Interior: Into<Junctions>> From<AncestorThen<Interior>> for MultiLocation {
452	fn from(AncestorThen(parents, interior): AncestorThen<Interior>) -> Self {
453		MultiLocation { parents, interior: interior.into() }
454	}
455}
456
457xcm_procedural::impl_conversion_functions_for_multilocation_v2!();
458xcm_procedural::impl_conversion_functions_for_junctions_v2!();
459
460/// Maximum number of `Junction`s that a `Junctions` can contain.
461const MAX_JUNCTIONS: usize = 8;
462
463/// Non-parent junctions that can be constructed, up to the length of 8. This specific `Junctions`
464/// implementation uses a Rust `enum` in order to make pattern matching easier.
465///
466/// Parent junctions cannot be constructed with this type. Refer to `MultiLocation` for
467/// instructions on constructing parent junctions.
468#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug, TypeInfo, MaxEncodedLen)]
469#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
470#[scale_info(replace_segment("staging_xcm", "xcm"))]
471pub enum Junctions {
472	/// The interpreting consensus system.
473	Here,
474	/// A relative path comprising 1 junction.
475	X1(Junction),
476	/// A relative path comprising 2 junctions.
477	X2(Junction, Junction),
478	/// A relative path comprising 3 junctions.
479	X3(Junction, Junction, Junction),
480	/// A relative path comprising 4 junctions.
481	X4(Junction, Junction, Junction, Junction),
482	/// A relative path comprising 5 junctions.
483	X5(Junction, Junction, Junction, Junction, Junction),
484	/// A relative path comprising 6 junctions.
485	X6(Junction, Junction, Junction, Junction, Junction, Junction),
486	/// A relative path comprising 7 junctions.
487	X7(Junction, Junction, Junction, Junction, Junction, Junction, Junction),
488	/// A relative path comprising 8 junctions.
489	X8(Junction, Junction, Junction, Junction, Junction, Junction, Junction, Junction),
490}
491
492pub struct JunctionsIterator(Junctions);
493impl Iterator for JunctionsIterator {
494	type Item = Junction;
495	fn next(&mut self) -> Option<Junction> {
496		self.0.take_first()
497	}
498}
499
500impl DoubleEndedIterator for JunctionsIterator {
501	fn next_back(&mut self) -> Option<Junction> {
502		self.0.take_last()
503	}
504}
505
506pub struct JunctionsRefIterator<'a> {
507	junctions: &'a Junctions,
508	next: usize,
509	back: usize,
510}
511
512impl<'a> Iterator for JunctionsRefIterator<'a> {
513	type Item = &'a Junction;
514	fn next(&mut self) -> Option<&'a Junction> {
515		if self.next.saturating_add(self.back) >= self.junctions.len() {
516			return None
517		}
518
519		let result = self.junctions.at(self.next);
520		self.next += 1;
521		result
522	}
523}
524
525impl<'a> DoubleEndedIterator for JunctionsRefIterator<'a> {
526	fn next_back(&mut self) -> Option<&'a Junction> {
527		let next_back = self.back.saturating_add(1);
528		// checked_sub here, because if the result is less than 0, we end iteration
529		let index = self.junctions.len().checked_sub(next_back)?;
530		if self.next > index {
531			return None
532		}
533		self.back = next_back;
534
535		self.junctions.at(index)
536	}
537}
538
539impl<'a> IntoIterator for &'a Junctions {
540	type Item = &'a Junction;
541	type IntoIter = JunctionsRefIterator<'a>;
542	fn into_iter(self) -> Self::IntoIter {
543		JunctionsRefIterator { junctions: self, next: 0, back: 0 }
544	}
545}
546
547impl IntoIterator for Junctions {
548	type Item = Junction;
549	type IntoIter = JunctionsIterator;
550	fn into_iter(self) -> Self::IntoIter {
551		JunctionsIterator(self)
552	}
553}
554
555impl Junctions {
556	/// Convert `self` into a `MultiLocation` containing 0 parents.
557	///
558	/// Similar to `Into::into`, except that this method can be used in a const evaluation context.
559	pub const fn into(self) -> MultiLocation {
560		MultiLocation { parents: 0, interior: self }
561	}
562
563	/// Convert `self` into a `MultiLocation` containing `n` parents.
564	///
565	/// Similar to `Self::into`, with the added ability to specify the number of parent junctions.
566	pub const fn into_exterior(self, n: u8) -> MultiLocation {
567		MultiLocation { parents: n, interior: self }
568	}
569
570	/// Returns first junction, or `None` if the location is empty.
571	pub fn first(&self) -> Option<&Junction> {
572		match &self {
573			Junctions::Here => None,
574			Junctions::X1(ref a) => Some(a),
575			Junctions::X2(ref a, ..) => Some(a),
576			Junctions::X3(ref a, ..) => Some(a),
577			Junctions::X4(ref a, ..) => Some(a),
578			Junctions::X5(ref a, ..) => Some(a),
579			Junctions::X6(ref a, ..) => Some(a),
580			Junctions::X7(ref a, ..) => Some(a),
581			Junctions::X8(ref a, ..) => Some(a),
582		}
583	}
584
585	/// Returns last junction, or `None` if the location is empty.
586	pub fn last(&self) -> Option<&Junction> {
587		match &self {
588			Junctions::Here => None,
589			Junctions::X1(ref a) => Some(a),
590			Junctions::X2(.., ref a) => Some(a),
591			Junctions::X3(.., ref a) => Some(a),
592			Junctions::X4(.., ref a) => Some(a),
593			Junctions::X5(.., ref a) => Some(a),
594			Junctions::X6(.., ref a) => Some(a),
595			Junctions::X7(.., ref a) => Some(a),
596			Junctions::X8(.., ref a) => Some(a),
597		}
598	}
599
600	/// Splits off the first junction, returning the remaining suffix (first item in tuple) and the
601	/// first element (second item in tuple) or `None` if it was empty.
602	pub fn split_first(self) -> (Junctions, Option<Junction>) {
603		match self {
604			Junctions::Here => (Junctions::Here, None),
605			Junctions::X1(a) => (Junctions::Here, Some(a)),
606			Junctions::X2(a, b) => (Junctions::X1(b), Some(a)),
607			Junctions::X3(a, b, c) => (Junctions::X2(b, c), Some(a)),
608			Junctions::X4(a, b, c, d) => (Junctions::X3(b, c, d), Some(a)),
609			Junctions::X5(a, b, c, d, e) => (Junctions::X4(b, c, d, e), Some(a)),
610			Junctions::X6(a, b, c, d, e, f) => (Junctions::X5(b, c, d, e, f), Some(a)),
611			Junctions::X7(a, b, c, d, e, f, g) => (Junctions::X6(b, c, d, e, f, g), Some(a)),
612			Junctions::X8(a, b, c, d, e, f, g, h) => (Junctions::X7(b, c, d, e, f, g, h), Some(a)),
613		}
614	}
615
616	/// Splits off the last junction, returning the remaining prefix (first item in tuple) and the
617	/// last element (second item in tuple) or `None` if it was empty.
618	pub fn split_last(self) -> (Junctions, Option<Junction>) {
619		match self {
620			Junctions::Here => (Junctions::Here, None),
621			Junctions::X1(a) => (Junctions::Here, Some(a)),
622			Junctions::X2(a, b) => (Junctions::X1(a), Some(b)),
623			Junctions::X3(a, b, c) => (Junctions::X2(a, b), Some(c)),
624			Junctions::X4(a, b, c, d) => (Junctions::X3(a, b, c), Some(d)),
625			Junctions::X5(a, b, c, d, e) => (Junctions::X4(a, b, c, d), Some(e)),
626			Junctions::X6(a, b, c, d, e, f) => (Junctions::X5(a, b, c, d, e), Some(f)),
627			Junctions::X7(a, b, c, d, e, f, g) => (Junctions::X6(a, b, c, d, e, f), Some(g)),
628			Junctions::X8(a, b, c, d, e, f, g, h) => (Junctions::X7(a, b, c, d, e, f, g), Some(h)),
629		}
630	}
631
632	/// Removes the first element from `self`, returning it (or `None` if it was empty).
633	pub fn take_first(&mut self) -> Option<Junction> {
634		let mut d = Junctions::Here;
635		mem::swap(&mut *self, &mut d);
636		let (tail, head) = d.split_first();
637		*self = tail;
638		head
639	}
640
641	/// Removes the last element from `self`, returning it (or `None` if it was empty).
642	pub fn take_last(&mut self) -> Option<Junction> {
643		let mut d = Junctions::Here;
644		mem::swap(&mut *self, &mut d);
645		let (head, tail) = d.split_last();
646		*self = head;
647		tail
648	}
649
650	/// Mutates `self` to be appended with `new` or returns an `Err` with `new` if would overflow.
651	pub fn push(&mut self, new: Junction) -> result::Result<(), Junction> {
652		let mut dummy = Junctions::Here;
653		mem::swap(self, &mut dummy);
654		match dummy.pushed_with(new) {
655			Ok(s) => {
656				*self = s;
657				Ok(())
658			},
659			Err((s, j)) => {
660				*self = s;
661				Err(j)
662			},
663		}
664	}
665
666	/// Mutates `self` to be prepended with `new` or returns an `Err` with `new` if would overflow.
667	pub fn push_front(&mut self, new: Junction) -> result::Result<(), Junction> {
668		let mut dummy = Junctions::Here;
669		mem::swap(self, &mut dummy);
670		match dummy.pushed_front_with(new) {
671			Ok(s) => {
672				*self = s;
673				Ok(())
674			},
675			Err((s, j)) => {
676				*self = s;
677				Err(j)
678			},
679		}
680	}
681
682	/// Consumes `self` and returns a `Junctions` suffixed with `new`, or an `Err` with the
683	/// original value of `self` and `new` in case of overflow.
684	pub fn pushed_with(self, new: Junction) -> result::Result<Self, (Self, Junction)> {
685		Ok(match self {
686			Junctions::Here => Junctions::X1(new),
687			Junctions::X1(a) => Junctions::X2(a, new),
688			Junctions::X2(a, b) => Junctions::X3(a, b, new),
689			Junctions::X3(a, b, c) => Junctions::X4(a, b, c, new),
690			Junctions::X4(a, b, c, d) => Junctions::X5(a, b, c, d, new),
691			Junctions::X5(a, b, c, d, e) => Junctions::X6(a, b, c, d, e, new),
692			Junctions::X6(a, b, c, d, e, f) => Junctions::X7(a, b, c, d, e, f, new),
693			Junctions::X7(a, b, c, d, e, f, g) => Junctions::X8(a, b, c, d, e, f, g, new),
694			s => Err((s, new))?,
695		})
696	}
697
698	/// Consumes `self` and returns a `Junctions` prefixed with `new`, or an `Err` with the
699	/// original value of `self` and `new` in case of overflow.
700	pub fn pushed_front_with(self, new: Junction) -> result::Result<Self, (Self, Junction)> {
701		Ok(match self {
702			Junctions::Here => Junctions::X1(new),
703			Junctions::X1(a) => Junctions::X2(new, a),
704			Junctions::X2(a, b) => Junctions::X3(new, a, b),
705			Junctions::X3(a, b, c) => Junctions::X4(new, a, b, c),
706			Junctions::X4(a, b, c, d) => Junctions::X5(new, a, b, c, d),
707			Junctions::X5(a, b, c, d, e) => Junctions::X6(new, a, b, c, d, e),
708			Junctions::X6(a, b, c, d, e, f) => Junctions::X7(new, a, b, c, d, e, f),
709			Junctions::X7(a, b, c, d, e, f, g) => Junctions::X8(new, a, b, c, d, e, f, g),
710			s => Err((s, new))?,
711		})
712	}
713
714	/// Returns the number of junctions in `self`.
715	pub const fn len(&self) -> usize {
716		match &self {
717			Junctions::Here => 0,
718			Junctions::X1(..) => 1,
719			Junctions::X2(..) => 2,
720			Junctions::X3(..) => 3,
721			Junctions::X4(..) => 4,
722			Junctions::X5(..) => 5,
723			Junctions::X6(..) => 6,
724			Junctions::X7(..) => 7,
725			Junctions::X8(..) => 8,
726		}
727	}
728
729	/// Returns the junction at index `i`, or `None` if the location doesn't contain that many
730	/// elements.
731	pub fn at(&self, i: usize) -> Option<&Junction> {
732		Some(match (i, self) {
733			(0, Junctions::X1(ref a)) => a,
734			(0, Junctions::X2(ref a, ..)) => a,
735			(0, Junctions::X3(ref a, ..)) => a,
736			(0, Junctions::X4(ref a, ..)) => a,
737			(0, Junctions::X5(ref a, ..)) => a,
738			(0, Junctions::X6(ref a, ..)) => a,
739			(0, Junctions::X7(ref a, ..)) => a,
740			(0, Junctions::X8(ref a, ..)) => a,
741			(1, Junctions::X2(_, ref a)) => a,
742			(1, Junctions::X3(_, ref a, ..)) => a,
743			(1, Junctions::X4(_, ref a, ..)) => a,
744			(1, Junctions::X5(_, ref a, ..)) => a,
745			(1, Junctions::X6(_, ref a, ..)) => a,
746			(1, Junctions::X7(_, ref a, ..)) => a,
747			(1, Junctions::X8(_, ref a, ..)) => a,
748			(2, Junctions::X3(_, _, ref a)) => a,
749			(2, Junctions::X4(_, _, ref a, ..)) => a,
750			(2, Junctions::X5(_, _, ref a, ..)) => a,
751			(2, Junctions::X6(_, _, ref a, ..)) => a,
752			(2, Junctions::X7(_, _, ref a, ..)) => a,
753			(2, Junctions::X8(_, _, ref a, ..)) => a,
754			(3, Junctions::X4(_, _, _, ref a)) => a,
755			(3, Junctions::X5(_, _, _, ref a, ..)) => a,
756			(3, Junctions::X6(_, _, _, ref a, ..)) => a,
757			(3, Junctions::X7(_, _, _, ref a, ..)) => a,
758			(3, Junctions::X8(_, _, _, ref a, ..)) => a,
759			(4, Junctions::X5(_, _, _, _, ref a)) => a,
760			(4, Junctions::X6(_, _, _, _, ref a, ..)) => a,
761			(4, Junctions::X7(_, _, _, _, ref a, ..)) => a,
762			(4, Junctions::X8(_, _, _, _, ref a, ..)) => a,
763			(5, Junctions::X6(_, _, _, _, _, ref a)) => a,
764			(5, Junctions::X7(_, _, _, _, _, ref a, ..)) => a,
765			(5, Junctions::X8(_, _, _, _, _, ref a, ..)) => a,
766			(6, Junctions::X7(_, _, _, _, _, _, ref a)) => a,
767			(6, Junctions::X8(_, _, _, _, _, _, ref a, ..)) => a,
768			(7, Junctions::X8(_, _, _, _, _, _, _, ref a)) => a,
769			_ => return None,
770		})
771	}
772
773	/// Returns a mutable reference to the junction at index `i`, or `None` if the location doesn't
774	/// contain that many elements.
775	pub fn at_mut(&mut self, i: usize) -> Option<&mut Junction> {
776		Some(match (i, self) {
777			(0, Junctions::X1(ref mut a)) => a,
778			(0, Junctions::X2(ref mut a, ..)) => a,
779			(0, Junctions::X3(ref mut a, ..)) => a,
780			(0, Junctions::X4(ref mut a, ..)) => a,
781			(0, Junctions::X5(ref mut a, ..)) => a,
782			(0, Junctions::X6(ref mut a, ..)) => a,
783			(0, Junctions::X7(ref mut a, ..)) => a,
784			(0, Junctions::X8(ref mut a, ..)) => a,
785			(1, Junctions::X2(_, ref mut a)) => a,
786			(1, Junctions::X3(_, ref mut a, ..)) => a,
787			(1, Junctions::X4(_, ref mut a, ..)) => a,
788			(1, Junctions::X5(_, ref mut a, ..)) => a,
789			(1, Junctions::X6(_, ref mut a, ..)) => a,
790			(1, Junctions::X7(_, ref mut a, ..)) => a,
791			(1, Junctions::X8(_, ref mut a, ..)) => a,
792			(2, Junctions::X3(_, _, ref mut a)) => a,
793			(2, Junctions::X4(_, _, ref mut a, ..)) => a,
794			(2, Junctions::X5(_, _, ref mut a, ..)) => a,
795			(2, Junctions::X6(_, _, ref mut a, ..)) => a,
796			(2, Junctions::X7(_, _, ref mut a, ..)) => a,
797			(2, Junctions::X8(_, _, ref mut a, ..)) => a,
798			(3, Junctions::X4(_, _, _, ref mut a)) => a,
799			(3, Junctions::X5(_, _, _, ref mut a, ..)) => a,
800			(3, Junctions::X6(_, _, _, ref mut a, ..)) => a,
801			(3, Junctions::X7(_, _, _, ref mut a, ..)) => a,
802			(3, Junctions::X8(_, _, _, ref mut a, ..)) => a,
803			(4, Junctions::X5(_, _, _, _, ref mut a)) => a,
804			(4, Junctions::X6(_, _, _, _, ref mut a, ..)) => a,
805			(4, Junctions::X7(_, _, _, _, ref mut a, ..)) => a,
806			(4, Junctions::X8(_, _, _, _, ref mut a, ..)) => a,
807			(5, Junctions::X6(_, _, _, _, _, ref mut a)) => a,
808			(5, Junctions::X7(_, _, _, _, _, ref mut a, ..)) => a,
809			(5, Junctions::X8(_, _, _, _, _, ref mut a, ..)) => a,
810			(6, Junctions::X7(_, _, _, _, _, _, ref mut a)) => a,
811			(6, Junctions::X8(_, _, _, _, _, _, ref mut a, ..)) => a,
812			(7, Junctions::X8(_, _, _, _, _, _, _, ref mut a)) => a,
813			_ => return None,
814		})
815	}
816
817	/// Returns a reference iterator over the junctions.
818	pub fn iter(&self) -> JunctionsRefIterator {
819		JunctionsRefIterator { junctions: self, next: 0, back: 0 }
820	}
821
822	/// Returns a reference iterator over the junctions in reverse.
823	#[deprecated(note = "Please use iter().rev()")]
824	pub fn iter_rev(&self) -> impl Iterator + '_ {
825		self.iter().rev()
826	}
827
828	/// Consumes `self` and returns an iterator over the junctions in reverse.
829	#[deprecated(note = "Please use into_iter().rev()")]
830	pub fn into_iter_rev(self) -> impl Iterator {
831		self.into_iter().rev()
832	}
833
834	/// Ensures that self begins with `prefix` and that it has a single `Junction` item following.
835	/// If so, returns a reference to this `Junction` item.
836	///
837	/// # Example
838	/// ```rust
839	/// # use staging_xcm::v2::{Junctions::*, Junction::*};
840	/// let mut m = X3(Parachain(2), PalletInstance(3), OnlyChild);
841	/// assert_eq!(m.match_and_split(&X2(Parachain(2), PalletInstance(3))), Some(&OnlyChild));
842	/// assert_eq!(m.match_and_split(&X1(Parachain(2))), None);
843	/// ```
844	pub fn match_and_split(&self, prefix: &Junctions) -> Option<&Junction> {
845		if prefix.len() + 1 != self.len() || !self.starts_with(prefix) {
846			return None
847		}
848		self.at(prefix.len())
849	}
850
851	/// Returns whether `self` begins with or is equal to `prefix`.
852	///
853	/// # Example
854	/// ```rust
855	/// # use staging_xcm::v2::{Junctions::*, Junction::*};
856	/// let mut j = X3(Parachain(2), PalletInstance(3), OnlyChild);
857	/// assert!(j.starts_with(&X2(Parachain(2), PalletInstance(3))));
858	/// assert!(j.starts_with(&j));
859	/// assert!(j.starts_with(&X1(Parachain(2))));
860	/// assert!(!j.starts_with(&X1(Parachain(999))));
861	/// assert!(!j.starts_with(&X4(Parachain(2), PalletInstance(3), OnlyChild, OnlyChild)));
862	/// ```
863	pub fn starts_with(&self, prefix: &Junctions) -> bool {
864		if self.len() < prefix.len() {
865			return false
866		}
867		prefix.iter().zip(self.iter()).all(|(l, r)| l == r)
868	}
869}
870
871impl TryFrom<MultiLocation> for Junctions {
872	type Error = ();
873	fn try_from(x: MultiLocation) -> result::Result<Self, ()> {
874		if x.parents > 0 {
875			Err(())
876		} else {
877			Ok(x.interior)
878		}
879	}
880}
881
882#[cfg(test)]
883mod tests {
884	use super::{Ancestor, AncestorThen, Junctions::*, MultiLocation, Parent, ParentThen};
885	use crate::opaque::v2::{Junction::*, NetworkId::*};
886	use codec::{Decode, Encode};
887
888	#[test]
889	fn inverted_works() {
890		let ancestry: MultiLocation = (Parachain(1000), PalletInstance(42)).into();
891		let target = (Parent, PalletInstance(69)).into();
892		let expected = (Parent, PalletInstance(42)).into();
893		let inverted = ancestry.inverted(&target).unwrap();
894		assert_eq!(inverted, expected);
895
896		let ancestry: MultiLocation = (Parachain(1000), PalletInstance(42), GeneralIndex(1)).into();
897		let target = (Parent, Parent, PalletInstance(69), GeneralIndex(2)).into();
898		let expected = (Parent, Parent, PalletInstance(42), GeneralIndex(1)).into();
899		let inverted = ancestry.inverted(&target).unwrap();
900		assert_eq!(inverted, expected);
901	}
902
903	#[test]
904	fn simplify_basic_works() {
905		let mut location: MultiLocation =
906			(Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into();
907		let context = X2(Parachain(1000), PalletInstance(42));
908		let expected = GeneralIndex(69).into();
909		location.simplify(&context);
910		assert_eq!(location, expected);
911
912		let mut location: MultiLocation = (Parent, PalletInstance(42), GeneralIndex(69)).into();
913		let context = X1(PalletInstance(42));
914		let expected = GeneralIndex(69).into();
915		location.simplify(&context);
916		assert_eq!(location, expected);
917
918		let mut location: MultiLocation = (Parent, PalletInstance(42), GeneralIndex(69)).into();
919		let context = X2(Parachain(1000), PalletInstance(42));
920		let expected = GeneralIndex(69).into();
921		location.simplify(&context);
922		assert_eq!(location, expected);
923
924		let mut location: MultiLocation =
925			(Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into();
926		let context = X3(OnlyChild, Parachain(1000), PalletInstance(42));
927		let expected = GeneralIndex(69).into();
928		location.simplify(&context);
929		assert_eq!(location, expected);
930	}
931
932	#[test]
933	fn simplify_incompatible_location_fails() {
934		let mut location: MultiLocation =
935			(Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into();
936		let context = X3(Parachain(1000), PalletInstance(42), GeneralIndex(42));
937		let expected =
938			(Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into();
939		location.simplify(&context);
940		assert_eq!(location, expected);
941
942		let mut location: MultiLocation =
943			(Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into();
944		let context = X1(Parachain(1000));
945		let expected =
946			(Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into();
947		location.simplify(&context);
948		assert_eq!(location, expected);
949	}
950
951	#[test]
952	fn reanchor_works() {
953		let mut id: MultiLocation = (Parent, Parachain(1000), GeneralIndex(42)).into();
954		let ancestry = Parachain(2000).into();
955		let target = (Parent, Parachain(1000)).into();
956		let expected = GeneralIndex(42).into();
957		id.reanchor(&target, &ancestry).unwrap();
958		assert_eq!(id, expected);
959	}
960
961	#[test]
962	fn encode_and_decode_works() {
963		let m = MultiLocation {
964			parents: 1,
965			interior: X2(Parachain(42), AccountIndex64 { network: Any, index: 23 }),
966		};
967		let encoded = m.encode();
968		assert_eq!(encoded, [1, 2, 0, 168, 2, 0, 92].to_vec());
969		let decoded = MultiLocation::decode(&mut &encoded[..]);
970		assert_eq!(decoded, Ok(m));
971	}
972
973	#[test]
974	fn match_and_split_works() {
975		let m = MultiLocation {
976			parents: 1,
977			interior: X2(Parachain(42), AccountIndex64 { network: Any, index: 23 }),
978		};
979		assert_eq!(m.match_and_split(&MultiLocation { parents: 1, interior: Here }), None);
980		assert_eq!(
981			m.match_and_split(&MultiLocation { parents: 1, interior: X1(Parachain(42)) }),
982			Some(&AccountIndex64 { network: Any, index: 23 })
983		);
984		assert_eq!(m.match_and_split(&m), None);
985	}
986
987	#[test]
988	fn starts_with_works() {
989		let full: MultiLocation =
990			(Parent, Parachain(1000), AccountId32 { network: Any, id: [0; 32] }).into();
991		let identity: MultiLocation = full.clone();
992		let prefix: MultiLocation = (Parent, Parachain(1000)).into();
993		let wrong_parachain: MultiLocation = (Parent, Parachain(1001)).into();
994		let wrong_account: MultiLocation =
995			(Parent, Parachain(1000), AccountId32 { network: Any, id: [1; 32] }).into();
996		let no_parents: MultiLocation = (Parachain(1000)).into();
997		let too_many_parents: MultiLocation = (Parent, Parent, Parachain(1000)).into();
998
999		assert!(full.starts_with(&identity));
1000		assert!(full.starts_with(&prefix));
1001		assert!(!full.starts_with(&wrong_parachain));
1002		assert!(!full.starts_with(&wrong_account));
1003		assert!(!full.starts_with(&no_parents));
1004		assert!(!full.starts_with(&too_many_parents));
1005	}
1006
1007	#[test]
1008	fn append_with_works() {
1009		let acc = AccountIndex64 { network: Any, index: 23 };
1010		let mut m = MultiLocation { parents: 1, interior: X1(Parachain(42)) };
1011		assert_eq!(m.append_with(X2(PalletInstance(3), acc.clone())), Ok(()));
1012		assert_eq!(
1013			m,
1014			MultiLocation {
1015				parents: 1,
1016				interior: X3(Parachain(42), PalletInstance(3), acc.clone())
1017			}
1018		);
1019
1020		// cannot append to create overly long multilocation
1021		let acc = AccountIndex64 { network: Any, index: 23 };
1022		let m = MultiLocation {
1023			parents: 254,
1024			interior: X5(Parachain(42), OnlyChild, OnlyChild, OnlyChild, OnlyChild),
1025		};
1026		let suffix = X4(PalletInstance(3), acc.clone(), OnlyChild, OnlyChild);
1027		assert_eq!(m.clone().append_with(suffix.clone()), Err(suffix));
1028	}
1029
1030	#[test]
1031	fn prepend_with_works() {
1032		let mut m = MultiLocation {
1033			parents: 1,
1034			interior: X2(Parachain(42), AccountIndex64 { network: Any, index: 23 }),
1035		};
1036		assert_eq!(m.prepend_with(MultiLocation { parents: 1, interior: X1(OnlyChild) }), Ok(()));
1037		assert_eq!(
1038			m,
1039			MultiLocation {
1040				parents: 1,
1041				interior: X2(Parachain(42), AccountIndex64 { network: Any, index: 23 })
1042			}
1043		);
1044
1045		// cannot prepend to create overly long multilocation
1046		let mut m = MultiLocation { parents: 254, interior: X1(Parachain(42)) };
1047		let prefix = MultiLocation { parents: 2, interior: Here };
1048		assert_eq!(m.prepend_with(prefix.clone()), Err(prefix));
1049
1050		let prefix = MultiLocation { parents: 1, interior: Here };
1051		assert_eq!(m.prepend_with(prefix), Ok(()));
1052		assert_eq!(m, MultiLocation { parents: 255, interior: X1(Parachain(42)) });
1053	}
1054
1055	#[test]
1056	fn double_ended_ref_iteration_works() {
1057		let m = X3(Parachain(1000), Parachain(3), PalletInstance(5));
1058		let mut iter = m.iter();
1059
1060		let first = iter.next().unwrap();
1061		assert_eq!(first, &Parachain(1000));
1062		let third = iter.next_back().unwrap();
1063		assert_eq!(third, &PalletInstance(5));
1064		let second = iter.next_back().unwrap();
1065		assert_eq!(iter.next(), None);
1066		assert_eq!(iter.next_back(), None);
1067		assert_eq!(second, &Parachain(3));
1068
1069		let res = Here
1070			.pushed_with(first.clone())
1071			.unwrap()
1072			.pushed_with(second.clone())
1073			.unwrap()
1074			.pushed_with(third.clone())
1075			.unwrap();
1076		assert_eq!(m, res);
1077
1078		// make sure there's no funny business with the 0 indexing
1079		let m = Here;
1080		let mut iter = m.iter();
1081
1082		assert_eq!(iter.next(), None);
1083		assert_eq!(iter.next_back(), None);
1084	}
1085
1086	#[test]
1087	fn conversion_from_other_types_works() {
1088		fn takes_multilocation<Arg: Into<MultiLocation>>(_arg: Arg) {}
1089
1090		takes_multilocation(Parent);
1091		takes_multilocation(Here);
1092		takes_multilocation(X1(Parachain(42)));
1093		takes_multilocation((255, PalletInstance(8)));
1094		takes_multilocation((Ancestor(5), Parachain(1), PalletInstance(3)));
1095		takes_multilocation((Ancestor(2), Here));
1096		takes_multilocation(AncestorThen(
1097			3,
1098			X2(Parachain(43), AccountIndex64 { network: Any, index: 155 }),
1099		));
1100		takes_multilocation((Parent, AccountId32 { network: Any, id: [0; 32] }));
1101		takes_multilocation((Parent, Here));
1102		takes_multilocation(ParentThen(X1(Parachain(75))));
1103		takes_multilocation([Parachain(100), PalletInstance(3)]);
1104	}
1105}