staging_xcm/v4/
location.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//! XCM `Location` datatype.
18
19use super::{traits::Reanchorable, Junction, Junctions};
20use crate::{v3::MultiLocation as OldLocation, VersionedLocation};
21use codec::{Decode, Encode, MaxEncodedLen};
22use core::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 `Location` 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 `Location` 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 `Location` value of `Null` simply refers to the interpreting consensus system.
51#[derive(
52	Clone,
53	Decode,
54	Encode,
55	Eq,
56	PartialEq,
57	Ord,
58	PartialOrd,
59	Debug,
60	TypeInfo,
61	MaxEncodedLen,
62	serde::Serialize,
63	serde::Deserialize,
64)]
65pub struct Location {
66	/// The number of parent junctions at the beginning of this `Location`.
67	pub parents: u8,
68	/// The interior (i.e. non-parent) junctions that this `Location` contains.
69	pub interior: Junctions,
70}
71
72impl Default for Location {
73	fn default() -> Self {
74		Self { parents: 0, interior: Junctions::Here }
75	}
76}
77
78/// A relative location which is constrained to be an interior location of the context.
79///
80/// See also `Location`.
81pub type InteriorLocation = Junctions;
82
83impl Location {
84	/// Creates a new `Location` with the given number of parents and interior junctions.
85	pub fn new(parents: u8, interior: impl Into<Junctions>) -> Location {
86		Location { parents, interior: interior.into() }
87	}
88
89	/// Consume `self` and return the equivalent `VersionedLocation` value.
90	pub const fn into_versioned(self) -> VersionedLocation {
91		VersionedLocation::V4(self)
92	}
93
94	/// Creates a new `Location` with 0 parents and a `Here` interior.
95	///
96	/// The resulting `Location` can be interpreted as the "current consensus system".
97	pub const fn here() -> Location {
98		Location { parents: 0, interior: Junctions::Here }
99	}
100
101	/// Creates a new `Location` which evaluates to the parent context.
102	pub const fn parent() -> Location {
103		Location { parents: 1, interior: Junctions::Here }
104	}
105
106	/// Creates a new `Location` with `parents` and an empty (`Here`) interior.
107	pub const fn ancestor(parents: u8) -> Location {
108		Location { parents, interior: Junctions::Here }
109	}
110
111	/// Whether the `Location` has no parents and has a `Here` interior.
112	pub fn is_here(&self) -> bool {
113		self.parents == 0 && self.interior.len() == 0
114	}
115
116	/// Remove the `NetworkId` value in any interior `Junction`s.
117	pub fn remove_network_id(&mut self) {
118		self.interior.remove_network_id();
119	}
120
121	/// Return a reference to the interior field.
122	pub fn interior(&self) -> &Junctions {
123		&self.interior
124	}
125
126	/// Return a mutable reference to the interior field.
127	pub fn interior_mut(&mut self) -> &mut Junctions {
128		&mut self.interior
129	}
130
131	/// Returns the number of `Parent` junctions at the beginning of `self`.
132	pub const fn parent_count(&self) -> u8 {
133		self.parents
134	}
135
136	/// Returns the parent count and the interior [`Junctions`] as a tuple.
137	///
138	/// To be used when pattern matching, for example:
139	///
140	/// ```rust
141	/// # use staging_xcm::v4::{Junctions::*, Junction::*, Location};
142	/// fn get_parachain_id(loc: &Location) -> Option<u32> {
143	///     match loc.unpack() {
144	///         (0, [Parachain(id)]) => Some(*id),
145	///         _ => None
146	///     }
147	/// }
148	/// ```
149	pub fn unpack(&self) -> (u8, &[Junction]) {
150		(self.parents, self.interior.as_slice())
151	}
152
153	/// Returns boolean indicating whether `self` contains only the specified amount of
154	/// parents and no interior junctions.
155	pub const fn contains_parents_only(&self, count: u8) -> bool {
156		matches!(self.interior, Junctions::Here) && self.parents == count
157	}
158
159	/// Returns the number of parents and junctions in `self`.
160	pub fn len(&self) -> usize {
161		self.parent_count() as usize + self.interior.len()
162	}
163
164	/// Returns the first interior junction, or `None` if the location is empty or contains only
165	/// parents.
166	pub fn first_interior(&self) -> Option<&Junction> {
167		self.interior.first()
168	}
169
170	/// Returns last junction, or `None` if the location is empty or contains only parents.
171	pub fn last(&self) -> Option<&Junction> {
172		self.interior.last()
173	}
174
175	/// Splits off the first interior junction, returning the remaining suffix (first item in tuple)
176	/// and the first element (second item in tuple) or `None` if it was empty.
177	pub fn split_first_interior(self) -> (Location, Option<Junction>) {
178		let Location { parents, interior: junctions } = self;
179		let (suffix, first) = junctions.split_first();
180		let location = Location { parents, interior: suffix };
181		(location, first)
182	}
183
184	/// Splits off the last interior junction, returning the remaining prefix (first item in tuple)
185	/// and the last element (second item in tuple) or `None` if it was empty or if `self` only
186	/// contains parents.
187	pub fn split_last_interior(self) -> (Location, Option<Junction>) {
188		let Location { parents, interior: junctions } = self;
189		let (prefix, last) = junctions.split_last();
190		let location = Location { parents, interior: prefix };
191		(location, last)
192	}
193
194	/// Mutates `self`, suffixing its interior junctions with `new`. Returns `Err` with `new` in
195	/// case of overflow.
196	pub fn push_interior(&mut self, new: impl Into<Junction>) -> result::Result<(), Junction> {
197		self.interior.push(new)
198	}
199
200	/// Mutates `self`, prefixing its interior junctions with `new`. Returns `Err` with `new` in
201	/// case of overflow.
202	pub fn push_front_interior(
203		&mut self,
204		new: impl Into<Junction>,
205	) -> result::Result<(), Junction> {
206		self.interior.push_front(new)
207	}
208
209	/// Consumes `self` and returns a `Location` suffixed with `new`, or an `Err` with
210	/// the original value of `self` in case of overflow.
211	pub fn pushed_with_interior(
212		self,
213		new: impl Into<Junction>,
214	) -> result::Result<Self, (Self, Junction)> {
215		match self.interior.pushed_with(new) {
216			Ok(i) => Ok(Location { interior: i, parents: self.parents }),
217			Err((i, j)) => Err((Location { interior: i, parents: self.parents }, j)),
218		}
219	}
220
221	/// Consumes `self` and returns a `Location` prefixed with `new`, or an `Err` with the
222	/// original value of `self` in case of overflow.
223	pub fn pushed_front_with_interior(
224		self,
225		new: impl Into<Junction>,
226	) -> result::Result<Self, (Self, Junction)> {
227		match self.interior.pushed_front_with(new) {
228			Ok(i) => Ok(Location { interior: i, parents: self.parents }),
229			Err((i, j)) => Err((Location { interior: i, parents: self.parents }, j)),
230		}
231	}
232
233	/// Returns the junction at index `i`, or `None` if the location is a parent or if the location
234	/// does not contain that many elements.
235	pub fn at(&self, i: usize) -> Option<&Junction> {
236		let num_parents = self.parents as usize;
237		if i < num_parents {
238			return None
239		}
240		self.interior.at(i - num_parents)
241	}
242
243	/// Returns a mutable reference to the junction at index `i`, or `None` if the location is a
244	/// parent or if it doesn't contain that many elements.
245	pub fn at_mut(&mut self, i: usize) -> Option<&mut Junction> {
246		let num_parents = self.parents as usize;
247		if i < num_parents {
248			return None
249		}
250		self.interior.at_mut(i - num_parents)
251	}
252
253	/// Decrements the parent count by 1.
254	pub fn dec_parent(&mut self) {
255		self.parents = self.parents.saturating_sub(1);
256	}
257
258	/// Removes the first interior junction from `self`, returning it
259	/// (or `None` if it was empty or if `self` contains only parents).
260	pub fn take_first_interior(&mut self) -> Option<Junction> {
261		self.interior.take_first()
262	}
263
264	/// Removes the last element from `interior`, returning it (or `None` if it was empty or if
265	/// `self` only contains parents).
266	pub fn take_last(&mut self) -> Option<Junction> {
267		self.interior.take_last()
268	}
269
270	/// Ensures that `self` has the same number of parents as `prefix`, its junctions begins with
271	/// the junctions of `prefix` and that it has a single `Junction` item following.
272	/// If so, returns a reference to this `Junction` item.
273	///
274	/// # Example
275	/// ```rust
276	/// # use staging_xcm::v4::{Junctions::*, Junction::*, Location};
277	/// # fn main() {
278	/// let mut m = Location::new(1, [PalletInstance(3), OnlyChild]);
279	/// assert_eq!(
280	///     m.match_and_split(&Location::new(1, [PalletInstance(3)])),
281	///     Some(&OnlyChild),
282	/// );
283	/// assert_eq!(m.match_and_split(&Location::new(1, Here)), None);
284	/// # }
285	/// ```
286	pub fn match_and_split(&self, prefix: &Location) -> Option<&Junction> {
287		if self.parents != prefix.parents {
288			return None
289		}
290		self.interior.match_and_split(&prefix.interior)
291	}
292
293	pub fn starts_with(&self, prefix: &Location) -> bool {
294		self.parents == prefix.parents && self.interior.starts_with(&prefix.interior)
295	}
296
297	/// Mutate `self` so that it is suffixed with `suffix`.
298	///
299	/// Does not modify `self` and returns `Err` with `suffix` in case of overflow.
300	///
301	/// # Example
302	/// ```rust
303	/// # use staging_xcm::v4::{Junctions::*, Junction::*, Location, Parent};
304	/// # fn main() {
305	/// let mut m: Location = (Parent, Parachain(21), 69u64).into();
306	/// assert_eq!(m.append_with((Parent, PalletInstance(3))), Ok(()));
307	/// assert_eq!(m, Location::new(1, [Parachain(21), PalletInstance(3)]));
308	/// # }
309	/// ```
310	pub fn append_with(&mut self, suffix: impl Into<Self>) -> Result<(), Self> {
311		let prefix = core::mem::replace(self, suffix.into());
312		match self.prepend_with(prefix) {
313			Ok(()) => Ok(()),
314			Err(prefix) => Err(core::mem::replace(self, prefix)),
315		}
316	}
317
318	/// Consume `self` and return its value suffixed with `suffix`.
319	///
320	/// Returns `Err` with the original value of `self` and `suffix` in case of overflow.
321	///
322	/// # Example
323	/// ```rust
324	/// # use staging_xcm::v4::{Junctions::*, Junction::*, Location, Parent};
325	/// # fn main() {
326	/// let mut m: Location = (Parent, Parachain(21), 69u64).into();
327	/// let r = m.appended_with((Parent, PalletInstance(3))).unwrap();
328	/// assert_eq!(r, Location::new(1, [Parachain(21), PalletInstance(3)]));
329	/// # }
330	/// ```
331	pub fn appended_with(mut self, suffix: impl Into<Self>) -> Result<Self, (Self, Self)> {
332		match self.append_with(suffix) {
333			Ok(()) => Ok(self),
334			Err(suffix) => Err((self, suffix)),
335		}
336	}
337
338	/// Mutate `self` so that it is prefixed with `prefix`.
339	///
340	/// Does not modify `self` and returns `Err` with `prefix` in case of overflow.
341	///
342	/// # Example
343	/// ```rust
344	/// # use staging_xcm::v4::{Junctions::*, Junction::*, Location, Parent};
345	/// # fn main() {
346	/// let mut m: Location = (Parent, Parent, PalletInstance(3)).into();
347	/// assert_eq!(m.prepend_with((Parent, Parachain(21), OnlyChild)), Ok(()));
348	/// assert_eq!(m, Location::new(1, [PalletInstance(3)]));
349	/// # }
350	/// ```
351	pub fn prepend_with(&mut self, prefix: impl Into<Self>) -> Result<(), Self> {
352		//     prefix     self (suffix)
353		// P .. P I .. I  p .. p i .. i
354		let mut prefix = prefix.into();
355		let prepend_interior = prefix.interior.len().saturating_sub(self.parents as usize);
356		let final_interior = self.interior.len().saturating_add(prepend_interior);
357		if final_interior > super::junctions::MAX_JUNCTIONS {
358			return Err(prefix)
359		}
360		let suffix_parents = (self.parents as usize).saturating_sub(prefix.interior.len());
361		let final_parents = (prefix.parents as usize).saturating_add(suffix_parents);
362		if final_parents > 255 {
363			return Err(prefix)
364		}
365
366		// cancel out the final item on the prefix interior for one of the suffix's parents.
367		while self.parents > 0 && prefix.take_last().is_some() {
368			self.dec_parent();
369		}
370
371		// now we have either removed all suffix's parents or prefix interior.
372		// this means we can combine the prefix's and suffix's remaining parents/interior since
373		// we know that with at least one empty, the overall order will be respected:
374		//     prefix     self (suffix)
375		// P .. P   (I)   p .. p i .. i => P + p .. (no I) i
376		//  -- or --
377		// P .. P I .. I    (p)  i .. i => P (no p) .. I + i
378
379		self.parents = self.parents.saturating_add(prefix.parents);
380		for j in prefix.interior.into_iter().rev() {
381			self.push_front_interior(j)
382				.expect("final_interior no greater than MAX_JUNCTIONS; qed");
383		}
384		Ok(())
385	}
386
387	/// Consume `self` and return its value prefixed with `prefix`.
388	///
389	/// Returns `Err` with the original value of `self` and `prefix` in case of overflow.
390	///
391	/// # Example
392	/// ```rust
393	/// # use staging_xcm::v4::{Junctions::*, Junction::*, Location, Parent};
394	/// # fn main() {
395	/// let m: Location = (Parent, Parent, PalletInstance(3)).into();
396	/// let r = m.prepended_with((Parent, Parachain(21), OnlyChild)).unwrap();
397	/// assert_eq!(r, Location::new(1, [PalletInstance(3)]));
398	/// # }
399	/// ```
400	pub fn prepended_with(mut self, prefix: impl Into<Self>) -> Result<Self, (Self, Self)> {
401		match self.prepend_with(prefix) {
402			Ok(()) => Ok(self),
403			Err(prefix) => Err((self, prefix)),
404		}
405	}
406
407	/// Remove any unneeded parents/junctions in `self` based on the given context it will be
408	/// interpreted in.
409	pub fn simplify(&mut self, context: &Junctions) {
410		if context.len() < self.parents as usize {
411			// Not enough context
412			return
413		}
414		while self.parents > 0 {
415			let maybe = context.at(context.len() - (self.parents as usize));
416			match (self.interior.first(), maybe) {
417				(Some(i), Some(j)) if i == j => {
418					self.interior.take_first();
419					self.parents -= 1;
420				},
421				_ => break,
422			}
423		}
424	}
425
426	/// Return the Location subsection identifying the chain that `self` points to.
427	pub fn chain_location(&self) -> Location {
428		let mut clone = self.clone();
429		// start popping junctions until we reach chain identifier
430		while let Some(j) = clone.last() {
431			if matches!(j, Junction::Parachain(_) | Junction::GlobalConsensus(_)) {
432				// return chain subsection
433				return clone
434			} else {
435				(clone, _) = clone.split_last_interior();
436			}
437		}
438		Location::new(clone.parents, Junctions::Here)
439	}
440}
441
442impl Reanchorable for Location {
443	type Error = Self;
444
445	/// Mutate `self` so that it represents the same location from the point of view of `target`.
446	/// The context of `self` is provided as `context`.
447	///
448	/// Does not modify `self` in case of overflow.
449	fn reanchor(&mut self, target: &Location, context: &InteriorLocation) -> Result<(), ()> {
450		// TODO: https://github.com/paritytech/polkadot/issues/4489 Optimize this.
451
452		// 1. Use our `context` to figure out how the `target` would address us.
453		let inverted_target = context.invert_target(target)?;
454
455		// 2. Prepend `inverted_target` to `self` to get self's location from the perspective of
456		// `target`.
457		self.prepend_with(inverted_target).map_err(|_| ())?;
458
459		// 3. Given that we know some of `target` context, ensure that any parents in `self` are
460		// strictly needed.
461		self.simplify(target.interior());
462
463		Ok(())
464	}
465
466	/// Consume `self` and return a new value representing the same location from the point of view
467	/// of `target`. The context of `self` is provided as `context`.
468	///
469	/// Returns the original `self` in case of overflow.
470	fn reanchored(mut self, target: &Location, context: &InteriorLocation) -> Result<Self, Self> {
471		match self.reanchor(target, context) {
472			Ok(()) => Ok(self),
473			Err(()) => Err(self),
474		}
475	}
476}
477
478impl TryFrom<OldLocation> for Option<Location> {
479	type Error = ();
480	fn try_from(value: OldLocation) -> result::Result<Self, Self::Error> {
481		Ok(Some(Location::try_from(value)?))
482	}
483}
484
485impl TryFrom<OldLocation> for Location {
486	type Error = ();
487	fn try_from(x: OldLocation) -> result::Result<Self, ()> {
488		Ok(Location { parents: x.parents, interior: x.interior.try_into()? })
489	}
490}
491
492/// A unit struct which can be converted into a `Location` of `parents` value 1.
493#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
494pub struct Parent;
495impl From<Parent> for Location {
496	fn from(_: Parent) -> Self {
497		Location { parents: 1, interior: Junctions::Here }
498	}
499}
500
501/// A tuple struct which can be converted into a `Location` of `parents` value 1 with the inner
502/// interior.
503#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
504pub struct ParentThen(pub Junctions);
505impl From<ParentThen> for Location {
506	fn from(ParentThen(interior): ParentThen) -> Self {
507		Location { parents: 1, interior }
508	}
509}
510
511/// A unit struct which can be converted into a `Location` of the inner `parents` value.
512#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
513pub struct Ancestor(pub u8);
514impl From<Ancestor> for Location {
515	fn from(Ancestor(parents): Ancestor) -> Self {
516		Location { parents, interior: Junctions::Here }
517	}
518}
519
520/// A unit struct which can be converted into a `Location` of the inner `parents` value and the
521/// inner interior.
522#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
523pub struct AncestorThen<Interior>(pub u8, pub Interior);
524impl<Interior: Into<Junctions>> From<AncestorThen<Interior>> for Location {
525	fn from(AncestorThen(parents, interior): AncestorThen<Interior>) -> Self {
526		Location { parents, interior: interior.into() }
527	}
528}
529
530impl From<[u8; 32]> for Location {
531	fn from(bytes: [u8; 32]) -> Self {
532		let junction: Junction = bytes.into();
533		junction.into()
534	}
535}
536
537impl From<sp_runtime::AccountId32> for Location {
538	fn from(id: sp_runtime::AccountId32) -> Self {
539		Junction::AccountId32 { network: None, id: id.into() }.into()
540	}
541}
542
543xcm_procedural::impl_conversion_functions_for_location_v4!();
544
545#[cfg(test)]
546mod tests {
547	use crate::v4::prelude::*;
548	use codec::{Decode, Encode};
549
550	#[test]
551	fn conversion_works() {
552		let x: Location = Parent.into();
553		assert_eq!(x, Location { parents: 1, interior: Here });
554		//		let x: Location = (Parent,).into();
555		//		assert_eq!(x, Location { parents: 1, interior: Here });
556		//		let x: Location = (Parent, Parent).into();
557		//		assert_eq!(x, Location { parents: 2, interior: Here });
558		let x: Location = (Parent, Parent, OnlyChild).into();
559		assert_eq!(x, Location { parents: 2, interior: OnlyChild.into() });
560		let x: Location = OnlyChild.into();
561		assert_eq!(x, Location { parents: 0, interior: OnlyChild.into() });
562		let x: Location = (OnlyChild,).into();
563		assert_eq!(x, Location { parents: 0, interior: OnlyChild.into() });
564	}
565
566	#[test]
567	fn simplify_basic_works() {
568		let mut location: Location =
569			(Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into();
570		let context = [Parachain(1000), PalletInstance(42)].into();
571		let expected = GeneralIndex(69).into();
572		location.simplify(&context);
573		assert_eq!(location, expected);
574
575		let mut location: Location = (Parent, PalletInstance(42), GeneralIndex(69)).into();
576		let context = [PalletInstance(42)].into();
577		let expected = GeneralIndex(69).into();
578		location.simplify(&context);
579		assert_eq!(location, expected);
580
581		let mut location: Location = (Parent, PalletInstance(42), GeneralIndex(69)).into();
582		let context = [Parachain(1000), PalletInstance(42)].into();
583		let expected = GeneralIndex(69).into();
584		location.simplify(&context);
585		assert_eq!(location, expected);
586
587		let mut location: Location =
588			(Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into();
589		let context = [OnlyChild, Parachain(1000), PalletInstance(42)].into();
590		let expected = GeneralIndex(69).into();
591		location.simplify(&context);
592		assert_eq!(location, expected);
593	}
594
595	#[test]
596	fn simplify_incompatible_location_fails() {
597		let mut location: Location =
598			(Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into();
599		let context = [Parachain(1000), PalletInstance(42), GeneralIndex(42)].into();
600		let expected =
601			(Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into();
602		location.simplify(&context);
603		assert_eq!(location, expected);
604
605		let mut location: Location =
606			(Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into();
607		let context = [Parachain(1000)].into();
608		let expected =
609			(Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into();
610		location.simplify(&context);
611		assert_eq!(location, expected);
612	}
613
614	#[test]
615	fn reanchor_works() {
616		let mut id: Location = (Parent, Parachain(1000), GeneralIndex(42)).into();
617		let context = Parachain(2000).into();
618		let target = (Parent, Parachain(1000)).into();
619		let expected = GeneralIndex(42).into();
620		id.reanchor(&target, &context).unwrap();
621		assert_eq!(id, expected);
622	}
623
624	#[test]
625	fn encode_and_decode_works() {
626		let m = Location {
627			parents: 1,
628			interior: [Parachain(42), AccountIndex64 { network: None, index: 23 }].into(),
629		};
630		let encoded = m.encode();
631		assert_eq!(encoded, [1, 2, 0, 168, 2, 0, 92].to_vec());
632		let decoded = Location::decode(&mut &encoded[..]);
633		assert_eq!(decoded, Ok(m));
634	}
635
636	#[test]
637	fn match_and_split_works() {
638		let m = Location {
639			parents: 1,
640			interior: [Parachain(42), AccountIndex64 { network: None, index: 23 }].into(),
641		};
642		assert_eq!(m.match_and_split(&Location { parents: 1, interior: Here }), None);
643		assert_eq!(
644			m.match_and_split(&Location { parents: 1, interior: [Parachain(42)].into() }),
645			Some(&AccountIndex64 { network: None, index: 23 })
646		);
647		assert_eq!(m.match_and_split(&m), None);
648	}
649
650	#[test]
651	fn append_with_works() {
652		let acc = AccountIndex64 { network: None, index: 23 };
653		let mut m = Location { parents: 1, interior: [Parachain(42)].into() };
654		assert_eq!(m.append_with([PalletInstance(3), acc]), Ok(()));
655		assert_eq!(
656			m,
657			Location { parents: 1, interior: [Parachain(42), PalletInstance(3), acc].into() }
658		);
659
660		// cannot append to create overly long location
661		let acc = AccountIndex64 { network: None, index: 23 };
662		let m = Location {
663			parents: 254,
664			interior: [Parachain(42), OnlyChild, OnlyChild, OnlyChild, OnlyChild].into(),
665		};
666		let suffix: Location = (PalletInstance(3), acc, OnlyChild, OnlyChild).into();
667		assert_eq!(m.clone().append_with(suffix.clone()), Err(suffix));
668	}
669
670	#[test]
671	fn prepend_with_works() {
672		let mut m = Location {
673			parents: 1,
674			interior: [Parachain(42), AccountIndex64 { network: None, index: 23 }].into(),
675		};
676		assert_eq!(m.prepend_with(Location { parents: 1, interior: [OnlyChild].into() }), Ok(()));
677		assert_eq!(
678			m,
679			Location {
680				parents: 1,
681				interior: [Parachain(42), AccountIndex64 { network: None, index: 23 }].into()
682			}
683		);
684
685		// cannot prepend to create overly long location
686		let mut m = Location { parents: 254, interior: [Parachain(42)].into() };
687		let prefix = Location { parents: 2, interior: Here };
688		assert_eq!(m.prepend_with(prefix.clone()), Err(prefix));
689
690		let prefix = Location { parents: 1, interior: Here };
691		assert_eq!(m.prepend_with(prefix.clone()), Ok(()));
692		assert_eq!(m, Location { parents: 255, interior: [Parachain(42)].into() });
693	}
694
695	#[test]
696	fn double_ended_ref_iteration_works() {
697		let m: Junctions = [Parachain(1000), Parachain(3), PalletInstance(5)].into();
698		let mut iter = m.iter();
699
700		let first = iter.next().unwrap();
701		assert_eq!(first, &Parachain(1000));
702		let third = iter.next_back().unwrap();
703		assert_eq!(third, &PalletInstance(5));
704		let second = iter.next_back().unwrap();
705		assert_eq!(iter.next(), None);
706		assert_eq!(iter.next_back(), None);
707		assert_eq!(second, &Parachain(3));
708
709		let res = Here
710			.pushed_with(*first)
711			.unwrap()
712			.pushed_with(*second)
713			.unwrap()
714			.pushed_with(*third)
715			.unwrap();
716		assert_eq!(m, res);
717
718		// make sure there's no funny business with the 0 indexing
719		let m = Here;
720		let mut iter = m.iter();
721
722		assert_eq!(iter.next(), None);
723		assert_eq!(iter.next_back(), None);
724	}
725
726	#[test]
727	fn conversion_from_other_types_works() {
728		use crate::v3;
729
730		fn takes_location<Arg: Into<Location>>(_arg: Arg) {}
731
732		takes_location(Parent);
733		takes_location(Here);
734		takes_location([Parachain(42)]);
735		takes_location((Ancestor(255), PalletInstance(8)));
736		takes_location((Ancestor(5), Parachain(1), PalletInstance(3)));
737		takes_location((Ancestor(2), Here));
738		takes_location(AncestorThen(
739			3,
740			[Parachain(43), AccountIndex64 { network: None, index: 155 }],
741		));
742		takes_location((Parent, AccountId32 { network: None, id: [0; 32] }));
743		takes_location((Parent, Here));
744		takes_location(ParentThen([Parachain(75)].into()));
745		takes_location([Parachain(100), PalletInstance(3)]);
746
747		assert_eq!(v3::Location::from(v3::Junctions::Here).try_into(), Ok(Location::here()));
748		assert_eq!(v3::Location::from(v3::Parent).try_into(), Ok(Location::parent()));
749		assert_eq!(
750			v3::Location::from((v3::Parent, v3::Parent, v3::Junction::GeneralIndex(42u128),))
751				.try_into(),
752			Ok(Location { parents: 2, interior: [GeneralIndex(42u128)].into() }),
753		);
754	}
755}