1use 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#[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 pub parents: u8,
68 pub interior: Junctions,
70}
71
72impl Default for Location {
73 fn default() -> Self {
74 Self { parents: 0, interior: Junctions::Here }
75 }
76}
77
78pub type InteriorLocation = Junctions;
82
83impl Location {
84 pub fn new(parents: u8, interior: impl Into<Junctions>) -> Location {
86 Location { parents, interior: interior.into() }
87 }
88
89 pub const fn into_versioned(self) -> VersionedLocation {
91 VersionedLocation::V4(self)
92 }
93
94 pub const fn here() -> Location {
98 Location { parents: 0, interior: Junctions::Here }
99 }
100
101 pub const fn parent() -> Location {
103 Location { parents: 1, interior: Junctions::Here }
104 }
105
106 pub const fn ancestor(parents: u8) -> Location {
108 Location { parents, interior: Junctions::Here }
109 }
110
111 pub fn is_here(&self) -> bool {
113 self.parents == 0 && self.interior.len() == 0
114 }
115
116 pub fn remove_network_id(&mut self) {
118 self.interior.remove_network_id();
119 }
120
121 pub fn interior(&self) -> &Junctions {
123 &self.interior
124 }
125
126 pub fn interior_mut(&mut self) -> &mut Junctions {
128 &mut self.interior
129 }
130
131 pub const fn parent_count(&self) -> u8 {
133 self.parents
134 }
135
136 pub fn unpack(&self) -> (u8, &[Junction]) {
150 (self.parents, self.interior.as_slice())
151 }
152
153 pub const fn contains_parents_only(&self, count: u8) -> bool {
156 matches!(self.interior, Junctions::Here) && self.parents == count
157 }
158
159 pub fn len(&self) -> usize {
161 self.parent_count() as usize + self.interior.len()
162 }
163
164 pub fn first_interior(&self) -> Option<&Junction> {
167 self.interior.first()
168 }
169
170 pub fn last(&self) -> Option<&Junction> {
172 self.interior.last()
173 }
174
175 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 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 pub fn push_interior(&mut self, new: impl Into<Junction>) -> result::Result<(), Junction> {
197 self.interior.push(new)
198 }
199
200 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 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 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 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 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 pub fn dec_parent(&mut self) {
255 self.parents = self.parents.saturating_sub(1);
256 }
257
258 pub fn take_first_interior(&mut self) -> Option<Junction> {
261 self.interior.take_first()
262 }
263
264 pub fn take_last(&mut self) -> Option<Junction> {
267 self.interior.take_last()
268 }
269
270 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 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 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 pub fn prepend_with(&mut self, prefix: impl Into<Self>) -> Result<(), Self> {
352 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 while self.parents > 0 && prefix.take_last().is_some() {
368 self.dec_parent();
369 }
370
371 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 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 pub fn simplify(&mut self, context: &Junctions) {
410 if context.len() < self.parents as usize {
411 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 pub fn chain_location(&self) -> Location {
428 let mut clone = self.clone();
429 while let Some(j) = clone.last() {
431 if matches!(j, Junction::Parachain(_) | Junction::GlobalConsensus(_)) {
432 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 fn reanchor(&mut self, target: &Location, context: &InteriorLocation) -> Result<(), ()> {
450 let inverted_target = context.invert_target(target)?;
454
455 self.prepend_with(inverted_target).map_err(|_| ())?;
458
459 self.simplify(target.interior());
462
463 Ok(())
464 }
465
466 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#[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#[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#[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#[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, 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 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 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 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}