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