cumulus: add asset-hub-rococo runtime based on asset-hub-kusama and add asset-bridging support to it (#1215)

This commit adds Rococo Asset Hub dedicated runtime so we can test new
features here, before merging them in Kusama Asset Hub.
Also adds one such feature: asset transfer over bridge (Rococo AssetHub
<> Wococo AssetHub)

- clone `asset-hub-kusama-runtime` -> `asset-hub-rococo-runtime`
- make it use Rococo primitives, names, assets, constants, etc
- add asset-transfer-over-bridge support to Rococo AssetHub <> Wococo
AssetHub

Fixes #1128

---------

Co-authored-by: Branislav Kontur <bkontur@gmail.com>
Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com>
Co-authored-by: Francisco Aguirre <franciscoaguirreperez@gmail.com>
This commit is contained in:
Adrian Catangiu
2023-10-18 09:47:45 +03:00
committed by GitHub
parent e73729b15f
commit 8b3905d2a5
95 changed files with 14143 additions and 767 deletions
@@ -8,7 +8,6 @@ description = "Utils for BridgeHub testing"
[dependencies]
codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] }
log = { version = "0.4.20", default-features = false }
assert_matches = "1.4.0"
# Substrate
frame-benchmarking = { path = "../../../../../substrate/frame/benchmarking", default-features = false, optional = true }
@@ -19,6 +18,7 @@ sp-core = { path = "../../../../../substrate/primitives/core", default-features
sp-io = { path = "../../../../../substrate/primitives/io", default-features = false}
sp-keyring = { path = "../../../../../substrate/primitives/keyring" }
sp-runtime = { path = "../../../../../substrate/primitives/runtime", default-features = false}
sp-tracing = { path = "../../../../../substrate/primitives/tracing" }
pallet-balances = { path = "../../../../../substrate/frame/balances", default-features = false}
pallet-utility = { path = "../../../../../substrate/frame/utility", default-features = false}
pallet-session = { path = "../../../../../substrate/frame/session", default-features = false}
@@ -16,7 +16,6 @@
//! Module contains predefined test-case scenarios for `Runtime` with bridging capabilities.
use assert_matches::assert_matches;
use bp_messages::{
target_chain::{DispatchMessage, DispatchMessageData, MessageDispatch, SourceHeaderChain},
LaneId, MessageKey, OutboundLaneData, Weight,
@@ -47,10 +46,16 @@ use parachains_runtimes_test_utils::{
};
use sp_core::H256;
use sp_keyring::AccountKeyring::*;
use sp_runtime::{traits::Header as HeaderT, AccountId32};
use sp_runtime::{
traits::{Header as HeaderT, Zero},
AccountId32,
};
use xcm::latest::prelude::*;
use xcm_builder::DispatchBlobError;
use xcm_executor::XcmExecutor;
use xcm_executor::{
traits::{TransactAsset, WeightBounds},
XcmExecutor,
};
// Re-export test_case from assets
pub use asset_test_utils::include_teleports_for_native_asset_works;
@@ -137,6 +142,9 @@ pub fn handle_export_message_from_system_parachain_to_outbound_queue_works<
>,
export_message_instruction: fn() -> Instruction<XcmConfig::RuntimeCall>,
expected_lane_id: LaneId,
existential_deposit: Option<MultiAsset>,
maybe_paid_export_message: Option<MultiAsset>,
prepare_configuration: impl Fn(),
) where
Runtime: frame_system::Config
+ pallet_balances::Config
@@ -161,6 +169,8 @@ pub fn handle_export_message_from_system_parachain_to_outbound_queue_works<
.with_tracing()
.build()
.execute_with(|| {
prepare_configuration();
// check queue before
assert_eq!(
pallet_bridge_messages::OutboundLanes::<Runtime, MessagesPalletInstance>::try_get(
@@ -170,10 +180,35 @@ pub fn handle_export_message_from_system_parachain_to_outbound_queue_works<
);
// prepare `ExportMessage`
let xcm = Xcm(vec![
UnpaidExecution { weight_limit: Unlimited, check_origin: None },
export_message_instruction(),
]);
let xcm = if let Some(fee) = maybe_paid_export_message {
// deposit ED to origin (if needed)
if let Some(ed) = existential_deposit {
XcmConfig::AssetTransactor::deposit_asset(
&ed,
&sibling_parachain_location,
&XcmContext::with_message_id([0; 32]),
)
.expect("deposited ed");
}
// deposit fee to origin
XcmConfig::AssetTransactor::deposit_asset(
&fee,
&sibling_parachain_location,
&XcmContext::with_message_id([0; 32]),
)
.expect("deposited fee");
Xcm(vec![
WithdrawAsset(MultiAssets::from(vec![fee.clone()])),
BuyExecution { fees: fee, weight_limit: Unlimited },
export_message_instruction(),
])
} else {
Xcm(vec![
UnpaidExecution { weight_limit: Unlimited, check_origin: None },
export_message_instruction(),
])
};
// execute XCM
let hash = xcm.using_encoded(sp_io::hashing::blake2_256);
@@ -231,6 +266,7 @@ pub fn message_dispatch_routing_works<
dyn Fn(Vec<u8>) -> Option<cumulus_pallet_xcmp_queue::Event<Runtime>>,
>,
expected_lane_id: LaneId,
prepare_configuration: impl Fn(),
) where
Runtime: frame_system::Config
+ pallet_balances::Config
@@ -249,6 +285,7 @@ pub fn message_dispatch_routing_works<
XcmConfig: xcm_executor::Config,
MessagesPalletInstance: 'static,
ValidatorIdOf<Runtime>: From<AccountIdOf<Runtime>>,
<Runtime as frame_system::Config>::AccountId: From<AccountId32>,
HrmpChannelOpener: frame_support::inherent::ProvideInherent<
Call = cumulus_pallet_parachain_system::Call<Runtime>,
>,
@@ -267,12 +304,14 @@ pub fn message_dispatch_routing_works<
.with_tracing()
.build()
.execute_with(|| {
prepare_configuration();
let mut alice = [0u8; 32];
alice[0] = 1;
let included_head = RuntimeHelper::<Runtime, AllPalletsWithoutSystem>::run_to_block(
2,
AccountId::from(alice),
AccountId::from(alice).into(),
);
// 1. this message is sent from other global consensus with destination of this Runtime relay chain (UMP)
let bridging_message =
@@ -343,6 +382,7 @@ pub fn relayed_incoming_message_works<Runtime, AllPalletsWithoutSystem, XcmConfi
sibling_parachain_id: u32,
local_relay_chain_id: NetworkId,
lane_id: LaneId,
prepare_configuration: impl Fn(),
) where
Runtime: frame_system::Config
+ pallet_balances::Config
@@ -374,11 +414,11 @@ pub fn relayed_incoming_message_works<Runtime, AllPalletsWithoutSystem, XcmConfi
ParaHash: From<<<Runtime as pallet_bridge_grandpa::Config<GPI>>::BridgedChain as bp_runtime::Chain>::Hash>,
<Runtime as frame_system::Config>::AccountId:
Into<<<Runtime as frame_system::Config>::RuntimeOrigin as OriginTrait>::AccountId>,
<Runtime as frame_system::Config>::AccountId: From<AccountId32>,
AccountIdOf<Runtime>: From<sp_core::sr25519::Public>,
<Runtime as pallet_bridge_messages::Config<MPI>>::InboundRelayer: From<AccountId32>,
{
assert_ne!(runtime_para_id, sibling_parachain_id);
assert_ne!(runtime_para_id, bridged_para_id);
ExtBuilder::<Runtime>::default()
.with_collators(collator_session_key.collators())
@@ -388,12 +428,14 @@ pub fn relayed_incoming_message_works<Runtime, AllPalletsWithoutSystem, XcmConfi
.with_tracing()
.build()
.execute_with(|| {
prepare_configuration();
let mut alice = [0u8; 32];
alice[0] = 1;
let included_head = RuntimeHelper::<Runtime, AllPalletsWithoutSystem>::run_to_block(
2,
AccountId::from(alice),
AccountId::from(alice).into(),
);
mock_open_hrmp_channel::<Runtime, HrmpChannelOpener>(
runtime_para_id.into(),
@@ -528,15 +570,24 @@ pub fn relayed_incoming_message_works<Runtime, AllPalletsWithoutSystem, XcmConfi
.last_delivered_nonce(),
1,
);
// verify relayed bridged XCM message is dispatched to destination sibling para
let dispatched = RuntimeHelper::<cumulus_pallet_xcmp_queue::Pallet<Runtime>>::take_xcm(
sibling_parachain_id.into(),
)
.unwrap();
let mut dispatched = xcm::latest::Xcm::<()>::try_from(dispatched).unwrap();
// We use `WithUniqueTopic`, so expect a trailing `SetTopic`.
assert_matches!(dispatched.0.pop(), Some(SetTopic(..)));
assert_eq!(dispatched, expected_dispatch);
// verify contains original message
let dispatched = xcm::latest::Xcm::<()>::try_from(dispatched).unwrap();
let mut dispatched_clone = dispatched.clone();
for (idx, expected_instr) in expected_dispatch.0.iter().enumerate() {
assert_eq!(expected_instr, &dispatched.0[idx]);
assert_eq!(expected_instr, &dispatched_clone.0.remove(0));
}
match dispatched_clone.0.len() {
0 => (),
1 => assert!(matches!(dispatched_clone.0[0], SetTopic(_))),
count => assert!(false, "Unexpected messages count: {:?}", count),
}
})
}
@@ -557,6 +608,7 @@ pub fn complex_relay_extrinsic_works<Runtime, AllPalletsWithoutSystem, XcmConfig
sp_keyring::AccountKeyring,
pallet_utility::Call::<Runtime>
) -> sp_runtime::DispatchOutcome,
prepare_configuration: impl Fn(),
) where
Runtime: frame_system::Config
+ pallet_balances::Config
@@ -591,6 +643,7 @@ pub fn complex_relay_extrinsic_works<Runtime, AllPalletsWithoutSystem, XcmConfig
<Runtime as frame_system::Config>::AccountId:
Into<<<Runtime as frame_system::Config>::RuntimeOrigin as OriginTrait>::AccountId>,
AccountIdOf<Runtime>: From<sp_core::sr25519::Public>,
<Runtime as frame_system::Config>::AccountId: From<AccountId32>,
<Runtime as pallet_bridge_messages::Config<MPI>>::InboundRelayer: From<AccountId32>,
<Runtime as pallet_utility::Config>::RuntimeCall:
From<pallet_bridge_grandpa::Call<Runtime, GPI>>
@@ -598,7 +651,6 @@ pub fn complex_relay_extrinsic_works<Runtime, AllPalletsWithoutSystem, XcmConfig
+ From<pallet_bridge_messages::Call<Runtime, MPI>>
{
assert_ne!(runtime_para_id, sibling_parachain_id);
assert_ne!(runtime_para_id, bridged_para_id);
// Relayer account at local/this BH.
let relayer_at_target = Bob;
@@ -617,12 +669,14 @@ pub fn complex_relay_extrinsic_works<Runtime, AllPalletsWithoutSystem, XcmConfig
.with_tracing()
.build()
.execute_with(|| {
prepare_configuration();
let mut alice = [0u8; 32];
alice[0] = 1;
let included_head = RuntimeHelper::<Runtime, AllPalletsWithoutSystem>::run_to_block(
2,
AccountId::from(alice),
AccountId::from(alice).into(),
);
let zero: BlockNumberFor<Runtime> = 0u32.into();
let genesis_hash = frame_system::Pallet::<Runtime>::block_hash(zero);
@@ -678,7 +732,7 @@ pub fn complex_relay_extrinsic_works<Runtime, AllPalletsWithoutSystem, XcmConfig
message_proof,
) = test_data::make_complex_relayer_proofs::<BridgedHeader<Runtime, GPI>, MB, ()>(
lane_id,
xcm.into(),
xcm.clone().into(),
message_nonce,
message_destination,
para_header_number,
@@ -769,18 +823,133 @@ pub fn complex_relay_extrinsic_works<Runtime, AllPalletsWithoutSystem, XcmConfig
msg_proofs_rewards_account
)
.is_some());
// verify relayed bridged XCM message is dispatched to destination sibling para
let dispatched = RuntimeHelper::<cumulus_pallet_xcmp_queue::Pallet<Runtime>>::take_xcm(
sibling_parachain_id.into(),
)
.unwrap();
let mut dispatched = xcm::latest::Xcm::<()>::try_from(dispatched).unwrap();
// We use `WithUniqueTopic`, so expect a trailing `SetTopic`.
assert_matches!(dispatched.0.pop(), Some(SetTopic(..)));
assert_eq!(dispatched, expected_dispatch);
// verify contains original message
let dispatched = xcm::latest::Xcm::<()>::try_from(dispatched).unwrap();
let mut dispatched_clone = dispatched.clone();
for (idx, expected_instr) in expected_dispatch.0.iter().enumerate() {
assert_eq!(expected_instr, &dispatched.0[idx]);
assert_eq!(expected_instr, &dispatched_clone.0.remove(0));
}
match dispatched_clone.0.len() {
0 => (),
1 => assert!(matches!(dispatched_clone.0[0], SetTopic(_))),
count => assert!(false, "Unexpected messages count: {:?}", count),
}
})
}
/// Estimates fee for paid `ExportMessage` processing.
pub fn can_calculate_weight_for_paid_export_message_with_reserve_transfer<
Runtime,
XcmConfig,
WeightToFee,
>() -> u128
where
Runtime: frame_system::Config + pallet_balances::Config,
XcmConfig: xcm_executor::Config,
WeightToFee: frame_support::weights::WeightToFee<Balance = BalanceOf<Runtime>>,
<WeightToFee as frame_support::weights::WeightToFee>::Balance: From<u128> + Into<u128>,
{
// data here are not relevant for weighing
let mut xcm = Xcm(vec![
WithdrawAsset(MultiAssets::from(vec![MultiAsset {
id: Concrete(MultiLocation { parents: 1, interior: Here }),
fun: Fungible(34333299),
}])),
BuyExecution {
fees: MultiAsset {
id: Concrete(MultiLocation { parents: 1, interior: Here }),
fun: Fungible(34333299),
},
weight_limit: Unlimited,
},
ExportMessage {
network: Polkadot,
destination: X1(Parachain(1000)),
xcm: Xcm(vec![
ReserveAssetDeposited(MultiAssets::from(vec![MultiAsset {
id: Concrete(MultiLocation {
parents: 2,
interior: X1(GlobalConsensus(Kusama)),
}),
fun: Fungible(1000000000000),
}])),
ClearOrigin,
BuyExecution {
fees: MultiAsset {
id: Concrete(MultiLocation {
parents: 2,
interior: X1(GlobalConsensus(Kusama)),
}),
fun: Fungible(1000000000000),
},
weight_limit: Unlimited,
},
DepositAsset {
assets: Wild(AllCounted(1)),
beneficiary: MultiLocation {
parents: 0,
interior: X1(xcm::latest::prelude::AccountId32 {
network: None,
id: [
212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159,
214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165,
109, 162, 125,
],
}),
},
},
SetTopic([
116, 82, 194, 132, 171, 114, 217, 165, 23, 37, 161, 177, 165, 179, 247, 114,
137, 101, 147, 70, 28, 157, 168, 32, 154, 63, 74, 228, 152, 180, 5, 63,
]),
]),
},
RefundSurplus,
DepositAsset {
assets: Wild(All),
beneficiary: MultiLocation { parents: 1, interior: X1(Parachain(1000)) },
},
SetTopic([
36, 224, 250, 165, 82, 195, 67, 110, 160, 170, 140, 87, 217, 62, 201, 164, 42, 98, 219,
157, 124, 105, 248, 25, 131, 218, 199, 36, 109, 173, 100, 122,
]),
]);
// get weight
let weight = XcmConfig::Weigher::weight(&mut xcm);
assert_ok!(weight);
let weight = weight.unwrap();
// check if sane
let max_expected = Runtime::BlockWeights::get().max_block / 10;
assert!(
weight.all_lte(max_expected),
"calculated weight: {:?}, max_expected: {:?}",
weight,
max_expected
);
// check fee, should not be 0
let estimated_fee = WeightToFee::weight_to_fee(&weight);
assert!(estimated_fee > BalanceOf::<Runtime>::zero());
sp_tracing::try_init_simple();
log::error!(
target: "bridges::estimate",
"Estimate fee: {:?} for `ExportMessage` for runtime: {:?}",
estimated_fee,
Runtime::Version::get(),
);
estimated_fee.into()
}
pub mod test_data {
use super::*;
use bp_header_chain::justification::GrandpaJustification;
@@ -928,7 +1097,7 @@ pub mod test_data {
);
/// Simulates `HaulBlobExporter` and all its wrapping and captures generated plain bytes,
/// which are transfered over bridge.
/// which are transferred over bridge.
pub(crate) fn simulate_message_exporter_on_bridged_chain<
SourceNetwork: Get<NetworkId>,
DestinationNetwork: Get<NetworkId>,