Skip to content

Commit

Permalink
Add tests that pallet-xcm-bridge-hub-router can work locally with `…
Browse files Browse the repository at this point in the history
…pallet-xcm-bridge-hub` for `ExportXcm` (needed for AH deploymend)
  • Loading branch information
bkontur committed Oct 26, 2024
1 parent e02c25f commit 049d46a
Show file tree
Hide file tree
Showing 3 changed files with 130 additions and 90 deletions.
133 changes: 71 additions & 62 deletions bridges/modules/xcm-bridge-hub/src/exporter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,9 @@ where
let bridge = Self::bridge(locations.bridge_id()).ok_or_else(|| {
log::error!(
target: LOG_TARGET,
"No opened bridge for requested bridge_origin_relative_location: {:?} and bridge_destination_universal_location: {:?}",
"No opened bridge for requested bridge_origin_relative_location: {:?} (bridge_origin_universal_location: {:?}) and bridge_destination_universal_location: {:?}",
locations.bridge_origin_relative_location(),
locations.bridge_origin_universal_location(),
locations.bridge_destination_universal_location(),
);
SendError::NotApplicable
Expand Down Expand Up @@ -360,12 +361,12 @@ impl HaulBlob for DummyHaulBlob {
#[cfg(test)]
mod tests {
use super::*;
use crate::{mock::*, Bridges, LaneToBridge, LanesManagerOf};
use crate::{mock::*, Bridges, LanesManagerOf};

use bp_runtime::RangeInclusiveExt;
use bp_xcm_bridge_hub::{Bridge, BridgeLocations, BridgeState};
use frame_support::assert_ok;
use pallet_bridge_messages::InboundLaneStorage;
use frame_support::traits::{Contains, EnsureOrigin};
use xcm_builder::{NetworkExportTable, UnpaidRemoteExporter};
use xcm_executor::traits::export_xcm;

Expand All @@ -381,61 +382,31 @@ mod tests {
BridgedUniversalDestination::get()
}

fn open_lane() -> (BridgeLocations, TestLaneIdType) {
fn open_lane(origin: RuntimeOrigin) -> (BridgeLocations, TestLaneIdType) {
// open expected outbound lane
let origin = OpenBridgeOrigin::sibling_parachain_origin();
let with = bridged_asset_hub_universal_location();
let locations =
XcmOverBridge::bridge_locations_from_origin(origin, Box::new(with.into())).unwrap();
XcmOverBridge::bridge_locations_from_origin(origin.clone(), Box::new(with.into())).unwrap();
let lane_id = locations.calculate_lane_id(xcm::latest::VERSION).unwrap();

if !Bridges::<TestRuntime, ()>::contains_key(locations.bridge_id()) {
// insert bridge
Bridges::<TestRuntime, ()>::insert(
locations.bridge_id(),
Bridge {
bridge_origin_relative_location: Box::new(SiblingLocation::get().into()),
bridge_origin_universal_location: Box::new(
locations.bridge_origin_universal_location().clone().into(),
),
bridge_destination_universal_location: Box::new(
locations.bridge_destination_universal_location().clone().into(),
),
state: BridgeState::Opened,
deposit: None,
lane_id,
},
);
LaneToBridge::<TestRuntime, ()>::insert(lane_id, locations.bridge_id());

// create lanes
let lanes_manager = LanesManagerOf::<TestRuntime, ()>::new();
if lanes_manager.create_inbound_lane(lane_id).is_ok() {
assert_eq!(
0,
lanes_manager
.active_inbound_lane(lane_id)
.unwrap()
.storage()
.data()
.last_confirmed_nonce
);
}
if lanes_manager.create_outbound_lane(lane_id).is_ok() {
assert!(lanes_manager
.active_outbound_lane(lane_id)
.unwrap()
.queued_messages()
.is_empty());
// fund origin (if needed)
if !<TestRuntime as Config<()>>::AllowWithoutBridgeDeposit::contains(
locations.bridge_origin_relative_location()
) {
fund_origin_sovereign_account(&locations, BridgeDeposit::get() + ExistentialDeposit::get());
}

// open bridge
assert_ok!(XcmOverBridge::do_open_bridge(locations.clone(), lane_id, true));
}
assert_ok!(XcmOverBridge::do_try_state());

(*locations, lane_id)
}

fn open_lane_and_send_regular_message() -> (BridgeId, TestLaneIdType) {
let (locations, lane_id) = open_lane();
fn open_lane_and_send_regular_message(source_origin: RuntimeOrigin) -> (BridgeId, TestLaneIdType) {
let (locations, lane_id) = open_lane(source_origin);

// now let's try to enqueue message using our `ExportXcm` implementation
export_xcm::<XcmOverBridge>(
Expand All @@ -453,7 +424,7 @@ mod tests {
#[test]
fn exporter_works() {
run_test(|| {
let (_, lane_id) = open_lane_and_send_regular_message();
let (_, lane_id) = open_lane_and_send_regular_message(OpenBridgeOrigin::sibling_parachain_origin());

// double check that the message has been pushed to the expected lane
// (it should already been checked during `send_message` call)
Expand All @@ -468,7 +439,7 @@ mod tests {
#[test]
fn exporter_does_not_suspend_the_bridge_if_outbound_bridge_queue_is_not_congested() {
run_test(|| {
let (bridge_id, _) = open_lane_and_send_regular_message();
let (bridge_id, _) = open_lane_and_send_regular_message(OpenBridgeOrigin::sibling_parachain_origin());
assert!(!TestLocalXcmChannelManager::is_bridge_suspened());
assert_eq!(XcmOverBridge::bridge(&bridge_id).unwrap().state, BridgeState::Opened);
});
Expand All @@ -477,31 +448,31 @@ mod tests {
#[test]
fn exporter_does_not_suspend_the_bridge_if_it_is_already_suspended() {
run_test(|| {
let (bridge_id, _) = open_lane_and_send_regular_message();
let (bridge_id, _) = open_lane_and_send_regular_message(OpenBridgeOrigin::sibling_parachain_origin());
Bridges::<TestRuntime, ()>::mutate_extant(bridge_id, |bridge| {
bridge.state = BridgeState::Suspended;
});
for _ in 1..OUTBOUND_LANE_CONGESTED_THRESHOLD {
open_lane_and_send_regular_message();
open_lane_and_send_regular_message(OpenBridgeOrigin::sibling_parachain_origin());
}

open_lane_and_send_regular_message();
open_lane_and_send_regular_message(OpenBridgeOrigin::sibling_parachain_origin());
assert!(!TestLocalXcmChannelManager::is_bridge_suspened());
});
}

#[test]
fn exporter_suspends_the_bridge_if_outbound_bridge_queue_is_congested() {
run_test(|| {
let (bridge_id, _) = open_lane_and_send_regular_message();
let (bridge_id, _) = open_lane_and_send_regular_message(OpenBridgeOrigin::sibling_parachain_origin());
for _ in 1..OUTBOUND_LANE_CONGESTED_THRESHOLD {
open_lane_and_send_regular_message();
open_lane_and_send_regular_message(OpenBridgeOrigin::sibling_parachain_origin());
}

assert!(!TestLocalXcmChannelManager::is_bridge_suspened());
assert_eq!(XcmOverBridge::bridge(&bridge_id).unwrap().state, BridgeState::Opened);

open_lane_and_send_regular_message();
open_lane_and_send_regular_message(OpenBridgeOrigin::sibling_parachain_origin());
assert!(TestLocalXcmChannelManager::is_bridge_suspened());
assert_eq!(XcmOverBridge::bridge(&bridge_id).unwrap().state, BridgeState::Suspended);
});
Expand All @@ -510,7 +481,7 @@ mod tests {
#[test]
fn bridge_is_not_resumed_if_outbound_bridge_queue_is_still_congested() {
run_test(|| {
let (bridge_id, lane_id) = open_lane_and_send_regular_message();
let (bridge_id, lane_id) = open_lane_and_send_regular_message(OpenBridgeOrigin::sibling_parachain_origin());
Bridges::<TestRuntime, ()>::mutate_extant(bridge_id, |bridge| {
bridge.state = BridgeState::Suspended;
});
Expand All @@ -527,7 +498,7 @@ mod tests {
#[test]
fn bridge_is_not_resumed_if_it_was_not_suspended_before() {
run_test(|| {
let (bridge_id, lane_id) = open_lane_and_send_regular_message();
let (bridge_id, lane_id) = open_lane_and_send_regular_message(OpenBridgeOrigin::sibling_parachain_origin());
XcmOverBridge::on_bridge_messages_delivered(
lane_id,
OUTBOUND_LANE_UNCONGESTED_THRESHOLD,
Expand All @@ -541,7 +512,7 @@ mod tests {
#[test]
fn bridge_is_resumed_when_enough_messages_are_delivered() {
run_test(|| {
let (bridge_id, lane_id) = open_lane_and_send_regular_message();
let (bridge_id, lane_id) = open_lane_and_send_regular_message(OpenBridgeOrigin::sibling_parachain_origin());
Bridges::<TestRuntime, ()>::mutate_extant(bridge_id, |bridge| {
bridge.state = BridgeState::Suspended;
});
Expand Down Expand Up @@ -637,13 +608,15 @@ mod tests {
}

#[test]
fn exporter_is_compatible_with_pallet_xcm_bridge_hub_router() {
fn pallet_as_exporter_is_compatible_with_pallet_xcm_bridge_hub_router_for_export_message() {
run_test(|| {
// valid routable destination
let dest = Location::new(2, BridgedUniversalDestination::get());

// open bridge
let (_, expected_lane_id) = open_lane();
let origin = OpenBridgeOrigin::sibling_parachain_origin();
let origin_as_location = OpenBridgeOriginOf::<TestRuntime, ()>::try_origin(origin.clone()).unwrap();
let (_, expected_lane_id) = open_lane(origin);

// check before - no messages
assert_eq!(
Expand All @@ -657,7 +630,7 @@ mod tests {
);

// send `ExportMessage(message)` by `UnpaidRemoteExporter`.
ExecuteXcmOverSendXcm::set_origin_for_execute(SiblingLocation::get());
ExecuteXcmOverSendXcm::set_origin_for_execute(origin_as_location.clone());
assert_ok!(send_xcm::<
UnpaidRemoteExporter<
NetworkExportTable<BridgeTable>,
Expand All @@ -667,8 +640,8 @@ mod tests {
>(dest.clone(), Xcm::<()>::default()));

// send `ExportMessage(message)` by `pallet_xcm_bridge_hub_router`.
ExecuteXcmOverSendXcm::set_origin_for_execute(SiblingLocation::get());
assert_ok!(send_xcm::<XcmOverBridgeRouter>(dest.clone(), Xcm::<()>::default()));
ExecuteXcmOverSendXcm::set_origin_for_execute(origin_as_location);
assert_ok!(send_xcm::<XcmOverBridgeWrappedWithExportMessageRouter>(dest, Xcm::<()>::default()));

// check after - a message ready to be relayed
assert_eq!(
Expand All @@ -683,6 +656,42 @@ mod tests {
})
}

#[test]
fn pallet_as_exporter_is_compatible_with_pallet_xcm_bridge_hub_router_for_export_xcm() {
run_test(|| {
// valid routable destination
let dest = Location::new(2, BridgedUniversalDestination::get());

// open bridge as a root on the local chain, which should be converted as `Location::here()`
let (_, expected_lane_id) = open_lane(RuntimeOrigin::root());

// check before - no messages
assert_eq!(
pallet_bridge_messages::Pallet::<TestRuntime, ()>::outbound_lane_data(
expected_lane_id
)
.unwrap()
.queued_messages()
.saturating_len(),
0
);

// trigger `ExportXcm` by `pallet_xcm_bridge_hub_router`.
assert_ok!(send_xcm::<XcmOverBridgeByExportXcmRouter>(dest, Xcm::<()>::default()));

// check after - a message ready to be relayed
assert_eq!(
pallet_bridge_messages::Pallet::<TestRuntime, ()>::outbound_lane_data(
expected_lane_id
)
.unwrap()
.queued_messages()
.saturating_len(),
1
);
})
}

#[test]
fn validate_works() {
run_test(|| {
Expand Down Expand Up @@ -760,7 +769,7 @@ mod tests {
);

// ok
let _ = open_lane();
let _ = open_lane(OpenBridgeOrigin::sibling_parachain_origin());
let mut dest_wrapper = Some(bridged_relative_destination());
assert_ok!(XcmOverBridge::validate(
BridgedRelayNetwork::get(),
Expand Down
15 changes: 4 additions & 11 deletions bridges/modules/xcm-bridge-hub/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -841,19 +841,11 @@ mod tests {
use bp_messages::LaneIdType;
use mock::*;

use frame_support::{assert_err, assert_noop, assert_ok, traits::fungible::Mutate, BoundedVec};
use frame_support::{assert_err, assert_noop, assert_ok, BoundedVec};
use frame_system::{EventRecord, Phase};
use sp_runtime::traits::Zero;
use sp_runtime::TryRuntimeError;

fn fund_origin_sovereign_account(locations: &BridgeLocations, balance: Balance) -> AccountId {
let bridge_owner_account =
LocationToAccountId::convert_location(locations.bridge_origin_relative_location())
.unwrap();
assert_ok!(Balances::mint_into(&bridge_owner_account, balance));
bridge_owner_account
}

fn mock_open_bridge_from_with(
origin: RuntimeOrigin,
deposit: Option<Balance>,
Expand Down Expand Up @@ -1094,11 +1086,12 @@ mod tests {
#[test]
fn open_bridge_works() {
run_test(|| {
// in our test runtime, we expect that bridge may be opened by parent relay chain
// and any sibling parachain
// in our test runtime, we expect that bridge may be opened by parent relay chain,
// any sibling parachain or local root
let origins = [
(OpenBridgeOrigin::parent_relay_chain_origin(), None),
(OpenBridgeOrigin::sibling_parachain_origin(), Some(BridgeDeposit::get())),
(RuntimeOrigin::root(), None),
];

// check that every origin may open the bridge
Expand Down
Loading

0 comments on commit 049d46a

Please sign in to comment.