From fe6fe32f498ad470521b2dc5188055f9a80619ab Mon Sep 17 00:00:00 2001 From: joepetrowski Date: Fri, 18 Nov 2022 13:50:29 +0100 Subject: [PATCH 1/3] add `starts_with` to v0 and v1 MultiLocation --- xcm/src/v0/multi_location.rs | 25 +++++++++++++++----- xcm/src/v1/multilocation.rs | 44 +++++++++++++++++++++++++++++++----- 2 files changed, 57 insertions(+), 12 deletions(-) diff --git a/xcm/src/v0/multi_location.rs b/xcm/src/v0/multi_location.rs index 0491e27d644f..443f497be478 100644 --- a/xcm/src/v0/multi_location.rs +++ b/xcm/src/v0/multi_location.rs @@ -356,17 +356,30 @@ impl MultiLocation { /// # } /// ``` pub fn match_and_split(&self, prefix: &MultiLocation) -> Option<&Junction> { - if prefix.len() + 1 != self.len() { + if prefix.len() + 1 != self.len() || !self.starts_with(prefix) { return None } - for i in 0..prefix.len() { - if prefix.at(i) != self.at(i) { - return None - } - } return self.at(prefix.len()) } + /// Returns whether `self` begins with or is equal to `prefix`. + /// + /// # Example + /// ```rust + /// # use xcm::v0::{Junction::*, MultiLocation::*}; + /// let m = X4(Parent, PalletInstance(3), OnlyChild, OnlyChild); + /// assert!(m.starts_with(&X2(Parent, PalletInstance(3)))); + /// assert!(m.starts_with(&m)); + /// assert!(!m.starts_with(&X2(Parent, GeneralIndex(99)))); + /// assert!(!m.starts_with(&X1(PalletInstance(3)))); + /// ``` + pub fn starts_with(&self, prefix: &MultiLocation) -> bool { + if self.len() < prefix.len() { + return false + } + prefix.iter().zip(self.iter()).all(|(l, r)| l == r) + } + /// Mutates `self`, suffixing it with `new`. Returns `Err` in case of overflow. pub fn push(&mut self, new: Junction) -> result::Result<(), ()> { let mut n = MultiLocation::Null; diff --git a/xcm/src/v1/multilocation.rs b/xcm/src/v1/multilocation.rs index 0c2b2da31698..026759ee199d 100644 --- a/xcm/src/v1/multilocation.rs +++ b/xcm/src/v1/multilocation.rs @@ -253,6 +253,24 @@ impl MultiLocation { self.interior.match_and_split(&prefix.interior) } + /// Returns whether `self` has the same number of parents as `prefix` and its junctions begins + /// with the junctions of `prefix`. + /// + /// # Example + /// ```rust + /// # use xcm::v1::{Junctions::*, Junction::*, MultiLocation}; + /// let m = MultiLocation::new(1, X3(PalletInstance(3), OnlyChild, OnlyChild)); + /// assert!(m.starts_with(&MultiLocation::new(1, X1(PalletInstance(3))))); + /// assert!(!m.starts_with(&MultiLocation::new(1, X1(GeneralIndex(99))))); + /// assert!(!m.starts_with(&MultiLocation::new(0, X1(PalletInstance(3))))); + /// ``` + pub fn starts_with(&self, prefix: &MultiLocation) -> bool { + if self.parents != prefix.parents { + return false + } + self.interior.starts_with(&prefix.interior) + } + /// Mutate `self` so that it is suffixed with `suffix`. /// /// Does not modify `self` and returns `Err` with `suffix` in case of overflow. @@ -801,15 +819,29 @@ impl Junctions { /// # } /// ``` pub fn match_and_split(&self, prefix: &Junctions) -> Option<&Junction> { - if prefix.len() + 1 != self.len() { + if prefix.len() + 1 != self.len() || !self.starts_with(prefix) { return None } - for i in 0..prefix.len() { - if prefix.at(i) != self.at(i) { - return None - } + self.at(prefix.len()) + } + + /// Returns whether `self` begins with or is equal to `prefix`. + /// + /// # Example + /// ```rust + /// # use xcm::v1::{Junctions::*, Junction::*}; + /// let mut j = X3(Parachain(2), PalletInstance(3), OnlyChild); + /// assert!(j.starts_with(&X2(Parachain(2), PalletInstance(3)))); + /// assert!(j.starts_with(&j)); + /// assert!(j.starts_with(&X1(Parachain(2)))); + /// assert!(!j.starts_with(&X1(Parachain(999)))); + /// assert!(!j.starts_with(&X4(Parachain(2), PalletInstance(3), OnlyChild, OnlyChild))); + /// ``` + pub fn starts_with(&self, prefix: &Junctions) -> bool { + if self.len() < prefix.len() { + return false } - return self.at(prefix.len()) + prefix.iter().zip(self.iter()).all(|(l, r)| l == r) } } From 4ce52fe438f94c7d879988e2be1903d649a11c7c Mon Sep 17 00:00:00 2001 From: joepetrowski Date: Sat, 19 Nov 2022 10:27:25 +0100 Subject: [PATCH 2/3] add tests --- xcm/src/v0/multi_location.rs | 18 ++++++++++++++++++ xcm/src/v1/multilocation.rs | 18 ++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/xcm/src/v0/multi_location.rs b/xcm/src/v0/multi_location.rs index 443f497be478..1bf49ad841a6 100644 --- a/xcm/src/v0/multi_location.rs +++ b/xcm/src/v0/multi_location.rs @@ -614,6 +614,24 @@ mod tests { assert_eq!(m.match_and_split(&m), None); } + #[test] + fn starts_with_works() { + let full = X3(Parent, Parachain(1000), AccountIndex64 { network: Any, index: 23 }); + let identity = full.clone(); + let prefix = X2(Parent, Parachain(1000)); + let wrong_parachain = X2(Parent, Parachain(1001)); + let wrong_account = X3(Parent, Parachain(1000), AccountIndex64 { network: Any, index: 24 }); + let no_parents = X1(Parachain(1000)); + let too_many_parents = X3(Parent, Parent, Parachain(1000)); + + assert!(full.starts_with(&identity)); + assert!(full.starts_with(&prefix)); + assert!(!full.starts_with(&wrong_parachain)); + assert!(!full.starts_with(&wrong_account)); + assert!(!full.starts_with(&no_parents)); + assert!(!full.starts_with(&too_many_parents)); + } + #[test] fn append_with_works() { let acc = AccountIndex64 { network: Any, index: 23 }; diff --git a/xcm/src/v1/multilocation.rs b/xcm/src/v1/multilocation.rs index 026759ee199d..ab56e727a97d 100644 --- a/xcm/src/v1/multilocation.rs +++ b/xcm/src/v1/multilocation.rs @@ -961,6 +961,24 @@ mod tests { assert_eq!(m.match_and_split(&m), None); } + #[test] + fn starts_with_works() { + let full: MultiLocation = (Parent, Parachain(1000), AccountId32 { network: Any, id: [0; 32] }).into(); + let identity: MultiLocation = full.clone(); + let prefix: MultiLocation = (Parent, Parachain(1000)).into(); + let wrong_parachain: MultiLocation = (Parent, Parachain(1001)).into(); + let wrong_account: MultiLocation = (Parent, Parachain(1000), AccountId32 { network: Any, id: [1; 32] }).into(); + let no_parents: MultiLocation = (Parachain(1000)).into(); + let too_many_parents: MultiLocation = (Parent, Parent, Parachain(1000)).into(); + + assert!(full.starts_with(&identity)); + assert!(full.starts_with(&prefix)); + assert!(!full.starts_with(&wrong_parachain)); + assert!(!full.starts_with(&wrong_account)); + assert!(!full.starts_with(&no_parents)); + assert!(!full.starts_with(&too_many_parents)); + } + #[test] fn append_with_works() { let acc = AccountIndex64 { network: Any, index: 23 }; From 99459db09fd235e52013b372a337fc67967402d7 Mon Sep 17 00:00:00 2001 From: joepetrowski Date: Sat, 19 Nov 2022 10:28:29 +0100 Subject: [PATCH 3/3] fmt --- xcm/src/v1/multilocation.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/xcm/src/v1/multilocation.rs b/xcm/src/v1/multilocation.rs index ab56e727a97d..83cf0095c3b8 100644 --- a/xcm/src/v1/multilocation.rs +++ b/xcm/src/v1/multilocation.rs @@ -963,11 +963,13 @@ mod tests { #[test] fn starts_with_works() { - let full: MultiLocation = (Parent, Parachain(1000), AccountId32 { network: Any, id: [0; 32] }).into(); + let full: MultiLocation = + (Parent, Parachain(1000), AccountId32 { network: Any, id: [0; 32] }).into(); let identity: MultiLocation = full.clone(); let prefix: MultiLocation = (Parent, Parachain(1000)).into(); let wrong_parachain: MultiLocation = (Parent, Parachain(1001)).into(); - let wrong_account: MultiLocation = (Parent, Parachain(1000), AccountId32 { network: Any, id: [1; 32] }).into(); + let wrong_account: MultiLocation = + (Parent, Parachain(1000), AccountId32 { network: Any, id: [1; 32] }).into(); let no_parents: MultiLocation = (Parachain(1000)).into(); let too_many_parents: MultiLocation = (Parent, Parent, Parachain(1000)).into();