1
// Copyright 2019-2021 Parity Technologies (UK) Ltd.
2
// This file is part of Parity Bridges Common.
3

            
4
// Parity Bridges Common 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
// Parity Bridges Common 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 Parity Bridges Common.  If not, see <http://www.gnu.org/licenses/>.
16

            
17
//! Primitives of the xcm-bridge-hub pallet.
18

            
19
#![warn(missing_docs)]
20
#![cfg_attr(not(feature = "std"), no_std)]
21

            
22
use bp_messages::LaneIdType;
23
use bp_runtime::{AccountIdOf, BalanceOf, Chain};
24
pub use call_info::XcmBridgeCall;
25
use frame_support::{
26
	ensure, sp_runtime::RuntimeDebug, CloneNoBound, PalletError, PartialEqNoBound,
27
	RuntimeDebugNoBound,
28
};
29
use parity_scale_codec::{Decode, Encode, MaxEncodedLen};
30
use scale_info::TypeInfo;
31
use serde::{Deserialize, Serialize};
32
use sp_core::H256;
33
use sp_io::hashing::blake2_256;
34
use sp_std::boxed::Box;
35
use xcm::{
36
	latest::prelude::*, prelude::XcmVersion, IntoVersion, VersionedInteriorLocation,
37
	VersionedLocation,
38
};
39

            
40
mod call_info;
41

            
42
/// Encoded XCM blob. We expect the bridge messages pallet to use this blob type for both inbound
43
/// and outbound payloads.
44
pub type XcmAsPlainPayload = sp_std::vec::Vec<u8>;
45

            
46
/// Bridge identifier - used **only** for communicating with sibling/parent chains in the same
47
/// consensus.
48
///
49
/// For example, `SendXcm` implementations (which use the `latest` XCM) can use it to identify a
50
/// bridge and the corresponding `LaneId` that is used for over-consensus communication between
51
/// bridge hubs.
52
///
53
/// This identifier is constructed from the `latest` XCM, so it is expected to ensure migration to
54
/// the `latest` XCM version. This could change the `BridgeId`, but it will not affect the `LaneId`.
55
/// In other words, `LaneId` will never change, while `BridgeId` could change with (every) XCM
56
/// upgrade.
57
#[derive(
58
	Clone,
59
	Copy,
60
	Decode,
61
	Encode,
62
	Eq,
63
	Ord,
64
	PartialOrd,
65
	PartialEq,
66
	TypeInfo,
67
	MaxEncodedLen,
68
	Serialize,
69
	Deserialize,
70
)]
71
pub struct BridgeId(H256);
72

            
73
impl BridgeId {
74
	/// Create bridge identifier from two universal locations.
75
	///
76
	/// Note: The `BridgeId` is constructed from `latest` XCM, so if stored, you need to ensure
77
	/// compatibility with newer XCM versions.
78
295252
	pub fn new(
79
295252
		universal_source: &InteriorLocation,
80
295252
		universal_destination: &InteriorLocation,
81
295252
	) -> Self {
82
295252
		const VALUES_SEPARATOR: [u8; 33] = *b"bridges-bridge-id-value-separator";
83
295252

            
84
295252
		BridgeId(
85
295252
			(universal_source, VALUES_SEPARATOR, universal_destination)
86
295252
				.using_encoded(blake2_256)
87
295252
				.into(),
88
295252
		)
89
295252
	}
90

            
91
	/// Access the inner representation.
92
	pub fn inner(&self) -> H256 {
93
		self.0
94
	}
95
}
96

            
97
impl core::fmt::Debug for BridgeId {
98
	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
99
		core::fmt::Debug::fmt(&self.0, f)
100
	}
101
}
102

            
103
/// Local XCM channel manager.
104
pub trait LocalXcmChannelManager<Bridge> {
105
	/// Error that may be returned when suspending/resuming the bridge.
106
	type Error: sp_std::fmt::Debug;
107

            
108
	/// Suspend the bridge, opened by given origin.
109
	///
110
	/// The `local_origin` is guaranteed to be in the same consensus. However, it may point to
111
	/// something below the chain level - like the contract or pallet instance, for example.
112
	fn suspend_bridge(local_origin: &Location, bridge: Bridge) -> Result<(), Self::Error>;
113

            
114
	/// Resume the previously suspended bridge, opened by given origin.
115
	///
116
	/// The `local_origin` is guaranteed to be in the same consensus. However, it may point to
117
	/// something below the chain level - like the contract or pallet instance, for example.
118
	fn resume_bridge(local_origin: &Location, bridge: Bridge) -> Result<(), Self::Error>;
119
}
120

            
121
impl<Bridge> LocalXcmChannelManager<Bridge> for () {
122
	type Error = ();
123

            
124
	fn suspend_bridge(_local_origin: &Location, _bridge: Bridge) -> Result<(), Self::Error> {
125
		Ok(())
126
	}
127

            
128
	fn resume_bridge(_local_origin: &Location, _bridge: Bridge) -> Result<(), Self::Error> {
129
		Ok(())
130
	}
131
}
132

            
133
/// Channel status provider that may report whether it is congested or not.
134
pub trait ChannelStatusProvider {
135
	/// Returns true if the channel is currently active and can be used.
136
	fn is_congested(with: &Location) -> bool;
137
}
138

            
139
/// Tuple implementation of `ChannelStatusProvider`, by default indicating no congestion.
140
#[impl_trait_for_tuples::impl_for_tuples(30)]
141
impl ChannelStatusProvider for Tuple {
142
	fn is_congested(with: &Location) -> bool {
143
		for_tuples!( #(
144
			if Tuple::is_congested(with) {
145
				return true;
146
			}
147
		)* );
148

            
149
		false
150
	}
151
}
152

            
153
/// Bridge state.
154
#[derive(Clone, Copy, Decode, Encode, Eq, PartialEq, TypeInfo, MaxEncodedLen, RuntimeDebug)]
155
pub enum BridgeState {
156
65654
	/// Bridge is opened. Associated lanes are also opened.
157
	Opened,
158
49178
	/// Bridge is suspended. Associated lanes are opened.
159
	/// *suspended* means that we have sent the "Suspended" message/signal to the local bridge
160
	/// origin.
161
	///
162
	/// We keep accepting messages to the bridge to allow any inflight messages to be processed.
163
	SoftSuspended,
164
7
	/// Bridge is suspended and new messages are now being actively dropped.
165
	HardSuspended,
166
4
	/// Bridge is closed. Associated lanes are also closed.
167
	/// After all outbound messages will be pruned, the bridge will vanish without any traces.
168
	Closed,
169
}
170

            
171
/// Bridge metadata.
172
#[derive(
173
	CloneNoBound, Decode, Encode, Eq, PartialEqNoBound, TypeInfo, MaxEncodedLen, RuntimeDebugNoBound,
174
)]
175
#[scale_info(skip_type_params(ThisChain, LaneId))]
176
pub struct Bridge<ThisChain: Chain, LaneId: LaneIdType> {
177
	/// Relative location of the bridge origin chain. This is expected to be **convertible** to the
178
	/// `latest` XCM, so the check and migration needs to be ensured.
179
	pub bridge_origin_relative_location: Box<VersionedLocation>,
180

            
181
	/// See [`BridgeLocations::bridge_origin_universal_location`].
182
	/// Stored for `BridgeId` sanity check.
183
	pub bridge_origin_universal_location: Box<VersionedInteriorLocation>,
184
	/// See [`BridgeLocations::bridge_destination_universal_location`].
185
	/// Stored for `BridgeId` sanity check.
186
	pub bridge_destination_universal_location: Box<VersionedInteriorLocation>,
187

            
188
	/// Current bridge state.
189
	pub state: BridgeState,
190

            
191
	/// Reserved amount on the sovereign account of the sibling bridge origin.
192
	/// The account is derived from `self.bridge_origin_relative_location`.
193
	pub deposit: Option<DepositOf<ThisChain>>,
194

            
195
	/// Mapping to the unique `LaneId`.
196
	pub lane_id: LaneId,
197

            
198
	/// Holds data about the `bridge_origin_relative_location` where notifications can be sent for
199
	/// handling congestion.
200
	pub maybe_notify: Option<Receiver>,
201
}
202

            
203
/// Receiver metadata.
204
#[derive(
205
	CloneNoBound,
206
	Decode,
207
	Encode,
208
	Eq,
209
	PartialEqNoBound,
210
	TypeInfo,
211
	MaxEncodedLen,
212
	RuntimeDebugNoBound,
213
	Serialize,
214
	Deserialize,
215
)]
216
pub struct Receiver {
217
	/// Pallet index.
218
	pub pallet_index: u8,
219
	/// Call/extrinsic index.
220
	pub call_index: u8,
221
}
222

            
223
impl Receiver {
224
	/// Create a new receiver.
225
11
	pub fn new(pallet_index: u8, call_index: u8) -> Self {
226
11
		Self {
227
11
			pallet_index,
228
11
			call_index,
229
11
		}
230
11
	}
231
}
232

            
233
/// An alias for the bridge deposit of `ThisChain`.
234
pub type DepositOf<ThisChain> = Deposit<AccountIdOf<ThisChain>, BalanceOf<ThisChain>>;
235

            
236
/// A structure containing information about from whom the deposit is reserved.
237
#[derive(Clone, Decode, Encode, Eq, PartialEq, TypeInfo, MaxEncodedLen, RuntimeDebug)]
238
pub struct Deposit<AccountId, Balance> {
239
	/// Account with the reserved funds.
240
	pub account: AccountId,
241
	/// Reserved amount.
242
	pub amount: Balance,
243
}
244

            
245
impl<AccountId, Balance> Deposit<AccountId, Balance> {
246
	/// Create new deposit.
247
22
	pub fn new(account: AccountId, amount: Balance) -> Self {
248
22
		Self { account, amount }
249
22
	}
250
}
251

            
252
/// Locations of bridge endpoints at both sides of the bridge.
253
#[derive(Clone, RuntimeDebug, PartialEq, Eq)]
254
pub struct BridgeLocations {
255
	/// Relative (to this bridge hub) location of this side of the bridge.
256
	bridge_origin_relative_location: Location,
257
	/// Universal (unique) location of this side of the bridge.
258
	bridge_origin_universal_location: InteriorLocation,
259
	/// Universal (unique) location of other side of the bridge.
260
	bridge_destination_universal_location: InteriorLocation,
261
	/// An identifier of the dedicated bridge message lane.
262
	bridge_id: BridgeId,
263
}
264

            
265
/// Errors that may happen when we check bridge locations.
266
#[derive(Encode, Decode, RuntimeDebug, PartialEq, Eq, PalletError, TypeInfo)]
267
pub enum BridgeLocationsError {
268
	/// Origin or destination locations are not universal.
269
	NonUniversalLocation,
270
	/// Bridge origin location is not supported.
271
	InvalidBridgeOrigin,
272
	/// Bridge destination is not supported (in general).
273
	InvalidBridgeDestination,
274
	/// Destination location is within the same global consensus.
275
	DestinationIsLocal,
276
	/// Destination network is not the network we are bridged with.
277
	UnreachableDestination,
278
	/// Destination location is unsupported. We only support bridges with relay
279
	/// chain or its parachains.
280
	UnsupportedDestinationLocation,
281
	/// The version of XCM location argument is unsupported.
282
	UnsupportedXcmVersion,
283
	/// The `LaneIdType` generator is not supported.
284
	UnsupportedLaneIdType,
285
}
286

            
287
impl BridgeLocations {
288
	/// Given XCM locations, generate lane id and universal locations of bridge endpoints.
289
	///
290
	/// The `here_universal_location` is the universal location of the bridge hub runtime.
291
	///
292
	/// The `bridge_origin_relative_location` is the relative (to the `here_universal_location`)
293
	/// location of the bridge endpoint at this side of the bridge. It may be the parent relay
294
	/// chain or the sibling parachain. All junctions below parachain level are dropped.
295
	///
296
	/// The `bridge_destination_universal_location` is the universal location of the bridge
297
	/// destination. It may be the parent relay or the sibling parachain of the **bridged**
298
	/// bridge hub. All junctions below parachain level are dropped.
299
	///
300
	/// Why we drop all junctions between parachain level - that's because the lane is a bridge
301
	/// between two chains. All routing under this level happens when the message is delivered
302
	/// to the bridge destination. So at bridge level we don't care about low level junctions.
303
	///
304
	/// Returns error if `bridge_origin_relative_location` is outside of `here_universal_location`
305
	/// local consensus OR if `bridge_destination_universal_location` is not a universal location.
306
164010
	pub fn bridge_locations(
307
164010
		here_universal_location: InteriorLocation,
308
164010
		bridge_origin_relative_location: Location,
309
164010
		bridge_destination_universal_location: InteriorLocation,
310
164010
		expected_remote_network: NetworkId,
311
164010
	) -> Result<Box<Self>, BridgeLocationsError> {
312
327984
		fn strip_low_level_junctions(
313
327984
			location: InteriorLocation,
314
327984
		) -> Result<InteriorLocation, BridgeLocationsError> {
315
327984
			let mut junctions = location.into_iter();
316

            
317
327984
			let global_consensus = junctions
318
327984
				.next()
319
327984
				.filter(|junction| matches!(junction, GlobalConsensus(_)))
320
327984
				.ok_or(BridgeLocationsError::NonUniversalLocation)?;
321

            
322
			// we only expect `Parachain` junction here. There are other junctions that
323
			// may need to be supported (like `GeneralKey` and `OnlyChild`), but now we
324
			// only support bridges with relay and parachans
325
			//
326
			// if there's something other than parachain, let's strip it
327
327984
			let maybe_parachain = junctions
328
327984
				.next()
329
327984
				.filter(|junction| matches!(junction, Parachain(_)));
330
327984
			Ok(match maybe_parachain {
331
327928
				Some(parachain) => [global_consensus, parachain].into(),
332
56
				None => [global_consensus].into(),
333
			})
334
327984
		}
335

            
336
		// ensure that the `here_universal_location` and `bridge_destination_universal_location`
337
		// are universal locations within different consensus systems
338
164010
		let local_network = here_universal_location
339
164010
			.global_consensus()
340
164010
			.map_err(|_| BridgeLocationsError::NonUniversalLocation)?;
341
164009
		let remote_network = bridge_destination_universal_location
342
164009
			.global_consensus()
343
164009
			.map_err(|_| BridgeLocationsError::NonUniversalLocation)?;
344
164008
		ensure!(
345
164008
			local_network != remote_network,
346
3
			BridgeLocationsError::DestinationIsLocal
347
		);
348
164005
		ensure!(
349
164005
			remote_network == expected_remote_network,
350
5
			BridgeLocationsError::UnreachableDestination
351
		);
352

            
353
		// get universal location of endpoint, located at this side of the bridge
354
164000
		let bridge_origin_universal_location = here_universal_location
355
164000
			.within_global(bridge_origin_relative_location.clone())
356
164000
			.map_err(|_| BridgeLocationsError::InvalidBridgeOrigin)?;
357
		// strip low-level junctions within universal locations
358
163992
		let bridge_origin_universal_location =
359
163992
			strip_low_level_junctions(bridge_origin_universal_location)?;
360
163992
		let bridge_destination_universal_location =
361
163992
			strip_low_level_junctions(bridge_destination_universal_location)?;
362

            
363
		// we know that the `bridge_destination_universal_location` starts from the
364
		// `GlobalConsensus` and we know that the `bridge_origin_universal_location`
365
		// is also within the `GlobalConsensus`. So we know that the lane id will be
366
		// the same on both ends of the bridge
367
163992
		let bridge_id = BridgeId::new(
368
163992
			&bridge_origin_universal_location,
369
163992
			&bridge_destination_universal_location,
370
163992
		);
371
163992

            
372
163992
		Ok(Box::new(BridgeLocations {
373
163992
			bridge_origin_relative_location,
374
163992
			bridge_origin_universal_location,
375
163992
			bridge_destination_universal_location,
376
163992
			bridge_id,
377
163992
		}))
378
164010
	}
379

            
380
	/// Getter for `bridge_origin_relative_location`
381
93
	pub fn bridge_origin_relative_location(&self) -> &Location {
382
93
		&self.bridge_origin_relative_location
383
93
	}
384

            
385
	/// Getter for `bridge_origin_universal_location`
386
32826
	pub fn bridge_origin_universal_location(&self) -> &InteriorLocation {
387
32826
		&self.bridge_origin_universal_location
388
32826
	}
389

            
390
	/// Getter for `bridge_destination_universal_location`
391
32838
	pub fn bridge_destination_universal_location(&self) -> &InteriorLocation {
392
32838
		&self.bridge_destination_universal_location
393
32838
	}
394

            
395
	/// Getter for `bridge_id`
396
164040
	pub fn bridge_id(&self) -> &BridgeId {
397
164040
		&self.bridge_id
398
164040
	}
399

            
400
	/// Generates the exact same `LaneId` on the both bridge hubs.
401
	///
402
	/// Note: Use this **only** when opening a new bridge.
403
32808
	pub fn calculate_lane_id<LaneId: LaneIdType>(
404
32808
		&self,
405
32808
		xcm_version: XcmVersion,
406
32808
	) -> Result<LaneId, BridgeLocationsError> {
407
32808
		// a tricky helper struct that adds required `Ord` support for
408
32808
		// `VersionedInteriorLocation`
409
32808
		#[derive(Eq, PartialEq, Ord, PartialOrd)]
410
32808
		struct EncodedVersionedInteriorLocation(sp_std::vec::Vec<u8>);
411
32808
		impl Encode for EncodedVersionedInteriorLocation {
412
131224
			fn encode(&self) -> sp_std::vec::Vec<u8> {
413
131224
				self.0.clone()
414
131224
			}
415
32808
		}
416
32808

            
417
32808
		let universal_location1 =
418
32808
			VersionedInteriorLocation::from(self.bridge_origin_universal_location.clone())
419
32808
				.into_version(xcm_version)
420
32808
				.map_err(|_| BridgeLocationsError::UnsupportedXcmVersion);
421
32808
		let universal_location2 =
422
32808
			VersionedInteriorLocation::from(self.bridge_destination_universal_location.clone())
423
32808
				.into_version(xcm_version)
424
32808
				.map_err(|_| BridgeLocationsError::UnsupportedXcmVersion);
425
32808

            
426
32808
		LaneId::try_new(
427
32808
			EncodedVersionedInteriorLocation(universal_location1.encode()),
428
32808
			EncodedVersionedInteriorLocation(universal_location2.encode()),
429
32808
		)
430
32808
		.map_err(|_| BridgeLocationsError::UnsupportedLaneIdType)
431
32808
	}
432
}
433

            
434
#[cfg(test)]
435
mod tests {
436
	use super::*;
437

            
438
	const LOCAL_NETWORK: NetworkId = Kusama;
439
	const REMOTE_NETWORK: NetworkId = Polkadot;
440
	const UNREACHABLE_NETWORK: NetworkId = NetworkId::Rococo;
441
	const SIBLING_PARACHAIN: u32 = 1000;
442
	const LOCAL_BRIDGE_HUB: u32 = 1001;
443
	const REMOTE_PARACHAIN: u32 = 2000;
444

            
445
	struct SuccessfulTest {
446
		here_universal_location: InteriorLocation,
447
		bridge_origin_relative_location: Location,
448

            
449
		bridge_origin_universal_location: InteriorLocation,
450
		bridge_destination_universal_location: InteriorLocation,
451

            
452
		expected_remote_network: NetworkId,
453
	}
454

            
455
14
	fn run_successful_test(test: SuccessfulTest) -> BridgeLocations {
456
14
		let locations = BridgeLocations::bridge_locations(
457
14
			test.here_universal_location,
458
14
			test.bridge_origin_relative_location.clone(),
459
14
			test.bridge_destination_universal_location.clone(),
460
14
			test.expected_remote_network,
461
14
		);
462
14
		assert_eq!(
463
14
			locations,
464
14
			Ok(Box::new(BridgeLocations {
465
14
				bridge_origin_relative_location: test.bridge_origin_relative_location,
466
14
				bridge_origin_universal_location: test.bridge_origin_universal_location.clone(),
467
14
				bridge_destination_universal_location: test
468
14
					.bridge_destination_universal_location
469
14
					.clone(),
470
14
				bridge_id: BridgeId::new(
471
14
					&test.bridge_origin_universal_location,
472
14
					&test.bridge_destination_universal_location,
473
14
				),
474
14
			})),
475
14
		);
476

            
477
14
		*locations.unwrap()
478
14
	}
479

            
480
	// successful tests that with various origins and destinations
481

            
482
	#[test]
483
1
	fn at_relay_from_local_relay_to_remote_relay_works() {
484
1
		run_successful_test(SuccessfulTest {
485
1
			here_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(),
486
1
			bridge_origin_relative_location: Here.into(),
487
1

            
488
1
			bridge_origin_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(),
489
1
			bridge_destination_universal_location: [GlobalConsensus(REMOTE_NETWORK)].into(),
490
1

            
491
1
			expected_remote_network: REMOTE_NETWORK,
492
1
		});
493
1
	}
494

            
495
	#[test]
496
1
	fn at_relay_from_sibling_parachain_to_remote_relay_works() {
497
1
		run_successful_test(SuccessfulTest {
498
1
			here_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(),
499
1
			bridge_origin_relative_location: [Parachain(SIBLING_PARACHAIN)].into(),
500
1

            
501
1
			bridge_origin_universal_location: [
502
1
				GlobalConsensus(LOCAL_NETWORK),
503
1
				Parachain(SIBLING_PARACHAIN),
504
1
			]
505
1
			.into(),
506
1
			bridge_destination_universal_location: [GlobalConsensus(REMOTE_NETWORK)].into(),
507
1

            
508
1
			expected_remote_network: REMOTE_NETWORK,
509
1
		});
510
1
	}
511

            
512
	#[test]
513
1
	fn at_relay_from_local_relay_to_remote_parachain_works() {
514
1
		run_successful_test(SuccessfulTest {
515
1
			here_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(),
516
1
			bridge_origin_relative_location: Here.into(),
517
1

            
518
1
			bridge_origin_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(),
519
1
			bridge_destination_universal_location: [
520
1
				GlobalConsensus(REMOTE_NETWORK),
521
1
				Parachain(REMOTE_PARACHAIN),
522
1
			]
523
1
			.into(),
524
1

            
525
1
			expected_remote_network: REMOTE_NETWORK,
526
1
		});
527
1
	}
528

            
529
	#[test]
530
1
	fn at_relay_from_sibling_parachain_to_remote_parachain_works() {
531
1
		run_successful_test(SuccessfulTest {
532
1
			here_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(),
533
1
			bridge_origin_relative_location: [Parachain(SIBLING_PARACHAIN)].into(),
534
1

            
535
1
			bridge_origin_universal_location: [
536
1
				GlobalConsensus(LOCAL_NETWORK),
537
1
				Parachain(SIBLING_PARACHAIN),
538
1
			]
539
1
			.into(),
540
1
			bridge_destination_universal_location: [
541
1
				GlobalConsensus(REMOTE_NETWORK),
542
1
				Parachain(REMOTE_PARACHAIN),
543
1
			]
544
1
			.into(),
545
1

            
546
1
			expected_remote_network: REMOTE_NETWORK,
547
1
		});
548
1
	}
549

            
550
	#[test]
551
1
	fn at_bridge_hub_from_local_relay_to_remote_relay_works() {
552
1
		run_successful_test(SuccessfulTest {
553
1
			here_universal_location: [GlobalConsensus(LOCAL_NETWORK), Parachain(LOCAL_BRIDGE_HUB)]
554
1
				.into(),
555
1
			bridge_origin_relative_location: Parent.into(),
556
1

            
557
1
			bridge_origin_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(),
558
1
			bridge_destination_universal_location: [GlobalConsensus(REMOTE_NETWORK)].into(),
559
1

            
560
1
			expected_remote_network: REMOTE_NETWORK,
561
1
		});
562
1
	}
563

            
564
	#[test]
565
1
	fn at_bridge_hub_from_sibling_parachain_to_remote_relay_works() {
566
1
		run_successful_test(SuccessfulTest {
567
1
			here_universal_location: [GlobalConsensus(LOCAL_NETWORK), Parachain(LOCAL_BRIDGE_HUB)]
568
1
				.into(),
569
1
			bridge_origin_relative_location: ParentThen([Parachain(SIBLING_PARACHAIN)].into())
570
1
				.into(),
571
1

            
572
1
			bridge_origin_universal_location: [
573
1
				GlobalConsensus(LOCAL_NETWORK),
574
1
				Parachain(SIBLING_PARACHAIN),
575
1
			]
576
1
			.into(),
577
1
			bridge_destination_universal_location: [GlobalConsensus(REMOTE_NETWORK)].into(),
578
1

            
579
1
			expected_remote_network: REMOTE_NETWORK,
580
1
		});
581
1
	}
582

            
583
	#[test]
584
1
	fn at_bridge_hub_from_local_relay_to_remote_parachain_works() {
585
1
		run_successful_test(SuccessfulTest {
586
1
			here_universal_location: [GlobalConsensus(LOCAL_NETWORK), Parachain(LOCAL_BRIDGE_HUB)]
587
1
				.into(),
588
1
			bridge_origin_relative_location: Parent.into(),
589
1

            
590
1
			bridge_origin_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(),
591
1
			bridge_destination_universal_location: [
592
1
				GlobalConsensus(REMOTE_NETWORK),
593
1
				Parachain(REMOTE_PARACHAIN),
594
1
			]
595
1
			.into(),
596
1

            
597
1
			expected_remote_network: REMOTE_NETWORK,
598
1
		});
599
1
	}
600

            
601
	#[test]
602
1
	fn at_bridge_hub_from_sibling_parachain_to_remote_parachain_works() {
603
1
		run_successful_test(SuccessfulTest {
604
1
			here_universal_location: [GlobalConsensus(LOCAL_NETWORK), Parachain(LOCAL_BRIDGE_HUB)]
605
1
				.into(),
606
1
			bridge_origin_relative_location: ParentThen([Parachain(SIBLING_PARACHAIN)].into())
607
1
				.into(),
608
1

            
609
1
			bridge_origin_universal_location: [
610
1
				GlobalConsensus(LOCAL_NETWORK),
611
1
				Parachain(SIBLING_PARACHAIN),
612
1
			]
613
1
			.into(),
614
1
			bridge_destination_universal_location: [
615
1
				GlobalConsensus(REMOTE_NETWORK),
616
1
				Parachain(REMOTE_PARACHAIN),
617
1
			]
618
1
			.into(),
619
1

            
620
1
			expected_remote_network: REMOTE_NETWORK,
621
1
		});
622
1
	}
623

            
624
	// successful tests that show that we are ignoring low-level junctions of bridge origins
625

            
626
	#[test]
627
1
	fn low_level_junctions_at_bridge_origin_are_stripped() {
628
1
		let locations1 = run_successful_test(SuccessfulTest {
629
1
			here_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(),
630
1
			bridge_origin_relative_location: Here.into(),
631
1

            
632
1
			bridge_origin_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(),
633
1
			bridge_destination_universal_location: [GlobalConsensus(REMOTE_NETWORK)].into(),
634
1

            
635
1
			expected_remote_network: REMOTE_NETWORK,
636
1
		});
637
1
		let locations2 = run_successful_test(SuccessfulTest {
638
1
			here_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(),
639
1
			bridge_origin_relative_location: [PalletInstance(0)].into(),
640
1

            
641
1
			bridge_origin_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(),
642
1
			bridge_destination_universal_location: [GlobalConsensus(REMOTE_NETWORK)].into(),
643
1

            
644
1
			expected_remote_network: REMOTE_NETWORK,
645
1
		});
646
1

            
647
1
		assert_eq!(locations1.bridge_id, locations2.bridge_id);
648
1
	}
649

            
650
	#[test]
651
1
	fn low_level_junctions_at_bridge_destination_are_stripped() {
652
1
		let locations1 = run_successful_test(SuccessfulTest {
653
1
			here_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(),
654
1
			bridge_origin_relative_location: Here.into(),
655
1

            
656
1
			bridge_origin_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(),
657
1
			bridge_destination_universal_location: [GlobalConsensus(REMOTE_NETWORK)].into(),
658
1

            
659
1
			expected_remote_network: REMOTE_NETWORK,
660
1
		});
661
1
		let locations2 = run_successful_test(SuccessfulTest {
662
1
			here_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(),
663
1
			bridge_origin_relative_location: Here.into(),
664
1

            
665
1
			bridge_origin_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(),
666
1
			bridge_destination_universal_location: [GlobalConsensus(REMOTE_NETWORK)].into(),
667
1

            
668
1
			expected_remote_network: REMOTE_NETWORK,
669
1
		});
670
1

            
671
1
		assert_eq!(locations1.bridge_id, locations2.bridge_id);
672
1
	}
673

            
674
	#[test]
675
1
	fn calculate_lane_id_works() {
676
1
		type TestLaneId = bp_messages::HashedLaneId;
677
1

            
678
1
		let from_local_to_remote = run_successful_test(SuccessfulTest {
679
1
			here_universal_location: [GlobalConsensus(LOCAL_NETWORK), Parachain(LOCAL_BRIDGE_HUB)]
680
1
				.into(),
681
1
			bridge_origin_relative_location: ParentThen([Parachain(SIBLING_PARACHAIN)].into())
682
1
				.into(),
683
1

            
684
1
			bridge_origin_universal_location: [
685
1
				GlobalConsensus(LOCAL_NETWORK),
686
1
				Parachain(SIBLING_PARACHAIN),
687
1
			]
688
1
			.into(),
689
1
			bridge_destination_universal_location: [
690
1
				GlobalConsensus(REMOTE_NETWORK),
691
1
				Parachain(REMOTE_PARACHAIN),
692
1
			]
693
1
			.into(),
694
1

            
695
1
			expected_remote_network: REMOTE_NETWORK,
696
1
		});
697
1

            
698
1
		let from_remote_to_local = run_successful_test(SuccessfulTest {
699
1
			here_universal_location: [GlobalConsensus(REMOTE_NETWORK), Parachain(LOCAL_BRIDGE_HUB)]
700
1
				.into(),
701
1
			bridge_origin_relative_location: ParentThen([Parachain(REMOTE_PARACHAIN)].into())
702
1
				.into(),
703
1

            
704
1
			bridge_origin_universal_location: [
705
1
				GlobalConsensus(REMOTE_NETWORK),
706
1
				Parachain(REMOTE_PARACHAIN),
707
1
			]
708
1
			.into(),
709
1
			bridge_destination_universal_location: [
710
1
				GlobalConsensus(LOCAL_NETWORK),
711
1
				Parachain(SIBLING_PARACHAIN),
712
1
			]
713
1
			.into(),
714
1

            
715
1
			expected_remote_network: LOCAL_NETWORK,
716
1
		});
717
1

            
718
1
		assert_ne!(
719
1
			from_local_to_remote.calculate_lane_id::<TestLaneId>(xcm::latest::VERSION),
720
1
			from_remote_to_local.calculate_lane_id::<TestLaneId>(xcm::latest::VERSION - 1),
721
1
		);
722
1
		assert_eq!(
723
1
			from_local_to_remote.calculate_lane_id::<TestLaneId>(xcm::latest::VERSION),
724
1
			from_remote_to_local.calculate_lane_id::<TestLaneId>(xcm::latest::VERSION),
725
1
		);
726
1
	}
727

            
728
	// negative tests
729

            
730
	#[test]
731
1
	fn bridge_locations_fails_when_here_is_not_universal_location() {
732
1
		assert_eq!(
733
1
			BridgeLocations::bridge_locations(
734
1
				[Parachain(1000)].into(),
735
1
				Here.into(),
736
1
				[GlobalConsensus(REMOTE_NETWORK)].into(),
737
1
				REMOTE_NETWORK,
738
1
			),
739
1
			Err(BridgeLocationsError::NonUniversalLocation),
740
1
		);
741
1
	}
742

            
743
	#[test]
744
1
	fn bridge_locations_fails_when_computed_destination_is_not_universal_location() {
745
1
		assert_eq!(
746
1
			BridgeLocations::bridge_locations(
747
1
				[GlobalConsensus(LOCAL_NETWORK)].into(),
748
1
				Here.into(),
749
1
				[OnlyChild].into(),
750
1
				REMOTE_NETWORK,
751
1
			),
752
1
			Err(BridgeLocationsError::NonUniversalLocation),
753
1
		);
754
1
	}
755

            
756
	#[test]
757
1
	fn bridge_locations_fails_when_computed_destination_is_local() {
758
1
		assert_eq!(
759
1
			BridgeLocations::bridge_locations(
760
1
				[GlobalConsensus(LOCAL_NETWORK)].into(),
761
1
				Here.into(),
762
1
				[GlobalConsensus(LOCAL_NETWORK), OnlyChild].into(),
763
1
				REMOTE_NETWORK,
764
1
			),
765
1
			Err(BridgeLocationsError::DestinationIsLocal),
766
1
		);
767
1
	}
768

            
769
	#[test]
770
1
	fn bridge_locations_fails_when_computed_destination_is_unreachable() {
771
1
		assert_eq!(
772
1
			BridgeLocations::bridge_locations(
773
1
				[GlobalConsensus(LOCAL_NETWORK)].into(),
774
1
				Here.into(),
775
1
				[GlobalConsensus(UNREACHABLE_NETWORK)].into(),
776
1
				REMOTE_NETWORK,
777
1
			),
778
1
			Err(BridgeLocationsError::UnreachableDestination),
779
1
		);
780
1
	}
781
}