1use super::Location;
20pub use crate::v3::{BodyId, BodyPart};
21use crate::{
22 v3::{Junction as OldJunction, NetworkId as OldNetworkId},
23 VersionedLocation,
24};
25use bounded_collections::{BoundedSlice, BoundedVec, ConstU32};
26use codec::{self, Decode, Encode, MaxEncodedLen};
27use scale_info::TypeInfo;
28use serde::{Deserialize, Serialize};
29
30#[derive(
34 Copy,
35 Clone,
36 Eq,
37 PartialEq,
38 Ord,
39 PartialOrd,
40 Encode,
41 Decode,
42 Debug,
43 TypeInfo,
44 MaxEncodedLen,
45 Serialize,
46 Deserialize,
47)]
48pub enum Junction {
49 Parachain(#[codec(compact)] u32),
53 AccountId32 { network: Option<NetworkId>, id: [u8; 32] },
58 AccountIndex64 {
63 network: Option<NetworkId>,
64 #[codec(compact)]
65 index: u64,
66 },
67 AccountKey20 { network: Option<NetworkId>, key: [u8; 20] },
72 PalletInstance(u8),
77 GeneralIndex(#[codec(compact)] u128),
83 GeneralKey { length: u8, data: [u8; 32] },
92 OnlyChild,
96 Plurality { id: BodyId, part: BodyPart },
101 GlobalConsensus(NetworkId),
104}
105
106#[derive(
111 Copy,
112 Clone,
113 Eq,
114 PartialEq,
115 Ord,
116 PartialOrd,
117 Encode,
118 Decode,
119 Debug,
120 TypeInfo,
121 MaxEncodedLen,
122 Serialize,
123 Deserialize,
124)]
125pub enum NetworkId {
126 ByGenesis([u8; 32]),
128 ByFork { block_number: u64, block_hash: [u8; 32] },
130 Polkadot,
132 Kusama,
134 Westend,
136 Rococo,
138 Wococo,
140 Ethereum {
142 #[codec(compact)]
144 chain_id: u64,
145 },
146 BitcoinCore,
148 BitcoinCash,
150 PolkadotBulletin,
152}
153
154impl From<OldNetworkId> for Option<NetworkId> {
155 fn from(old: OldNetworkId) -> Self {
156 Some(NetworkId::from(old))
157 }
158}
159
160impl From<OldNetworkId> for NetworkId {
161 fn from(old: OldNetworkId) -> Self {
162 use OldNetworkId::*;
163 match old {
164 ByGenesis(hash) => Self::ByGenesis(hash),
165 ByFork { block_number, block_hash } => Self::ByFork { block_number, block_hash },
166 Polkadot => Self::Polkadot,
167 Kusama => Self::Kusama,
168 Westend => Self::Westend,
169 Rococo => Self::Rococo,
170 Wococo => Self::Wococo,
171 Ethereum { chain_id } => Self::Ethereum { chain_id },
172 BitcoinCore => Self::BitcoinCore,
173 BitcoinCash => Self::BitcoinCash,
174 PolkadotBulletin => Self::PolkadotBulletin,
175 }
176 }
177}
178
179impl From<NetworkId> for Junction {
180 fn from(n: NetworkId) -> Self {
181 Self::GlobalConsensus(n)
182 }
183}
184
185impl From<[u8; 32]> for Junction {
186 fn from(id: [u8; 32]) -> Self {
187 Self::AccountId32 { network: None, id }
188 }
189}
190
191impl From<BoundedVec<u8, ConstU32<32>>> for Junction {
192 fn from(key: BoundedVec<u8, ConstU32<32>>) -> Self {
193 key.as_bounded_slice().into()
194 }
195}
196
197impl<'a> From<BoundedSlice<'a, u8, ConstU32<32>>> for Junction {
198 fn from(key: BoundedSlice<'a, u8, ConstU32<32>>) -> Self {
199 let mut data = [0u8; 32];
200 data[..key.len()].copy_from_slice(&key[..]);
201 Self::GeneralKey { length: key.len() as u8, data }
202 }
203}
204
205impl<'a> TryFrom<&'a Junction> for BoundedSlice<'a, u8, ConstU32<32>> {
206 type Error = ();
207 fn try_from(key: &'a Junction) -> Result<Self, ()> {
208 match key {
209 Junction::GeneralKey { length, data } =>
210 BoundedSlice::try_from(&data[..data.len().min(*length as usize)]).map_err(|_| ()),
211 _ => Err(()),
212 }
213 }
214}
215
216impl From<[u8; 20]> for Junction {
217 fn from(key: [u8; 20]) -> Self {
218 Self::AccountKey20 { network: None, key }
219 }
220}
221
222impl From<u64> for Junction {
223 fn from(index: u64) -> Self {
224 Self::AccountIndex64 { network: None, index }
225 }
226}
227
228impl From<u128> for Junction {
229 fn from(id: u128) -> Self {
230 Self::GeneralIndex(id)
231 }
232}
233
234impl TryFrom<OldJunction> for Junction {
235 type Error = ();
236 fn try_from(value: OldJunction) -> Result<Self, ()> {
237 use OldJunction::*;
238 Ok(match value {
239 Parachain(id) => Self::Parachain(id),
240 AccountId32 { network: maybe_network, id } =>
241 Self::AccountId32 { network: maybe_network.map(|network| network.into()), id },
242 AccountIndex64 { network: maybe_network, index } =>
243 Self::AccountIndex64 { network: maybe_network.map(|network| network.into()), index },
244 AccountKey20 { network: maybe_network, key } =>
245 Self::AccountKey20 { network: maybe_network.map(|network| network.into()), key },
246 PalletInstance(index) => Self::PalletInstance(index),
247 GeneralIndex(id) => Self::GeneralIndex(id),
248 GeneralKey { length, data } => Self::GeneralKey { length, data },
249 OnlyChild => Self::OnlyChild,
250 Plurality { id, part } => Self::Plurality { id, part },
251 GlobalConsensus(network) => Self::GlobalConsensus(network.into()),
252 })
253 }
254}
255
256impl Junction {
257 pub fn into_location(self) -> Location {
261 Location::new(0, [self])
262 }
263
264 pub fn into_exterior(self, n: u8) -> Location {
269 Location::new(n, [self])
270 }
271
272 pub fn into_versioned(self) -> VersionedLocation {
276 self.into_location().into_versioned()
277 }
278
279 pub fn remove_network_id(&mut self) {
281 use Junction::*;
282 match self {
283 AccountId32 { ref mut network, .. } |
284 AccountIndex64 { ref mut network, .. } |
285 AccountKey20 { ref mut network, .. } => *network = None,
286 _ => {},
287 }
288 }
289}
290
291#[cfg(test)]
292mod tests {
293 use super::*;
294 use alloc::vec;
295
296 #[test]
297 fn junction_round_trip_works() {
298 let j = Junction::GeneralKey { length: 32, data: [1u8; 32] };
299 let k = Junction::try_from(OldJunction::try_from(j).unwrap()).unwrap();
300 assert_eq!(j, k);
301
302 let j = OldJunction::GeneralKey { length: 32, data: [1u8; 32] };
303 let k = OldJunction::try_from(Junction::try_from(j).unwrap()).unwrap();
304 assert_eq!(j, k);
305
306 let j = Junction::from(BoundedVec::try_from(vec![1u8, 2, 3, 4]).unwrap());
307 let k = Junction::try_from(OldJunction::try_from(j).unwrap()).unwrap();
308 assert_eq!(j, k);
309 let s: BoundedSlice<_, _> = (&k).try_into().unwrap();
310 assert_eq!(s, &[1u8, 2, 3, 4][..]);
311
312 let j = OldJunction::GeneralKey { length: 32, data: [1u8; 32] };
313 let k = OldJunction::try_from(Junction::try_from(j).unwrap()).unwrap();
314 assert_eq!(j, k);
315 }
316}