referrerpolicy=no-referrer-when-downgrade

staging_xcm/v4/
junctions.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 `Junctions`/`InteriorLocation` datatype.
18
19use super::{Junction, Location, NetworkId};
20use alloc::sync::Arc;
21use codec::{Decode, DecodeWithMemTracking, Encode, MaxEncodedLen};
22use core::{mem, ops::Range, result};
23use scale_info::TypeInfo;
24
25/// Maximum number of `Junction`s that a `Junctions` can contain.
26pub(crate) const MAX_JUNCTIONS: usize = 8;
27
28/// Non-parent junctions that can be constructed, up to the length of 8. This specific `Junctions`
29/// implementation uses a Rust `enum` in order to make pattern matching easier.
30///
31/// Parent junctions cannot be constructed with this type. Refer to `Location` for
32/// instructions on constructing parent junctions.
33#[derive(
34	Clone,
35	Eq,
36	PartialEq,
37	Ord,
38	PartialOrd,
39	Encode,
40	Decode,
41	DecodeWithMemTracking,
42	Debug,
43	TypeInfo,
44	MaxEncodedLen,
45	serde::Serialize,
46	serde::Deserialize,
47)]
48pub enum Junctions {
49	/// The interpreting consensus system.
50	Here,
51	/// A relative path comprising 1 junction.
52	X1(Arc<[Junction; 1]>),
53	/// A relative path comprising 2 junctions.
54	X2(Arc<[Junction; 2]>),
55	/// A relative path comprising 3 junctions.
56	X3(Arc<[Junction; 3]>),
57	/// A relative path comprising 4 junctions.
58	X4(Arc<[Junction; 4]>),
59	/// A relative path comprising 5 junctions.
60	X5(Arc<[Junction; 5]>),
61	/// A relative path comprising 6 junctions.
62	X6(Arc<[Junction; 6]>),
63	/// A relative path comprising 7 junctions.
64	X7(Arc<[Junction; 7]>),
65	/// A relative path comprising 8 junctions.
66	X8(Arc<[Junction; 8]>),
67}
68
69macro_rules! impl_junctions {
70	($count:expr, $variant:ident) => {
71		impl From<[Junction; $count]> for Junctions {
72			fn from(junctions: [Junction; $count]) -> Self {
73				Self::$variant(Arc::new(junctions))
74			}
75		}
76		impl PartialEq<[Junction; $count]> for Junctions {
77			fn eq(&self, rhs: &[Junction; $count]) -> bool {
78				self.as_slice() == rhs
79			}
80		}
81	};
82}
83
84impl_junctions!(1, X1);
85impl_junctions!(2, X2);
86impl_junctions!(3, X3);
87impl_junctions!(4, X4);
88impl_junctions!(5, X5);
89impl_junctions!(6, X6);
90impl_junctions!(7, X7);
91impl_junctions!(8, X8);
92
93pub struct JunctionsIterator {
94	junctions: Junctions,
95	range: Range<usize>,
96}
97
98impl Iterator for JunctionsIterator {
99	type Item = Junction;
100	fn next(&mut self) -> Option<Junction> {
101		self.junctions.at(self.range.next()?).cloned()
102	}
103}
104
105impl DoubleEndedIterator for JunctionsIterator {
106	fn next_back(&mut self) -> Option<Junction> {
107		self.junctions.at(self.range.next_back()?).cloned()
108	}
109}
110
111pub struct JunctionsRefIterator<'a> {
112	junctions: &'a Junctions,
113	range: Range<usize>,
114}
115
116impl<'a> Iterator for JunctionsRefIterator<'a> {
117	type Item = &'a Junction;
118	fn next(&mut self) -> Option<&'a Junction> {
119		self.junctions.at(self.range.next()?)
120	}
121}
122
123impl<'a> DoubleEndedIterator for JunctionsRefIterator<'a> {
124	fn next_back(&mut self) -> Option<&'a Junction> {
125		self.junctions.at(self.range.next_back()?)
126	}
127}
128impl<'a> IntoIterator for &'a Junctions {
129	type Item = &'a Junction;
130	type IntoIter = JunctionsRefIterator<'a>;
131	fn into_iter(self) -> Self::IntoIter {
132		JunctionsRefIterator { junctions: self, range: 0..self.len() }
133	}
134}
135
136impl IntoIterator for Junctions {
137	type Item = Junction;
138	type IntoIter = JunctionsIterator;
139	fn into_iter(self) -> Self::IntoIter {
140		JunctionsIterator { range: 0..self.len(), junctions: self }
141	}
142}
143
144impl Junctions {
145	/// Convert `self` into a `Location` containing 0 parents.
146	///
147	/// Similar to `Into::into`, except that this method can be used in a const evaluation context.
148	pub const fn into_location(self) -> Location {
149		Location { parents: 0, interior: self }
150	}
151
152	/// Convert `self` into a `Location` containing `n` parents.
153	///
154	/// Similar to `Self::into_location`, with the added ability to specify the number of parent
155	/// junctions.
156	pub const fn into_exterior(self, n: u8) -> Location {
157		Location { parents: n, interior: self }
158	}
159
160	/// Casts `self` into a slice containing `Junction`s.
161	pub fn as_slice(&self) -> &[Junction] {
162		match self {
163			Junctions::Here => &[],
164			Junctions::X1(ref a) => &a[..],
165			Junctions::X2(ref a) => &a[..],
166			Junctions::X3(ref a) => &a[..],
167			Junctions::X4(ref a) => &a[..],
168			Junctions::X5(ref a) => &a[..],
169			Junctions::X6(ref a) => &a[..],
170			Junctions::X7(ref a) => &a[..],
171			Junctions::X8(ref a) => &a[..],
172		}
173	}
174
175	/// Casts `self` into a mutable slice containing `Junction`s.
176	pub fn as_slice_mut(&mut self) -> &mut [Junction] {
177		match self {
178			Junctions::Here => &mut [],
179			Junctions::X1(ref mut a) => &mut Arc::make_mut(a)[..],
180			Junctions::X2(ref mut a) => &mut Arc::make_mut(a)[..],
181			Junctions::X3(ref mut a) => &mut Arc::make_mut(a)[..],
182			Junctions::X4(ref mut a) => &mut Arc::make_mut(a)[..],
183			Junctions::X5(ref mut a) => &mut Arc::make_mut(a)[..],
184			Junctions::X6(ref mut a) => &mut Arc::make_mut(a)[..],
185			Junctions::X7(ref mut a) => &mut Arc::make_mut(a)[..],
186			Junctions::X8(ref mut a) => &mut Arc::make_mut(a)[..],
187		}
188	}
189
190	/// Remove the `NetworkId` value in any `Junction`s.
191	pub fn remove_network_id(&mut self) {
192		self.for_each_mut(Junction::remove_network_id);
193	}
194
195	/// Treating `self` as the universal context, return the location of the local consensus system
196	/// from the point of view of the given `target`.
197	pub fn invert_target(&self, target: &Location) -> Result<Location, ()> {
198		let mut itself = self.clone();
199		let mut junctions = Self::Here;
200		for _ in 0..target.parent_count() {
201			junctions = junctions
202				.pushed_front_with(itself.take_last().unwrap_or(Junction::OnlyChild))
203				.map_err(|_| ())?;
204		}
205		let parents = target.interior().len() as u8;
206		Ok(Location::new(parents, junctions))
207	}
208
209	/// Execute a function `f` on every junction. We use this since we cannot implement a mutable
210	/// `Iterator` without unsafe code.
211	pub fn for_each_mut(&mut self, x: impl FnMut(&mut Junction)) {
212		self.as_slice_mut().iter_mut().for_each(x)
213	}
214
215	/// Extract the network ID treating this value as a universal location.
216	///
217	/// This will return an `Err` if the first item is not a `GlobalConsensus`, which would indicate
218	/// that this value is not a universal location.
219	pub fn global_consensus(&self) -> Result<NetworkId, ()> {
220		if let Some(Junction::GlobalConsensus(network)) = self.first() {
221			Ok(*network)
222		} else {
223			Err(())
224		}
225	}
226
227	/// Extract the network ID and the interior consensus location, treating this value as a
228	/// universal location.
229	///
230	/// This will return an `Err` if the first item is not a `GlobalConsensus`, which would indicate
231	/// that this value is not a universal location.
232	pub fn split_global(self) -> Result<(NetworkId, Junctions), ()> {
233		match self.split_first() {
234			(location, Some(Junction::GlobalConsensus(network))) => Ok((network, location)),
235			_ => return Err(()),
236		}
237	}
238
239	/// Treat `self` as a universal location and the context of `relative`, returning the universal
240	/// location of relative.
241	///
242	/// This will return an error if `relative` has as many (or more) parents than there are
243	/// junctions in `self`, implying that relative refers into a different global consensus.
244	pub fn within_global(mut self, relative: Location) -> Result<Self, ()> {
245		if self.len() <= relative.parent_count() as usize {
246			return Err(())
247		}
248		for _ in 0..relative.parent_count() {
249			self.take_last();
250		}
251		for j in relative.interior() {
252			self.push(*j).map_err(|_| ())?;
253		}
254		Ok(self)
255	}
256
257	/// Consumes `self` and returns how `viewer` would address it locally.
258	pub fn relative_to(mut self, viewer: &Junctions) -> Location {
259		let mut i = 0;
260		while match (self.first(), viewer.at(i)) {
261			(Some(x), Some(y)) => x == y,
262			_ => false,
263		} {
264			self = self.split_first().0;
265			// NOTE: Cannot overflow as loop can only iterate at most `MAX_JUNCTIONS` times.
266			i += 1;
267		}
268		// AUDIT NOTES:
269		// - above loop ensures that `i <= viewer.len()`.
270		// - `viewer.len()` is at most `MAX_JUNCTIONS`, so won't overflow a `u8`.
271		Location::new((viewer.len() - i) as u8, self)
272	}
273
274	/// Returns first junction, or `None` if the location is empty.
275	pub fn first(&self) -> Option<&Junction> {
276		self.as_slice().first()
277	}
278
279	/// Returns last junction, or `None` if the location is empty.
280	pub fn last(&self) -> Option<&Junction> {
281		self.as_slice().last()
282	}
283
284	/// Splits off the first junction, returning the remaining suffix (first item in tuple) and the
285	/// first element (second item in tuple) or `None` if it was empty.
286	pub fn split_first(self) -> (Junctions, Option<Junction>) {
287		match self {
288			Junctions::Here => (Junctions::Here, None),
289			Junctions::X1(xs) => {
290				let [a] = *xs;
291				(Junctions::Here, Some(a))
292			},
293			Junctions::X2(xs) => {
294				let [a, b] = *xs;
295				([b].into(), Some(a))
296			},
297			Junctions::X3(xs) => {
298				let [a, b, c] = *xs;
299				([b, c].into(), Some(a))
300			},
301			Junctions::X4(xs) => {
302				let [a, b, c, d] = *xs;
303				([b, c, d].into(), Some(a))
304			},
305			Junctions::X5(xs) => {
306				let [a, b, c, d, e] = *xs;
307				([b, c, d, e].into(), Some(a))
308			},
309			Junctions::X6(xs) => {
310				let [a, b, c, d, e, f] = *xs;
311				([b, c, d, e, f].into(), Some(a))
312			},
313			Junctions::X7(xs) => {
314				let [a, b, c, d, e, f, g] = *xs;
315				([b, c, d, e, f, g].into(), Some(a))
316			},
317			Junctions::X8(xs) => {
318				let [a, b, c, d, e, f, g, h] = *xs;
319				([b, c, d, e, f, g, h].into(), Some(a))
320			},
321		}
322	}
323
324	/// Splits off the last junction, returning the remaining prefix (first item in tuple) and the
325	/// last element (second item in tuple) or `None` if it was empty.
326	pub fn split_last(self) -> (Junctions, Option<Junction>) {
327		match self {
328			Junctions::Here => (Junctions::Here, None),
329			Junctions::X1(xs) => {
330				let [a] = *xs;
331				(Junctions::Here, Some(a))
332			},
333			Junctions::X2(xs) => {
334				let [a, b] = *xs;
335				([a].into(), Some(b))
336			},
337			Junctions::X3(xs) => {
338				let [a, b, c] = *xs;
339				([a, b].into(), Some(c))
340			},
341			Junctions::X4(xs) => {
342				let [a, b, c, d] = *xs;
343				([a, b, c].into(), Some(d))
344			},
345			Junctions::X5(xs) => {
346				let [a, b, c, d, e] = *xs;
347				([a, b, c, d].into(), Some(e))
348			},
349			Junctions::X6(xs) => {
350				let [a, b, c, d, e, f] = *xs;
351				([a, b, c, d, e].into(), Some(f))
352			},
353			Junctions::X7(xs) => {
354				let [a, b, c, d, e, f, g] = *xs;
355				([a, b, c, d, e, f].into(), Some(g))
356			},
357			Junctions::X8(xs) => {
358				let [a, b, c, d, e, f, g, h] = *xs;
359				([a, b, c, d, e, f, g].into(), Some(h))
360			},
361		}
362	}
363
364	/// Removes the first element from `self`, returning it (or `None` if it was empty).
365	pub fn take_first(&mut self) -> Option<Junction> {
366		let mut d = Junctions::Here;
367		mem::swap(&mut *self, &mut d);
368		let (tail, head) = d.split_first();
369		*self = tail;
370		head
371	}
372
373	/// Removes the last element from `self`, returning it (or `None` if it was empty).
374	pub fn take_last(&mut self) -> Option<Junction> {
375		let mut d = Junctions::Here;
376		mem::swap(&mut *self, &mut d);
377		let (head, tail) = d.split_last();
378		*self = head;
379		tail
380	}
381
382	/// Mutates `self` to be appended with `new` or returns an `Err` with `new` if would overflow.
383	pub fn push(&mut self, new: impl Into<Junction>) -> result::Result<(), Junction> {
384		let new = new.into();
385		let mut dummy = Junctions::Here;
386		mem::swap(self, &mut dummy);
387		match dummy.pushed_with(new) {
388			Ok(s) => {
389				*self = s;
390				Ok(())
391			},
392			Err((s, j)) => {
393				*self = s;
394				Err(j)
395			},
396		}
397	}
398
399	/// Mutates `self` to be prepended with `new` or returns an `Err` with `new` if would overflow.
400	pub fn push_front(&mut self, new: impl Into<Junction>) -> result::Result<(), Junction> {
401		let new = new.into();
402		let mut dummy = Junctions::Here;
403		mem::swap(self, &mut dummy);
404		match dummy.pushed_front_with(new) {
405			Ok(s) => {
406				*self = s;
407				Ok(())
408			},
409			Err((s, j)) => {
410				*self = s;
411				Err(j)
412			},
413		}
414	}
415
416	/// Consumes `self` and returns a `Junctions` suffixed with `new`, or an `Err` with the
417	/// original value of `self` and `new` in case of overflow.
418	pub fn pushed_with(self, new: impl Into<Junction>) -> result::Result<Self, (Self, Junction)> {
419		let new = new.into();
420		Ok(match self {
421			Junctions::Here => [new].into(),
422			Junctions::X1(xs) => {
423				let [a] = *xs;
424				[a, new].into()
425			},
426			Junctions::X2(xs) => {
427				let [a, b] = *xs;
428				[a, b, new].into()
429			},
430			Junctions::X3(xs) => {
431				let [a, b, c] = *xs;
432				[a, b, c, new].into()
433			},
434			Junctions::X4(xs) => {
435				let [a, b, c, d] = *xs;
436				[a, b, c, d, new].into()
437			},
438			Junctions::X5(xs) => {
439				let [a, b, c, d, e] = *xs;
440				[a, b, c, d, e, new].into()
441			},
442			Junctions::X6(xs) => {
443				let [a, b, c, d, e, f] = *xs;
444				[a, b, c, d, e, f, new].into()
445			},
446			Junctions::X7(xs) => {
447				let [a, b, c, d, e, f, g] = *xs;
448				[a, b, c, d, e, f, g, new].into()
449			},
450			s => Err((s, new))?,
451		})
452	}
453
454	/// Consumes `self` and returns a `Junctions` prefixed with `new`, or an `Err` with the
455	/// original value of `self` and `new` in case of overflow.
456	pub fn pushed_front_with(
457		self,
458		new: impl Into<Junction>,
459	) -> result::Result<Self, (Self, Junction)> {
460		let new = new.into();
461		Ok(match self {
462			Junctions::Here => [new].into(),
463			Junctions::X1(xs) => {
464				let [a] = *xs;
465				[new, a].into()
466			},
467			Junctions::X2(xs) => {
468				let [a, b] = *xs;
469				[new, a, b].into()
470			},
471			Junctions::X3(xs) => {
472				let [a, b, c] = *xs;
473				[new, a, b, c].into()
474			},
475			Junctions::X4(xs) => {
476				let [a, b, c, d] = *xs;
477				[new, a, b, c, d].into()
478			},
479			Junctions::X5(xs) => {
480				let [a, b, c, d, e] = *xs;
481				[new, a, b, c, d, e].into()
482			},
483			Junctions::X6(xs) => {
484				let [a, b, c, d, e, f] = *xs;
485				[new, a, b, c, d, e, f].into()
486			},
487			Junctions::X7(xs) => {
488				let [a, b, c, d, e, f, g] = *xs;
489				[new, a, b, c, d, e, f, g].into()
490			},
491			s => Err((s, new))?,
492		})
493	}
494
495	/// Mutate `self` so that it is suffixed with `suffix`.
496	///
497	/// Does not modify `self` and returns `Err` with `suffix` in case of overflow.
498	///
499	/// # Example
500	/// ```rust
501	/// # use staging_xcm::v4::{Junctions, Junction::*, Location};
502	/// # fn main() {
503	/// let mut m = Junctions::from([Parachain(21)]);
504	/// assert_eq!(m.append_with([PalletInstance(3)]), Ok(()));
505	/// assert_eq!(m, [Parachain(21), PalletInstance(3)]);
506	/// # }
507	/// ```
508	pub fn append_with(&mut self, suffix: impl Into<Junctions>) -> Result<(), Junctions> {
509		let suffix = suffix.into();
510		if self.len().saturating_add(suffix.len()) > MAX_JUNCTIONS {
511			return Err(suffix)
512		}
513		for j in suffix.into_iter() {
514			self.push(j).expect("Already checked the sum of the len()s; qed")
515		}
516		Ok(())
517	}
518
519	/// Returns the number of junctions in `self`.
520	pub fn len(&self) -> usize {
521		self.as_slice().len()
522	}
523
524	/// Returns the junction at index `i`, or `None` if the location doesn't contain that many
525	/// elements.
526	pub fn at(&self, i: usize) -> Option<&Junction> {
527		self.as_slice().get(i)
528	}
529
530	/// Returns a mutable reference to the junction at index `i`, or `None` if the location doesn't
531	/// contain that many elements.
532	pub fn at_mut(&mut self, i: usize) -> Option<&mut Junction> {
533		self.as_slice_mut().get_mut(i)
534	}
535
536	/// Returns a reference iterator over the junctions.
537	pub fn iter(&self) -> JunctionsRefIterator {
538		JunctionsRefIterator { junctions: self, range: 0..self.len() }
539	}
540
541	/// Ensures that self begins with `prefix` and that it has a single `Junction` item following.
542	/// If so, returns a reference to this `Junction` item.
543	///
544	/// # Example
545	/// ```rust
546	/// # use staging_xcm::v4::{Junctions, Junction::*};
547	/// # fn main() {
548	/// let mut m = Junctions::from([Parachain(2), PalletInstance(3), OnlyChild]);
549	/// assert_eq!(m.match_and_split(&[Parachain(2), PalletInstance(3)].into()), Some(&OnlyChild));
550	/// assert_eq!(m.match_and_split(&[Parachain(2)].into()), None);
551	/// # }
552	/// ```
553	pub fn match_and_split(&self, prefix: &Junctions) -> Option<&Junction> {
554		if prefix.len() + 1 != self.len() {
555			return None
556		}
557		for i in 0..prefix.len() {
558			if prefix.at(i) != self.at(i) {
559				return None
560			}
561		}
562		return self.at(prefix.len())
563	}
564
565	pub fn starts_with(&self, prefix: &Junctions) -> bool {
566		prefix.len() <= self.len() && prefix.iter().zip(self.iter()).all(|(x, y)| x == y)
567	}
568}
569
570impl TryFrom<Location> for Junctions {
571	type Error = Location;
572	fn try_from(x: Location) -> result::Result<Self, Location> {
573		if x.parent_count() > 0 {
574			Err(x)
575		} else {
576			Ok(x.interior().clone())
577		}
578	}
579}
580
581impl<T: Into<Junction>> From<T> for Junctions {
582	fn from(x: T) -> Self {
583		[x.into()].into()
584	}
585}
586
587impl From<[Junction; 0]> for Junctions {
588	fn from(_: [Junction; 0]) -> Self {
589		Self::Here
590	}
591}
592
593impl From<()> for Junctions {
594	fn from(_: ()) -> Self {
595		Self::Here
596	}
597}
598
599xcm_procedural::impl_conversion_functions_for_junctions_v4!();
600
601#[cfg(test)]
602mod tests {
603	use super::{super::prelude::*, *};
604
605	#[test]
606	fn inverting_works() {
607		let context: InteriorLocation = (Parachain(1000), PalletInstance(42)).into();
608		let target = (Parent, PalletInstance(69)).into();
609		let expected = (Parent, PalletInstance(42)).into();
610		let inverted = context.invert_target(&target).unwrap();
611		assert_eq!(inverted, expected);
612
613		let context: InteriorLocation =
614			(Parachain(1000), PalletInstance(42), GeneralIndex(1)).into();
615		let target = (Parent, Parent, PalletInstance(69), GeneralIndex(2)).into();
616		let expected = (Parent, Parent, PalletInstance(42), GeneralIndex(1)).into();
617		let inverted = context.invert_target(&target).unwrap();
618		assert_eq!(inverted, expected);
619	}
620
621	#[test]
622	fn relative_to_works() {
623		use NetworkId::*;
624		assert_eq!(
625			Junctions::from([Polkadot.into()]).relative_to(&Junctions::from([Kusama.into()])),
626			(Parent, Polkadot).into()
627		);
628		let base = Junctions::from([Kusama.into(), Parachain(1), PalletInstance(1)]);
629
630		// Ancestors.
631		assert_eq!(Here.relative_to(&base), (Parent, Parent, Parent).into());
632		assert_eq!(Junctions::from([Kusama.into()]).relative_to(&base), (Parent, Parent).into());
633		assert_eq!(
634			Junctions::from([Kusama.into(), Parachain(1)]).relative_to(&base),
635			(Parent,).into()
636		);
637		assert_eq!(
638			Junctions::from([Kusama.into(), Parachain(1), PalletInstance(1)]).relative_to(&base),
639			Here.into()
640		);
641
642		// Ancestors with one child.
643		assert_eq!(
644			Junctions::from([Polkadot.into()]).relative_to(&base),
645			(Parent, Parent, Parent, Polkadot).into()
646		);
647		assert_eq!(
648			Junctions::from([Kusama.into(), Parachain(2)]).relative_to(&base),
649			(Parent, Parent, Parachain(2)).into()
650		);
651		assert_eq!(
652			Junctions::from([Kusama.into(), Parachain(1), PalletInstance(2)]).relative_to(&base),
653			(Parent, PalletInstance(2)).into()
654		);
655		assert_eq!(
656			Junctions::from([Kusama.into(), Parachain(1), PalletInstance(1), [1u8; 32].into()])
657				.relative_to(&base),
658			([1u8; 32],).into()
659		);
660
661		// Ancestors with grandchildren.
662		assert_eq!(
663			Junctions::from([Polkadot.into(), Parachain(1)]).relative_to(&base),
664			(Parent, Parent, Parent, Polkadot, Parachain(1)).into()
665		);
666		assert_eq!(
667			Junctions::from([Kusama.into(), Parachain(2), PalletInstance(1)]).relative_to(&base),
668			(Parent, Parent, Parachain(2), PalletInstance(1)).into()
669		);
670		assert_eq!(
671			Junctions::from([Kusama.into(), Parachain(1), PalletInstance(2), [1u8; 32].into()])
672				.relative_to(&base),
673			(Parent, PalletInstance(2), [1u8; 32]).into()
674		);
675		assert_eq!(
676			Junctions::from([
677				Kusama.into(),
678				Parachain(1),
679				PalletInstance(1),
680				[1u8; 32].into(),
681				1u128.into()
682			])
683			.relative_to(&base),
684			([1u8; 32], 1u128).into()
685		);
686	}
687
688	#[test]
689	fn global_consensus_works() {
690		use NetworkId::*;
691		assert_eq!(Junctions::from([Polkadot.into()]).global_consensus(), Ok(Polkadot));
692		assert_eq!(Junctions::from([Kusama.into(), 1u64.into()]).global_consensus(), Ok(Kusama));
693		assert_eq!(Here.global_consensus(), Err(()));
694		assert_eq!(Junctions::from([1u64.into()]).global_consensus(), Err(()));
695		assert_eq!(Junctions::from([1u64.into(), Kusama.into()]).global_consensus(), Err(()));
696	}
697
698	#[test]
699	fn test_conversion() {
700		use super::{Junction::*, NetworkId::*};
701		let x: Junctions = GlobalConsensus(Polkadot).into();
702		assert_eq!(x, Junctions::from([GlobalConsensus(Polkadot)]));
703		let x: Junctions = Polkadot.into();
704		assert_eq!(x, Junctions::from([GlobalConsensus(Polkadot)]));
705		let x: Junctions = (Polkadot, Kusama).into();
706		assert_eq!(x, Junctions::from([GlobalConsensus(Polkadot), GlobalConsensus(Kusama)]));
707	}
708
709	#[test]
710	fn encode_decode_junctions_works() {
711		let original = Junctions::from([
712			Polkadot.into(),
713			Kusama.into(),
714			1u64.into(),
715			GlobalConsensus(Polkadot),
716			Parachain(123),
717			PalletInstance(45),
718		]);
719		let encoded = original.encode();
720		assert_eq!(encoded, &[6, 9, 2, 9, 3, 2, 0, 4, 9, 2, 0, 237, 1, 4, 45]);
721		let decoded = Junctions::decode(&mut &encoded[..]).unwrap();
722		assert_eq!(decoded, original);
723	}
724}