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

            
4
// Substrate 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
// Substrate 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
//! Cross-Consensus Message format data structures.
18

            
19
// NOTE, this crate is meant to be used in many different environments, notably wasm, but not
20
// necessarily related to FRAME or even Substrate.
21
//
22
// Hence, `no_std` rather than sp-runtime.
23
#![cfg_attr(not(feature = "std"), no_std)]
24
// Because of XCMv2.
25
#![allow(deprecated)]
26

            
27
extern crate alloc;
28

            
29
use codec::{Decode, DecodeLimit, Encode, Error as CodecError, Input, MaxEncodedLen};
30
use derivative::Derivative;
31
use scale_info::TypeInfo;
32

            
33
#[deprecated(
34
	note = "XCMv2 will be removed once XCMv5 is released. Please use XCMv3 or XCMv4 instead."
35
)]
36
pub mod v2;
37
pub mod v3;
38
pub mod v4;
39

            
40
pub mod lts {
41
	pub use super::v4::*;
42
}
43

            
44
pub mod latest {
45
	pub use super::v4::*;
46
}
47

            
48
mod double_encoded;
49
pub use double_encoded::DoubleEncoded;
50

            
51
#[cfg(test)]
52
mod tests;
53

            
54
/// Maximum nesting level for XCM decoding.
55
pub const MAX_XCM_DECODE_DEPTH: u32 = 8;
56

            
57
/// A version of XCM.
58
pub type Version = u32;
59

            
60
#[derive(Clone, Eq, PartialEq, Debug)]
61
pub enum Unsupported {}
62
impl Encode for Unsupported {}
63
impl Decode for Unsupported {
64
	fn decode<I: Input>(_: &mut I) -> Result<Self, CodecError> {
65
		Err("Not decodable".into())
66
	}
67
}
68

            
69
/// Attempt to convert `self` into a particular version of itself.
70
pub trait IntoVersion: Sized {
71
	/// Consume `self` and return same value expressed in some particular `version` of XCM.
72
	fn into_version(self, version: Version) -> Result<Self, ()>;
73

            
74
	/// Consume `self` and return same value expressed the latest version of XCM.
75
	fn into_latest(self) -> Result<Self, ()> {
76
		self.into_version(latest::VERSION)
77
	}
78
}
79

            
80
pub trait TryAs<T> {
81
	fn try_as(&self) -> Result<&T, ()>;
82
}
83

            
84
macro_rules! versioned_type {
85
	($(#[$attr:meta])* pub enum $n:ident {
86
		$(#[$index3:meta])+
87
		V3($v3:ty),
88
		$(#[$index4:meta])+
89
		V4($v4:ty),
90
	}) => {
91
41
		#[derive(Derivative, Encode, Decode, TypeInfo)]
92
		#[derivative(
93
			Clone(bound = ""),
94
			Eq(bound = ""),
95
			PartialEq(bound = ""),
96
			Debug(bound = "")
97
		)]
98
		#[codec(encode_bound())]
99
		#[codec(decode_bound())]
100
		#[scale_info(replace_segment("staging_xcm", "xcm"))]
101
		$(#[$attr])*
102
		pub enum $n {
103
6
			$(#[$index3])*
104
6
			V3($v3),
105
30
			$(#[$index4])*
106
30
			V4($v4),
107
		}
108
		impl $n {
109
			pub fn try_as<T>(&self) -> Result<&T, ()> where Self: TryAs<T> {
110
				<Self as TryAs<T>>::try_as(&self)
111
			}
112
		}
113
		impl TryAs<$v3> for $n {
114
			fn try_as(&self) -> Result<&$v3, ()> {
115
				match &self {
116
					Self::V3(ref x) => Ok(x),
117
					_ => Err(()),
118
				}
119
			}
120
		}
121
		impl TryAs<$v4> for $n {
122
			fn try_as(&self) -> Result<&$v4, ()> {
123
				match &self {
124
					Self::V4(ref x) => Ok(x),
125
					_ => Err(()),
126
				}
127
			}
128
		}
129
		impl IntoVersion for $n {
130
			fn into_version(self, n: Version) -> Result<Self, ()> {
131
				Ok(match n {
132
					3 => Self::V3(self.try_into()?),
133
					4 => Self::V4(self.try_into()?),
134
					_ => return Err(()),
135
				})
136
			}
137
		}
138
		impl From<$v3> for $n {
139
			fn from(x: $v3) -> Self {
140
				$n::V3(x.into())
141
			}
142
		}
143
		impl From<$v4> for $n {
144
			fn from(x: $v4) -> Self {
145
				$n::V4(x.into())
146
			}
147
		}
148
		impl TryFrom<$n> for $v3 {
149
			type Error = ();
150
			fn try_from(x: $n) -> Result<Self, ()> {
151
				use $n::*;
152
				match x {
153
					V3(x) => Ok(x),
154
					V4(x) => x.try_into(),
155
				}
156
			}
157
		}
158
		impl TryFrom<$n> for $v4 {
159
			type Error = ();
160
2
			fn try_from(x: $n) -> Result<Self, ()> {
161
				use $n::*;
162
2
				match x {
163
					V3(x) => x.try_into().map_err(|_| ()),
164
2
					V4(x) => Ok(x),
165
				}
166
2
			}
167
		}
168
		impl MaxEncodedLen for $n {
169
			fn max_encoded_len() -> usize {
170
				<$v3>::max_encoded_len()
171
			}
172
		}
173
		impl IdentifyVersion for $n {
174
			fn identify_version(&self) -> Version {
175
				use $n::*;
176
				match self {
177
					V3(_) => v3::VERSION,
178
					V4(_) => v4::VERSION,
179
				}
180
			}
181
		}
182
	};
183

            
184
	($(#[$attr:meta])* pub enum $n:ident {
185
		$(#[$index2:meta])+
186
		V2($v2:ty),
187
		$(#[$index3:meta])+
188
		V3($v3:ty),
189
		$(#[$index4:meta])+
190
		V4($v4:ty),
191
	}) => {
192
33002
		#[derive(Derivative, Encode, Decode, TypeInfo)]
193
		#[derivative(
194
			Clone(bound = ""),
195
			Eq(bound = ""),
196
			PartialEq(bound = ""),
197
			Debug(bound = "")
198
		)]
199
		#[codec(encode_bound())]
200
		#[codec(decode_bound())]
201
		#[scale_info(replace_segment("staging_xcm", "xcm"))]
202
		$(#[$attr])*
203
		pub enum $n {
204
6084
			$(#[$index2])*
205
6084
			V2($v2),
206
2898
			$(#[$index3])*
207
2898
			V3($v3),
208
3558
			$(#[$index4])*
209
3558
			V4($v4),
210
		}
211
		impl $n {
212
			pub fn try_as<T>(&self) -> Result<&T, ()> where Self: TryAs<T> {
213
				<Self as TryAs<T>>::try_as(&self)
214
			}
215
		}
216
		impl TryAs<$v2> for $n {
217
			fn try_as(&self) -> Result<&$v2, ()> {
218
				match &self {
219
					Self::V2(ref x) => Ok(x),
220
					_ => Err(()),
221
				}
222
			}
223
		}
224
		impl TryAs<$v3> for $n {
225
			fn try_as(&self) -> Result<&$v3, ()> {
226
				match &self {
227
					Self::V3(ref x) => Ok(x),
228
					_ => Err(()),
229
				}
230
			}
231
		}
232
		impl TryAs<$v4> for $n {
233
			fn try_as(&self) -> Result<&$v4, ()> {
234
				match &self {
235
					Self::V4(ref x) => Ok(x),
236
					_ => Err(()),
237
				}
238
			}
239
		}
240
		impl IntoVersion for $n {
241
38
			fn into_version(self, n: Version) -> Result<Self, ()> {
242
38
				Ok(match n {
243
2
					1 | 2 => Self::V2(self.try_into()?),
244
30
					3 => Self::V3(self.try_into()?),
245
6
					4 => Self::V4(self.try_into()?),
246
					_ => return Err(()),
247
				})
248
38
			}
249
		}
250
		impl From<$v2> for $n {
251
			fn from(x: $v2) -> Self {
252
				$n::V2(x)
253
			}
254
		}
255
		impl<T: Into<$v4>> From<T> for $n {
256
4748
			fn from(x: T) -> Self {
257
4748
				$n::V4(x.into())
258
4748
			}
259
		}
260
		impl TryFrom<$n> for $v2 {
261
			type Error = ();
262
10
			fn try_from(x: $n) -> Result<Self, ()> {
263
				use $n::*;
264
10
				match x {
265
8
					V2(x) => Ok(x),
266
					V3(x) => x.try_into(),
267
2
					V4(x) => {
268
2
						let v3: $v3 = x.try_into().map_err(|_| ())?;
269
2
						v3.try_into()
270
					},
271
				}
272
10
			}
273
		}
274
		impl TryFrom<$n> for $v3 {
275
			type Error = ();
276
30
			fn try_from(x: $n) -> Result<Self, ()> {
277
				use $n::*;
278
30
				match x {
279
					V2(x) => x.try_into(),
280
					V3(x) => Ok(x),
281
30
					V4(x) => x.try_into().map_err(|_| ()),
282
				}
283
30
			}
284
		}
285
		impl TryFrom<$n> for $v4 {
286
			type Error = ();
287
2772
			fn try_from(x: $n) -> Result<Self, ()> {
288
				use $n::*;
289
2772
				match x {
290
1442
					V2(x) => {
291
1442
						let v3: $v3 = x.try_into().map_err(|_| ())?;
292
1434
						v3.try_into().map_err(|_| ())
293
					},
294
830
					V3(x) => x.try_into().map_err(|_| ()),
295
500
					V4(x) => Ok(x),
296
				}
297
2772
			}
298
		}
299
		impl MaxEncodedLen for $n {
300
			fn max_encoded_len() -> usize {
301
				<$v3>::max_encoded_len()
302
			}
303
		}
304
		impl IdentifyVersion for $n {
305
92
			fn identify_version(&self) -> Version {
306
				use $n::*;
307
92
				match self {
308
20
					V2(_) => v2::VERSION,
309
60
					V3(_) => v3::VERSION,
310
12
					V4(_) => v4::VERSION,
311
				}
312
92
			}
313
		}
314
	};
315
}
316

            
317
versioned_type! {
318
	/// A single version's `AssetId` value, together with its version code.
319
	pub enum VersionedAssetId {
320
		#[codec(index = 3)]
321
		V3(v3::AssetId),
322
		#[codec(index = 4)]
323
		V4(v4::AssetId),
324
	}
325
}
326

            
327
versioned_type! {
328
	/// A single version's `Response` value, together with its version code.
329
	pub enum VersionedResponse {
330
		#[codec(index = 2)]
331
		V2(v2::Response),
332
		#[codec(index = 3)]
333
		V3(v3::Response),
334
		#[codec(index = 4)]
335
		V4(v4::Response),
336
	}
337
}
338

            
339
versioned_type! {
340
	/// A single `NetworkId` value, together with its version code.
341
	pub enum VersionedNetworkId {
342
		#[codec(index = 2)]
343
		V2(v2::NetworkId),
344
		#[codec(index = 3)]
345
		V3(v3::NetworkId),
346
		#[codec(index = 4)]
347
		V4(v4::NetworkId),
348
	}
349
}
350

            
351
versioned_type! {
352
	/// A single `Junction` value, together with its version code.
353
	pub enum VersionedJunction {
354
		#[codec(index = 2)]
355
		V2(v2::Junction),
356
		#[codec(index = 3)]
357
		V3(v3::Junction),
358
		#[codec(index = 4)]
359
		V4(v4::Junction),
360
	}
361
}
362

            
363
versioned_type! {
364
	/// A single `Location` value, together with its version code.
365
	#[derive(Ord, PartialOrd)]
366
	pub enum VersionedLocation {
367
		#[codec(index = 1)] // v2 is same as v1 and therefore re-using the v1 index
368
		V2(v2::MultiLocation),
369
		#[codec(index = 3)]
370
		V3(v3::MultiLocation),
371
		#[codec(index = 4)]
372
		V4(v4::Location),
373
	}
374
}
375

            
376
#[deprecated(note = "Use `VersionedLocation` instead")]
377
pub type VersionedMultiLocation = VersionedLocation;
378

            
379
versioned_type! {
380
	/// A single `InteriorLocation` value, together with its version code.
381
	pub enum VersionedInteriorLocation {
382
		#[codec(index = 2)] // while this is same as v1::Junctions, VersionedInteriorLocation is introduced in v3
383
		V2(v2::InteriorMultiLocation),
384
		#[codec(index = 3)]
385
		V3(v3::InteriorMultiLocation),
386
		#[codec(index = 4)]
387
		V4(v4::InteriorLocation),
388
	}
389
}
390

            
391
#[deprecated(note = "Use `VersionedInteriorLocation` instead")]
392
pub type VersionedInteriorMultiLocation = VersionedInteriorLocation;
393

            
394
versioned_type! {
395
	/// A single `Asset` value, together with its version code.
396
	pub enum VersionedAsset {
397
		#[codec(index = 1)] // v2 is same as v1 and therefore re-using the v1 index
398
		V2(v2::MultiAsset),
399
		#[codec(index = 3)]
400
		V3(v3::MultiAsset),
401
		#[codec(index = 4)]
402
		V4(v4::Asset),
403
	}
404
}
405

            
406
#[deprecated(note = "Use `VersionedAsset` instead")]
407
pub type VersionedMultiAsset = VersionedAsset;
408

            
409
versioned_type! {
410
	/// A single `MultiAssets` value, together with its version code.
411
	pub enum VersionedAssets {
412
		#[codec(index = 1)] // v2 is same as v1 and therefore re-using the v1 index
413
		V2(v2::MultiAssets),
414
		#[codec(index = 3)]
415
		V3(v3::MultiAssets),
416
		#[codec(index = 4)]
417
		V4(v4::Assets),
418
	}
419
}
420

            
421
#[deprecated(note = "Use `VersionedAssets` instead")]
422
pub type VersionedMultiAssets = VersionedAssets;
423

            
424
/// A single XCM message, together with its version code.
425
148622
#[derive(Derivative, Encode, Decode, TypeInfo)]
426
#[derivative(Clone(bound = ""), Eq(bound = ""), PartialEq(bound = ""), Debug(bound = ""))]
427
#[codec(encode_bound())]
428
#[codec(decode_bound())]
429
#[scale_info(bounds(), skip_type_params(RuntimeCall))]
430
#[scale_info(replace_segment("staging_xcm", "xcm"))]
431
pub enum VersionedXcm<RuntimeCall> {
432
11505
	#[codec(index = 2)]
433
	#[deprecated]
434
11505
	V2(v2::Xcm<RuntimeCall>),
435
11388
	#[codec(index = 3)]
436
11388
	V3(v3::Xcm<RuntimeCall>),
437
22770
	#[codec(index = 4)]
438
22770
	V4(v4::Xcm<RuntimeCall>),
439
}
440

            
441
impl<C> IntoVersion for VersionedXcm<C> {
442
1995
	fn into_version(self, n: Version) -> Result<Self, ()> {
443
1995
		Ok(match n {
444
			2 => Self::V2(self.try_into()?),
445
			3 => Self::V3(self.try_into()?),
446
1995
			4 => Self::V4(self.try_into()?),
447
			_ => return Err(()),
448
		})
449
1995
	}
450
}
451

            
452
impl<C> IdentifyVersion for VersionedXcm<C> {
453
	fn identify_version(&self) -> Version {
454
		match self {
455
			Self::V2(_) => v2::VERSION,
456
			Self::V3(_) => v3::VERSION,
457
			Self::V4(_) => v4::VERSION,
458
		}
459
	}
460
}
461

            
462
impl<C> VersionedXcm<C> {
463
	/// Checks that the XCM is decodable with `MAX_XCM_DECODE_DEPTH`. Consequently, it also checks
464
	/// all decode implementations and limits, such as MAX_ITEMS_IN_ASSETS or
465
	/// MAX_INSTRUCTIONS_TO_DECODE.
466
	///
467
	/// Note that this uses the limit of the sender - not the receiver. It is a best effort.
468
1995
	pub fn validate_xcm_nesting(&self) -> Result<(), ()> {
469
1995
		self.using_encoded(|mut enc| {
470
1995
			Self::decode_all_with_depth_limit(MAX_XCM_DECODE_DEPTH, &mut enc).map(|_| ())
471
1995
		})
472
1995
		.map_err(|e| {
473
153
			log::error!(target: "xcm::validate_xcm_nesting", "Decode error: {e:?} for xcm: {self:?}!");
474
153
			()
475
1995
		})
476
1995
	}
477
}
478

            
479
impl<RuntimeCall> From<v2::Xcm<RuntimeCall>> for VersionedXcm<RuntimeCall> {
480
	fn from(x: v2::Xcm<RuntimeCall>) -> Self {
481
		VersionedXcm::V2(x)
482
	}
483
}
484

            
485
impl<RuntimeCall> From<v3::Xcm<RuntimeCall>> for VersionedXcm<RuntimeCall> {
486
	fn from(x: v3::Xcm<RuntimeCall>) -> Self {
487
		VersionedXcm::V3(x)
488
	}
489
}
490

            
491
impl<RuntimeCall> From<v4::Xcm<RuntimeCall>> for VersionedXcm<RuntimeCall> {
492
1995
	fn from(x: v4::Xcm<RuntimeCall>) -> Self {
493
1995
		VersionedXcm::V4(x)
494
1995
	}
495
}
496

            
497
impl<RuntimeCall> TryFrom<VersionedXcm<RuntimeCall>> for v2::Xcm<RuntimeCall> {
498
	type Error = ();
499
	fn try_from(x: VersionedXcm<RuntimeCall>) -> Result<Self, ()> {
500
		use VersionedXcm::*;
501
		match x {
502
			V2(x) => Ok(x),
503
			V3(x) => x.try_into(),
504
			V4(x) => {
505
				let v3: v3::Xcm<RuntimeCall> = x.try_into()?;
506
				v3.try_into()
507
			},
508
		}
509
	}
510
}
511

            
512
impl<Call> TryFrom<VersionedXcm<Call>> for v3::Xcm<Call> {
513
	type Error = ();
514
	fn try_from(x: VersionedXcm<Call>) -> Result<Self, ()> {
515
		use VersionedXcm::*;
516
		match x {
517
			V2(x) => x.try_into(),
518
			V3(x) => Ok(x),
519
			V4(x) => x.try_into(),
520
		}
521
	}
522
}
523

            
524
impl<Call> TryFrom<VersionedXcm<Call>> for v4::Xcm<Call> {
525
	type Error = ();
526
26952
	fn try_from(x: VersionedXcm<Call>) -> Result<Self, ()> {
527
		use VersionedXcm::*;
528
26952
		match x {
529
5790
			V2(x) => {
530
5790
				let v3: v3::Xcm<Call> = x.try_into()?;
531
4611
				v3.try_into()
532
			},
533
5238
			V3(x) => x.try_into(),
534
15924
			V4(x) => Ok(x),
535
		}
536
26952
	}
537
}
538

            
539
/// Convert an `Xcm` datum into a `VersionedXcm`, based on a destination `Location` which will
540
/// interpret it.
541
pub trait WrapVersion {
542
	fn wrap_version<RuntimeCall>(
543
		dest: &latest::Location,
544
		xcm: impl Into<VersionedXcm<RuntimeCall>>,
545
	) -> Result<VersionedXcm<RuntimeCall>, ()>;
546
}
547

            
548
/// Used to get the version out of a versioned type.
549
// TODO(XCMv5): This could be `GetVersion` and we change the current one to `GetVersionFor`.
550
pub trait IdentifyVersion {
551
	fn identify_version(&self) -> Version;
552
}
553

            
554
/// Check and return the `Version` that should be used for the `Xcm` datum for the destination
555
/// `Location`, which will interpret it.
556
pub trait GetVersion {
557
	fn get_version_for(dest: &latest::Location) -> Option<Version>;
558
}
559

            
560
/// `()` implementation does nothing with the XCM, just sending with whatever version it was
561
/// authored as.
562
impl WrapVersion for () {
563
	fn wrap_version<RuntimeCall>(
564
		_: &latest::Location,
565
		xcm: impl Into<VersionedXcm<RuntimeCall>>,
566
	) -> Result<VersionedXcm<RuntimeCall>, ()> {
567
		Ok(xcm.into())
568
	}
569
}
570

            
571
/// `WrapVersion` implementation which attempts to always convert the XCM to version 2 before
572
/// wrapping it.
573
pub struct AlwaysV2;
574
impl WrapVersion for AlwaysV2 {
575
	fn wrap_version<RuntimeCall>(
576
		_: &latest::Location,
577
		xcm: impl Into<VersionedXcm<RuntimeCall>>,
578
	) -> Result<VersionedXcm<RuntimeCall>, ()> {
579
		Ok(VersionedXcm::<RuntimeCall>::V2(xcm.into().try_into()?))
580
	}
581
}
582
impl GetVersion for AlwaysV2 {
583
	fn get_version_for(_dest: &latest::Location) -> Option<Version> {
584
		Some(v2::VERSION)
585
	}
586
}
587

            
588
/// `WrapVersion` implementation which attempts to always convert the XCM to version 3 before
589
/// wrapping it.
590
pub struct AlwaysV3;
591
impl WrapVersion for AlwaysV3 {
592
	fn wrap_version<Call>(
593
		_: &latest::Location,
594
		xcm: impl Into<VersionedXcm<Call>>,
595
	) -> Result<VersionedXcm<Call>, ()> {
596
		Ok(VersionedXcm::<Call>::V3(xcm.into().try_into()?))
597
	}
598
}
599
impl GetVersion for AlwaysV3 {
600
	fn get_version_for(_dest: &latest::Location) -> Option<Version> {
601
		Some(v3::VERSION)
602
	}
603
}
604

            
605
/// `WrapVersion` implementation which attempts to always convert the XCM to version 3 before
606
/// wrapping it.
607
pub struct AlwaysV4;
608
impl WrapVersion for AlwaysV4 {
609
	fn wrap_version<Call>(
610
		_: &latest::Location,
611
		xcm: impl Into<VersionedXcm<Call>>,
612
	) -> Result<VersionedXcm<Call>, ()> {
613
		Ok(VersionedXcm::<Call>::V4(xcm.into().try_into()?))
614
	}
615
}
616
impl GetVersion for AlwaysV4 {
617
	fn get_version_for(_dest: &latest::Location) -> Option<Version> {
618
		Some(v4::VERSION)
619
	}
620
}
621

            
622
/// `WrapVersion` implementation which attempts to always convert the XCM to the latest version
623
/// before wrapping it.
624
pub type AlwaysLatest = AlwaysV4;
625

            
626
/// `WrapVersion` implementation which attempts to always convert the XCM to the most recent Long-
627
/// Term-Support version before wrapping it.
628
pub type AlwaysLts = AlwaysV4;
629

            
630
pub mod prelude {
631
	pub use super::{
632
		latest::prelude::*, AlwaysLatest, AlwaysLts, AlwaysV2, AlwaysV3, AlwaysV4, GetVersion,
633
		IdentifyVersion, IntoVersion, Unsupported, Version as XcmVersion, VersionedAsset,
634
		VersionedAssetId, VersionedAssets, VersionedInteriorLocation, VersionedLocation,
635
		VersionedResponse, VersionedXcm, WrapVersion,
636
	};
637
}
638

            
639
pub mod opaque {
640
	pub mod v2 {
641
		// Everything from v2
642
		pub use crate::v2::*;
643
		// Then override with the opaque types in v2
644
		pub use crate::v2::opaque::{Instruction, Xcm};
645
	}
646
	pub mod v3 {
647
		// Everything from v3
648
		pub use crate::v3::*;
649
		// Then override with the opaque types in v3
650
		pub use crate::v3::opaque::{Instruction, Xcm};
651
	}
652
	pub mod v4 {
653
		// Everything from v4
654
		pub use crate::v4::*;
655
		// Then override with the opaque types in v4
656
		pub use crate::v4::opaque::{Instruction, Xcm};
657
	}
658

            
659
	pub mod latest {
660
		pub use super::v4::*;
661
	}
662

            
663
	pub mod lts {
664
		pub use super::v4::*;
665
	}
666

            
667
	/// The basic `VersionedXcm` type which just uses the `Vec<u8>` as an encoded call.
668
	pub type VersionedXcm = super::VersionedXcm<()>;
669
}
670

            
671
#[test]
672
fn conversion_works() {
673
	use latest::prelude::*;
674
	let assets: Assets = (Here, 1u128).into();
675
	let _: VersionedAssets = assets.into();
676
}
677

            
678
#[test]
679
fn size_limits() {
680
	extern crate std;
681

            
682
	let mut test_failed = false;
683
	macro_rules! check_sizes {
684
        ($(($kind:ty, $expected:expr),)+) => {
685
            $({
686
                let s = core::mem::size_of::<$kind>();
687
                // Since the types often affect the size of other types in which they're included
688
                // it is more convenient to check multiple types at the same time and only fail
689
                // the test at the end. For debugging it's also useful to print out all of the sizes,
690
                // even if they're within the expected range.
691
                if s > $expected {
692
                    test_failed = true;
693
                    std::eprintln!(
694
                        "assertion failed: size of '{}' is {} (which is more than the expected {})",
695
                        stringify!($kind),
696
                        s,
697
                        $expected
698
                    );
699
                } else {
700
                    std::println!(
701
                        "type '{}' is of size {} which is within the expected {}",
702
                        stringify!($kind),
703
                        s,
704
                        $expected
705
                    );
706
                }
707
            })+
708
        }
709
    }
710

            
711
	check_sizes! {
712
		(crate::latest::Instruction<()>, 112),
713
		(crate::latest::Asset, 80),
714
		(crate::latest::Location, 24),
715
		(crate::latest::AssetId, 40),
716
		(crate::latest::Junctions, 16),
717
		(crate::latest::Junction, 88),
718
		(crate::latest::Response, 40),
719
		(crate::latest::AssetInstance, 48),
720
		(crate::latest::NetworkId, 48),
721
		(crate::latest::BodyId, 32),
722
		(crate::latest::Assets, 24),
723
		(crate::latest::BodyPart, 12),
724
	}
725
	assert!(!test_failed);
726
}
727

            
728
#[test]
729
fn validate_xcm_nesting_works() {
730
	use crate::latest::{
731
		prelude::{GeneralIndex, ReserveAssetDeposited, SetAppendix},
732
		Assets, Xcm, MAX_INSTRUCTIONS_TO_DECODE, MAX_ITEMS_IN_ASSETS,
733
	};
734

            
735
	// closure generates assets of `count`
736
	let assets = |count| {
737
		let mut assets = Assets::new();
738
		for i in 0..count {
739
			assets.push((GeneralIndex(i as u128), 100).into());
740
		}
741
		assets
742
	};
743

            
744
	// closer generates `Xcm` with nested instructions of `depth`
745
	let with_instr = |depth| {
746
		let mut xcm = Xcm::<()>(vec![]);
747
		for _ in 0..depth - 1 {
748
			xcm = Xcm::<()>(vec![SetAppendix(xcm)]);
749
		}
750
		xcm
751
	};
752

            
753
	// `MAX_INSTRUCTIONS_TO_DECODE` check
754
	assert!(VersionedXcm::<()>::from(Xcm(vec![
755
		ReserveAssetDeposited(assets(1));
756
		(MAX_INSTRUCTIONS_TO_DECODE - 1) as usize
757
	]))
758
	.validate_xcm_nesting()
759
	.is_ok());
760
	assert!(VersionedXcm::<()>::from(Xcm(vec![
761
		ReserveAssetDeposited(assets(1));
762
		MAX_INSTRUCTIONS_TO_DECODE as usize
763
	]))
764
	.validate_xcm_nesting()
765
	.is_ok());
766
	assert!(VersionedXcm::<()>::from(Xcm(vec![
767
		ReserveAssetDeposited(assets(1));
768
		(MAX_INSTRUCTIONS_TO_DECODE + 1) as usize
769
	]))
770
	.validate_xcm_nesting()
771
	.is_err());
772

            
773
	// `MAX_XCM_DECODE_DEPTH` check
774
	assert!(VersionedXcm::<()>::from(with_instr(MAX_XCM_DECODE_DEPTH - 1))
775
		.validate_xcm_nesting()
776
		.is_ok());
777
	assert!(VersionedXcm::<()>::from(with_instr(MAX_XCM_DECODE_DEPTH))
778
		.validate_xcm_nesting()
779
		.is_ok());
780
	assert!(VersionedXcm::<()>::from(with_instr(MAX_XCM_DECODE_DEPTH + 1))
781
		.validate_xcm_nesting()
782
		.is_err());
783

            
784
	// `MAX_ITEMS_IN_ASSETS` check
785
	assert!(VersionedXcm::<()>::from(Xcm(vec![ReserveAssetDeposited(assets(
786
		MAX_ITEMS_IN_ASSETS
787
	))]))
788
	.validate_xcm_nesting()
789
	.is_ok());
790
	assert!(VersionedXcm::<()>::from(Xcm(vec![ReserveAssetDeposited(assets(
791
		MAX_ITEMS_IN_ASSETS - 1
792
	))]))
793
	.validate_xcm_nesting()
794
	.is_ok());
795
	assert!(VersionedXcm::<()>::from(Xcm(vec![ReserveAssetDeposited(assets(
796
		MAX_ITEMS_IN_ASSETS + 1
797
	))]))
798
	.validate_xcm_nesting()
799
	.is_err());
800
}