referrerpolicy=no-referrer-when-downgrade

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