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
		const VALUES_SEPARATOR: [u8; 33] = *b"bridges-bridge-id-value-separator";
83

            
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
		// a tricky helper struct that adds required `Ord` support for
408
		// `VersionedInteriorLocation`
409
		#[derive(Eq, PartialEq, Ord, PartialOrd)]
410
		struct EncodedVersionedInteriorLocation(sp_std::vec::Vec<u8>);
411
		impl Encode for EncodedVersionedInteriorLocation {
412
131224
			fn encode(&self) -> sp_std::vec::Vec<u8> {
413
131224
				self.0.clone()
414
131224
			}
415
		}
416

            
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
	use xcm::latest::ROCOCO_GENESIS_HASH;
438

            
439
	const LOCAL_NETWORK: NetworkId = Kusama;
440
	const REMOTE_NETWORK: NetworkId = Polkadot;
441
	const UNREACHABLE_NETWORK: NetworkId = NetworkId::ByGenesis(ROCOCO_GENESIS_HASH);
442
	const SIBLING_PARACHAIN: u32 = 1000;
443
	const LOCAL_BRIDGE_HUB: u32 = 1001;
444
	const REMOTE_PARACHAIN: u32 = 2000;
445

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

            
450
		bridge_origin_universal_location: InteriorLocation,
451
		bridge_destination_universal_location: InteriorLocation,
452

            
453
		expected_remote_network: NetworkId,
454
	}
455

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            
729
	// negative tests
730

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

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

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

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