From 520ea8d21b71adde06fd20e22056c602d42242ba Mon Sep 17 00:00:00 2001 From: Gav Date: Tue, 14 Feb 2023 12:09:49 +0000 Subject: [PATCH 1/3] v3::Junction supports small (32-byte max) "vecs". --- xcm/src/v2/junction.rs | 6 +++--- xcm/src/v3/junction.rs | 43 +++++++++++++++++++++++++++++++++++++++--- 2 files changed, 43 insertions(+), 6 deletions(-) diff --git a/xcm/src/v2/junction.rs b/xcm/src/v2/junction.rs index 0ed629ccf219..87fe6d8ff20e 100644 --- a/xcm/src/v2/junction.rs +++ b/xcm/src/v2/junction.rs @@ -92,11 +92,11 @@ impl TryFrom for Junction { Self::AccountKey20 { network: network.try_into()?, key }, PalletInstance(index) => Self::PalletInstance(index), GeneralIndex(id) => Self::GeneralIndex(id), - GeneralKey(key) => Self::GeneralKey( - key[..] + GeneralKey { length, data } => Self::GeneralKey( + data[0..data.len().min(length as usize)] .to_vec() .try_into() - .expect("array is of size 32 and so will never be out of bounds; qed"), + .expect("key is bounded to 32 and so will never be out of bounds; qed"), ), OnlyChild => Self::OnlyChild, Plurality { id, part } => Self::Plurality { id: id.into(), part: part.into() }, diff --git a/xcm/src/v3/junction.rs b/xcm/src/v3/junction.rs index 7c1050624477..08ed72e6a495 100644 --- a/xcm/src/v3/junction.rs +++ b/xcm/src/v3/junction.rs @@ -25,6 +25,7 @@ use crate::{ VersionedMultiLocation, }; use core::convert::{TryFrom, TryInto}; +use bounded_collections::{BoundedVec, ConstU32, BoundedSlice}; use parity_scale_codec::{self, Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; @@ -237,12 +238,15 @@ pub enum Junction { /// /// NOTE: Try to avoid using this and instead use a more specific item. GeneralIndex(#[codec(compact)] u128), - /// A nondescript 128-byte datum acting as a key within the context location. + /// A nondescript array datum, 32 bytes, acting as a key within the context + /// location. /// /// Usage will vary widely owing to its generality. /// /// NOTE: Try to avoid using this and instead use a more specific item. - GeneralKey([u8; 32]), + // Note this is implemented as an array with a length rather than using `BoundedVec` owing to + // the bound for `Copy`. + GeneralKey { length: u8, data: [u8; 32] }, /// The unambiguous child. /// /// Not currently used except as a fallback when deriving context. @@ -269,6 +273,32 @@ impl From<[u8; 32]> for Junction { } } +impl From>> for Junction { + fn from(key: BoundedVec>) -> Self { + key.as_bounded_slice().into() + } +} + +impl<'a> From>> for Junction { + fn from(key: BoundedSlice<'a, u8, ConstU32<32>>) -> Self { + let mut data = [0u8; 32]; + data[..key.len()].copy_from_slice(&key[..]); + Self::GeneralKey { length: key.len() as u8, data } + } +} + +impl<'a> TryFrom<&'a Junction> for BoundedSlice<'a, u8, ConstU32<32>> { + type Error = (); + fn try_from(key: &'a Junction) -> Result { + match key { + Junction::GeneralKey { length, data } => { + BoundedSlice::try_from(&data[..data.len().min(*length as usize)]).map_err(|_| ()) + } + _ => Err(()), + } + } +} + impl From<[u8; 20]> for Junction { fn from(key: [u8; 20]) -> Self { Self::AccountKey20 { network: None, key } @@ -299,7 +329,14 @@ impl TryFrom for Junction { AccountKey20 { network, key } => Self::AccountKey20 { network: network.into(), key }, PalletInstance(index) => Self::PalletInstance(index), GeneralIndex(id) => Self::GeneralIndex(id), - GeneralKey(_key) => return Err(()), + GeneralKey(key) => match key.len() { + len @ 0..=32 => Self::GeneralKey { length: len as u8, data: { + let mut data = [0u8; 32]; + data[..len].copy_from_slice(&key[..]); + data + } }, + _ => return Err(()), + }, OnlyChild => Self::OnlyChild, Plurality { id, part } => Self::Plurality { id: id.try_into()?, part: part.try_into()? }, From c35e949c4acf3c09320374697cbce63b7468f51e Mon Sep 17 00:00:00 2001 From: Gav Date: Tue, 14 Feb 2023 12:12:28 +0000 Subject: [PATCH 2/3] Formatting --- xcm/src/v3/junction.rs | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/xcm/src/v3/junction.rs b/xcm/src/v3/junction.rs index 08ed72e6a495..ecb26cdcf9fa 100644 --- a/xcm/src/v3/junction.rs +++ b/xcm/src/v3/junction.rs @@ -24,8 +24,8 @@ use crate::{ }, VersionedMultiLocation, }; +use bounded_collections::{BoundedSlice, BoundedVec, ConstU32}; use core::convert::{TryFrom, TryInto}; -use bounded_collections::{BoundedVec, ConstU32, BoundedSlice}; use parity_scale_codec::{self, Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; @@ -291,9 +291,8 @@ impl<'a> TryFrom<&'a Junction> for BoundedSlice<'a, u8, ConstU32<32>> { type Error = (); fn try_from(key: &'a Junction) -> Result { match key { - Junction::GeneralKey { length, data } => { - BoundedSlice::try_from(&data[..data.len().min(*length as usize)]).map_err(|_| ()) - } + Junction::GeneralKey { length, data } => + BoundedSlice::try_from(&data[..data.len().min(*length as usize)]).map_err(|_| ()), _ => Err(()), } } @@ -330,11 +329,14 @@ impl TryFrom for Junction { PalletInstance(index) => Self::PalletInstance(index), GeneralIndex(id) => Self::GeneralIndex(id), GeneralKey(key) => match key.len() { - len @ 0..=32 => Self::GeneralKey { length: len as u8, data: { - let mut data = [0u8; 32]; - data[..len].copy_from_slice(&key[..]); - data - } }, + len @ 0..=32 => Self::GeneralKey { + length: len as u8, + data: { + let mut data = [0u8; 32]; + data[..len].copy_from_slice(&key[..]); + data + }, + }, _ => return Err(()), }, OnlyChild => Self::OnlyChild, From e8d530cdaaa3161a56d7e68556103905e748137d Mon Sep 17 00:00:00 2001 From: Gav Date: Tue, 14 Feb 2023 12:29:06 +0000 Subject: [PATCH 3/3] Add test --- xcm/src/v3/junction.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/xcm/src/v3/junction.rs b/xcm/src/v3/junction.rs index ecb26cdcf9fa..57877f95450c 100644 --- a/xcm/src/v3/junction.rs +++ b/xcm/src/v3/junction.rs @@ -379,3 +379,30 @@ impl Junction { } } } + +#[cfg(test)] +mod tests { + use super::*; + use alloc::vec; + + #[test] + fn junction_round_trip_works() { + let j = Junction::GeneralKey { length: 32, data: [1u8; 32] }; + let k = Junction::try_from(OldJunction::try_from(j).unwrap()).unwrap(); + assert_eq!(j, k); + + let j = OldJunction::GeneralKey(vec![1u8; 32].try_into().unwrap()); + let k = OldJunction::try_from(Junction::try_from(j.clone()).unwrap()).unwrap(); + assert_eq!(j, k); + + let j = Junction::from(BoundedVec::try_from(vec![1u8, 2, 3, 4]).unwrap()); + let k = Junction::try_from(OldJunction::try_from(j).unwrap()).unwrap(); + assert_eq!(j, k); + let s: BoundedSlice<_, _> = (&k).try_into().unwrap(); + assert_eq!(s, &[1u8, 2, 3, 4][..]); + + let j = OldJunction::GeneralKey(vec![1u8, 2, 3, 4].try_into().unwrap()); + let k = OldJunction::try_from(Junction::try_from(j.clone()).unwrap()).unwrap(); + assert_eq!(j, k); + } +}