1
// Copyright (C) Parity Technologies (UK) Ltd.
2
// This file is part of Polkadot.
3

            
4
// Polkadot is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8

            
9
// Polkadot is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13

            
14
// You should have received a copy of the GNU General Public License
15
// along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.
16

            
17
//! XCM `Location` datatype.
18

            
19
use super::{traits::Reanchorable, Junction, Junctions};
20
use crate::{v3::MultiLocation as OldLocation, VersionedLocation};
21
use codec::{Decode, Encode, MaxEncodedLen};
22
use core::result;
23
use scale_info::TypeInfo;
24

            
25
/// A relative path between state-bearing consensus systems.
26
///
27
/// A location in a consensus system is defined as an *isolatable state machine* held within global
28
/// consensus. The location in question need not have a sophisticated consensus algorithm of its
29
/// own; a single account within Ethereum, for example, could be considered a location.
30
///
31
/// A very-much non-exhaustive list of types of location include:
32
/// - A (normal, layer-1) block chain, e.g. the Bitcoin mainnet or a parachain.
33
/// - A layer-0 super-chain, e.g. the Polkadot Relay chain.
34
/// - A layer-2 smart contract, e.g. an ERC-20 on Ethereum.
35
/// - A logical functional component of a chain, e.g. a single instance of a pallet on a Frame-based
36
///   Substrate chain.
37
/// - An account.
38
///
39
/// A `Location` is a *relative identifier*, meaning that it can only be used to define the
40
/// relative path between two locations, and cannot generally be used to refer to a location
41
/// universally. It is comprised of an integer number of parents specifying the number of times to
42
/// "escape" upwards into the containing consensus system and then a number of *junctions*, each
43
/// diving down and specifying some interior portion of state (which may be considered a
44
/// "sub-consensus" system).
45
///
46
/// This specific `Location` implementation uses a `Junctions` datatype which is a Rust `enum`
47
/// in order to make pattern matching easier. There are occasions where it is important to ensure
48
/// that a value is strictly an interior location, in those cases, `Junctions` may be used.
49
///
50
/// The `Location` value of `Null` simply refers to the interpreting consensus system.
51
#[derive(
52
	Clone,
53
	Decode,
54
	Encode,
55
	Eq,
56
	PartialEq,
57
	Ord,
58
	PartialOrd,
59
	Debug,
60
	TypeInfo,
61
	MaxEncodedLen,
62
	serde::Serialize,
63
	serde::Deserialize,
64
)]
65
pub struct Location {
66
	/// The number of parent junctions at the beginning of this `Location`.
67
	pub parents: u8,
68
	/// The interior (i.e. non-parent) junctions that this `Location` contains.
69
	pub interior: Junctions,
70
}
71

            
72
impl Default for Location {
73
1880
	fn default() -> Self {
74
1880
		Self { parents: 0, interior: Junctions::Here }
75
1880
	}
76
}
77

            
78
/// A relative location which is constrained to be an interior location of the context.
79
///
80
/// See also `Location`.
81
pub type InteriorLocation = Junctions;
82

            
83
impl Location {
84
	/// Creates a new `Location` with the given number of parents and interior junctions.
85
2502
	pub fn new(parents: u8, interior: impl Into<Junctions>) -> Location {
86
2502
		Location { parents, interior: interior.into() }
87
2502
	}
88

            
89
	/// Consume `self` and return the equivalent `VersionedLocation` value.
90
	pub const fn into_versioned(self) -> VersionedLocation {
91
		VersionedLocation::V4(self)
92
	}
93

            
94
	/// Creates a new `Location` with 0 parents and a `Here` interior.
95
	///
96
	/// The resulting `Location` can be interpreted as the "current consensus system".
97
2320
	pub const fn here() -> Location {
98
2320
		Location { parents: 0, interior: Junctions::Here }
99
2320
	}
100

            
101
	/// Creates a new `Location` which evaluates to the parent context.
102
	pub const fn parent() -> Location {
103
		Location { parents: 1, interior: Junctions::Here }
104
	}
105

            
106
	/// Creates a new `Location` with `parents` and an empty (`Here`) interior.
107
	pub const fn ancestor(parents: u8) -> Location {
108
		Location { parents, interior: Junctions::Here }
109
	}
110

            
111
	/// Whether the `Location` has no parents and has a `Here` interior.
112
	pub fn is_here(&self) -> bool {
113
		self.parents == 0 && self.interior.len() == 0
114
	}
115

            
116
	/// Remove the `NetworkId` value in any interior `Junction`s.
117
	pub fn remove_network_id(&mut self) {
118
		self.interior.remove_network_id();
119
	}
120

            
121
	/// Return a reference to the interior field.
122
9712
	pub fn interior(&self) -> &Junctions {
123
9712
		&self.interior
124
9712
	}
125

            
126
	/// Return a mutable reference to the interior field.
127
	pub fn interior_mut(&mut self) -> &mut Junctions {
128
		&mut self.interior
129
	}
130

            
131
	/// Returns the number of `Parent` junctions at the beginning of `self`.
132
7068
	pub const fn parent_count(&self) -> u8 {
133
7068
		self.parents
134
7068
	}
135

            
136
	/// Returns the parent count and the interior [`Junctions`] as a tuple.
137
	///
138
	/// To be used when pattern matching, for example:
139
	///
140
	/// ```rust
141
	/// # use staging_xcm::v4::{Junctions::*, Junction::*, Location};
142
	/// fn get_parachain_id(loc: &Location) -> Option<u32> {
143
	///     match loc.unpack() {
144
	///         (0, [Parachain(id)]) => Some(*id),
145
	///         _ => None
146
	///     }
147
	/// }
148
	/// ```
149
10108
	pub fn unpack(&self) -> (u8, &[Junction]) {
150
10108
		(self.parents, self.interior.as_slice())
151
10108
	}
152

            
153
	/// Returns boolean indicating whether `self` contains only the specified amount of
154
	/// parents and no interior junctions.
155
	pub const fn contains_parents_only(&self, count: u8) -> bool {
156
		matches!(self.interior, Junctions::Here) && self.parents == count
157
	}
158

            
159
	/// Returns the number of parents and junctions in `self`.
160
	pub fn len(&self) -> usize {
161
		self.parent_count() as usize + self.interior.len()
162
	}
163

            
164
	/// Returns the first interior junction, or `None` if the location is empty or contains only
165
	/// parents.
166
150
	pub fn first_interior(&self) -> Option<&Junction> {
167
150
		self.interior.first()
168
150
	}
169

            
170
	/// Returns last junction, or `None` if the location is empty or contains only parents.
171
184
	pub fn last(&self) -> Option<&Junction> {
172
184
		self.interior.last()
173
184
	}
174

            
175
	/// Splits off the first interior junction, returning the remaining suffix (first item in tuple)
176
	/// and the first element (second item in tuple) or `None` if it was empty.
177
18
	pub fn split_first_interior(self) -> (Location, Option<Junction>) {
178
18
		let Location { parents, interior: junctions } = self;
179
18
		let (suffix, first) = junctions.split_first();
180
18
		let location = Location { parents, interior: suffix };
181
18
		(location, first)
182
18
	}
183

            
184
	/// Splits off the last interior junction, returning the remaining prefix (first item in tuple)
185
	/// and the last element (second item in tuple) or `None` if it was empty or if `self` only
186
	/// contains parents.
187
80
	pub fn split_last_interior(self) -> (Location, Option<Junction>) {
188
80
		let Location { parents, interior: junctions } = self;
189
80
		let (prefix, last) = junctions.split_last();
190
80
		let location = Location { parents, interior: prefix };
191
80
		(location, last)
192
80
	}
193

            
194
	/// Mutates `self`, suffixing its interior junctions with `new`. Returns `Err` with `new` in
195
	/// case of overflow.
196
	pub fn push_interior(&mut self, new: impl Into<Junction>) -> result::Result<(), Junction> {
197
		self.interior.push(new)
198
	}
199

            
200
	/// Mutates `self`, prefixing its interior junctions with `new`. Returns `Err` with `new` in
201
	/// case of overflow.
202
1080
	pub fn push_front_interior(
203
1080
		&mut self,
204
1080
		new: impl Into<Junction>,
205
1080
	) -> result::Result<(), Junction> {
206
1080
		self.interior.push_front(new)
207
1080
	}
208

            
209
	/// Consumes `self` and returns a `Location` suffixed with `new`, or an `Err` with
210
	/// the original value of `self` in case of overflow.
211
	pub fn pushed_with_interior(
212
		self,
213
		new: impl Into<Junction>,
214
	) -> result::Result<Self, (Self, Junction)> {
215
		match self.interior.pushed_with(new) {
216
			Ok(i) => Ok(Location { interior: i, parents: self.parents }),
217
			Err((i, j)) => Err((Location { interior: i, parents: self.parents }, j)),
218
		}
219
	}
220

            
221
	/// Consumes `self` and returns a `Location` prefixed with `new`, or an `Err` with the
222
	/// original value of `self` in case of overflow.
223
	pub fn pushed_front_with_interior(
224
		self,
225
		new: impl Into<Junction>,
226
	) -> result::Result<Self, (Self, Junction)> {
227
		match self.interior.pushed_front_with(new) {
228
			Ok(i) => Ok(Location { interior: i, parents: self.parents }),
229
			Err((i, j)) => Err((Location { interior: i, parents: self.parents }, j)),
230
		}
231
	}
232

            
233
	/// Returns the junction at index `i`, or `None` if the location is a parent or if the location
234
	/// does not contain that many elements.
235
	pub fn at(&self, i: usize) -> Option<&Junction> {
236
		let num_parents = self.parents as usize;
237
		if i < num_parents {
238
			return None
239
		}
240
		self.interior.at(i - num_parents)
241
	}
242

            
243
	/// Returns a mutable reference to the junction at index `i`, or `None` if the location is a
244
	/// parent or if it doesn't contain that many elements.
245
	pub fn at_mut(&mut self, i: usize) -> Option<&mut Junction> {
246
		let num_parents = self.parents as usize;
247
		if i < num_parents {
248
			return None
249
		}
250
		self.interior.at_mut(i - num_parents)
251
	}
252

            
253
	/// Decrements the parent count by 1.
254
284
	pub fn dec_parent(&mut self) {
255
284
		self.parents = self.parents.saturating_sub(1);
256
284
	}
257

            
258
	/// Removes the first interior junction from `self`, returning it
259
	/// (or `None` if it was empty or if `self` contains only parents).
260
	pub fn take_first_interior(&mut self) -> Option<Junction> {
261
		self.interior.take_first()
262
	}
263

            
264
	/// Removes the last element from `interior`, returning it (or `None` if it was empty or if
265
	/// `self` only contains parents).
266
396
	pub fn take_last(&mut self) -> Option<Junction> {
267
396
		self.interior.take_last()
268
396
	}
269

            
270
	/// Ensures that `self` has the same number of parents as `prefix`, its junctions begins with
271
	/// the junctions of `prefix` and that it has a single `Junction` item following.
272
	/// If so, returns a reference to this `Junction` item.
273
	///
274
	/// # Example
275
	/// ```rust
276
	/// # use staging_xcm::v4::{Junctions::*, Junction::*, Location};
277
	/// # fn main() {
278
	/// let mut m = Location::new(1, [PalletInstance(3), OnlyChild]);
279
	/// assert_eq!(
280
	///     m.match_and_split(&Location::new(1, [PalletInstance(3)])),
281
	///     Some(&OnlyChild),
282
	/// );
283
	/// assert_eq!(m.match_and_split(&Location::new(1, Here)), None);
284
	/// # }
285
	/// ```
286
	pub fn match_and_split(&self, prefix: &Location) -> Option<&Junction> {
287
		if self.parents != prefix.parents {
288
			return None
289
		}
290
		self.interior.match_and_split(&prefix.interior)
291
	}
292

            
293
	pub fn starts_with(&self, prefix: &Location) -> bool {
294
		self.parents == prefix.parents && self.interior.starts_with(&prefix.interior)
295
	}
296

            
297
	/// Mutate `self` so that it is suffixed with `suffix`.
298
	///
299
	/// Does not modify `self` and returns `Err` with `suffix` in case of overflow.
300
	///
301
	/// # Example
302
	/// ```rust
303
	/// # use staging_xcm::v4::{Junctions::*, Junction::*, Location, Parent};
304
	/// # fn main() {
305
	/// let mut m: Location = (Parent, Parachain(21), 69u64).into();
306
	/// assert_eq!(m.append_with((Parent, PalletInstance(3))), Ok(()));
307
	/// assert_eq!(m, Location::new(1, [Parachain(21), PalletInstance(3)]));
308
	/// # }
309
	/// ```
310
339
	pub fn append_with(&mut self, suffix: impl Into<Self>) -> Result<(), Self> {
311
339
		let prefix = core::mem::replace(self, suffix.into());
312
339
		match self.prepend_with(prefix) {
313
336
			Ok(()) => Ok(()),
314
3
			Err(prefix) => Err(core::mem::replace(self, prefix)),
315
		}
316
339
	}
317

            
318
	/// Consume `self` and return its value suffixed with `suffix`.
319
	///
320
	/// Returns `Err` with the original value of `self` and `suffix` in case of overflow.
321
	///
322
	/// # Example
323
	/// ```rust
324
	/// # use staging_xcm::v4::{Junctions::*, Junction::*, Location, Parent};
325
	/// # fn main() {
326
	/// let mut m: Location = (Parent, Parachain(21), 69u64).into();
327
	/// let r = m.appended_with((Parent, PalletInstance(3))).unwrap();
328
	/// assert_eq!(r, Location::new(1, [Parachain(21), PalletInstance(3)]));
329
	/// # }
330
	/// ```
331
	pub fn appended_with(mut self, suffix: impl Into<Self>) -> Result<Self, (Self, Self)> {
332
		match self.append_with(suffix) {
333
			Ok(()) => Ok(self),
334
			Err(suffix) => Err((self, suffix)),
335
		}
336
	}
337

            
338
	/// Mutate `self` so that it is prefixed with `prefix`.
339
	///
340
	/// Does not modify `self` and returns `Err` with `prefix` in case of overflow.
341
	///
342
	/// # Example
343
	/// ```rust
344
	/// # use staging_xcm::v4::{Junctions::*, Junction::*, Location, Parent};
345
	/// # fn main() {
346
	/// let mut m: Location = (Parent, Parent, PalletInstance(3)).into();
347
	/// assert_eq!(m.prepend_with((Parent, Parachain(21), OnlyChild)), Ok(()));
348
	/// assert_eq!(m, Location::new(1, [PalletInstance(3)]));
349
	/// # }
350
	/// ```
351
1229
	pub fn prepend_with(&mut self, prefix: impl Into<Self>) -> Result<(), Self> {
352
1229
		//     prefix     self (suffix)
353
1229
		// P .. P I .. I  p .. p i .. i
354
1229
		let mut prefix = prefix.into();
355
1229
		let prepend_interior = prefix.interior.len().saturating_sub(self.parents as usize);
356
1229
		let final_interior = self.interior.len().saturating_add(prepend_interior);
357
1229
		if final_interior > super::junctions::MAX_JUNCTIONS {
358
65
			return Err(prefix)
359
1164
		}
360
1164
		let suffix_parents = (self.parents as usize).saturating_sub(prefix.interior.len());
361
1164
		let final_parents = (prefix.parents as usize).saturating_add(suffix_parents);
362
1164
		if final_parents > 255 {
363
4
			return Err(prefix)
364
1160
		}
365

            
366
		// cancel out the final item on the prefix interior for one of the suffix's parents.
367
1444
		while self.parents > 0 && prefix.take_last().is_some() {
368
284
			self.dec_parent();
369
284
		}
370

            
371
		// now we have either removed all suffix's parents or prefix interior.
372
		// this means we can combine the prefix's and suffix's remaining parents/interior since
373
		// we know that with at least one empty, the overall order will be respected:
374
		//     prefix     self (suffix)
375
		// P .. P   (I)   p .. p i .. i => P + p .. (no I) i
376
		//  -- or --
377
		// P .. P I .. I    (p)  i .. i => P (no p) .. I + i
378

            
379
1160
		self.parents = self.parents.saturating_add(prefix.parents);
380
1196
		for j in prefix.interior.into_iter().rev() {
381
1080
			self.push_front_interior(j)
382
1080
				.expect("final_interior no greater than MAX_JUNCTIONS; qed");
383
1080
		}
384
1160
		Ok(())
385
1229
	}
386

            
387
	/// Consume `self` and return its value prefixed with `prefix`.
388
	///
389
	/// Returns `Err` with the original value of `self` and `prefix` in case of overflow.
390
	///
391
	/// # Example
392
	/// ```rust
393
	/// # use staging_xcm::v4::{Junctions::*, Junction::*, Location, Parent};
394
	/// # fn main() {
395
	/// let m: Location = (Parent, Parent, PalletInstance(3)).into();
396
	/// let r = m.prepended_with((Parent, Parachain(21), OnlyChild)).unwrap();
397
	/// assert_eq!(r, Location::new(1, [PalletInstance(3)]));
398
	/// # }
399
	/// ```
400
	pub fn prepended_with(mut self, prefix: impl Into<Self>) -> Result<Self, (Self, Self)> {
401
		match self.prepend_with(prefix) {
402
			Ok(()) => Ok(self),
403
			Err(prefix) => Err((self, prefix)),
404
		}
405
	}
406

            
407
	/// Remove any unneeded parents/junctions in `self` based on the given context it will be
408
	/// interpreted in.
409
824
	pub fn simplify(&mut self, context: &Junctions) {
410
824
		if context.len() < self.parents as usize {
411
			// Not enough context
412
112
			return
413
712
		}
414
746
		while self.parents > 0 {
415
312
			let maybe = context.at(context.len() - (self.parents as usize));
416
312
			match (self.interior.first(), maybe) {
417
300
				(Some(i), Some(j)) if i == j => {
418
34
					self.interior.take_first();
419
34
					self.parents -= 1;
420
34
				},
421
278
				_ => break,
422
			}
423
		}
424
824
	}
425

            
426
	/// Return the Location subsection identifying the chain that `self` points to.
427
104
	pub fn chain_location(&self) -> Location {
428
104
		let mut clone = self.clone();
429
		// start popping junctions until we reach chain identifier
430
184
		while let Some(j) = clone.last() {
431
102
			if matches!(j, Junction::Parachain(_) | Junction::GlobalConsensus(_)) {
432
				// return chain subsection
433
22
				return clone
434
80
			} else {
435
80
				(clone, _) = clone.split_last_interior();
436
80
			}
437
		}
438
82
		Location::new(clone.parents, Junctions::Here)
439
104
	}
440
}
441

            
442
impl Reanchorable for Location {
443
	type Error = Self;
444

            
445
	/// Mutate `self` so that it represents the same location from the point of view of `target`.
446
	/// The context of `self` is provided as `context`.
447
	///
448
	/// Does not modify `self` in case of overflow.
449
1086
	fn reanchor(&mut self, target: &Location, context: &InteriorLocation) -> Result<(), ()> {
450
		// TODO: https://github.com/paritytech/polkadot/issues/4489 Optimize this.
451

            
452
		// 1. Use our `context` to figure out how the `target` would address us.
453
1086
		let inverted_target = context.invert_target(target)?;
454

            
455
		// 2. Prepend `inverted_target` to `self` to get self's location from the perspective of
456
		// `target`.
457
890
		self.prepend_with(inverted_target).map_err(|_| ())?;
458

            
459
		// 3. Given that we know some of `target` context, ensure that any parents in `self` are
460
		// strictly needed.
461
824
		self.simplify(target.interior());
462
824

            
463
824
		Ok(())
464
1086
	}
465

            
466
	/// Consume `self` and return a new value representing the same location from the point of view
467
	/// of `target`. The context of `self` is provided as `context`.
468
	///
469
	/// Returns the original `self` in case of overflow.
470
768
	fn reanchored(mut self, target: &Location, context: &InteriorLocation) -> Result<Self, Self> {
471
768
		match self.reanchor(target, context) {
472
606
			Ok(()) => Ok(self),
473
162
			Err(()) => Err(self),
474
		}
475
768
	}
476
}
477

            
478
impl TryFrom<OldLocation> for Option<Location> {
479
	type Error = ();
480
52
	fn try_from(value: OldLocation) -> result::Result<Self, Self::Error> {
481
52
		Ok(Some(Location::try_from(value)?))
482
52
	}
483
}
484

            
485
impl TryFrom<OldLocation> for Location {
486
	type Error = ();
487
14974
	fn try_from(x: OldLocation) -> result::Result<Self, ()> {
488
14974
		Ok(Location { parents: x.parents, interior: x.interior.try_into()? })
489
14974
	}
490
}
491

            
492
/// A unit struct which can be converted into a `Location` of `parents` value 1.
493
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
494
pub struct Parent;
495
impl From<Parent> for Location {
496
	fn from(_: Parent) -> Self {
497
		Location { parents: 1, interior: Junctions::Here }
498
	}
499
}
500

            
501
/// A tuple struct which can be converted into a `Location` of `parents` value 1 with the inner
502
/// interior.
503
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
504
pub struct ParentThen(pub Junctions);
505
impl From<ParentThen> for Location {
506
	fn from(ParentThen(interior): ParentThen) -> Self {
507
		Location { parents: 1, interior }
508
	}
509
}
510

            
511
/// A unit struct which can be converted into a `Location` of the inner `parents` value.
512
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
513
pub struct Ancestor(pub u8);
514
impl From<Ancestor> for Location {
515
	fn from(Ancestor(parents): Ancestor) -> Self {
516
		Location { parents, interior: Junctions::Here }
517
	}
518
}
519

            
520
/// A unit struct which can be converted into a `Location` of the inner `parents` value and the
521
/// inner interior.
522
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
523
pub struct AncestorThen<Interior>(pub u8, pub Interior);
524
impl<Interior: Into<Junctions>> From<AncestorThen<Interior>> for Location {
525
	fn from(AncestorThen(parents, interior): AncestorThen<Interior>) -> Self {
526
		Location { parents, interior: interior.into() }
527
	}
528
}
529

            
530
impl From<[u8; 32]> for Location {
531
	fn from(bytes: [u8; 32]) -> Self {
532
		let junction: Junction = bytes.into();
533
		junction.into()
534
	}
535
}
536

            
537
21682
xcm_procedural::impl_conversion_functions_for_location_v4!();
538

            
539
#[cfg(test)]
540
mod tests {
541
	use crate::v4::prelude::*;
542
	use codec::{Decode, Encode};
543

            
544
	#[test]
545
	fn conversion_works() {
546
		let x: Location = Parent.into();
547
		assert_eq!(x, Location { parents: 1, interior: Here });
548
		//		let x: Location = (Parent,).into();
549
		//		assert_eq!(x, Location { parents: 1, interior: Here });
550
		//		let x: Location = (Parent, Parent).into();
551
		//		assert_eq!(x, Location { parents: 2, interior: Here });
552
		let x: Location = (Parent, Parent, OnlyChild).into();
553
		assert_eq!(x, Location { parents: 2, interior: OnlyChild.into() });
554
		let x: Location = OnlyChild.into();
555
		assert_eq!(x, Location { parents: 0, interior: OnlyChild.into() });
556
		let x: Location = (OnlyChild,).into();
557
		assert_eq!(x, Location { parents: 0, interior: OnlyChild.into() });
558
	}
559

            
560
	#[test]
561
	fn simplify_basic_works() {
562
		let mut location: Location =
563
			(Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into();
564
		let context = [Parachain(1000), PalletInstance(42)].into();
565
		let expected = GeneralIndex(69).into();
566
		location.simplify(&context);
567
		assert_eq!(location, expected);
568

            
569
		let mut location: Location = (Parent, PalletInstance(42), GeneralIndex(69)).into();
570
		let context = [PalletInstance(42)].into();
571
		let expected = GeneralIndex(69).into();
572
		location.simplify(&context);
573
		assert_eq!(location, expected);
574

            
575
		let mut location: Location = (Parent, PalletInstance(42), GeneralIndex(69)).into();
576
		let context = [Parachain(1000), PalletInstance(42)].into();
577
		let expected = GeneralIndex(69).into();
578
		location.simplify(&context);
579
		assert_eq!(location, expected);
580

            
581
		let mut location: Location =
582
			(Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into();
583
		let context = [OnlyChild, Parachain(1000), PalletInstance(42)].into();
584
		let expected = GeneralIndex(69).into();
585
		location.simplify(&context);
586
		assert_eq!(location, expected);
587
	}
588

            
589
	#[test]
590
	fn simplify_incompatible_location_fails() {
591
		let mut location: Location =
592
			(Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into();
593
		let context = [Parachain(1000), PalletInstance(42), GeneralIndex(42)].into();
594
		let expected =
595
			(Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into();
596
		location.simplify(&context);
597
		assert_eq!(location, expected);
598

            
599
		let mut location: Location =
600
			(Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into();
601
		let context = [Parachain(1000)].into();
602
		let expected =
603
			(Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into();
604
		location.simplify(&context);
605
		assert_eq!(location, expected);
606
	}
607

            
608
	#[test]
609
	fn reanchor_works() {
610
		let mut id: Location = (Parent, Parachain(1000), GeneralIndex(42)).into();
611
		let context = Parachain(2000).into();
612
		let target = (Parent, Parachain(1000)).into();
613
		let expected = GeneralIndex(42).into();
614
		id.reanchor(&target, &context).unwrap();
615
		assert_eq!(id, expected);
616
	}
617

            
618
	#[test]
619
	fn encode_and_decode_works() {
620
		let m = Location {
621
			parents: 1,
622
			interior: [Parachain(42), AccountIndex64 { network: None, index: 23 }].into(),
623
		};
624
		let encoded = m.encode();
625
		assert_eq!(encoded, [1, 2, 0, 168, 2, 0, 92].to_vec());
626
		let decoded = Location::decode(&mut &encoded[..]);
627
		assert_eq!(decoded, Ok(m));
628
	}
629

            
630
	#[test]
631
	fn match_and_split_works() {
632
		let m = Location {
633
			parents: 1,
634
			interior: [Parachain(42), AccountIndex64 { network: None, index: 23 }].into(),
635
		};
636
		assert_eq!(m.match_and_split(&Location { parents: 1, interior: Here }), None);
637
		assert_eq!(
638
			m.match_and_split(&Location { parents: 1, interior: [Parachain(42)].into() }),
639
			Some(&AccountIndex64 { network: None, index: 23 })
640
		);
641
		assert_eq!(m.match_and_split(&m), None);
642
	}
643

            
644
	#[test]
645
	fn append_with_works() {
646
		let acc = AccountIndex64 { network: None, index: 23 };
647
		let mut m = Location { parents: 1, interior: [Parachain(42)].into() };
648
		assert_eq!(m.append_with([PalletInstance(3), acc]), Ok(()));
649
		assert_eq!(
650
			m,
651
			Location { parents: 1, interior: [Parachain(42), PalletInstance(3), acc].into() }
652
		);
653

            
654
		// cannot append to create overly long location
655
		let acc = AccountIndex64 { network: None, index: 23 };
656
		let m = Location {
657
			parents: 254,
658
			interior: [Parachain(42), OnlyChild, OnlyChild, OnlyChild, OnlyChild].into(),
659
		};
660
		let suffix: Location = (PalletInstance(3), acc, OnlyChild, OnlyChild).into();
661
		assert_eq!(m.clone().append_with(suffix.clone()), Err(suffix));
662
	}
663

            
664
	#[test]
665
	fn prepend_with_works() {
666
		let mut m = Location {
667
			parents: 1,
668
			interior: [Parachain(42), AccountIndex64 { network: None, index: 23 }].into(),
669
		};
670
		assert_eq!(m.prepend_with(Location { parents: 1, interior: [OnlyChild].into() }), Ok(()));
671
		assert_eq!(
672
			m,
673
			Location {
674
				parents: 1,
675
				interior: [Parachain(42), AccountIndex64 { network: None, index: 23 }].into()
676
			}
677
		);
678

            
679
		// cannot prepend to create overly long location
680
		let mut m = Location { parents: 254, interior: [Parachain(42)].into() };
681
		let prefix = Location { parents: 2, interior: Here };
682
		assert_eq!(m.prepend_with(prefix.clone()), Err(prefix));
683

            
684
		let prefix = Location { parents: 1, interior: Here };
685
		assert_eq!(m.prepend_with(prefix.clone()), Ok(()));
686
		assert_eq!(m, Location { parents: 255, interior: [Parachain(42)].into() });
687
	}
688

            
689
	#[test]
690
	fn double_ended_ref_iteration_works() {
691
		let m: Junctions = [Parachain(1000), Parachain(3), PalletInstance(5)].into();
692
		let mut iter = m.iter();
693

            
694
		let first = iter.next().unwrap();
695
		assert_eq!(first, &Parachain(1000));
696
		let third = iter.next_back().unwrap();
697
		assert_eq!(third, &PalletInstance(5));
698
		let second = iter.next_back().unwrap();
699
		assert_eq!(iter.next(), None);
700
		assert_eq!(iter.next_back(), None);
701
		assert_eq!(second, &Parachain(3));
702

            
703
		let res = Here
704
			.pushed_with(*first)
705
			.unwrap()
706
			.pushed_with(*second)
707
			.unwrap()
708
			.pushed_with(*third)
709
			.unwrap();
710
		assert_eq!(m, res);
711

            
712
		// make sure there's no funny business with the 0 indexing
713
		let m = Here;
714
		let mut iter = m.iter();
715

            
716
		assert_eq!(iter.next(), None);
717
		assert_eq!(iter.next_back(), None);
718
	}
719

            
720
	#[test]
721
	fn conversion_from_other_types_works() {
722
		use crate::v3;
723

            
724
		fn takes_location<Arg: Into<Location>>(_arg: Arg) {}
725

            
726
		takes_location(Parent);
727
		takes_location(Here);
728
		takes_location([Parachain(42)]);
729
		takes_location((Ancestor(255), PalletInstance(8)));
730
		takes_location((Ancestor(5), Parachain(1), PalletInstance(3)));
731
		takes_location((Ancestor(2), Here));
732
		takes_location(AncestorThen(
733
			3,
734
			[Parachain(43), AccountIndex64 { network: None, index: 155 }],
735
		));
736
		takes_location((Parent, AccountId32 { network: None, id: [0; 32] }));
737
		takes_location((Parent, Here));
738
		takes_location(ParentThen([Parachain(75)].into()));
739
		takes_location([Parachain(100), PalletInstance(3)]);
740

            
741
		assert_eq!(v3::Location::from(v3::Junctions::Here).try_into(), Ok(Location::here()));
742
		assert_eq!(v3::Location::from(v3::Parent).try_into(), Ok(Location::parent()));
743
		assert_eq!(
744
			v3::Location::from((v3::Parent, v3::Parent, v3::Junction::GeneralIndex(42u128),))
745
				.try_into(),
746
			Ok(Location { parents: 2, interior: [GeneralIndex(42u128)].into() }),
747
		);
748
	}
749
}