From eef706e76cbe9bac734a18fde272d511b00be7f3 Mon Sep 17 00:00:00 2001 From: Clara van Staden Date: Tue, 16 Jan 2024 20:31:51 +0200 Subject: [PATCH] Adds emulated test comments (#97) * adds emulated test comments * pr comments * rename XCMs --------- Co-authored-by: claravanstaden --- .../bridge-hub-rococo/src/tests/snowbridge.rs | 115 +++++++++++++----- 1 file changed, 83 insertions(+), 32 deletions(-) diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs index fe0e479d8e5c..5a7f13aab35e 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs @@ -48,17 +48,19 @@ pub enum SnowbridgeControl { Control(ControlCall), } +/// Create an agent on Ethereum. An agent is a representation of an entity in the Polkadot +/// ecosystem (like a parachain) on Ethereum. #[test] fn create_agent() { let origin_para: u32 = 1001; - + // Fund the origin parachain sovereign account so that it can pay execution fees. BridgeHubRococo::fund_para_sovereign(origin_para.into(), INITIAL_FUND); let sudo_origin = ::RuntimeOrigin::root(); let destination = Rococo::child_location_of(BridgeHubRococo::para_id()).into(); let create_agent_call = SnowbridgeControl::Control(ControlCall::CreateAgent {}); - + // Construct XCM to create an agent for para 1001 let remote_xcm = VersionedXcm::from(Xcm(vec![ UnpaidExecution { weight_limit: Unlimited, check_origin: None }, DescendOrigin(Parachain(origin_para).into()), @@ -69,7 +71,7 @@ fn create_agent() { }, ])); - //Rococo Global Consensus + // Rococo Global Consensus // Send XCM message from Relay Chain to Bridge Hub source Parachain Rococo::execute_with(|| { assert_ok!(::XcmPallet::send( @@ -79,7 +81,7 @@ fn create_agent() { )); type RuntimeEvent = ::RuntimeEvent; - + // Check that the Transact message was sent assert_expected_events!( Rococo, vec![ @@ -90,7 +92,7 @@ fn create_agent() { BridgeHubRococo::execute_with(|| { type RuntimeEvent = ::RuntimeEvent; - + // Check that a message was sent to Ethereum to create the agent assert_expected_events!( BridgeHubRococo, vec![ @@ -102,10 +104,12 @@ fn create_agent() { }); } +/// Create a channel for a consensus system. A channel is a bidirectional messaging channel +/// between BridgeHub and Ethereum. #[test] fn create_channel() { let origin_para: u32 = 1001; - + // Fund AssetHub sovereign account so that it can pay execution fees. BridgeHubRococo::fund_para_sovereign(origin_para.into(), INITIAL_FUND); let sudo_origin = ::RuntimeOrigin::root(); @@ -113,7 +117,7 @@ fn create_channel() { Rococo::child_location_of(BridgeHubRococo::para_id()).into(); let create_agent_call = SnowbridgeControl::Control(ControlCall::CreateAgent {}); - + // Construct XCM to create an agent for para 1001 let create_agent_xcm = VersionedXcm::from(Xcm(vec![ UnpaidExecution { weight_limit: Unlimited, check_origin: None }, DescendOrigin(Parachain(origin_para).into()), @@ -126,7 +130,7 @@ fn create_channel() { let create_channel_call = SnowbridgeControl::Control(ControlCall::CreateChannel { mode: OperatingMode::Normal }); - + // Construct XCM to create a channel for para 1001 let create_channel_xcm = VersionedXcm::from(Xcm(vec![ UnpaidExecution { weight_limit: Unlimited, check_origin: None }, DescendOrigin(Parachain(origin_para).into()), @@ -137,7 +141,7 @@ fn create_channel() { }, ])); - //Rococo Global Consensus + // Rococo Global Consensus // Send XCM message from Relay Chain to Bridge Hub source Parachain Rococo::execute_with(|| { assert_ok!(::XcmPallet::send( @@ -165,6 +169,7 @@ fn create_channel() { BridgeHubRococo::execute_with(|| { type RuntimeEvent = ::RuntimeEvent; + // Check that the Channel was created assert_expected_events!( BridgeHubRococo, vec![ @@ -176,21 +181,23 @@ fn create_channel() { }); } +/// Tests the registering of a token as an asset on AssetHub. #[test] fn register_weth_token_from_ethereum_to_asset_hub() { + // Fund AssetHub sovereign account so that it can pay execution fees. BridgeHubRococo::fund_para_sovereign(AssetHubRococo::para_id().into(), INITIAL_FUND); - let message_id_: H256 = [1; 32].into(); + let message_id: H256 = [1; 32].into(); BridgeHubRococo::execute_with(|| { type RuntimeEvent = ::RuntimeEvent; type EthereumInboundQueue = - ::EthereumInboundQueue; + ::EthereumInboundQueue; let message = VersionedMessage::V1(MessageV1 { chain_id: CHAIN_ID, command: Command::RegisterToken { token: WETH.into(), fee: XCM_FEE }, }); - let (xcm, fee) = EthereumInboundQueue::do_convert(message_id_, message).unwrap(); + let (xcm, fee) = EthereumInboundQueue::do_convert(message_id, message).unwrap(); assert_ok!(EthereumInboundQueue::burn_fees(AssetHubRococo::para_id().into(), fee)); @@ -216,32 +223,38 @@ fn register_weth_token_from_ethereum_to_asset_hub() { }); } +/// Tests sending a token to a 3rd party parachain, called PenPal. The token reserve is +/// still located on AssetHub. #[test] fn send_token_from_ethereum_to_penpal() { let asset_hub_sovereign = BridgeHubRococo::sovereign_account_id_of(Location::new( 1, [Parachain(AssetHubRococo::para_id().into())], )); + // Fund AssetHub sovereign account so it can pay execution fees for the asset transfer BridgeHubRococo::fund_accounts(vec![(asset_hub_sovereign.clone(), INITIAL_FUND)]); + // Fund PenPal sender and receiver PenpalA::fund_accounts(vec![ (PenpalAReceiver::get(), INITIAL_FUND), (PenpalASender::get(), INITIAL_FUND), ]); + // The Weth asset location, identified by the contract address on Ethereum let weth_asset_location: Location = (Parent, Parent, EthereumNetwork::get(), AccountKey20 { network: None, key: WETH }).into(); + // Converts the Weth asset location into an asset ID let weth_asset_id: v3::Location = weth_asset_location.try_into().unwrap(); let origin_location = (Parent, Parent, EthereumNetwork::get()).into(); - // Fund ethereum sovereign in asset hub + // Fund ethereum sovereign on AssetHub let ethereum_sovereign: AccountId = GlobalConsensusEthereumConvertsFor::::convert_location(&origin_location) .unwrap(); AssetHubRococo::fund_accounts(vec![(ethereum_sovereign.clone(), INITIAL_FUND)]); - // Create asset on assethub. + // Create asset on AssetHub, since that is where the asset reserve is located AssetHubRococo::execute_with(|| { assert_ok!(::ForeignAssets::create( pallet_xcm::Origin::Xcm(origin_location).into(), @@ -255,7 +268,7 @@ fn send_token_from_ethereum_to_penpal() { )); }); - // Create asset on penpal. + // Create asset on the Penpal parachain. PenpalA::execute_with(|| { assert_ok!(::ForeignAssets::create( ::RuntimeOrigin::signed(PenpalASender::get()), @@ -267,12 +280,13 @@ fn send_token_from_ethereum_to_penpal() { assert!(::ForeignAssets::asset_exists(weth_asset_id)); }); - let message_id_: H256 = [1; 32].into(); + let message_id: H256 = [1; 32].into(); BridgeHubRococo::execute_with(|| { type RuntimeEvent = ::RuntimeEvent; type EthereumInboundQueue = - ::EthereumInboundQueue; + ::EthereumInboundQueue; + // Construct SendToken message let message = VersionedMessage::V1(MessageV1 { chain_id: CHAIN_ID, command: Command::SendToken { @@ -286,7 +300,9 @@ fn send_token_from_ethereum_to_penpal() { fee: XCM_FEE, }, }); - let (xcm, _) = EthereumInboundQueue::do_convert(message_id_, message).unwrap(); + // Convert the message to XCM + let (xcm, _) = EthereumInboundQueue::do_convert(message_id, message).unwrap(); + // Send the XCM let _ = EthereumInboundQueue::send_xcm(xcm, AssetHubRococo::para_id().into()).unwrap(); assert_expected_events!( @@ -299,7 +315,7 @@ fn send_token_from_ethereum_to_penpal() { AssetHubRococo::execute_with(|| { type RuntimeEvent = ::RuntimeEvent; - + // Check that the assets were issued on AssetHub assert_expected_events!( AssetHubRococo, vec![ @@ -311,7 +327,7 @@ fn send_token_from_ethereum_to_penpal() { PenpalA::execute_with(|| { type RuntimeEvent = ::RuntimeEvent; - + // Check that the assets were issued on PenPal assert_expected_events!( PenpalA, vec![ @@ -321,25 +337,32 @@ fn send_token_from_ethereum_to_penpal() { }); } +/// Tests the registering of a token as an asset on AssetHub, and then subsequently sending +/// a token from Ethereum to AssetHub. #[test] fn send_token_from_ethereum_to_asset_hub() { BridgeHubRococo::fund_para_sovereign(AssetHubRococo::para_id().into(), INITIAL_FUND); - // Fund ethereum sovereign in asset hub + // Fund ethereum sovereign on AssetHub AssetHubRococo::fund_accounts(vec![(AssetHubRococoReceiver::get(), INITIAL_FUND)]); - let message_id_: H256 = [1; 32].into(); + let message_id: H256 = [1; 32].into(); BridgeHubRococo::execute_with(|| { type RuntimeEvent = ::RuntimeEvent; type EthereumInboundQueue = - ::EthereumInboundQueue; + ::EthereumInboundQueue; + // Construct RegisterToken message let message = VersionedMessage::V1(MessageV1 { chain_id: CHAIN_ID, command: Command::RegisterToken { token: WETH.into(), fee: XCM_FEE }, }); - let (xcm, _) = EthereumInboundQueue::do_convert(message_id_, message).unwrap(); + // Convert the message to XCM + let (xcm, _) = EthereumInboundQueue::do_convert(message_id, message).unwrap(); + // Send the XCM let _ = EthereumInboundQueue::send_xcm(xcm, AssetHubRococo::para_id().into()).unwrap(); + + // Construct SendToken message let message = VersionedMessage::V1(MessageV1 { chain_id: CHAIN_ID, command: Command::SendToken { @@ -349,9 +372,12 @@ fn send_token_from_ethereum_to_asset_hub() { fee: XCM_FEE, }, }); - let (xcm, _) = EthereumInboundQueue::do_convert(message_id_, message).unwrap(); + // Convert the message to XCM + let (xcm, _) = EthereumInboundQueue::do_convert(message_id, message).unwrap(); + // Send the XCM let _ = EthereumInboundQueue::send_xcm(xcm, AssetHubRococo::para_id().into()).unwrap(); + // Check that the message was sent assert_expected_events!( BridgeHubRococo, vec![ @@ -363,6 +389,7 @@ fn send_token_from_ethereum_to_asset_hub() { AssetHubRococo::execute_with(|| { type RuntimeEvent = ::RuntimeEvent; + // Check that the token was received and issued as a foreign asset on AssetHub assert_expected_events!( AssetHubRococo, vec![ @@ -372,6 +399,10 @@ fn send_token_from_ethereum_to_asset_hub() { }); } +/// Tests the full cycle of token transfers: +/// - registering a token on AssetHub +/// - sending a token to AssetHub +/// - returning the token to Ethereum #[test] fn send_weth_asset_from_asset_hub_to_ethereum() { use asset_hub_rococo_runtime::xcm_config::bridging::to_ethereum::DefaultBridgeHubEthereumBaseFee; @@ -391,19 +422,32 @@ fn send_weth_asset_from_asset_hub_to_ethereum() { AssetHubRococo::fund_accounts(vec![(AssetHubRococoReceiver::get(), INITIAL_FUND)]); const WETH_AMOUNT: u128 = 1_000_000_000; - let message_id_: H256 = [1; 32].into(); + let message_id_register_token: H256 = [1; 32].into(); + let message_id_send_token: H256 = [2; 32].into(); BridgeHubRococo::execute_with(|| { type RuntimeEvent = ::RuntimeEvent; type EthereumInboundQueue = - ::EthereumInboundQueue; + ::EthereumInboundQueue; + // Register ERC-20 token on AssetHub let message = VersionedMessage::V1(MessageV1 { chain_id: CHAIN_ID, command: Command::RegisterToken { token: WETH.into(), fee: XCM_FEE }, }); - let (xcm, _) = EthereumInboundQueue::do_convert(message_id_, message).unwrap(); + // Converts the versioned message to XCM + let (xcm, _) = EthereumInboundQueue::do_convert(message_id_register_token, message).unwrap(); let _ = EthereumInboundQueue::send_xcm(xcm, AssetHubRococo::para_id().into()).unwrap(); + + // Check that the register token message was sent using xcm + assert_expected_events!( + BridgeHubRococo, + vec![ + RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. }) => {}, + ] + ); + + // Send ERC-20 token to AssetHub let message = VersionedMessage::V1(MessageV1 { chain_id: CHAIN_ID, command: Command::SendToken { @@ -413,9 +457,11 @@ fn send_weth_asset_from_asset_hub_to_ethereum() { fee: XCM_FEE, }, }); - let (xcm, _) = EthereumInboundQueue::do_convert(message_id_, message).unwrap(); + // Converts the versioned message to XCM + let (xcm, _) = EthereumInboundQueue::do_convert(message_id_send_token, message).unwrap(); let _ = EthereumInboundQueue::send_xcm(xcm, AssetHubRococo::para_id().into()).unwrap(); + // Check that the send token message was sent using xcm assert_expected_events!( BridgeHubRococo, vec![ @@ -428,6 +474,7 @@ fn send_weth_asset_from_asset_hub_to_ethereum() { type RuntimeEvent = ::RuntimeEvent; type RuntimeOrigin = ::RuntimeOrigin; + // Check that AssetHub has issued the foreign asset assert_expected_events!( AssetHubRococo, vec![ @@ -459,6 +506,7 @@ fn send_weth_asset_from_asset_hub_to_ethereum() { let free_balance_before = ::Balances::free_balance( AssetHubRococoReceiver::get(), ); + // Send the Weth back to Ethereum ::PolkadotXcm::reserve_transfer_assets( RuntimeOrigin::signed(AssetHubRococoReceiver::get()), Box::new(destination), @@ -466,18 +514,19 @@ fn send_weth_asset_from_asset_hub_to_ethereum() { Box::new(multi_assets), 0, ) - .unwrap(); + .unwrap(); let free_balance_after = ::Balances::free_balance( AssetHubRococoReceiver::get(), ); - // assert at least DefaultBridgeHubEthereumBaseFee charged from the sender + // Assert at least DefaultBridgeHubEthereumBaseFee charged from the sender let free_balance_diff = free_balance_before - free_balance_after; assert!(free_balance_diff > DefaultBridgeHubEthereumBaseFee::get()); }); BridgeHubRococo::execute_with(|| { type RuntimeEvent = ::RuntimeEvent; - + // Check that the transfer token back to Ethereum message was queue in the Ethereum + // Outbound Queue assert_expected_events!( BridgeHubRococo, vec![ @@ -485,6 +534,7 @@ fn send_weth_asset_from_asset_hub_to_ethereum() { ] ); let events = BridgeHubRococo::events(); + // Check that the local fee was credited to the Snowbridge sovereign account assert!( events.iter().any(|event| matches!( event, @@ -493,6 +543,7 @@ fn send_weth_asset_from_asset_hub_to_ethereum() { )), "Snowbridge sovereign takes local fee." ); + // Check that the remote fee was credited to the AssetHub sovereign account assert!( events.iter().any(|event| matches!( event,