fix: Complete snowbridge pezpallet rebrand and critical bug fixes

- snowbridge-pezpallet-* → pezsnowbridge-pezpallet-* (201 refs)
- pallet/ directories → pezpallet/ (4 locations)
- Fixed pezpallet.rs self-include recursion bug
- Fixed sc-chain-spec hardcoded crate name in derive macro
- Reverted .pezpallet_by_name() to .pallet_by_name() (subxt API)
- Added BizinikiwiConfig type alias for zombienet tests
- Deleted obsolete session state files

Verified: pezsnowbridge-pezpallet-*, pezpallet-staking,
pezpallet-staking-async, pezframe-benchmarking-cli all pass cargo check
This commit is contained in:
2025-12-16 09:57:23 +03:00
parent eea003e14d
commit 3139ffa25e
3022 changed files with 42157 additions and 23579 deletions
@@ -0,0 +1,43 @@
// Copyright (C) Parity Technologies (UK) Ltd.
// This file is part of Parity Bridges Common.
// Parity Bridges Common is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity Bridges Common is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
//! Defines structures related to calls of the `pezpallet-xcm-bridge-hub` pezpallet.
use bp_messages::MessageNonce;
use codec::{Decode, Encode};
use scale_info::TypeInfo;
use pezsp_std::boxed::Box;
use xcm::prelude::VersionedInteriorLocation;
/// A minimized version of `pezpallet_xcm_bridge_hub::Call` that can be used without a runtime.
#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)]
#[allow(non_camel_case_types)]
pub enum XcmBridgeHubCall {
/// `pezpallet_xcm_bridge_hub::Call::open_bridge`
#[codec(index = 0)]
open_bridge {
/// Universal `InteriorLocation` from the bridged consensus.
bridge_destination_universal_location: Box<VersionedInteriorLocation>,
},
/// `pezpallet_xcm_bridge_hub::Call::close_bridge`
#[codec(index = 1)]
close_bridge {
/// Universal `InteriorLocation` from the bridged consensus.
bridge_destination_universal_location: Box<VersionedInteriorLocation>,
/// The number of messages that we may prune in a single call.
may_prune_messages: MessageNonce,
},
}
@@ -0,0 +1,715 @@
// Copyright 2019-2021 Parity Technologies (UK) Ltd.
// This file is part of Parity Bridges Common.
// Parity Bridges Common is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity Bridges Common is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
//! Primitives of the xcm-bridge-hub pezpallet.
#![warn(missing_docs)]
#![cfg_attr(not(feature = "std"), no_std)]
use bp_messages::LaneIdType;
use pezbp_runtime::{AccountIdOf, BalanceOf, Chain};
pub use call_info::XcmBridgeHubCall;
use codec::{Decode, DecodeWithMemTracking, Encode, MaxEncodedLen};
use pezframe_support::{
ensure, pezsp_runtime::RuntimeDebug, CloneNoBound, PalletError, PartialEqNoBound,
RuntimeDebugNoBound,
};
use scale_info::TypeInfo;
use serde::{Deserialize, Serialize};
use pezsp_core::H256;
use pezsp_io::hashing::blake2_256;
use pezsp_std::boxed::Box;
use xcm::{
latest::prelude::*, prelude::XcmVersion, IntoVersion, VersionedInteriorLocation,
VersionedLocation,
};
mod call_info;
/// Encoded XCM blob. We expect the bridge messages pezpallet to use this blob type for both inbound
/// and outbound payloads.
pub type XcmAsPlainPayload = pezsp_std::vec::Vec<u8>;
/// Bridge identifier - used **only** for communicating with sibling/parent chains in the same
/// consensus.
///
/// For example, `SendXcm` implementations (which use the `latest` XCM) can use it to identify a
/// bridge and the corresponding `LaneId` that is used for over-consensus communication between
/// bridge hubs.
///
/// This identifier is constructed from the `latest` XCM, so it is expected to ensure migration to
/// the `latest` XCM version. This could change the `BridgeId`, but it will not affect the `LaneId`.
/// In other words, `LaneId` will never change, while `BridgeId` could change with (every) XCM
/// upgrade.
#[derive(
Clone,
Copy,
Decode,
Encode,
DecodeWithMemTracking,
Eq,
Ord,
PartialOrd,
PartialEq,
TypeInfo,
MaxEncodedLen,
Serialize,
Deserialize,
)]
pub struct BridgeId(H256);
impl BridgeId {
/// Create bridge identifier from two universal locations.
///
/// Note: The `BridgeId` is constructed from `latest` XCM, so if stored, you need to ensure
/// compatibility with newer XCM versions.
pub fn new(
universal_source: &InteriorLocation,
universal_destination: &InteriorLocation,
) -> Self {
const VALUES_SEPARATOR: [u8; 33] = *b"bridges-bridge-id-value-separator";
BridgeId(
(universal_source, VALUES_SEPARATOR, universal_destination)
.using_encoded(blake2_256)
.into(),
)
}
/// Access the inner representation.
pub fn inner(&self) -> H256 {
self.0
}
}
impl core::fmt::Debug for BridgeId {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
core::fmt::Debug::fmt(&self.0, f)
}
}
/// Local XCM channel manager.
pub trait LocalXcmChannelManager {
/// Error that may be returned when suspending/resuming the bridge.
type Error: pezsp_std::fmt::Debug;
/// Returns true if the channel with given location is currently congested.
///
/// The `with` is guaranteed to be in the same consensus. However, it may point to something
/// below the chain level - like the contract or pezpallet instance, for example.
fn is_congested(with: &Location) -> bool;
/// Suspend the bridge, opened by given origin.
///
/// The `local_origin` is guaranteed to be in the same consensus. However, it may point to
/// something below the chain level - like the contract or pezpallet instance, for example.
fn suspend_bridge(local_origin: &Location, bridge: BridgeId) -> Result<(), Self::Error>;
/// Resume the previously suspended bridge, opened by given origin.
///
/// The `local_origin` is guaranteed to be in the same consensus. However, it may point to
/// something below the chain level - like the contract or pezpallet instance, for example.
fn resume_bridge(local_origin: &Location, bridge: BridgeId) -> Result<(), Self::Error>;
}
impl LocalXcmChannelManager for () {
type Error = ();
fn is_congested(_with: &Location) -> bool {
false
}
fn suspend_bridge(_local_origin: &Location, _bridge: BridgeId) -> Result<(), Self::Error> {
Ok(())
}
fn resume_bridge(_local_origin: &Location, _bridge: BridgeId) -> Result<(), Self::Error> {
Ok(())
}
}
/// Bridge state.
#[derive(Clone, Copy, Decode, Encode, Eq, PartialEq, TypeInfo, MaxEncodedLen, RuntimeDebug)]
pub enum BridgeState {
/// Bridge is opened. Associated lanes are also opened.
Opened,
/// Bridge is suspended. Associated lanes are opened.
///
/// We keep accepting messages to the bridge. The only difference with the `Opened` state
/// is that we have sent the "Suspended" message/signal to the local bridge origin.
Suspended,
/// Bridge is closed. Associated lanes are also closed.
/// After all outbound messages will be pruned, the bridge will vanish without any traces.
Closed,
}
/// Bridge metadata.
#[derive(
CloneNoBound, Decode, Encode, Eq, PartialEqNoBound, TypeInfo, MaxEncodedLen, RuntimeDebugNoBound,
)]
#[scale_info(skip_type_params(ThisChain, LaneId))]
pub struct Bridge<ThisChain: Chain, LaneId: LaneIdType> {
/// Relative location of the bridge origin chain. This is expected to be **convertible** to the
/// `latest` XCM, so the check and migration needs to be ensured.
pub bridge_origin_relative_location: Box<VersionedLocation>,
/// See [`BridgeLocations::bridge_origin_universal_location`].
/// Stored for `BridgeId` sanity check.
pub bridge_origin_universal_location: Box<VersionedInteriorLocation>,
/// See [`BridgeLocations::bridge_destination_universal_location`].
/// Stored for `BridgeId` sanity check.
pub bridge_destination_universal_location: Box<VersionedInteriorLocation>,
/// Current bridge state.
pub state: BridgeState,
/// Account with the reserved funds. Derived from `self.bridge_origin_relative_location`.
pub bridge_owner_account: AccountIdOf<ThisChain>,
/// Reserved amount on the sovereign account of the sibling bridge origin.
pub deposit: BalanceOf<ThisChain>,
/// Mapping to the unique `LaneId`.
pub lane_id: LaneId,
}
/// Locations of bridge endpoints at both sides of the bridge.
#[derive(Clone, RuntimeDebug, PartialEq, Eq)]
pub struct BridgeLocations {
/// Relative (to this bridge hub) location of this side of the bridge.
bridge_origin_relative_location: Location,
/// Universal (unique) location of this side of the bridge.
bridge_origin_universal_location: InteriorLocation,
/// Universal (unique) location of other side of the bridge.
bridge_destination_universal_location: InteriorLocation,
/// An identifier of the dedicated bridge message lane.
bridge_id: BridgeId,
}
/// Errors that may happen when we check bridge locations.
#[derive(
Encode, Decode, DecodeWithMemTracking, RuntimeDebug, PartialEq, Eq, PalletError, TypeInfo,
)]
pub enum BridgeLocationsError {
/// Origin or destination locations are not universal.
NonUniversalLocation,
/// Bridge origin location is not supported.
InvalidBridgeOrigin,
/// Bridge destination is not supported (in general).
InvalidBridgeDestination,
/// Destination location is within the same global consensus.
DestinationIsLocal,
/// Destination network is not the network we are bridged with.
UnreachableDestination,
/// Destination location is unsupported. We only support bridges with relay
/// chain or its teyrchains.
UnsupportedDestinationLocation,
/// The version of XCM location argument is unsupported.
UnsupportedXcmVersion,
/// The `LaneIdType` generator is not supported.
UnsupportedLaneIdType,
}
impl BridgeLocations {
/// Given XCM locations, generate lane id and universal locations of bridge endpoints.
///
/// The `here_universal_location` is the universal location of the bridge hub runtime.
///
/// The `bridge_origin_relative_location` is the relative (to the `here_universal_location`)
/// location of the bridge endpoint at this side of the bridge. It may be the parent relay
/// chain or the sibling teyrchain. All junctions below teyrchain level are dropped.
///
/// The `bridge_destination_universal_location` is the universal location of the bridge
/// destination. It may be the parent relay or the sibling teyrchain of the **bridged**
/// bridge hub. All junctions below teyrchain level are dropped.
///
/// Why we drop all junctions between teyrchain level - that's because the lane is a bridge
/// between two chains. All routing under this level happens when the message is delivered
/// to the bridge destination. So at bridge level we don't care about low level junctions.
///
/// Returns error if `bridge_origin_relative_location` is outside of `here_universal_location`
/// local consensus OR if `bridge_destination_universal_location` is not a universal location.
pub fn bridge_locations(
here_universal_location: InteriorLocation,
bridge_origin_relative_location: Location,
bridge_destination_universal_location: InteriorLocation,
expected_remote_network: NetworkId,
) -> Result<Box<Self>, BridgeLocationsError> {
fn strip_low_level_junctions(
location: InteriorLocation,
) -> Result<InteriorLocation, BridgeLocationsError> {
let mut junctions = location.into_iter();
let global_consensus = junctions
.next()
.filter(|junction| matches!(junction, GlobalConsensus(_)))
.ok_or(BridgeLocationsError::NonUniversalLocation)?;
// we only expect `Teyrchain` junction here. There are other junctions that
// may need to be supported (like `GeneralKey` and `OnlyChild`), but now we
// only support bridges with relay and parachans
//
// if there's something other than teyrchain, let's strip it
let maybe_teyrchain =
junctions.next().filter(|junction| matches!(junction, Teyrchain(_)));
Ok(match maybe_teyrchain {
Some(teyrchain) => [global_consensus, teyrchain].into(),
None => [global_consensus].into(),
})
}
// ensure that the `here_universal_location` and `bridge_destination_universal_location`
// are universal locations within different consensus systems
let local_network = here_universal_location
.global_consensus()
.map_err(|_| BridgeLocationsError::NonUniversalLocation)?;
let remote_network = bridge_destination_universal_location
.global_consensus()
.map_err(|_| BridgeLocationsError::NonUniversalLocation)?;
ensure!(local_network != remote_network, BridgeLocationsError::DestinationIsLocal);
ensure!(
remote_network == expected_remote_network,
BridgeLocationsError::UnreachableDestination
);
// get universal location of endpoint, located at this side of the bridge
let bridge_origin_universal_location = here_universal_location
.within_global(bridge_origin_relative_location.clone())
.map_err(|_| BridgeLocationsError::InvalidBridgeOrigin)?;
// strip low-level junctions within universal locations
let bridge_origin_universal_location =
strip_low_level_junctions(bridge_origin_universal_location)?;
let bridge_destination_universal_location =
strip_low_level_junctions(bridge_destination_universal_location)?;
// we know that the `bridge_destination_universal_location` starts from the
// `GlobalConsensus` and we know that the `bridge_origin_universal_location`
// is also within the `GlobalConsensus`. So we know that the lane id will be
// the same on both ends of the bridge
let bridge_id = BridgeId::new(
&bridge_origin_universal_location,
&bridge_destination_universal_location,
);
Ok(Box::new(BridgeLocations {
bridge_origin_relative_location,
bridge_origin_universal_location,
bridge_destination_universal_location,
bridge_id,
}))
}
/// Getter for `bridge_origin_relative_location`
pub fn bridge_origin_relative_location(&self) -> &Location {
&self.bridge_origin_relative_location
}
/// Getter for `bridge_origin_universal_location`
pub fn bridge_origin_universal_location(&self) -> &InteriorLocation {
&self.bridge_origin_universal_location
}
/// Getter for `bridge_destination_universal_location`
pub fn bridge_destination_universal_location(&self) -> &InteriorLocation {
&self.bridge_destination_universal_location
}
/// Getter for `bridge_id`
pub fn bridge_id(&self) -> &BridgeId {
&self.bridge_id
}
/// Generates the exact same `LaneId` on the both bridge hubs.
///
/// Note: Use this **only** when opening a new bridge.
pub fn calculate_lane_id<LaneId: LaneIdType>(
&self,
xcm_version: XcmVersion,
) -> Result<LaneId, BridgeLocationsError> {
// a tricky helper struct that adds required `Ord` support for
// `VersionedInteriorLocation`
#[derive(Eq, PartialEq, Ord, PartialOrd)]
struct EncodedVersionedInteriorLocation(pezsp_std::vec::Vec<u8>);
impl Encode for EncodedVersionedInteriorLocation {
fn encode(&self) -> pezsp_std::vec::Vec<u8> {
self.0.clone()
}
}
let universal_location1 =
VersionedInteriorLocation::from(self.bridge_origin_universal_location.clone())
.into_version(xcm_version)
.map_err(|_| BridgeLocationsError::UnsupportedXcmVersion);
let universal_location2 =
VersionedInteriorLocation::from(self.bridge_destination_universal_location.clone())
.into_version(xcm_version)
.map_err(|_| BridgeLocationsError::UnsupportedXcmVersion);
LaneId::try_new(
EncodedVersionedInteriorLocation(universal_location1.encode()),
EncodedVersionedInteriorLocation(universal_location2.encode()),
)
.map_err(|_| BridgeLocationsError::UnsupportedLaneIdType)
}
}
#[cfg(test)]
mod tests {
use super::*;
use xcm::latest::PEZKUWICHAIN_GENESIS_HASH;
const LOCAL_NETWORK: NetworkId = Kusama;
const REMOTE_NETWORK: NetworkId = Pezkuwi;
const UNREACHABLE_NETWORK: NetworkId = NetworkId::ByGenesis(PEZKUWICHAIN_GENESIS_HASH);
const SIBLING_TEYRCHAIN: u32 = 1000;
const LOCAL_BRIDGE_HUB: u32 = 1001;
const REMOTE_TEYRCHAIN: u32 = 2000;
struct SuccessfulTest {
here_universal_location: InteriorLocation,
bridge_origin_relative_location: Location,
bridge_origin_universal_location: InteriorLocation,
bridge_destination_universal_location: InteriorLocation,
expected_remote_network: NetworkId,
}
fn run_successful_test(test: SuccessfulTest) -> BridgeLocations {
let locations = BridgeLocations::bridge_locations(
test.here_universal_location,
test.bridge_origin_relative_location.clone(),
test.bridge_destination_universal_location.clone(),
test.expected_remote_network,
);
assert_eq!(
locations,
Ok(Box::new(BridgeLocations {
bridge_origin_relative_location: test.bridge_origin_relative_location,
bridge_origin_universal_location: test.bridge_origin_universal_location.clone(),
bridge_destination_universal_location: test
.bridge_destination_universal_location
.clone(),
bridge_id: BridgeId::new(
&test.bridge_origin_universal_location,
&test.bridge_destination_universal_location,
),
})),
);
*locations.unwrap()
}
// successful tests that with various origins and destinations
#[test]
fn at_relay_from_local_relay_to_remote_relay_works() {
run_successful_test(SuccessfulTest {
here_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(),
bridge_origin_relative_location: Here.into(),
bridge_origin_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(),
bridge_destination_universal_location: [GlobalConsensus(REMOTE_NETWORK)].into(),
expected_remote_network: REMOTE_NETWORK,
});
}
#[test]
fn at_relay_from_sibling_teyrchain_to_remote_relay_works() {
run_successful_test(SuccessfulTest {
here_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(),
bridge_origin_relative_location: [Teyrchain(SIBLING_TEYRCHAIN)].into(),
bridge_origin_universal_location: [
GlobalConsensus(LOCAL_NETWORK),
Teyrchain(SIBLING_TEYRCHAIN),
]
.into(),
bridge_destination_universal_location: [GlobalConsensus(REMOTE_NETWORK)].into(),
expected_remote_network: REMOTE_NETWORK,
});
}
#[test]
fn at_relay_from_local_relay_to_remote_teyrchain_works() {
run_successful_test(SuccessfulTest {
here_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(),
bridge_origin_relative_location: Here.into(),
bridge_origin_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(),
bridge_destination_universal_location: [
GlobalConsensus(REMOTE_NETWORK),
Teyrchain(REMOTE_TEYRCHAIN),
]
.into(),
expected_remote_network: REMOTE_NETWORK,
});
}
#[test]
fn at_relay_from_sibling_teyrchain_to_remote_teyrchain_works() {
run_successful_test(SuccessfulTest {
here_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(),
bridge_origin_relative_location: [Teyrchain(SIBLING_TEYRCHAIN)].into(),
bridge_origin_universal_location: [
GlobalConsensus(LOCAL_NETWORK),
Teyrchain(SIBLING_TEYRCHAIN),
]
.into(),
bridge_destination_universal_location: [
GlobalConsensus(REMOTE_NETWORK),
Teyrchain(REMOTE_TEYRCHAIN),
]
.into(),
expected_remote_network: REMOTE_NETWORK,
});
}
#[test]
fn at_bridge_hub_from_local_relay_to_remote_relay_works() {
run_successful_test(SuccessfulTest {
here_universal_location: [GlobalConsensus(LOCAL_NETWORK), Teyrchain(LOCAL_BRIDGE_HUB)]
.into(),
bridge_origin_relative_location: Parent.into(),
bridge_origin_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(),
bridge_destination_universal_location: [GlobalConsensus(REMOTE_NETWORK)].into(),
expected_remote_network: REMOTE_NETWORK,
});
}
#[test]
fn at_bridge_hub_from_sibling_teyrchain_to_remote_relay_works() {
run_successful_test(SuccessfulTest {
here_universal_location: [GlobalConsensus(LOCAL_NETWORK), Teyrchain(LOCAL_BRIDGE_HUB)]
.into(),
bridge_origin_relative_location: ParentThen([Teyrchain(SIBLING_TEYRCHAIN)].into())
.into(),
bridge_origin_universal_location: [
GlobalConsensus(LOCAL_NETWORK),
Teyrchain(SIBLING_TEYRCHAIN),
]
.into(),
bridge_destination_universal_location: [GlobalConsensus(REMOTE_NETWORK)].into(),
expected_remote_network: REMOTE_NETWORK,
});
}
#[test]
fn at_bridge_hub_from_local_relay_to_remote_teyrchain_works() {
run_successful_test(SuccessfulTest {
here_universal_location: [GlobalConsensus(LOCAL_NETWORK), Teyrchain(LOCAL_BRIDGE_HUB)]
.into(),
bridge_origin_relative_location: Parent.into(),
bridge_origin_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(),
bridge_destination_universal_location: [
GlobalConsensus(REMOTE_NETWORK),
Teyrchain(REMOTE_TEYRCHAIN),
]
.into(),
expected_remote_network: REMOTE_NETWORK,
});
}
#[test]
fn at_bridge_hub_from_sibling_teyrchain_to_remote_teyrchain_works() {
run_successful_test(SuccessfulTest {
here_universal_location: [GlobalConsensus(LOCAL_NETWORK), Teyrchain(LOCAL_BRIDGE_HUB)]
.into(),
bridge_origin_relative_location: ParentThen([Teyrchain(SIBLING_TEYRCHAIN)].into())
.into(),
bridge_origin_universal_location: [
GlobalConsensus(LOCAL_NETWORK),
Teyrchain(SIBLING_TEYRCHAIN),
]
.into(),
bridge_destination_universal_location: [
GlobalConsensus(REMOTE_NETWORK),
Teyrchain(REMOTE_TEYRCHAIN),
]
.into(),
expected_remote_network: REMOTE_NETWORK,
});
}
// successful tests that show that we are ignoring low-level junctions of bridge origins
#[test]
fn low_level_junctions_at_bridge_origin_are_stripped() {
let locations1 = run_successful_test(SuccessfulTest {
here_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(),
bridge_origin_relative_location: Here.into(),
bridge_origin_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(),
bridge_destination_universal_location: [GlobalConsensus(REMOTE_NETWORK)].into(),
expected_remote_network: REMOTE_NETWORK,
});
let locations2 = run_successful_test(SuccessfulTest {
here_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(),
bridge_origin_relative_location: [PalletInstance(0)].into(),
bridge_origin_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(),
bridge_destination_universal_location: [GlobalConsensus(REMOTE_NETWORK)].into(),
expected_remote_network: REMOTE_NETWORK,
});
assert_eq!(locations1.bridge_id, locations2.bridge_id);
}
#[test]
fn low_level_junctions_at_bridge_destination_are_stripped() {
let locations1 = run_successful_test(SuccessfulTest {
here_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(),
bridge_origin_relative_location: Here.into(),
bridge_origin_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(),
bridge_destination_universal_location: [GlobalConsensus(REMOTE_NETWORK)].into(),
expected_remote_network: REMOTE_NETWORK,
});
let locations2 = run_successful_test(SuccessfulTest {
here_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(),
bridge_origin_relative_location: Here.into(),
bridge_origin_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(),
bridge_destination_universal_location: [GlobalConsensus(REMOTE_NETWORK)].into(),
expected_remote_network: REMOTE_NETWORK,
});
assert_eq!(locations1.bridge_id, locations2.bridge_id);
}
#[test]
fn calculate_lane_id_works() {
type TestLaneId = bp_messages::HashedLaneId;
let from_local_to_remote = run_successful_test(SuccessfulTest {
here_universal_location: [GlobalConsensus(LOCAL_NETWORK), Teyrchain(LOCAL_BRIDGE_HUB)]
.into(),
bridge_origin_relative_location: ParentThen([Teyrchain(SIBLING_TEYRCHAIN)].into())
.into(),
bridge_origin_universal_location: [
GlobalConsensus(LOCAL_NETWORK),
Teyrchain(SIBLING_TEYRCHAIN),
]
.into(),
bridge_destination_universal_location: [
GlobalConsensus(REMOTE_NETWORK),
Teyrchain(REMOTE_TEYRCHAIN),
]
.into(),
expected_remote_network: REMOTE_NETWORK,
});
let from_remote_to_local = run_successful_test(SuccessfulTest {
here_universal_location: [GlobalConsensus(REMOTE_NETWORK), Teyrchain(LOCAL_BRIDGE_HUB)]
.into(),
bridge_origin_relative_location: ParentThen([Teyrchain(REMOTE_TEYRCHAIN)].into())
.into(),
bridge_origin_universal_location: [
GlobalConsensus(REMOTE_NETWORK),
Teyrchain(REMOTE_TEYRCHAIN),
]
.into(),
bridge_destination_universal_location: [
GlobalConsensus(LOCAL_NETWORK),
Teyrchain(SIBLING_TEYRCHAIN),
]
.into(),
expected_remote_network: LOCAL_NETWORK,
});
assert_ne!(
from_local_to_remote.calculate_lane_id::<TestLaneId>(xcm::latest::VERSION),
from_remote_to_local.calculate_lane_id::<TestLaneId>(xcm::latest::VERSION - 1),
);
assert_eq!(
from_local_to_remote.calculate_lane_id::<TestLaneId>(xcm::latest::VERSION),
from_remote_to_local.calculate_lane_id::<TestLaneId>(xcm::latest::VERSION),
);
}
// negative tests
#[test]
fn bridge_locations_fails_when_here_is_not_universal_location() {
assert_eq!(
BridgeLocations::bridge_locations(
[Teyrchain(1000)].into(),
Here.into(),
[GlobalConsensus(REMOTE_NETWORK)].into(),
REMOTE_NETWORK,
),
Err(BridgeLocationsError::NonUniversalLocation),
);
}
#[test]
fn bridge_locations_fails_when_computed_destination_is_not_universal_location() {
assert_eq!(
BridgeLocations::bridge_locations(
[GlobalConsensus(LOCAL_NETWORK)].into(),
Here.into(),
[OnlyChild].into(),
REMOTE_NETWORK,
),
Err(BridgeLocationsError::NonUniversalLocation),
);
}
#[test]
fn bridge_locations_fails_when_computed_destination_is_local() {
assert_eq!(
BridgeLocations::bridge_locations(
[GlobalConsensus(LOCAL_NETWORK)].into(),
Here.into(),
[GlobalConsensus(LOCAL_NETWORK), OnlyChild].into(),
REMOTE_NETWORK,
),
Err(BridgeLocationsError::DestinationIsLocal),
);
}
#[test]
fn bridge_locations_fails_when_computed_destination_is_unreachable() {
assert_eq!(
BridgeLocations::bridge_locations(
[GlobalConsensus(LOCAL_NETWORK)].into(),
Here.into(),
[GlobalConsensus(UNREACHABLE_NETWORK)].into(),
REMOTE_NETWORK,
),
Err(BridgeLocationsError::UnreachableDestination),
);
}
}