1use super::Location;
20pub use crate::v3::{BodyId, BodyPart};
21use crate::{
22 v3::{Junction as OldJunction, NetworkId as OldNetworkId},
23 v5::{Junction as NewJunction, NetworkId as NewNetworkId},
24 VersionedLocation,
25};
26use bounded_collections::{BoundedSlice, BoundedVec, ConstU32};
27use codec::{self, Decode, DecodeWithMemTracking, Encode, MaxEncodedLen};
28use scale_info::TypeInfo;
29use serde::{Deserialize, Serialize};
30
31#[derive(
35 Copy,
36 Clone,
37 Eq,
38 PartialEq,
39 Ord,
40 PartialOrd,
41 Encode,
42 Decode,
43 DecodeWithMemTracking,
44 Debug,
45 TypeInfo,
46 MaxEncodedLen,
47 Serialize,
48 Deserialize,
49)]
50pub enum Junction {
51 Parachain(#[codec(compact)] u32),
55 AccountId32 { network: Option<NetworkId>, id: [u8; 32] },
60 AccountIndex64 {
65 network: Option<NetworkId>,
66 #[codec(compact)]
67 index: u64,
68 },
69 AccountKey20 { network: Option<NetworkId>, key: [u8; 20] },
74 PalletInstance(u8),
78 GeneralIndex(#[codec(compact)] u128),
84 GeneralKey { length: u8, data: [u8; 32] },
93 OnlyChild,
97 Plurality { id: BodyId, part: BodyPart },
102 GlobalConsensus(NetworkId),
105}
106
107impl From<NewNetworkId> for Option<NetworkId> {
108 fn from(new: NewNetworkId) -> Self {
109 Some(NetworkId::from(new))
110 }
111}
112
113impl From<NewNetworkId> for NetworkId {
114 fn from(new: NewNetworkId) -> Self {
115 use NewNetworkId::*;
116 match new {
117 ByGenesis(hash) => Self::ByGenesis(hash),
118 ByFork { block_number, block_hash } => Self::ByFork { block_number, block_hash },
119 Polkadot => Self::Polkadot,
120 Kusama => Self::Kusama,
121 Ethereum { chain_id } => Self::Ethereum { chain_id },
122 BitcoinCore => Self::BitcoinCore,
123 BitcoinCash => Self::BitcoinCash,
124 PolkadotBulletin => Self::PolkadotBulletin,
125 }
126 }
127}
128
129#[derive(
134 Copy,
135 Clone,
136 Eq,
137 PartialEq,
138 Ord,
139 PartialOrd,
140 Encode,
141 Decode,
142 DecodeWithMemTracking,
143 Debug,
144 TypeInfo,
145 MaxEncodedLen,
146 Serialize,
147 Deserialize,
148)]
149pub enum NetworkId {
150 ByGenesis([u8; 32]),
152 ByFork { block_number: u64, block_hash: [u8; 32] },
154 Polkadot,
156 Kusama,
158 Westend,
160 Rococo,
162 Wococo,
164 Ethereum {
166 #[codec(compact)]
168 chain_id: u64,
169 },
170 BitcoinCore,
172 BitcoinCash,
174 PolkadotBulletin,
176}
177
178impl From<OldNetworkId> for Option<NetworkId> {
179 fn from(old: OldNetworkId) -> Self {
180 Some(NetworkId::from(old))
181 }
182}
183
184impl From<OldNetworkId> for NetworkId {
185 fn from(old: OldNetworkId) -> Self {
186 use OldNetworkId::*;
187 match old {
188 ByGenesis(hash) => Self::ByGenesis(hash),
189 ByFork { block_number, block_hash } => Self::ByFork { block_number, block_hash },
190 Polkadot => Self::Polkadot,
191 Kusama => Self::Kusama,
192 Westend => Self::Westend,
193 Rococo => Self::Rococo,
194 Wococo => Self::Wococo,
195 Ethereum { chain_id } => Self::Ethereum { chain_id },
196 BitcoinCore => Self::BitcoinCore,
197 BitcoinCash => Self::BitcoinCash,
198 PolkadotBulletin => Self::PolkadotBulletin,
199 }
200 }
201}
202
203impl From<NetworkId> for Junction {
204 fn from(n: NetworkId) -> Self {
205 Self::GlobalConsensus(n)
206 }
207}
208
209impl From<[u8; 32]> for Junction {
210 fn from(id: [u8; 32]) -> Self {
211 Self::AccountId32 { network: None, id }
212 }
213}
214
215impl From<BoundedVec<u8, ConstU32<32>>> for Junction {
216 fn from(key: BoundedVec<u8, ConstU32<32>>) -> Self {
217 key.as_bounded_slice().into()
218 }
219}
220
221impl<'a> From<BoundedSlice<'a, u8, ConstU32<32>>> for Junction {
222 fn from(key: BoundedSlice<'a, u8, ConstU32<32>>) -> Self {
223 let mut data = [0u8; 32];
224 data[..key.len()].copy_from_slice(&key[..]);
225 Self::GeneralKey { length: key.len() as u8, data }
226 }
227}
228
229impl<'a> TryFrom<&'a Junction> for BoundedSlice<'a, u8, ConstU32<32>> {
230 type Error = ();
231 fn try_from(key: &'a Junction) -> Result<Self, ()> {
232 match key {
233 Junction::GeneralKey { length, data } =>
234 BoundedSlice::try_from(&data[..data.len().min(*length as usize)]).map_err(|_| ()),
235 _ => Err(()),
236 }
237 }
238}
239
240impl From<[u8; 20]> for Junction {
241 fn from(key: [u8; 20]) -> Self {
242 Self::AccountKey20 { network: None, key }
243 }
244}
245
246impl From<u64> for Junction {
247 fn from(index: u64) -> Self {
248 Self::AccountIndex64 { network: None, index }
249 }
250}
251
252impl From<u128> for Junction {
253 fn from(id: u128) -> Self {
254 Self::GeneralIndex(id)
255 }
256}
257
258impl TryFrom<OldJunction> for Junction {
259 type Error = ();
260 fn try_from(value: OldJunction) -> Result<Self, ()> {
261 use OldJunction::*;
262 Ok(match value {
263 Parachain(id) => Self::Parachain(id),
264 AccountId32 { network: maybe_network, id } =>
265 Self::AccountId32 { network: maybe_network.map(|network| network.into()), id },
266 AccountIndex64 { network: maybe_network, index } =>
267 Self::AccountIndex64 { network: maybe_network.map(|network| network.into()), index },
268 AccountKey20 { network: maybe_network, key } =>
269 Self::AccountKey20 { network: maybe_network.map(|network| network.into()), key },
270 PalletInstance(index) => Self::PalletInstance(index),
271 GeneralIndex(id) => Self::GeneralIndex(id),
272 GeneralKey { length, data } => Self::GeneralKey { length, data },
273 OnlyChild => Self::OnlyChild,
274 Plurality { id, part } => Self::Plurality { id, part },
275 GlobalConsensus(network) => Self::GlobalConsensus(network.into()),
276 })
277 }
278}
279
280impl TryFrom<NewJunction> for Junction {
281 type Error = ();
282
283 fn try_from(value: NewJunction) -> Result<Self, Self::Error> {
284 use NewJunction::*;
285 Ok(match value {
286 Parachain(id) => Self::Parachain(id),
287 AccountId32 { network: maybe_network, id } =>
288 Self::AccountId32 { network: maybe_network.map(|network| network.into()), id },
289 AccountIndex64 { network: maybe_network, index } =>
290 Self::AccountIndex64 { network: maybe_network.map(|network| network.into()), index },
291 AccountKey20 { network: maybe_network, key } =>
292 Self::AccountKey20 { network: maybe_network.map(|network| network.into()), key },
293 PalletInstance(index) => Self::PalletInstance(index),
294 GeneralIndex(id) => Self::GeneralIndex(id),
295 GeneralKey { length, data } => Self::GeneralKey { length, data },
296 OnlyChild => Self::OnlyChild,
297 Plurality { id, part } => Self::Plurality { id, part },
298 GlobalConsensus(network) => Self::GlobalConsensus(network.into()),
299 })
300 }
301}
302
303impl Junction {
304 pub fn into_location(self) -> Location {
308 Location::new(0, [self])
309 }
310
311 pub fn into_exterior(self, n: u8) -> Location {
316 Location::new(n, [self])
317 }
318
319 pub fn into_versioned(self) -> VersionedLocation {
323 self.into_location().into_versioned()
324 }
325
326 pub fn remove_network_id(&mut self) {
328 use Junction::*;
329 match self {
330 AccountId32 { ref mut network, .. } |
331 AccountIndex64 { ref mut network, .. } |
332 AccountKey20 { ref mut network, .. } => *network = None,
333 _ => {},
334 }
335 }
336}
337
338#[cfg(test)]
339mod tests {
340 use super::*;
341 use alloc::vec;
342
343 #[test]
344 fn junction_round_trip_works() {
345 let j = Junction::GeneralKey { length: 32, data: [1u8; 32] };
346 let k = Junction::try_from(OldJunction::try_from(j).unwrap()).unwrap();
347 assert_eq!(j, k);
348
349 let j = OldJunction::GeneralKey { length: 32, data: [1u8; 32] };
350 let k = OldJunction::try_from(Junction::try_from(j).unwrap()).unwrap();
351 assert_eq!(j, k);
352
353 let j = Junction::from(BoundedVec::try_from(vec![1u8, 2, 3, 4]).unwrap());
354 let k = Junction::try_from(OldJunction::try_from(j).unwrap()).unwrap();
355 assert_eq!(j, k);
356 let s: BoundedSlice<_, _> = (&k).try_into().unwrap();
357 assert_eq!(s, &[1u8, 2, 3, 4][..]);
358
359 let j = OldJunction::GeneralKey { length: 32, data: [1u8; 32] };
360 let k = OldJunction::try_from(Junction::try_from(j).unwrap()).unwrap();
361 assert_eq!(j, k);
362 }
363}