1use super::{Junction, Junctions};
20use crate::{v4::Location as NewMultiLocation, VersionedLocation};
21use codec::{Decode, DecodeWithMemTracking, Encode, MaxEncodedLen};
22use core::result;
23use scale_info::TypeInfo;
24
25#[derive(
52 Copy,
53 Clone,
54 Decode,
55 Encode,
56 DecodeWithMemTracking,
57 Eq,
58 PartialEq,
59 Ord,
60 PartialOrd,
61 Debug,
62 TypeInfo,
63 MaxEncodedLen,
64 serde::Serialize,
65 serde::Deserialize,
66)]
67#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
68pub struct MultiLocation {
69 pub parents: u8,
71 pub interior: Junctions,
73}
74
75pub type Location = MultiLocation;
77
78impl Default for MultiLocation {
79 fn default() -> Self {
80 Self { parents: 0, interior: Junctions::Here }
81 }
82}
83
84pub type InteriorMultiLocation = Junctions;
88
89impl MultiLocation {
90 pub fn new(parents: u8, interior: impl Into<Junctions>) -> MultiLocation {
92 MultiLocation { parents, interior: interior.into() }
93 }
94
95 pub const fn into_versioned(self) -> VersionedLocation {
97 VersionedLocation::V3(self)
98 }
99
100 pub const fn here() -> MultiLocation {
104 MultiLocation { parents: 0, interior: Junctions::Here }
105 }
106
107 pub const fn parent() -> MultiLocation {
109 MultiLocation { parents: 1, interior: Junctions::Here }
110 }
111
112 pub const fn grandparent() -> MultiLocation {
114 MultiLocation { parents: 2, interior: Junctions::Here }
115 }
116
117 pub const fn ancestor(parents: u8) -> MultiLocation {
119 MultiLocation { parents, interior: Junctions::Here }
120 }
121
122 pub const fn is_here(&self) -> bool {
124 self.parents == 0 && self.interior.len() == 0
125 }
126
127 pub fn remove_network_id(&mut self) {
129 self.interior.remove_network_id();
130 }
131
132 pub fn interior(&self) -> &Junctions {
134 &self.interior
135 }
136
137 pub fn interior_mut(&mut self) -> &mut Junctions {
139 &mut self.interior
140 }
141
142 pub const fn parent_count(&self) -> u8 {
144 self.parents
145 }
146
147 pub const fn contains_parents_only(&self, count: u8) -> bool {
150 matches!(self.interior, Junctions::Here) && self.parents == count
151 }
152
153 pub const fn len(&self) -> usize {
155 self.parent_count() as usize + self.interior.len()
156 }
157
158 pub fn first_interior(&self) -> Option<&Junction> {
161 self.interior.first()
162 }
163
164 pub fn last(&self) -> Option<&Junction> {
166 self.interior.last()
167 }
168
169 pub fn split_first_interior(self) -> (MultiLocation, Option<Junction>) {
172 let MultiLocation { parents, interior: junctions } = self;
173 let (suffix, first) = junctions.split_first();
174 let multilocation = MultiLocation { parents, interior: suffix };
175 (multilocation, first)
176 }
177
178 pub fn split_last_interior(self) -> (MultiLocation, Option<Junction>) {
182 let MultiLocation { parents, interior: junctions } = self;
183 let (prefix, last) = junctions.split_last();
184 let multilocation = MultiLocation { parents, interior: prefix };
185 (multilocation, last)
186 }
187
188 pub fn push_interior(&mut self, new: impl Into<Junction>) -> result::Result<(), Junction> {
191 self.interior.push(new)
192 }
193
194 pub fn push_front_interior(
197 &mut self,
198 new: impl Into<Junction>,
199 ) -> result::Result<(), Junction> {
200 self.interior.push_front(new)
201 }
202
203 pub fn pushed_with_interior(
206 self,
207 new: impl Into<Junction>,
208 ) -> result::Result<Self, (Self, Junction)> {
209 match self.interior.pushed_with(new) {
210 Ok(i) => Ok(MultiLocation { interior: i, parents: self.parents }),
211 Err((i, j)) => Err((MultiLocation { interior: i, parents: self.parents }, j)),
212 }
213 }
214
215 pub fn pushed_front_with_interior(
218 self,
219 new: impl Into<Junction>,
220 ) -> result::Result<Self, (Self, Junction)> {
221 match self.interior.pushed_front_with(new) {
222 Ok(i) => Ok(MultiLocation { interior: i, parents: self.parents }),
223 Err((i, j)) => Err((MultiLocation { interior: i, parents: self.parents }, j)),
224 }
225 }
226
227 pub fn at(&self, i: usize) -> Option<&Junction> {
230 let num_parents = self.parents as usize;
231 if i < num_parents {
232 return None
233 }
234 self.interior.at(i - num_parents)
235 }
236
237 pub fn at_mut(&mut self, i: usize) -> Option<&mut Junction> {
240 let num_parents = self.parents as usize;
241 if i < num_parents {
242 return None
243 }
244 self.interior.at_mut(i - num_parents)
245 }
246
247 pub fn dec_parent(&mut self) {
249 self.parents = self.parents.saturating_sub(1);
250 }
251
252 pub fn take_first_interior(&mut self) -> Option<Junction> {
255 self.interior.take_first()
256 }
257
258 pub fn take_last(&mut self) -> Option<Junction> {
261 self.interior.take_last()
262 }
263
264 pub fn match_and_split(&self, prefix: &MultiLocation) -> Option<&Junction> {
279 if self.parents != prefix.parents {
280 return None
281 }
282 self.interior.match_and_split(&prefix.interior)
283 }
284
285 pub fn starts_with(&self, prefix: &MultiLocation) -> bool {
286 self.parents == prefix.parents && self.interior.starts_with(&prefix.interior)
287 }
288
289 pub fn append_with(&mut self, suffix: impl Into<Self>) -> Result<(), Self> {
301 let prefix = core::mem::replace(self, suffix.into());
302 match self.prepend_with(prefix) {
303 Ok(()) => Ok(()),
304 Err(prefix) => Err(core::mem::replace(self, prefix)),
305 }
306 }
307
308 pub fn appended_with(mut self, suffix: impl Into<Self>) -> Result<Self, (Self, Self)> {
320 match self.append_with(suffix) {
321 Ok(()) => Ok(self),
322 Err(suffix) => Err((self, suffix)),
323 }
324 }
325
326 pub fn prepend_with(&mut self, prefix: impl Into<Self>) -> Result<(), Self> {
338 let mut prefix = prefix.into();
341 let prepend_interior = prefix.interior.len().saturating_sub(self.parents as usize);
342 let final_interior = self.interior.len().saturating_add(prepend_interior);
343 if final_interior > super::junctions::MAX_JUNCTIONS {
344 return Err(prefix)
345 }
346 let suffix_parents = (self.parents as usize).saturating_sub(prefix.interior.len());
347 let final_parents = (prefix.parents as usize).saturating_add(suffix_parents);
348 if final_parents > 255 {
349 return Err(prefix)
350 }
351
352 while self.parents > 0 && prefix.take_last().is_some() {
354 self.dec_parent();
355 }
356
357 self.parents = self.parents.saturating_add(prefix.parents);
366 for j in prefix.interior.into_iter().rev() {
367 self.push_front_interior(j)
368 .expect("final_interior no greater than MAX_JUNCTIONS; qed");
369 }
370 Ok(())
371 }
372
373 pub fn prepended_with(mut self, prefix: impl Into<Self>) -> Result<Self, (Self, Self)> {
385 match self.prepend_with(prefix) {
386 Ok(()) => Ok(self),
387 Err(prefix) => Err((self, prefix)),
388 }
389 }
390
391 pub fn reanchor(
396 &mut self,
397 target: &MultiLocation,
398 context: InteriorMultiLocation,
399 ) -> Result<(), ()> {
400 let inverted_target = context.invert_target(target)?;
404
405 self.prepend_with(inverted_target).map_err(|_| ())?;
408
409 self.simplify(target.interior());
412
413 Ok(())
414 }
415
416 pub fn reanchored(
421 mut self,
422 target: &MultiLocation,
423 context: InteriorMultiLocation,
424 ) -> Result<Self, Self> {
425 match self.reanchor(target, context) {
426 Ok(()) => Ok(self),
427 Err(()) => Err(self),
428 }
429 }
430
431 pub fn simplify(&mut self, context: &Junctions) {
434 if context.len() < self.parents as usize {
435 return
437 }
438 while self.parents > 0 {
439 let maybe = context.at(context.len() - (self.parents as usize));
440 match (self.interior.first(), maybe) {
441 (Some(i), Some(j)) if i == j => {
442 self.interior.take_first();
443 self.parents -= 1;
444 },
445 _ => break,
446 }
447 }
448 }
449
450 pub fn chain_location(&self) -> MultiLocation {
452 let mut clone = *self;
453 while let Some(j) = clone.last() {
455 if matches!(j, Junction::Parachain(_) | Junction::GlobalConsensus(_)) {
456 return clone
458 } else {
459 (clone, _) = clone.split_last_interior();
460 }
461 }
462 MultiLocation::new(clone.parents, Junctions::Here)
463 }
464}
465
466impl TryFrom<NewMultiLocation> for Option<MultiLocation> {
467 type Error = ();
468 fn try_from(new: NewMultiLocation) -> result::Result<Self, Self::Error> {
469 Ok(Some(MultiLocation::try_from(new)?))
470 }
471}
472
473impl TryFrom<NewMultiLocation> for MultiLocation {
474 type Error = ();
475 fn try_from(new: NewMultiLocation) -> result::Result<Self, ()> {
476 Ok(MultiLocation {
477 parents: new.parent_count(),
478 interior: new.interior().clone().try_into()?,
479 })
480 }
481}
482
483#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
485pub struct Parent;
486impl From<Parent> for MultiLocation {
487 fn from(_: Parent) -> Self {
488 MultiLocation { parents: 1, interior: Junctions::Here }
489 }
490}
491
492#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
495pub struct ParentThen(pub Junctions);
496impl From<ParentThen> for MultiLocation {
497 fn from(ParentThen(interior): ParentThen) -> Self {
498 MultiLocation { parents: 1, interior }
499 }
500}
501
502#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
504pub struct Ancestor(pub u8);
505impl From<Ancestor> for MultiLocation {
506 fn from(Ancestor(parents): Ancestor) -> Self {
507 MultiLocation { parents, interior: Junctions::Here }
508 }
509}
510
511#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
514pub struct AncestorThen<Interior>(pub u8, pub Interior);
515impl<Interior: Into<Junctions>> From<AncestorThen<Interior>> for MultiLocation {
516 fn from(AncestorThen(parents, interior): AncestorThen<Interior>) -> Self {
517 MultiLocation { parents, interior: interior.into() }
518 }
519}
520
521xcm_procedural::impl_conversion_functions_for_multilocation_v3!();
522
523#[cfg(test)]
524mod tests {
525 use crate::v3::prelude::*;
526 use codec::{Decode, Encode};
527
528 #[test]
529 fn conversion_works() {
530 let x: MultiLocation = Parent.into();
531 assert_eq!(x, MultiLocation { parents: 1, interior: Here });
532 let x: MultiLocation = (Parent, Parent, OnlyChild).into();
537 assert_eq!(x, MultiLocation { parents: 2, interior: OnlyChild.into() });
538 let x: MultiLocation = OnlyChild.into();
539 assert_eq!(x, MultiLocation { parents: 0, interior: OnlyChild.into() });
540 let x: MultiLocation = (OnlyChild,).into();
541 assert_eq!(x, MultiLocation { parents: 0, interior: OnlyChild.into() });
542 }
543
544 #[test]
545 fn simplify_basic_works() {
546 let mut location: MultiLocation =
547 (Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into();
548 let context = X2(Parachain(1000), PalletInstance(42));
549 let expected = GeneralIndex(69).into();
550 location.simplify(&context);
551 assert_eq!(location, expected);
552
553 let mut location: MultiLocation = (Parent, PalletInstance(42), GeneralIndex(69)).into();
554 let context = X1(PalletInstance(42));
555 let expected = GeneralIndex(69).into();
556 location.simplify(&context);
557 assert_eq!(location, expected);
558
559 let mut location: MultiLocation = (Parent, PalletInstance(42), GeneralIndex(69)).into();
560 let context = X2(Parachain(1000), PalletInstance(42));
561 let expected = GeneralIndex(69).into();
562 location.simplify(&context);
563 assert_eq!(location, expected);
564
565 let mut location: MultiLocation =
566 (Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into();
567 let context = X3(OnlyChild, Parachain(1000), PalletInstance(42));
568 let expected = GeneralIndex(69).into();
569 location.simplify(&context);
570 assert_eq!(location, expected);
571 }
572
573 #[test]
574 fn simplify_incompatible_location_fails() {
575 let mut location: MultiLocation =
576 (Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into();
577 let context = X3(Parachain(1000), PalletInstance(42), GeneralIndex(42));
578 let expected =
579 (Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into();
580 location.simplify(&context);
581 assert_eq!(location, expected);
582
583 let mut location: MultiLocation =
584 (Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into();
585 let context = X1(Parachain(1000));
586 let expected =
587 (Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into();
588 location.simplify(&context);
589 assert_eq!(location, expected);
590 }
591
592 #[test]
593 fn reanchor_works() {
594 let mut id: MultiLocation = (Parent, Parachain(1000), GeneralIndex(42)).into();
595 let context = Parachain(2000).into();
596 let target = (Parent, Parachain(1000)).into();
597 let expected = GeneralIndex(42).into();
598 id.reanchor(&target, context).unwrap();
599 assert_eq!(id, expected);
600 }
601
602 #[test]
603 fn encode_and_decode_works() {
604 let m = MultiLocation {
605 parents: 1,
606 interior: X2(Parachain(42), AccountIndex64 { network: None, index: 23 }),
607 };
608 let encoded = m.encode();
609 assert_eq!(encoded, [1, 2, 0, 168, 2, 0, 92].to_vec());
610 let decoded = MultiLocation::decode(&mut &encoded[..]);
611 assert_eq!(decoded, Ok(m));
612 }
613
614 #[test]
615 fn match_and_split_works() {
616 let m = MultiLocation {
617 parents: 1,
618 interior: X2(Parachain(42), AccountIndex64 { network: None, index: 23 }),
619 };
620 assert_eq!(m.match_and_split(&MultiLocation { parents: 1, interior: Here }), None);
621 assert_eq!(
622 m.match_and_split(&MultiLocation { parents: 1, interior: X1(Parachain(42)) }),
623 Some(&AccountIndex64 { network: None, index: 23 })
624 );
625 assert_eq!(m.match_and_split(&m), None);
626 }
627
628 #[test]
629 fn append_with_works() {
630 let acc = AccountIndex64 { network: None, index: 23 };
631 let mut m = MultiLocation { parents: 1, interior: X1(Parachain(42)) };
632 assert_eq!(m.append_with(X2(PalletInstance(3), acc)), Ok(()));
633 assert_eq!(
634 m,
635 MultiLocation { parents: 1, interior: X3(Parachain(42), PalletInstance(3), acc) }
636 );
637
638 let acc = AccountIndex64 { network: None, index: 23 };
640 let m = MultiLocation {
641 parents: 254,
642 interior: X5(Parachain(42), OnlyChild, OnlyChild, OnlyChild, OnlyChild),
643 };
644 let suffix: MultiLocation = (PalletInstance(3), acc, OnlyChild, OnlyChild).into();
645 assert_eq!(m.clone().append_with(suffix), Err(suffix));
646 }
647
648 #[test]
649 fn prepend_with_works() {
650 let mut m = MultiLocation {
651 parents: 1,
652 interior: X2(Parachain(42), AccountIndex64 { network: None, index: 23 }),
653 };
654 assert_eq!(m.prepend_with(MultiLocation { parents: 1, interior: X1(OnlyChild) }), Ok(()));
655 assert_eq!(
656 m,
657 MultiLocation {
658 parents: 1,
659 interior: X2(Parachain(42), AccountIndex64 { network: None, index: 23 })
660 }
661 );
662
663 let mut m = MultiLocation { parents: 254, interior: X1(Parachain(42)) };
665 let prefix = MultiLocation { parents: 2, interior: Here };
666 assert_eq!(m.prepend_with(prefix), Err(prefix));
667
668 let prefix = MultiLocation { parents: 1, interior: Here };
669 assert_eq!(m.prepend_with(prefix), Ok(()));
670 assert_eq!(m, MultiLocation { parents: 255, interior: X1(Parachain(42)) });
671 }
672
673 #[test]
674 fn double_ended_ref_iteration_works() {
675 let m = X3(Parachain(1000), Parachain(3), PalletInstance(5));
676 let mut iter = m.iter();
677
678 let first = iter.next().unwrap();
679 assert_eq!(first, &Parachain(1000));
680 let third = iter.next_back().unwrap();
681 assert_eq!(third, &PalletInstance(5));
682 let second = iter.next_back().unwrap();
683 assert_eq!(iter.next(), None);
684 assert_eq!(iter.next_back(), None);
685 assert_eq!(second, &Parachain(3));
686
687 let res = Here
688 .pushed_with(*first)
689 .unwrap()
690 .pushed_with(*second)
691 .unwrap()
692 .pushed_with(*third)
693 .unwrap();
694 assert_eq!(m, res);
695
696 let m = Here;
698 let mut iter = m.iter();
699
700 assert_eq!(iter.next(), None);
701 assert_eq!(iter.next_back(), None);
702 }
703
704 #[test]
705 fn chain_location_works() {
706 let relay_to_local = MultiLocation::new(0, (PalletInstance(42), GeneralIndex(42)));
708 assert_eq!(relay_to_local.chain_location(), MultiLocation::here());
709
710 let relay_to_child =
712 MultiLocation::new(0, (Parachain(42), PalletInstance(42), GeneralIndex(42)));
713 let expected = MultiLocation::new(0, Parachain(42));
714 assert_eq!(relay_to_child.chain_location(), expected);
715
716 let relay_to_remote_relay =
718 MultiLocation::new(1, (GlobalConsensus(Kusama), PalletInstance(42), GeneralIndex(42)));
719 let expected = MultiLocation::new(1, GlobalConsensus(Kusama));
720 assert_eq!(relay_to_remote_relay.chain_location(), expected);
721
722 let relay_to_remote_para = MultiLocation::new(
724 1,
725 (GlobalConsensus(Kusama), Parachain(42), PalletInstance(42), GeneralIndex(42)),
726 );
727 let expected = MultiLocation::new(1, (GlobalConsensus(Kusama), Parachain(42)));
728 assert_eq!(relay_to_remote_para.chain_location(), expected);
729
730 let para_to_relay = MultiLocation::new(1, (PalletInstance(42), GeneralIndex(42)));
732 assert_eq!(para_to_relay.chain_location(), MultiLocation::parent());
733
734 let para_to_sibling =
736 MultiLocation::new(1, (Parachain(42), PalletInstance(42), GeneralIndex(42)));
737 let expected = MultiLocation::new(1, Parachain(42));
738 assert_eq!(para_to_sibling.chain_location(), expected);
739
740 let para_to_remote_relay =
742 MultiLocation::new(2, (GlobalConsensus(Kusama), PalletInstance(42), GeneralIndex(42)));
743 let expected = MultiLocation::new(2, GlobalConsensus(Kusama));
744 assert_eq!(para_to_remote_relay.chain_location(), expected);
745
746 let para_to_remote_para = MultiLocation::new(
748 2,
749 (GlobalConsensus(Kusama), Parachain(42), PalletInstance(42), GeneralIndex(42)),
750 );
751 let expected = MultiLocation::new(2, (GlobalConsensus(Kusama), Parachain(42)));
752 assert_eq!(para_to_remote_para.chain_location(), expected);
753 }
754}