[testnet] Add AssetHubRococo <-> AssetHubWestend asset bridging support (#1967)

## Summary

Asset bridging support for AssetHub**Rococo** <-> AssetHub**Wococo** was
added [here](https://github.com/paritytech/polkadot-sdk/pull/1215), so
now we aim to bridge AssetHub**Rococo** and AssetHub**Westend**. (And
perhaps retire AssetHubWococo and the Wococo chains).

## Solution

**bridge-hub-westend-runtime**
- added new runtime as a copy of `bridge-hub-rococo-runtime`
- added support for bridging to `BridgeHubRococo`
- added tests and benchmarks

**bridge-hub-rococo-runtime**
- added support for bridging to `BridgeHubWestend`
- added tests and benchmarks
- internal refactoring by splitting bridge configuration per network,
e.g., `bridge_to_whatevernetwork_config.rs`.

**asset-hub-rococo-runtime**
- added support for asset bridging to `AssetHubWestend` (allows to
receive only WNDs)
- added new xcm router for `Westend`
- added tests and benchmarks

**asset-hub-westend-runtime**
- added support for asset bridging to `AssetHubRococo` (allows to
receive only ROCs)
- added new xcm router for `Rococo`
- added tests and benchmarks

## Deployment

All changes will be deployed as a part of
https://github.com/paritytech/polkadot-sdk/issues/1988.

## TODO

- [x] benchmarks for all pallet instances
- [x] integration tests
- [x] local run scripts


Relates to:
https://github.com/paritytech/parity-bridges-common/issues/2602
Relates to: https://github.com/paritytech/polkadot-sdk/issues/1988

---------

Co-authored-by: command-bot <>
Co-authored-by: Adrian Catangiu <adrian@parity.io>
Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com>
This commit is contained in:
Branislav Kontur
2023-11-02 00:39:49 +01:00
committed by GitHub
parent c66ae375e6
commit 1b1fab0da3
112 changed files with 10028 additions and 1638 deletions
@@ -19,20 +19,19 @@
use asset_hub_westend_runtime::{
xcm_config::{
AssetFeeAsExistentialDepositMultiplierFeeCharger, ForeignCreatorsSovereignAccountOf,
WestendLocation,
self, bridging, AssetFeeAsExistentialDepositMultiplierFeeCharger, CheckingAccount,
ForeignCreatorsSovereignAccountOf, LocationToAccountId, TrustBackedAssetsPalletLocation,
WestendLocation, XcmConfig,
},
AllPalletsWithoutSystem, MetadataDepositBase, MetadataDepositPerByte, RuntimeCall,
RuntimeEvent,
AllPalletsWithoutSystem, AssetDeposit, Assets, Balances, ExistentialDeposit, ForeignAssets,
ForeignAssetsInstance, MetadataDepositBase, MetadataDepositPerByte, ParachainSystem, Runtime,
RuntimeCall, RuntimeEvent, SessionKeys, ToRococoXcmRouterInstance, TrustBackedAssetsInstance,
XcmpQueue,
};
pub use asset_hub_westend_runtime::{
xcm_config::{CheckingAccount, TrustBackedAssetsPalletLocation, XcmConfig},
AllowMultiAssetPools, AssetDeposit, Assets, Balances, ExistentialDeposit, ForeignAssets,
ForeignAssetsInstance, ParachainSystem, Runtime, SessionKeys, System,
TrustBackedAssetsInstance,
use asset_test_utils::{
test_cases_over_bridge::TestBridgingConfig, CollatorSessionKey, CollatorSessionKeys, ExtBuilder,
};
use asset_test_utils::{CollatorSessionKeys, ExtBuilder, XcmReceivedFrom};
use codec::{Decode, DecodeLimit, Encode};
use codec::{Decode, Encode};
use cumulus_primitives_utility::ChargeWeightInFungibles;
use frame_support::{
assert_noop, assert_ok,
@@ -42,14 +41,10 @@ use frame_support::{
use parachains_common::{
westend::fee::WeightToFee, AccountId, AssetIdForTrustBackedAssets, AuraId, Balance,
};
use sp_io;
use sp_runtime::traits::MaybeEquivalence;
use std::convert::Into;
use xcm::{latest::prelude::*, VersionedXcm, MAX_XCM_DECODE_DEPTH};
use xcm_executor::{
traits::{Identity, JustTry, WeightTrader},
XcmExecutor,
};
use xcm::latest::prelude::*;
use xcm_executor::traits::{Identity, JustTry, WeightTrader};
const ALICE: [u8; 32] = [1u8; 32];
const SOME_ASSET_ADMIN: [u8; 32] = [5u8; 32];
@@ -59,14 +54,18 @@ type AssetIdForTrustBackedAssetsConvert =
type RuntimeHelper = asset_test_utils::RuntimeHelper<Runtime, AllPalletsWithoutSystem>;
fn collator_session_keys() -> CollatorSessionKeys<Runtime> {
CollatorSessionKeys::new(
AccountId::from(ALICE),
AccountId::from(ALICE),
SessionKeys { aura: AuraId::from(sp_core::sr25519::Public::from_raw(ALICE)) },
fn collator_session_key(account: [u8; 32]) -> CollatorSessionKey<Runtime> {
CollatorSessionKey::new(
AccountId::from(account),
AccountId::from(account),
SessionKeys { aura: AuraId::from(sp_core::sr25519::Public::from_raw(account)) },
)
}
fn collator_session_keys() -> CollatorSessionKeys<Runtime> {
CollatorSessionKeys::default().add(collator_session_key(ALICE))
}
#[test]
fn test_asset_xcm_trader() {
ExtBuilder::<Runtime>::default()
@@ -253,7 +252,7 @@ fn test_asset_xcm_trader_refund_not_possible_since_amount_less_than_ed() {
// Set Alice as block author, who will receive fees
RuntimeHelper::run_to_block(2, AccountId::from(ALICE));
// We are going to buy 5e9 weight
// We are going to buy small amount
let bought = Weight::from_parts(500_000_000u64, 0);
let asset_multilocation = AssetIdForTrustBackedAssetsConvert::convert_back(&1).unwrap();
@@ -641,28 +640,178 @@ asset_test_utils::include_create_and_manage_foreign_assets_for_local_consensus_p
})
);
#[test]
fn plain_receive_teleported_asset_works() {
ExtBuilder::<Runtime>::default()
.with_collators(vec![AccountId::from(ALICE)])
.with_session_keys(vec![(
AccountId::from(ALICE),
AccountId::from(ALICE),
SessionKeys { aura: AuraId::from(sp_core::sr25519::Public::from_raw(ALICE)) },
)])
.build()
.execute_with(|| {
let data = hex_literal::hex!("02100204000100000b00a0724e18090a13000100000b00a0724e180901e20f5e480d010004000101001299557001f55815d3fcb53c74463acb0cf6d14d4639b340982c60877f384609").to_vec();
let message_id = sp_io::hashing::blake2_256(&data);
let maybe_msg = VersionedXcm::<RuntimeCall>::decode_all_with_depth_limit(
MAX_XCM_DECODE_DEPTH,
&mut data.as_ref(),
)
.map(xcm::v3::Xcm::<RuntimeCall>::try_from).expect("failed").expect("failed");
let outcome =
XcmExecutor::<XcmConfig>::execute_xcm(Parent, maybe_msg, message_id, RuntimeHelper::xcm_max_weight(XcmReceivedFrom::Parent));
assert_eq!(outcome.ensure_complete(), Ok(()));
})
fn bridging_to_asset_hub_rococo() -> TestBridgingConfig {
TestBridgingConfig {
bridged_network: bridging::to_rococo::RococoNetwork::get(),
local_bridge_hub_para_id: bridging::SiblingBridgeHubParaId::get(),
local_bridge_hub_location: bridging::SiblingBridgeHub::get(),
bridged_target_location: bridging::to_rococo::AssetHubRococo::get(),
}
}
#[test]
fn limited_reserve_transfer_assets_for_native_asset_to_asset_hub_rococo_works() {
asset_test_utils::test_cases_over_bridge::limited_reserve_transfer_assets_for_native_asset_works::<
Runtime,
AllPalletsWithoutSystem,
XcmConfig,
ParachainSystem,
XcmpQueue,
LocationToAccountId,
>(
collator_session_keys(),
ExistentialDeposit::get(),
AccountId::from(ALICE),
Box::new(|runtime_event_encoded: Vec<u8>| {
match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) {
Ok(RuntimeEvent::PolkadotXcm(event)) => Some(event),
_ => None,
}
}),
Box::new(|runtime_event_encoded: Vec<u8>| {
match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) {
Ok(RuntimeEvent::XcmpQueue(event)) => Some(event),
_ => None,
}
}),
bridging_to_asset_hub_rococo,
WeightLimit::Unlimited,
Some(xcm_config::bridging::XcmBridgeHubRouterFeeAssetId::get()),
Some(xcm_config::TreasuryAccount::get()),
)
}
#[test]
fn receive_reserve_asset_deposited_roc_from_asset_hub_rococo_works() {
const BLOCK_AUTHOR_ACCOUNT: [u8; 32] = [13; 32];
asset_test_utils::test_cases_over_bridge::receive_reserve_asset_deposited_from_different_consensus_works::<
Runtime,
AllPalletsWithoutSystem,
XcmConfig,
LocationToAccountId,
ForeignAssetsInstance,
>(
collator_session_keys().add(collator_session_key(BLOCK_AUTHOR_ACCOUNT)),
ExistentialDeposit::get(),
AccountId::from([73; 32]),
AccountId::from(BLOCK_AUTHOR_ACCOUNT),
// receiving ROCs
(MultiLocation { parents: 2, interior: X1(GlobalConsensus(Rococo)) }, 1000000000000, 1_000_000_000),
bridging_to_asset_hub_rococo,
(
X1(PalletInstance(bp_bridge_hub_westend::WITH_BRIDGE_WESTEND_TO_ROCOCO_MESSAGES_PALLET_INDEX)),
GlobalConsensus(Rococo),
X1(Parachain(1000))
)
)
}
#[test]
fn report_bridge_status_from_xcm_bridge_router_for_rococo_works() {
asset_test_utils::test_cases_over_bridge::report_bridge_status_from_xcm_bridge_router_works::<
Runtime,
AllPalletsWithoutSystem,
XcmConfig,
LocationToAccountId,
ToRococoXcmRouterInstance,
>(
collator_session_keys(),
bridging_to_asset_hub_rococo,
|| {
sp_std::vec![
UnpaidExecution { weight_limit: Unlimited, check_origin: None },
Transact {
origin_kind: OriginKind::Xcm,
require_weight_at_most:
bp_asset_hub_westend::XcmBridgeHubRouterTransactCallMaxWeight::get(),
call: bp_asset_hub_westend::Call::ToRococoXcmRouter(
bp_asset_hub_westend::XcmBridgeHubRouterCall::report_bridge_status {
bridge_id: Default::default(),
is_congested: true,
}
)
.encode()
.into(),
}
]
.into()
},
|| {
sp_std::vec![
UnpaidExecution { weight_limit: Unlimited, check_origin: None },
Transact {
origin_kind: OriginKind::Xcm,
require_weight_at_most:
bp_asset_hub_westend::XcmBridgeHubRouterTransactCallMaxWeight::get(),
call: bp_asset_hub_westend::Call::ToRococoXcmRouter(
bp_asset_hub_westend::XcmBridgeHubRouterCall::report_bridge_status {
bridge_id: Default::default(),
is_congested: false,
}
)
.encode()
.into(),
}
]
.into()
},
)
}
#[test]
fn test_report_bridge_status_call_compatibility() {
// if this test fails, make sure `bp_asset_hub_rococo` has valid encoding
assert_eq!(
RuntimeCall::ToRococoXcmRouter(pallet_xcm_bridge_hub_router::Call::report_bridge_status {
bridge_id: Default::default(),
is_congested: true,
})
.encode(),
bp_asset_hub_westend::Call::ToRococoXcmRouter(
bp_asset_hub_westend::XcmBridgeHubRouterCall::report_bridge_status {
bridge_id: Default::default(),
is_congested: true,
}
)
.encode()
)
}
#[test]
fn check_sane_weight_report_bridge_status() {
use pallet_xcm_bridge_hub_router::WeightInfo;
let actual = <Runtime as pallet_xcm_bridge_hub_router::Config<
ToRococoXcmRouterInstance,
>>::WeightInfo::report_bridge_status();
let max_weight = bp_asset_hub_westend::XcmBridgeHubRouterTransactCallMaxWeight::get();
assert!(
actual.all_lte(max_weight),
"max_weight: {:?} should be adjusted to actual {:?}",
max_weight,
actual
);
}
#[test]
fn change_xcm_bridge_hub_router_byte_fee_by_governance_works() {
asset_test_utils::test_cases::change_storage_constant_by_governance_works::<
Runtime,
bridging::XcmBridgeHubRouterByteFee,
Balance,
>(
collator_session_keys(),
1000,
Box::new(|call| RuntimeCall::System(call).encode()),
|| {
(
bridging::XcmBridgeHubRouterByteFee::key().to_vec(),
bridging::XcmBridgeHubRouterByteFee::get(),
)
},
|old_value| {
if let Some(new_value) = old_value.checked_add(1) {
new_value
} else {
old_value.checked_sub(1).unwrap()
}
},
)
}