mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-31 00:31:02 +00:00
Tests for BridgeHub(s) <> remote GRANDPA chain (#2692)
So far the `bridge-hub-test-utils` contained a tests set for testing BridgeHub runtime that is bridging with the remote **parachain**. But we have https://github.com/paritytech/polkadot-sdk/pull/2540 coming, which would add Rococo <> Bulletin chain bridge (where Bulletin = standalone chain that is using GRANDPA finality). Then it'll be expanded to Polkadot BH as well. So this PR adds the same set of tests to the `bridge-hub-test-utils`, but for the case when remote chain is the chain with GRANDPA finality. There's a lot of changes in this PR - I'll describe some: - I've added `BasicParachainRuntime` trait to decrease number of lines we need to add to `where` clause. Could revert, but imo it is useful; - `cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_data` is a submodule for generating test data for the test sets. `from_parachain.rs` is used in tests for the case when remote chain is a parachain, `from_grandpa_chain.rs` - for the bridges with remote GRANDPA chains. `mod.rs` has some code, shared by both types of tests; - `cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_data` is a submodule with all test cases. The `mod.rs` has tests, suitable for all cases. There's also `wth_parachain.rs` and `with_grandpa_chain.rs` with the same meaning as above; - I've merged the "core" code of two previous tests - `relayed_incoming_message_works` and `complex_relay_extrinsic_works` into one single `relayed_incoming_message_works` test. So now we are always constructing extrinsics and are dispatching them using executive module (meaning all signed extensions are also tested). New test set is used here: https://github.com/paritytech/polkadot-sdk/pull/2540. Once this PR is merged, I'll merge that other PR with master to remove duplicate changes. I'm also planning to cleanup generic constraints + remove some unnecessary assumptions about used chains in a follow-up PRs. But for now I think this PR has enough changes, so don't want to complicate it even more. --- Breaking changes for the code that have used those tests before: - the `construct_and_apply_extrinsic` callback now accepts the `RuntimeCall` instead of the `pallet_utility::Call`; - the `construct_and_apply_extrinsic` now may be called multiple times for the single test, so make sure the `frame_system::CheckNonce` is correctly constructed; - all previous tests have been moved from `bridge_hub_test_utils::test_cases` to `bridge_hub_test_utils::test_cases::from_parachain` module; - there are several changes in test arguments - please refer to https://github.com/paritytech/polkadot-sdk/compare/sv-tests-for-bridge-with-remote-grandpa-chain?expand=1#diff-79a28d4d3e1749050341c2424f00c4c139825b1a20937767f83e58b95166735c for details.
This commit is contained in:
committed by
GitHub
parent
3c5fcbe637
commit
9ecb2d3391
Generated
+2
@@ -1991,6 +1991,7 @@ dependencies = [
|
|||||||
"frame-executive",
|
"frame-executive",
|
||||||
"frame-support",
|
"frame-support",
|
||||||
"frame-system",
|
"frame-system",
|
||||||
|
"impl-trait-for-tuples",
|
||||||
"log",
|
"log",
|
||||||
"pallet-balances",
|
"pallet-balances",
|
||||||
"pallet-bridge-grandpa",
|
"pallet-bridge-grandpa",
|
||||||
@@ -2009,6 +2010,7 @@ dependencies = [
|
|||||||
"sp-io",
|
"sp-io",
|
||||||
"sp-keyring",
|
"sp-keyring",
|
||||||
"sp-runtime",
|
"sp-runtime",
|
||||||
|
"sp-std 8.0.0",
|
||||||
"sp-tracing 10.0.0",
|
"sp-tracing 10.0.0",
|
||||||
"staging-parachain-info",
|
"staging-parachain-info",
|
||||||
"staging-xcm",
|
"staging-xcm",
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ use bridge_hub_rococo_runtime::{
|
|||||||
};
|
};
|
||||||
use codec::{Decode, Encode};
|
use codec::{Decode, Encode};
|
||||||
use frame_support::{dispatch::GetDispatchInfo, parameter_types, traits::ConstU8};
|
use frame_support::{dispatch::GetDispatchInfo, parameter_types, traits::ConstU8};
|
||||||
use frame_system::pallet_prelude::HeaderFor;
|
|
||||||
use parachains_common::{rococo::fee::WeightToFee, AccountId, AuraId, Balance};
|
use parachains_common::{rococo::fee::WeightToFee, AccountId, AuraId, Balance};
|
||||||
use sp_keyring::AccountKeyring::Alice;
|
use sp_keyring::AccountKeyring::Alice;
|
||||||
use sp_runtime::{
|
use sp_runtime::{
|
||||||
@@ -46,13 +45,16 @@ fn construct_extrinsic(
|
|||||||
sender: sp_keyring::AccountKeyring,
|
sender: sp_keyring::AccountKeyring,
|
||||||
call: RuntimeCall,
|
call: RuntimeCall,
|
||||||
) -> UncheckedExtrinsic {
|
) -> UncheckedExtrinsic {
|
||||||
|
let account_id = AccountId32::from(sender.public());
|
||||||
let extra: SignedExtra = (
|
let extra: SignedExtra = (
|
||||||
frame_system::CheckNonZeroSender::<Runtime>::new(),
|
frame_system::CheckNonZeroSender::<Runtime>::new(),
|
||||||
frame_system::CheckSpecVersion::<Runtime>::new(),
|
frame_system::CheckSpecVersion::<Runtime>::new(),
|
||||||
frame_system::CheckTxVersion::<Runtime>::new(),
|
frame_system::CheckTxVersion::<Runtime>::new(),
|
||||||
frame_system::CheckGenesis::<Runtime>::new(),
|
frame_system::CheckGenesis::<Runtime>::new(),
|
||||||
frame_system::CheckEra::<Runtime>::from(Era::immortal()),
|
frame_system::CheckEra::<Runtime>::from(Era::immortal()),
|
||||||
frame_system::CheckNonce::<Runtime>::from(0),
|
frame_system::CheckNonce::<Runtime>::from(
|
||||||
|
frame_system::Pallet::<Runtime>::account(&account_id).nonce,
|
||||||
|
),
|
||||||
frame_system::CheckWeight::<Runtime>::new(),
|
frame_system::CheckWeight::<Runtime>::new(),
|
||||||
pallet_transaction_payment::ChargeTransactionPayment::<Runtime>::from(0),
|
pallet_transaction_payment::ChargeTransactionPayment::<Runtime>::from(0),
|
||||||
BridgeRejectObsoleteHeadersAndMessages::default(),
|
BridgeRejectObsoleteHeadersAndMessages::default(),
|
||||||
@@ -62,7 +64,7 @@ fn construct_extrinsic(
|
|||||||
let signature = payload.using_encoded(|e| sender.sign(e));
|
let signature = payload.using_encoded(|e| sender.sign(e));
|
||||||
UncheckedExtrinsic::new_signed(
|
UncheckedExtrinsic::new_signed(
|
||||||
call,
|
call,
|
||||||
AccountId32::from(sender.public()).into(),
|
account_id.into(),
|
||||||
Signature::Sr25519(signature.clone()),
|
Signature::Sr25519(signature.clone()),
|
||||||
extra,
|
extra,
|
||||||
)
|
)
|
||||||
@@ -70,10 +72,9 @@ fn construct_extrinsic(
|
|||||||
|
|
||||||
fn construct_and_apply_extrinsic(
|
fn construct_and_apply_extrinsic(
|
||||||
relayer_at_target: sp_keyring::AccountKeyring,
|
relayer_at_target: sp_keyring::AccountKeyring,
|
||||||
batch: pallet_utility::Call<Runtime>,
|
call: RuntimeCall,
|
||||||
) -> sp_runtime::DispatchOutcome {
|
) -> sp_runtime::DispatchOutcome {
|
||||||
let batch_call = RuntimeCall::Utility(batch);
|
let xt = construct_extrinsic(relayer_at_target, call);
|
||||||
let xt = construct_extrinsic(relayer_at_target, batch_call);
|
|
||||||
let r = Executive::apply_extrinsic(xt);
|
let r = Executive::apply_extrinsic(xt);
|
||||||
r.unwrap()
|
r.unwrap()
|
||||||
}
|
}
|
||||||
@@ -85,10 +86,6 @@ fn construct_and_estimate_extrinsic_fee(batch: pallet_utility::Call<Runtime>) ->
|
|||||||
TransactionPayment::compute_fee(xt.encoded_size() as _, &batch_info, 0)
|
TransactionPayment::compute_fee(xt.encoded_size() as _, &batch_info, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn executive_init_block(header: &HeaderFor<Runtime>) {
|
|
||||||
Executive::initialize_block(header)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn collator_session_keys() -> bridge_hub_test_utils::CollatorSessionKeys<Runtime> {
|
fn collator_session_keys() -> bridge_hub_test_utils::CollatorSessionKeys<Runtime> {
|
||||||
bridge_hub_test_utils::CollatorSessionKeys::new(
|
bridge_hub_test_utils::CollatorSessionKeys::new(
|
||||||
AccountId::from(Alice),
|
AccountId::from(Alice),
|
||||||
@@ -237,10 +234,9 @@ mod bridge_hub_rococo_tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn relayed_incoming_message_works() {
|
fn relayed_incoming_message_works() {
|
||||||
// from Westend
|
// from Westend
|
||||||
bridge_hub_test_utils::test_cases::relayed_incoming_message_works::<
|
bridge_hub_test_utils::test_cases::from_parachain::relayed_incoming_message_works::<
|
||||||
Runtime,
|
Runtime,
|
||||||
AllPalletsWithoutSystem,
|
AllPalletsWithoutSystem,
|
||||||
XcmConfig,
|
|
||||||
ParachainSystem,
|
ParachainSystem,
|
||||||
BridgeGrandpaWestendInstance,
|
BridgeGrandpaWestendInstance,
|
||||||
BridgeParachainWestendInstance,
|
BridgeParachainWestendInstance,
|
||||||
@@ -250,17 +246,19 @@ mod bridge_hub_rococo_tests {
|
|||||||
collator_session_keys(),
|
collator_session_keys(),
|
||||||
bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID,
|
bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID,
|
||||||
bp_bridge_hub_westend::BRIDGE_HUB_WESTEND_PARACHAIN_ID,
|
bp_bridge_hub_westend::BRIDGE_HUB_WESTEND_PARACHAIN_ID,
|
||||||
|
BridgeHubWestendChainId::get(),
|
||||||
SIBLING_PARACHAIN_ID,
|
SIBLING_PARACHAIN_ID,
|
||||||
Rococo,
|
Rococo,
|
||||||
XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WESTEND,
|
XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WESTEND,
|
||||||
|| (),
|
|| (),
|
||||||
|
construct_and_apply_extrinsic,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
pub fn complex_relay_extrinsic_works() {
|
pub fn complex_relay_extrinsic_works() {
|
||||||
// for Westend
|
// for Westend
|
||||||
bridge_hub_test_utils::test_cases::complex_relay_extrinsic_works::<
|
bridge_hub_test_utils::test_cases::from_parachain::complex_relay_extrinsic_works::<
|
||||||
Runtime,
|
Runtime,
|
||||||
AllPalletsWithoutSystem,
|
AllPalletsWithoutSystem,
|
||||||
XcmConfig,
|
XcmConfig,
|
||||||
@@ -277,10 +275,8 @@ mod bridge_hub_rococo_tests {
|
|||||||
BridgeHubWestendChainId::get(),
|
BridgeHubWestendChainId::get(),
|
||||||
Rococo,
|
Rococo,
|
||||||
XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WESTEND,
|
XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WESTEND,
|
||||||
ExistentialDeposit::get(),
|
|
||||||
executive_init_block,
|
|
||||||
construct_and_apply_extrinsic,
|
|
||||||
|| (),
|
|| (),
|
||||||
|
construct_and_apply_extrinsic,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -304,7 +300,7 @@ mod bridge_hub_rococo_tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
pub fn can_calculate_fee_for_complex_message_delivery_transaction() {
|
pub fn can_calculate_fee_for_complex_message_delivery_transaction() {
|
||||||
let estimated = bridge_hub_test_utils::test_cases::can_calculate_fee_for_complex_message_delivery_transaction::<
|
let estimated = bridge_hub_test_utils::test_cases::from_parachain::can_calculate_fee_for_complex_message_delivery_transaction::<
|
||||||
Runtime,
|
Runtime,
|
||||||
BridgeGrandpaWestendInstance,
|
BridgeGrandpaWestendInstance,
|
||||||
BridgeParachainWestendInstance,
|
BridgeParachainWestendInstance,
|
||||||
@@ -327,7 +323,7 @@ mod bridge_hub_rococo_tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
pub fn can_calculate_fee_for_complex_message_confirmation_transaction() {
|
pub fn can_calculate_fee_for_complex_message_confirmation_transaction() {
|
||||||
let estimated = bridge_hub_test_utils::test_cases::can_calculate_fee_for_complex_message_confirmation_transaction::<
|
let estimated = bridge_hub_test_utils::test_cases::from_parachain::can_calculate_fee_for_complex_message_confirmation_transaction::<
|
||||||
Runtime,
|
Runtime,
|
||||||
BridgeGrandpaWestendInstance,
|
BridgeGrandpaWestendInstance,
|
||||||
BridgeParachainWestendInstance,
|
BridgeParachainWestendInstance,
|
||||||
|
|||||||
@@ -32,7 +32,6 @@ use bridge_to_rococo_config::{
|
|||||||
};
|
};
|
||||||
use codec::{Decode, Encode};
|
use codec::{Decode, Encode};
|
||||||
use frame_support::{dispatch::GetDispatchInfo, parameter_types, traits::ConstU8};
|
use frame_support::{dispatch::GetDispatchInfo, parameter_types, traits::ConstU8};
|
||||||
use frame_system::pallet_prelude::HeaderFor;
|
|
||||||
use parachains_common::{westend::fee::WeightToFee, AccountId, AuraId, Balance};
|
use parachains_common::{westend::fee::WeightToFee, AccountId, AuraId, Balance};
|
||||||
use sp_keyring::AccountKeyring::Alice;
|
use sp_keyring::AccountKeyring::Alice;
|
||||||
use sp_runtime::{
|
use sp_runtime::{
|
||||||
@@ -52,13 +51,16 @@ fn construct_extrinsic(
|
|||||||
sender: sp_keyring::AccountKeyring,
|
sender: sp_keyring::AccountKeyring,
|
||||||
call: RuntimeCall,
|
call: RuntimeCall,
|
||||||
) -> UncheckedExtrinsic {
|
) -> UncheckedExtrinsic {
|
||||||
|
let account_id = AccountId32::from(sender.public());
|
||||||
let extra: SignedExtra = (
|
let extra: SignedExtra = (
|
||||||
frame_system::CheckNonZeroSender::<Runtime>::new(),
|
frame_system::CheckNonZeroSender::<Runtime>::new(),
|
||||||
frame_system::CheckSpecVersion::<Runtime>::new(),
|
frame_system::CheckSpecVersion::<Runtime>::new(),
|
||||||
frame_system::CheckTxVersion::<Runtime>::new(),
|
frame_system::CheckTxVersion::<Runtime>::new(),
|
||||||
frame_system::CheckGenesis::<Runtime>::new(),
|
frame_system::CheckGenesis::<Runtime>::new(),
|
||||||
frame_system::CheckEra::<Runtime>::from(Era::immortal()),
|
frame_system::CheckEra::<Runtime>::from(Era::immortal()),
|
||||||
frame_system::CheckNonce::<Runtime>::from(0),
|
frame_system::CheckNonce::<Runtime>::from(
|
||||||
|
frame_system::Pallet::<Runtime>::account(&account_id).nonce,
|
||||||
|
),
|
||||||
frame_system::CheckWeight::<Runtime>::new(),
|
frame_system::CheckWeight::<Runtime>::new(),
|
||||||
pallet_transaction_payment::ChargeTransactionPayment::<Runtime>::from(0),
|
pallet_transaction_payment::ChargeTransactionPayment::<Runtime>::from(0),
|
||||||
BridgeRejectObsoleteHeadersAndMessages::default(),
|
BridgeRejectObsoleteHeadersAndMessages::default(),
|
||||||
@@ -68,7 +70,7 @@ fn construct_extrinsic(
|
|||||||
let signature = payload.using_encoded(|e| sender.sign(e));
|
let signature = payload.using_encoded(|e| sender.sign(e));
|
||||||
UncheckedExtrinsic::new_signed(
|
UncheckedExtrinsic::new_signed(
|
||||||
call,
|
call,
|
||||||
AccountId32::from(sender.public()).into(),
|
account_id.into(),
|
||||||
Signature::Sr25519(signature.clone()),
|
Signature::Sr25519(signature.clone()),
|
||||||
extra,
|
extra,
|
||||||
)
|
)
|
||||||
@@ -76,10 +78,9 @@ fn construct_extrinsic(
|
|||||||
|
|
||||||
fn construct_and_apply_extrinsic(
|
fn construct_and_apply_extrinsic(
|
||||||
relayer_at_target: sp_keyring::AccountKeyring,
|
relayer_at_target: sp_keyring::AccountKeyring,
|
||||||
batch: pallet_utility::Call<Runtime>,
|
call: RuntimeCall,
|
||||||
) -> sp_runtime::DispatchOutcome {
|
) -> sp_runtime::DispatchOutcome {
|
||||||
let batch_call = RuntimeCall::Utility(batch);
|
let xt = construct_extrinsic(relayer_at_target, call);
|
||||||
let xt = construct_extrinsic(relayer_at_target, batch_call);
|
|
||||||
let r = Executive::apply_extrinsic(xt);
|
let r = Executive::apply_extrinsic(xt);
|
||||||
r.unwrap()
|
r.unwrap()
|
||||||
}
|
}
|
||||||
@@ -91,10 +92,6 @@ fn construct_and_estimate_extrinsic_fee(batch: pallet_utility::Call<Runtime>) ->
|
|||||||
TransactionPayment::compute_fee(xt.encoded_size() as _, &batch_info, 0)
|
TransactionPayment::compute_fee(xt.encoded_size() as _, &batch_info, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn executive_init_block(header: &HeaderFor<Runtime>) {
|
|
||||||
Executive::initialize_block(header)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn collator_session_keys() -> bridge_hub_test_utils::CollatorSessionKeys<Runtime> {
|
fn collator_session_keys() -> bridge_hub_test_utils::CollatorSessionKeys<Runtime> {
|
||||||
bridge_hub_test_utils::CollatorSessionKeys::new(
|
bridge_hub_test_utils::CollatorSessionKeys::new(
|
||||||
AccountId::from(Alice),
|
AccountId::from(Alice),
|
||||||
@@ -222,10 +219,9 @@ fn message_dispatch_routing_works() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn relayed_incoming_message_works() {
|
fn relayed_incoming_message_works() {
|
||||||
bridge_hub_test_utils::test_cases::relayed_incoming_message_works::<
|
bridge_hub_test_utils::test_cases::from_parachain::relayed_incoming_message_works::<
|
||||||
Runtime,
|
Runtime,
|
||||||
AllPalletsWithoutSystem,
|
AllPalletsWithoutSystem,
|
||||||
XcmConfig,
|
|
||||||
ParachainSystem,
|
ParachainSystem,
|
||||||
BridgeGrandpaRococoInstance,
|
BridgeGrandpaRococoInstance,
|
||||||
BridgeParachainRococoInstance,
|
BridgeParachainRococoInstance,
|
||||||
@@ -235,16 +231,18 @@ fn relayed_incoming_message_works() {
|
|||||||
collator_session_keys(),
|
collator_session_keys(),
|
||||||
bp_bridge_hub_westend::BRIDGE_HUB_WESTEND_PARACHAIN_ID,
|
bp_bridge_hub_westend::BRIDGE_HUB_WESTEND_PARACHAIN_ID,
|
||||||
bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID,
|
bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID,
|
||||||
|
BridgeHubRococoChainId::get(),
|
||||||
SIBLING_PARACHAIN_ID,
|
SIBLING_PARACHAIN_ID,
|
||||||
Westend,
|
Westend,
|
||||||
XCM_LANE_FOR_ASSET_HUB_WESTEND_TO_ASSET_HUB_ROCOCO,
|
XCM_LANE_FOR_ASSET_HUB_WESTEND_TO_ASSET_HUB_ROCOCO,
|
||||||
|| (),
|
|| (),
|
||||||
|
construct_and_apply_extrinsic,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
pub fn complex_relay_extrinsic_works() {
|
pub fn complex_relay_extrinsic_works() {
|
||||||
bridge_hub_test_utils::test_cases::complex_relay_extrinsic_works::<
|
bridge_hub_test_utils::test_cases::from_parachain::complex_relay_extrinsic_works::<
|
||||||
Runtime,
|
Runtime,
|
||||||
AllPalletsWithoutSystem,
|
AllPalletsWithoutSystem,
|
||||||
XcmConfig,
|
XcmConfig,
|
||||||
@@ -261,10 +259,8 @@ pub fn complex_relay_extrinsic_works() {
|
|||||||
BridgeHubRococoChainId::get(),
|
BridgeHubRococoChainId::get(),
|
||||||
Westend,
|
Westend,
|
||||||
XCM_LANE_FOR_ASSET_HUB_WESTEND_TO_ASSET_HUB_ROCOCO,
|
XCM_LANE_FOR_ASSET_HUB_WESTEND_TO_ASSET_HUB_ROCOCO,
|
||||||
ExistentialDeposit::get(),
|
|
||||||
executive_init_block,
|
|
||||||
construct_and_apply_extrinsic,
|
|
||||||
|| (),
|
|| (),
|
||||||
|
construct_and_apply_extrinsic,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -288,7 +284,7 @@ pub fn can_calculate_weight_for_paid_export_message_with_reserve_transfer() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
pub fn can_calculate_fee_for_complex_message_delivery_transaction() {
|
pub fn can_calculate_fee_for_complex_message_delivery_transaction() {
|
||||||
let estimated = bridge_hub_test_utils::test_cases::can_calculate_fee_for_complex_message_delivery_transaction::<
|
let estimated = bridge_hub_test_utils::test_cases::from_parachain::can_calculate_fee_for_complex_message_delivery_transaction::<
|
||||||
Runtime,
|
Runtime,
|
||||||
BridgeGrandpaRococoInstance,
|
BridgeGrandpaRococoInstance,
|
||||||
BridgeParachainRococoInstance,
|
BridgeParachainRococoInstance,
|
||||||
@@ -311,7 +307,7 @@ pub fn can_calculate_fee_for_complex_message_delivery_transaction() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
pub fn can_calculate_fee_for_complex_message_confirmation_transaction() {
|
pub fn can_calculate_fee_for_complex_message_confirmation_transaction() {
|
||||||
let estimated = bridge_hub_test_utils::test_cases::can_calculate_fee_for_complex_message_confirmation_transaction::<
|
let estimated = bridge_hub_test_utils::test_cases::from_parachain::can_calculate_fee_for_complex_message_confirmation_transaction::<
|
||||||
Runtime,
|
Runtime,
|
||||||
BridgeGrandpaRococoInstance,
|
BridgeGrandpaRococoInstance,
|
||||||
BridgeParachainRococoInstance,
|
BridgeParachainRococoInstance,
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ license = "Apache-2.0"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] }
|
codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] }
|
||||||
|
impl-trait-for-tuples = "0.2"
|
||||||
log = { version = "0.4.20", default-features = false }
|
log = { version = "0.4.20", default-features = false }
|
||||||
|
|
||||||
# Substrate
|
# Substrate
|
||||||
@@ -19,6 +20,7 @@ sp-core = { path = "../../../../../substrate/primitives/core", default-features
|
|||||||
sp-io = { path = "../../../../../substrate/primitives/io", default-features = false }
|
sp-io = { path = "../../../../../substrate/primitives/io", default-features = false }
|
||||||
sp-keyring = { path = "../../../../../substrate/primitives/keyring" }
|
sp-keyring = { path = "../../../../../substrate/primitives/keyring" }
|
||||||
sp-runtime = { path = "../../../../../substrate/primitives/runtime", default-features = false }
|
sp-runtime = { path = "../../../../../substrate/primitives/runtime", default-features = false }
|
||||||
|
sp-std = { path = "../../../../../substrate/primitives/std", default-features = false }
|
||||||
sp-tracing = { path = "../../../../../substrate/primitives/tracing" }
|
sp-tracing = { path = "../../../../../substrate/primitives/tracing" }
|
||||||
pallet-balances = { path = "../../../../../substrate/frame/balances", default-features = false }
|
pallet-balances = { path = "../../../../../substrate/frame/balances", default-features = false }
|
||||||
pallet-utility = { path = "../../../../../substrate/frame/utility", default-features = false }
|
pallet-utility = { path = "../../../../../substrate/frame/utility", default-features = false }
|
||||||
@@ -90,6 +92,7 @@ std = [
|
|||||||
"sp-core/std",
|
"sp-core/std",
|
||||||
"sp-io/std",
|
"sp-io/std",
|
||||||
"sp-runtime/std",
|
"sp-runtime/std",
|
||||||
|
"sp-std/std",
|
||||||
"xcm-builder/std",
|
"xcm-builder/std",
|
||||||
"xcm-executor/std",
|
"xcm-executor/std",
|
||||||
"xcm/std",
|
"xcm/std",
|
||||||
|
|||||||
@@ -17,5 +17,7 @@
|
|||||||
//! Module contains predefined test-case scenarios for "BridgeHub" `Runtime`s.
|
//! Module contains predefined test-case scenarios for "BridgeHub" `Runtime`s.
|
||||||
|
|
||||||
pub mod test_cases;
|
pub mod test_cases;
|
||||||
|
pub mod test_data;
|
||||||
|
|
||||||
pub use bp_test_utils::test_header;
|
pub use bp_test_utils::test_header;
|
||||||
pub use parachains_runtimes_test_utils::*;
|
pub use parachains_runtimes_test_utils::*;
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
+442
@@ -0,0 +1,442 @@
|
|||||||
|
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Cumulus.
|
||||||
|
|
||||||
|
// Cumulus 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.
|
||||||
|
|
||||||
|
// Cumulus 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 Cumulus. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//! Module contains predefined test-case scenarios for `Runtime` with bridging capabilities
|
||||||
|
//! with remote GRANDPA chain.
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
test_cases::{helpers, run_test},
|
||||||
|
test_data,
|
||||||
|
};
|
||||||
|
|
||||||
|
use bp_header_chain::ChainWithGrandpa;
|
||||||
|
use bp_messages::{
|
||||||
|
source_chain::TargetHeaderChain, target_chain::SourceHeaderChain, LaneId,
|
||||||
|
UnrewardedRelayersState,
|
||||||
|
};
|
||||||
|
use bp_relayers::{RewardsAccountOwner, RewardsAccountParams};
|
||||||
|
use bp_runtime::{HashOf, UnderlyingChainOf};
|
||||||
|
use bridge_runtime_common::{
|
||||||
|
messages::{
|
||||||
|
source::FromBridgedChainMessagesDeliveryProof, target::FromBridgedChainMessagesProof,
|
||||||
|
BridgedChain as MessageBridgedChain, MessageBridge, ThisChain as MessageThisChain,
|
||||||
|
},
|
||||||
|
messages_xcm_extension::XcmAsPlainPayload,
|
||||||
|
};
|
||||||
|
use frame_support::traits::{Get, OnFinalize, OnInitialize, OriginTrait};
|
||||||
|
use frame_system::pallet_prelude::BlockNumberFor;
|
||||||
|
use parachains_runtimes_test_utils::{
|
||||||
|
AccountIdOf, BasicParachainRuntime, CollatorSessionKeys, ValidatorIdOf,
|
||||||
|
};
|
||||||
|
use sp_keyring::AccountKeyring::*;
|
||||||
|
use sp_runtime::{traits::Header as HeaderT, AccountId32};
|
||||||
|
use xcm::latest::prelude::*;
|
||||||
|
|
||||||
|
/// Test-case makes sure that Runtime can dispatch XCM messages submitted by relayer,
|
||||||
|
/// with proofs (finality, message) independently submitted.
|
||||||
|
/// Also verifies relayer transaction signed extensions work as intended.
|
||||||
|
pub fn relayed_incoming_message_works<
|
||||||
|
Runtime,
|
||||||
|
AllPalletsWithoutSystem,
|
||||||
|
HrmpChannelOpener,
|
||||||
|
GPI,
|
||||||
|
MPI,
|
||||||
|
MB,
|
||||||
|
>(
|
||||||
|
collator_session_key: CollatorSessionKeys<Runtime>,
|
||||||
|
runtime_para_id: u32,
|
||||||
|
bridged_chain_id: bp_runtime::ChainId,
|
||||||
|
sibling_parachain_id: u32,
|
||||||
|
local_relay_chain_id: NetworkId,
|
||||||
|
lane_id: LaneId,
|
||||||
|
prepare_configuration: impl Fn(),
|
||||||
|
construct_and_apply_extrinsic: fn(
|
||||||
|
sp_keyring::AccountKeyring,
|
||||||
|
<Runtime as frame_system::Config>::RuntimeCall,
|
||||||
|
) -> sp_runtime::DispatchOutcome,
|
||||||
|
) where
|
||||||
|
Runtime: BasicParachainRuntime
|
||||||
|
+ cumulus_pallet_xcmp_queue::Config
|
||||||
|
+ pallet_bridge_grandpa::Config<
|
||||||
|
GPI,
|
||||||
|
BridgedChain = UnderlyingChainOf<MessageBridgedChain<MB>>,
|
||||||
|
> + pallet_bridge_messages::Config<MPI>
|
||||||
|
+ pallet_bridge_relayers::Config,
|
||||||
|
AllPalletsWithoutSystem:
|
||||||
|
OnInitialize<BlockNumberFor<Runtime>> + OnFinalize<BlockNumberFor<Runtime>>,
|
||||||
|
GPI: 'static,
|
||||||
|
MPI: 'static,
|
||||||
|
MB: MessageBridge,
|
||||||
|
<MB as MessageBridge>::BridgedChain: Send + Sync + 'static,
|
||||||
|
<MB as MessageBridge>::ThisChain: Send + Sync + 'static,
|
||||||
|
UnderlyingChainOf<MessageBridgedChain<MB>>: ChainWithGrandpa,
|
||||||
|
HrmpChannelOpener: frame_support::inherent::ProvideInherent<
|
||||||
|
Call = cumulus_pallet_parachain_system::Call<Runtime>,
|
||||||
|
>,
|
||||||
|
ValidatorIdOf<Runtime>: From<AccountIdOf<Runtime>>,
|
||||||
|
<Runtime as pallet_bridge_messages::Config<MPI>>::SourceHeaderChain: SourceHeaderChain<
|
||||||
|
MessagesProof = FromBridgedChainMessagesProof<HashOf<MessageBridgedChain<MB>>>,
|
||||||
|
>,
|
||||||
|
<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>,
|
||||||
|
<Runtime as frame_system::Config>::RuntimeCall: From<pallet_bridge_grandpa::Call<Runtime, GPI>>
|
||||||
|
+ From<pallet_bridge_messages::Call<Runtime, MPI>>,
|
||||||
|
{
|
||||||
|
helpers::relayed_incoming_message_works::<
|
||||||
|
Runtime,
|
||||||
|
AllPalletsWithoutSystem,
|
||||||
|
HrmpChannelOpener,
|
||||||
|
MPI,
|
||||||
|
>(
|
||||||
|
collator_session_key,
|
||||||
|
runtime_para_id,
|
||||||
|
sibling_parachain_id,
|
||||||
|
local_relay_chain_id,
|
||||||
|
construct_and_apply_extrinsic,
|
||||||
|
|relayer_id_at_this_chain,
|
||||||
|
relayer_id_at_bridged_chain,
|
||||||
|
message_destination,
|
||||||
|
message_nonce,
|
||||||
|
xcm| {
|
||||||
|
let relay_header_number = 5u32.into();
|
||||||
|
|
||||||
|
prepare_configuration();
|
||||||
|
|
||||||
|
// start with bridged relay chain block#0
|
||||||
|
helpers::initialize_bridge_grandpa_pallet::<Runtime, GPI>(
|
||||||
|
test_data::initialization_data::<Runtime, GPI>(0),
|
||||||
|
);
|
||||||
|
|
||||||
|
// generate bridged relay chain finality, parachain heads and message proofs,
|
||||||
|
// to be submitted by relayer to this chain.
|
||||||
|
let (relay_chain_header, grandpa_justification, message_proof) =
|
||||||
|
test_data::from_grandpa_chain::make_complex_relayer_delivery_proofs::<MB, ()>(
|
||||||
|
lane_id,
|
||||||
|
xcm.into(),
|
||||||
|
message_nonce,
|
||||||
|
message_destination,
|
||||||
|
relay_header_number,
|
||||||
|
);
|
||||||
|
|
||||||
|
let relay_chain_header_hash = relay_chain_header.hash();
|
||||||
|
vec![
|
||||||
|
(
|
||||||
|
pallet_bridge_grandpa::Call::<Runtime, GPI>::submit_finality_proof {
|
||||||
|
finality_target: Box::new(relay_chain_header),
|
||||||
|
justification: grandpa_justification,
|
||||||
|
}.into(),
|
||||||
|
helpers::VerifySubmitGrandpaFinalityProofOutcome::<Runtime, GPI>::expect_best_header_hash(relay_chain_header_hash),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
pallet_bridge_messages::Call::<Runtime, MPI>::receive_messages_proof {
|
||||||
|
relayer_id_at_bridged_chain,
|
||||||
|
proof: message_proof,
|
||||||
|
messages_count: 1,
|
||||||
|
dispatch_weight: Weight::from_parts(1000000000, 0),
|
||||||
|
}.into(),
|
||||||
|
Box::new((
|
||||||
|
helpers::VerifySubmitMessagesProofOutcome::<Runtime, MPI>::expect_last_delivered_nonce(lane_id, 1),
|
||||||
|
helpers::VerifyRelayerRewarded::<Runtime>::expect_relayer_reward(
|
||||||
|
relayer_id_at_this_chain,
|
||||||
|
RewardsAccountParams::new(
|
||||||
|
lane_id,
|
||||||
|
bridged_chain_id,
|
||||||
|
RewardsAccountOwner::ThisChain,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Test-case makes sure that Runtime can dispatch XCM messages submitted by relayer,
|
||||||
|
/// with proofs (finality, message) batched together in signed extrinsic.
|
||||||
|
/// Also verifies relayer transaction signed extensions work as intended.
|
||||||
|
pub fn complex_relay_extrinsic_works<
|
||||||
|
Runtime,
|
||||||
|
AllPalletsWithoutSystem,
|
||||||
|
XcmConfig,
|
||||||
|
HrmpChannelOpener,
|
||||||
|
GPI,
|
||||||
|
MPI,
|
||||||
|
MB,
|
||||||
|
>(
|
||||||
|
collator_session_key: CollatorSessionKeys<Runtime>,
|
||||||
|
runtime_para_id: u32,
|
||||||
|
sibling_parachain_id: u32,
|
||||||
|
bridged_chain_id: bp_runtime::ChainId,
|
||||||
|
local_relay_chain_id: NetworkId,
|
||||||
|
lane_id: LaneId,
|
||||||
|
prepare_configuration: impl Fn(),
|
||||||
|
construct_and_apply_extrinsic: fn(
|
||||||
|
sp_keyring::AccountKeyring,
|
||||||
|
<Runtime as frame_system::Config>::RuntimeCall,
|
||||||
|
) -> sp_runtime::DispatchOutcome,
|
||||||
|
) where
|
||||||
|
Runtime: BasicParachainRuntime
|
||||||
|
+ cumulus_pallet_xcmp_queue::Config
|
||||||
|
+ pallet_bridge_grandpa::Config<
|
||||||
|
GPI,
|
||||||
|
BridgedChain = UnderlyingChainOf<MessageBridgedChain<MB>>,
|
||||||
|
> + pallet_bridge_messages::Config<MPI>
|
||||||
|
+ pallet_bridge_relayers::Config
|
||||||
|
+ pallet_utility::Config,
|
||||||
|
AllPalletsWithoutSystem:
|
||||||
|
OnInitialize<BlockNumberFor<Runtime>> + OnFinalize<BlockNumberFor<Runtime>>,
|
||||||
|
GPI: 'static,
|
||||||
|
MPI: 'static,
|
||||||
|
MB: MessageBridge,
|
||||||
|
<MB as MessageBridge>::BridgedChain: Send + Sync + 'static,
|
||||||
|
<MB as MessageBridge>::ThisChain: Send + Sync + 'static,
|
||||||
|
UnderlyingChainOf<MessageBridgedChain<MB>>: ChainWithGrandpa,
|
||||||
|
HrmpChannelOpener: frame_support::inherent::ProvideInherent<
|
||||||
|
Call = cumulus_pallet_parachain_system::Call<Runtime>,
|
||||||
|
>,
|
||||||
|
ValidatorIdOf<Runtime>: From<AccountIdOf<Runtime>>,
|
||||||
|
<Runtime as pallet_bridge_messages::Config<MPI>>::SourceHeaderChain: SourceHeaderChain<
|
||||||
|
MessagesProof = FromBridgedChainMessagesProof<HashOf<MessageBridgedChain<MB>>>,
|
||||||
|
>,
|
||||||
|
<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>,
|
||||||
|
<Runtime as pallet_utility::Config>::RuntimeCall: From<pallet_bridge_grandpa::Call<Runtime, GPI>>
|
||||||
|
+ From<pallet_bridge_messages::Call<Runtime, MPI>>,
|
||||||
|
<Runtime as frame_system::Config>::RuntimeCall: From<pallet_utility::Call<Runtime>>,
|
||||||
|
{
|
||||||
|
helpers::relayed_incoming_message_works::<
|
||||||
|
Runtime,
|
||||||
|
AllPalletsWithoutSystem,
|
||||||
|
HrmpChannelOpener,
|
||||||
|
MPI,
|
||||||
|
>(
|
||||||
|
collator_session_key,
|
||||||
|
runtime_para_id,
|
||||||
|
sibling_parachain_id,
|
||||||
|
local_relay_chain_id,
|
||||||
|
construct_and_apply_extrinsic,
|
||||||
|
|relayer_id_at_this_chain,
|
||||||
|
relayer_id_at_bridged_chain,
|
||||||
|
message_destination,
|
||||||
|
message_nonce,
|
||||||
|
xcm| {
|
||||||
|
let relay_header_number = 1u32.into();
|
||||||
|
|
||||||
|
prepare_configuration();
|
||||||
|
|
||||||
|
// start with bridged relay chain block#0
|
||||||
|
helpers::initialize_bridge_grandpa_pallet::<Runtime, GPI>(
|
||||||
|
test_data::initialization_data::<Runtime, GPI>(0),
|
||||||
|
);
|
||||||
|
|
||||||
|
// generate bridged relay chain finality, parachain heads and message proofs,
|
||||||
|
// to be submitted by relayer to this chain.
|
||||||
|
let (relay_chain_header, grandpa_justification, message_proof) =
|
||||||
|
test_data::from_grandpa_chain::make_complex_relayer_delivery_proofs::<MB, ()>(
|
||||||
|
lane_id,
|
||||||
|
xcm.into(),
|
||||||
|
message_nonce,
|
||||||
|
message_destination,
|
||||||
|
relay_header_number,
|
||||||
|
);
|
||||||
|
|
||||||
|
let relay_chain_header_hash = relay_chain_header.hash();
|
||||||
|
vec![(
|
||||||
|
pallet_utility::Call::<Runtime>::batch_all {
|
||||||
|
calls: vec![
|
||||||
|
pallet_bridge_grandpa::Call::<Runtime, GPI>::submit_finality_proof {
|
||||||
|
finality_target: Box::new(relay_chain_header),
|
||||||
|
justification: grandpa_justification,
|
||||||
|
}.into(),
|
||||||
|
pallet_bridge_messages::Call::<Runtime, MPI>::receive_messages_proof {
|
||||||
|
relayer_id_at_bridged_chain,
|
||||||
|
proof: message_proof,
|
||||||
|
messages_count: 1,
|
||||||
|
dispatch_weight: Weight::from_parts(1000000000, 0),
|
||||||
|
}.into(),
|
||||||
|
],
|
||||||
|
}.into(),
|
||||||
|
Box::new((
|
||||||
|
helpers::VerifySubmitGrandpaFinalityProofOutcome::<Runtime, GPI>::expect_best_header_hash(relay_chain_header_hash),
|
||||||
|
helpers::VerifySubmitMessagesProofOutcome::<Runtime, MPI>::expect_last_delivered_nonce(lane_id, 1),
|
||||||
|
helpers::VerifyRelayerRewarded::<Runtime>::expect_relayer_reward(
|
||||||
|
relayer_id_at_this_chain,
|
||||||
|
RewardsAccountParams::new(
|
||||||
|
lane_id,
|
||||||
|
bridged_chain_id,
|
||||||
|
RewardsAccountOwner::ThisChain,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
)]
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Estimates transaction fee for default message delivery transaction (batched with required
|
||||||
|
/// proofs) from bridged GRANDPA chain.
|
||||||
|
pub fn can_calculate_fee_for_complex_message_delivery_transaction<Runtime, GPI, MPI, MB>(
|
||||||
|
collator_session_key: CollatorSessionKeys<Runtime>,
|
||||||
|
compute_extrinsic_fee: fn(pallet_utility::Call<Runtime>) -> u128,
|
||||||
|
) -> u128
|
||||||
|
where
|
||||||
|
Runtime: BasicParachainRuntime
|
||||||
|
+ pallet_bridge_grandpa::Config<
|
||||||
|
GPI,
|
||||||
|
BridgedChain = UnderlyingChainOf<MessageBridgedChain<MB>>,
|
||||||
|
> + pallet_bridge_messages::Config<
|
||||||
|
MPI,
|
||||||
|
InboundPayload = XcmAsPlainPayload,
|
||||||
|
InboundRelayer = bp_runtime::AccountIdOf<MessageBridgedChain<MB>>,
|
||||||
|
> + pallet_utility::Config,
|
||||||
|
GPI: 'static,
|
||||||
|
MPI: 'static,
|
||||||
|
MB: MessageBridge,
|
||||||
|
<MB as MessageBridge>::BridgedChain: Send + Sync + 'static,
|
||||||
|
<MB as MessageBridge>::ThisChain: Send + Sync + 'static,
|
||||||
|
UnderlyingChainOf<MessageBridgedChain<MB>>: bp_runtime::Chain + ChainWithGrandpa,
|
||||||
|
ValidatorIdOf<Runtime>: From<AccountIdOf<Runtime>>,
|
||||||
|
<Runtime as pallet_bridge_messages::Config<MPI>>::SourceHeaderChain: SourceHeaderChain<
|
||||||
|
MessagesProof = FromBridgedChainMessagesProof<HashOf<MessageBridgedChain<MB>>>,
|
||||||
|
>,
|
||||||
|
bp_runtime::AccountIdOf<MessageBridgedChain<MB>>: From<sp_core::sr25519::Public>,
|
||||||
|
<Runtime as pallet_utility::Config>::RuntimeCall: From<pallet_bridge_grandpa::Call<Runtime, GPI>>
|
||||||
|
+ From<pallet_bridge_messages::Call<Runtime, MPI>>,
|
||||||
|
{
|
||||||
|
run_test::<Runtime, _>(collator_session_key, 1000, vec![], || {
|
||||||
|
// generate bridged relay chain finality, parachain heads and message proofs,
|
||||||
|
// to be submitted by relayer to this chain.
|
||||||
|
//
|
||||||
|
// we don't care about parameter values here, apart from the XCM message size. But we
|
||||||
|
// do not need to have a large message here, because we're charging for every byte of
|
||||||
|
// the message additionally
|
||||||
|
let (relay_chain_header, grandpa_justification, message_proof) =
|
||||||
|
test_data::from_grandpa_chain::make_complex_relayer_delivery_proofs::<MB, ()>(
|
||||||
|
LaneId::default(),
|
||||||
|
vec![xcm::v3::Instruction::<()>::ClearOrigin; 1_024].into(),
|
||||||
|
1,
|
||||||
|
X2(GlobalConsensus(Polkadot), Parachain(1_000)),
|
||||||
|
1u32.into(),
|
||||||
|
);
|
||||||
|
|
||||||
|
// generate batch call that provides finality for bridged relay and parachains + message
|
||||||
|
// proof
|
||||||
|
let batch = test_data::from_grandpa_chain::make_complex_relayer_delivery_batch::<
|
||||||
|
Runtime,
|
||||||
|
GPI,
|
||||||
|
MPI,
|
||||||
|
>(
|
||||||
|
relay_chain_header,
|
||||||
|
grandpa_justification,
|
||||||
|
message_proof,
|
||||||
|
Dave.public().into(),
|
||||||
|
);
|
||||||
|
let estimated_fee = compute_extrinsic_fee(batch);
|
||||||
|
|
||||||
|
log::error!(
|
||||||
|
target: "bridges::estimate",
|
||||||
|
"Estimate fee: {:?} for single message delivery for runtime: {:?}",
|
||||||
|
estimated_fee,
|
||||||
|
Runtime::Version::get(),
|
||||||
|
);
|
||||||
|
|
||||||
|
estimated_fee
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Estimates transaction fee for default message confirmation transaction (batched with required
|
||||||
|
/// proofs) from bridged GRANDPA chain.
|
||||||
|
pub fn can_calculate_fee_for_complex_message_confirmation_transaction<Runtime, GPI, MPI, MB>(
|
||||||
|
collator_session_key: CollatorSessionKeys<Runtime>,
|
||||||
|
compute_extrinsic_fee: fn(pallet_utility::Call<Runtime>) -> u128,
|
||||||
|
) -> u128
|
||||||
|
where
|
||||||
|
Runtime: BasicParachainRuntime
|
||||||
|
+ pallet_bridge_grandpa::Config<
|
||||||
|
GPI,
|
||||||
|
BridgedChain = UnderlyingChainOf<MessageBridgedChain<MB>>,
|
||||||
|
> + pallet_bridge_messages::Config<MPI, OutboundPayload = XcmAsPlainPayload>
|
||||||
|
+ pallet_utility::Config,
|
||||||
|
GPI: 'static,
|
||||||
|
MPI: 'static,
|
||||||
|
MB: MessageBridge,
|
||||||
|
<MB as MessageBridge>::BridgedChain: Send + Sync + 'static,
|
||||||
|
<MB as MessageBridge>::ThisChain: Send + Sync + 'static,
|
||||||
|
<<MB as MessageBridge>::ThisChain as bp_runtime::Chain>::AccountId: From<AccountId32>,
|
||||||
|
UnderlyingChainOf<MessageBridgedChain<MB>>: ChainWithGrandpa,
|
||||||
|
ValidatorIdOf<Runtime>: From<AccountIdOf<Runtime>>,
|
||||||
|
<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>,
|
||||||
|
<Runtime as pallet_bridge_messages::Config<MPI>>::TargetHeaderChain: TargetHeaderChain<
|
||||||
|
XcmAsPlainPayload,
|
||||||
|
Runtime::AccountId,
|
||||||
|
MessagesDeliveryProof = FromBridgedChainMessagesDeliveryProof<
|
||||||
|
HashOf<UnderlyingChainOf<MessageBridgedChain<MB>>>,
|
||||||
|
>,
|
||||||
|
>,
|
||||||
|
<Runtime as pallet_utility::Config>::RuntimeCall: From<pallet_bridge_grandpa::Call<Runtime, GPI>>
|
||||||
|
+ From<pallet_bridge_messages::Call<Runtime, MPI>>,
|
||||||
|
bp_runtime::AccountIdOf<MessageThisChain<MB>>: From<sp_core::sr25519::Public>,
|
||||||
|
{
|
||||||
|
run_test::<Runtime, _>(collator_session_key, 1000, vec![], || {
|
||||||
|
// generate bridged relay chain finality, parachain heads and message proofs,
|
||||||
|
// to be submitted by relayer to this chain.
|
||||||
|
let unrewarded_relayers = UnrewardedRelayersState {
|
||||||
|
unrewarded_relayer_entries: 1,
|
||||||
|
total_messages: 1,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
let (relay_chain_header, grandpa_justification, message_delivery_proof) =
|
||||||
|
test_data::from_grandpa_chain::make_complex_relayer_confirmation_proofs::<MB, ()>(
|
||||||
|
LaneId::default(),
|
||||||
|
1u32.into(),
|
||||||
|
Alice.public().into(),
|
||||||
|
unrewarded_relayers.clone(),
|
||||||
|
);
|
||||||
|
|
||||||
|
// generate batch call that provides finality for bridged relay and parachains + message
|
||||||
|
// proof
|
||||||
|
let batch = test_data::from_grandpa_chain::make_complex_relayer_confirmation_batch::<
|
||||||
|
Runtime,
|
||||||
|
GPI,
|
||||||
|
MPI,
|
||||||
|
>(
|
||||||
|
relay_chain_header,
|
||||||
|
grandpa_justification,
|
||||||
|
message_delivery_proof,
|
||||||
|
unrewarded_relayers,
|
||||||
|
);
|
||||||
|
let estimated_fee = compute_extrinsic_fee(batch);
|
||||||
|
|
||||||
|
log::error!(
|
||||||
|
target: "bridges::estimate",
|
||||||
|
"Estimate fee: {:?} for single message confirmation for runtime: {:?}",
|
||||||
|
estimated_fee,
|
||||||
|
Runtime::Version::get(),
|
||||||
|
);
|
||||||
|
|
||||||
|
estimated_fee
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,544 @@
|
|||||||
|
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Cumulus.
|
||||||
|
|
||||||
|
// Cumulus 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.
|
||||||
|
|
||||||
|
// Cumulus 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 Cumulus. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//! Module contains predefined test-case scenarios for `Runtime` with bridging capabilities
|
||||||
|
//! with remote parachain.
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
test_cases::{helpers, run_test},
|
||||||
|
test_data,
|
||||||
|
};
|
||||||
|
|
||||||
|
use bp_messages::{
|
||||||
|
source_chain::TargetHeaderChain, target_chain::SourceHeaderChain, LaneId,
|
||||||
|
UnrewardedRelayersState,
|
||||||
|
};
|
||||||
|
use bp_polkadot_core::parachains::ParaHash;
|
||||||
|
use bp_relayers::{RewardsAccountOwner, RewardsAccountParams};
|
||||||
|
use bp_runtime::{Parachain, UnderlyingChainOf};
|
||||||
|
use bridge_runtime_common::{
|
||||||
|
messages::{
|
||||||
|
source::FromBridgedChainMessagesDeliveryProof, target::FromBridgedChainMessagesProof,
|
||||||
|
BridgedChain as MessageBridgedChain, MessageBridge,
|
||||||
|
},
|
||||||
|
messages_xcm_extension::XcmAsPlainPayload,
|
||||||
|
};
|
||||||
|
use frame_support::traits::{Get, OnFinalize, OnInitialize, OriginTrait};
|
||||||
|
use frame_system::pallet_prelude::BlockNumberFor;
|
||||||
|
use pallet_bridge_parachains::{RelayBlockHash, RelayBlockNumber};
|
||||||
|
use parachains_runtimes_test_utils::{
|
||||||
|
AccountIdOf, BasicParachainRuntime, CollatorSessionKeys, ValidatorIdOf,
|
||||||
|
};
|
||||||
|
use sp_keyring::AccountKeyring::*;
|
||||||
|
use sp_runtime::{traits::Header as HeaderT, AccountId32};
|
||||||
|
use xcm::latest::prelude::*;
|
||||||
|
|
||||||
|
/// Test-case makes sure that Runtime can dispatch XCM messages submitted by relayer,
|
||||||
|
/// with proofs (finality, para heads, message) independently submitted.
|
||||||
|
/// Also verifies relayer transaction signed extensions work as intended.
|
||||||
|
pub fn relayed_incoming_message_works<
|
||||||
|
Runtime,
|
||||||
|
AllPalletsWithoutSystem,
|
||||||
|
HrmpChannelOpener,
|
||||||
|
GPI,
|
||||||
|
PPI,
|
||||||
|
MPI,
|
||||||
|
MB,
|
||||||
|
>(
|
||||||
|
collator_session_key: CollatorSessionKeys<Runtime>,
|
||||||
|
runtime_para_id: u32,
|
||||||
|
bridged_para_id: u32,
|
||||||
|
bridged_chain_id: bp_runtime::ChainId,
|
||||||
|
sibling_parachain_id: u32,
|
||||||
|
local_relay_chain_id: NetworkId,
|
||||||
|
lane_id: LaneId,
|
||||||
|
prepare_configuration: impl Fn(),
|
||||||
|
construct_and_apply_extrinsic: fn(
|
||||||
|
sp_keyring::AccountKeyring,
|
||||||
|
<Runtime as frame_system::Config>::RuntimeCall,
|
||||||
|
) -> sp_runtime::DispatchOutcome,
|
||||||
|
) where
|
||||||
|
Runtime: BasicParachainRuntime
|
||||||
|
+ cumulus_pallet_xcmp_queue::Config
|
||||||
|
+ cumulus_pallet_parachain_system::Config
|
||||||
|
+ pallet_bridge_grandpa::Config<GPI>
|
||||||
|
+ pallet_bridge_parachains::Config<PPI>
|
||||||
|
+ pallet_bridge_messages::Config<MPI>
|
||||||
|
+ pallet_bridge_relayers::Config,
|
||||||
|
AllPalletsWithoutSystem:
|
||||||
|
OnInitialize<BlockNumberFor<Runtime>> + OnFinalize<BlockNumberFor<Runtime>>,
|
||||||
|
GPI: 'static,
|
||||||
|
PPI: 'static,
|
||||||
|
MPI: 'static,
|
||||||
|
MB: MessageBridge,
|
||||||
|
<MB as MessageBridge>::BridgedChain: Send + Sync + 'static,
|
||||||
|
<MB as MessageBridge>::ThisChain: Send + Sync + 'static,
|
||||||
|
UnderlyingChainOf<MessageBridgedChain<MB>>: bp_runtime::Chain<Hash = ParaHash> + Parachain,
|
||||||
|
HrmpChannelOpener: frame_support::inherent::ProvideInherent<
|
||||||
|
Call = cumulus_pallet_parachain_system::Call<Runtime>,
|
||||||
|
>,
|
||||||
|
ValidatorIdOf<Runtime>: From<AccountIdOf<Runtime>>,
|
||||||
|
<Runtime as pallet_bridge_messages::Config<MPI>>::SourceHeaderChain:
|
||||||
|
SourceHeaderChain<MessagesProof = FromBridgedChainMessagesProof<ParaHash>>,
|
||||||
|
<Runtime as pallet_bridge_grandpa::Config<GPI>>::BridgedChain:
|
||||||
|
bp_runtime::Chain<Hash = RelayBlockHash, BlockNumber = RelayBlockNumber>,
|
||||||
|
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>,
|
||||||
|
<Runtime as frame_system::Config>::RuntimeCall: From<pallet_bridge_grandpa::Call<Runtime, GPI>>
|
||||||
|
+ From<pallet_bridge_parachains::Call<Runtime, PPI>>
|
||||||
|
+ From<pallet_bridge_messages::Call<Runtime, MPI>>,
|
||||||
|
{
|
||||||
|
helpers::relayed_incoming_message_works::<
|
||||||
|
Runtime,
|
||||||
|
AllPalletsWithoutSystem,
|
||||||
|
HrmpChannelOpener,
|
||||||
|
MPI,
|
||||||
|
>(
|
||||||
|
collator_session_key,
|
||||||
|
runtime_para_id,
|
||||||
|
sibling_parachain_id,
|
||||||
|
local_relay_chain_id,
|
||||||
|
construct_and_apply_extrinsic,
|
||||||
|
|relayer_id_at_this_chain,
|
||||||
|
relayer_id_at_bridged_chain,
|
||||||
|
message_destination,
|
||||||
|
message_nonce,
|
||||||
|
xcm| {
|
||||||
|
let para_header_number = 5;
|
||||||
|
let relay_header_number = 1;
|
||||||
|
|
||||||
|
prepare_configuration();
|
||||||
|
|
||||||
|
// start with bridged relay chain block#0
|
||||||
|
helpers::initialize_bridge_grandpa_pallet::<Runtime, GPI>(
|
||||||
|
test_data::initialization_data::<Runtime, GPI>(0),
|
||||||
|
);
|
||||||
|
|
||||||
|
// generate bridged relay chain finality, parachain heads and message proofs,
|
||||||
|
// to be submitted by relayer to this chain.
|
||||||
|
let (
|
||||||
|
relay_chain_header,
|
||||||
|
grandpa_justification,
|
||||||
|
parachain_head,
|
||||||
|
parachain_heads,
|
||||||
|
para_heads_proof,
|
||||||
|
message_proof,
|
||||||
|
) = test_data::from_parachain::make_complex_relayer_delivery_proofs::<
|
||||||
|
<Runtime as pallet_bridge_grandpa::Config<GPI>>::BridgedChain,
|
||||||
|
MB,
|
||||||
|
(),
|
||||||
|
>(
|
||||||
|
lane_id,
|
||||||
|
xcm.into(),
|
||||||
|
message_nonce,
|
||||||
|
message_destination,
|
||||||
|
para_header_number,
|
||||||
|
relay_header_number,
|
||||||
|
bridged_para_id,
|
||||||
|
);
|
||||||
|
|
||||||
|
let parachain_head_hash = parachain_head.hash();
|
||||||
|
let relay_chain_header_hash = relay_chain_header.hash();
|
||||||
|
let relay_chain_header_number = *relay_chain_header.number();
|
||||||
|
vec![
|
||||||
|
(
|
||||||
|
pallet_bridge_grandpa::Call::<Runtime, GPI>::submit_finality_proof {
|
||||||
|
finality_target: Box::new(relay_chain_header),
|
||||||
|
justification: grandpa_justification,
|
||||||
|
}.into(),
|
||||||
|
helpers::VerifySubmitGrandpaFinalityProofOutcome::<Runtime, GPI>::expect_best_header_hash(relay_chain_header_hash),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
pallet_bridge_parachains::Call::<Runtime, PPI>::submit_parachain_heads {
|
||||||
|
at_relay_block: (relay_chain_header_number, relay_chain_header_hash),
|
||||||
|
parachains: parachain_heads,
|
||||||
|
parachain_heads_proof: para_heads_proof,
|
||||||
|
}.into(),
|
||||||
|
helpers::VerifySubmitParachainHeaderProofOutcome::<Runtime, PPI>::expect_best_header_hash(bridged_para_id, parachain_head_hash),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
pallet_bridge_messages::Call::<Runtime, MPI>::receive_messages_proof {
|
||||||
|
relayer_id_at_bridged_chain,
|
||||||
|
proof: message_proof,
|
||||||
|
messages_count: 1,
|
||||||
|
dispatch_weight: Weight::from_parts(1000000000, 0),
|
||||||
|
}.into(),
|
||||||
|
Box::new((
|
||||||
|
helpers::VerifySubmitMessagesProofOutcome::<Runtime, MPI>::expect_last_delivered_nonce(lane_id, 1),
|
||||||
|
helpers::VerifyRelayerRewarded::<Runtime>::expect_relayer_reward(
|
||||||
|
relayer_id_at_this_chain,
|
||||||
|
RewardsAccountParams::new(
|
||||||
|
lane_id,
|
||||||
|
bridged_chain_id,
|
||||||
|
RewardsAccountOwner::ThisChain,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Test-case makes sure that Runtime can dispatch XCM messages submitted by relayer,
|
||||||
|
/// with proofs (finality, para heads, message) batched together in signed extrinsic.
|
||||||
|
/// Also verifies relayer transaction signed extensions work as intended.
|
||||||
|
pub fn complex_relay_extrinsic_works<
|
||||||
|
Runtime,
|
||||||
|
AllPalletsWithoutSystem,
|
||||||
|
XcmConfig,
|
||||||
|
HrmpChannelOpener,
|
||||||
|
GPI,
|
||||||
|
PPI,
|
||||||
|
MPI,
|
||||||
|
MB,
|
||||||
|
>(
|
||||||
|
collator_session_key: CollatorSessionKeys<Runtime>,
|
||||||
|
runtime_para_id: u32,
|
||||||
|
bridged_para_id: u32,
|
||||||
|
sibling_parachain_id: u32,
|
||||||
|
bridged_chain_id: bp_runtime::ChainId,
|
||||||
|
local_relay_chain_id: NetworkId,
|
||||||
|
lane_id: LaneId,
|
||||||
|
prepare_configuration: impl Fn(),
|
||||||
|
construct_and_apply_extrinsic: fn(
|
||||||
|
sp_keyring::AccountKeyring,
|
||||||
|
<Runtime as frame_system::Config>::RuntimeCall,
|
||||||
|
) -> sp_runtime::DispatchOutcome,
|
||||||
|
) where
|
||||||
|
Runtime: BasicParachainRuntime
|
||||||
|
+ cumulus_pallet_xcmp_queue::Config
|
||||||
|
+ cumulus_pallet_parachain_system::Config
|
||||||
|
+ pallet_bridge_grandpa::Config<GPI>
|
||||||
|
+ pallet_bridge_parachains::Config<PPI>
|
||||||
|
+ pallet_bridge_messages::Config<MPI>
|
||||||
|
+ pallet_bridge_relayers::Config
|
||||||
|
+ pallet_utility::Config,
|
||||||
|
AllPalletsWithoutSystem:
|
||||||
|
OnInitialize<BlockNumberFor<Runtime>> + OnFinalize<BlockNumberFor<Runtime>>,
|
||||||
|
GPI: 'static,
|
||||||
|
PPI: 'static,
|
||||||
|
MPI: 'static,
|
||||||
|
MB: MessageBridge,
|
||||||
|
<MB as MessageBridge>::BridgedChain: Send + Sync + 'static,
|
||||||
|
<MB as MessageBridge>::ThisChain: Send + Sync + 'static,
|
||||||
|
UnderlyingChainOf<MessageBridgedChain<MB>>: bp_runtime::Chain<Hash = ParaHash> + Parachain,
|
||||||
|
HrmpChannelOpener: frame_support::inherent::ProvideInherent<
|
||||||
|
Call = cumulus_pallet_parachain_system::Call<Runtime>,
|
||||||
|
>,
|
||||||
|
ValidatorIdOf<Runtime>: From<AccountIdOf<Runtime>>,
|
||||||
|
<Runtime as pallet_bridge_messages::Config<MPI>>::SourceHeaderChain:
|
||||||
|
SourceHeaderChain<MessagesProof = FromBridgedChainMessagesProof<ParaHash>>,
|
||||||
|
<Runtime as pallet_bridge_grandpa::Config<GPI>>::BridgedChain:
|
||||||
|
bp_runtime::Chain<Hash = RelayBlockHash, BlockNumber = RelayBlockNumber>,
|
||||||
|
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>,
|
||||||
|
<Runtime as pallet_utility::Config>::RuntimeCall: From<pallet_bridge_grandpa::Call<Runtime, GPI>>
|
||||||
|
+ From<pallet_bridge_parachains::Call<Runtime, PPI>>
|
||||||
|
+ From<pallet_bridge_messages::Call<Runtime, MPI>>,
|
||||||
|
<Runtime as frame_system::Config>::RuntimeCall: From<pallet_utility::Call<Runtime>>,
|
||||||
|
{
|
||||||
|
helpers::relayed_incoming_message_works::<
|
||||||
|
Runtime,
|
||||||
|
AllPalletsWithoutSystem,
|
||||||
|
HrmpChannelOpener,
|
||||||
|
MPI,
|
||||||
|
>(
|
||||||
|
collator_session_key,
|
||||||
|
runtime_para_id,
|
||||||
|
sibling_parachain_id,
|
||||||
|
local_relay_chain_id,
|
||||||
|
construct_and_apply_extrinsic,
|
||||||
|
|relayer_id_at_this_chain,
|
||||||
|
relayer_id_at_bridged_chain,
|
||||||
|
message_destination,
|
||||||
|
message_nonce,
|
||||||
|
xcm| {
|
||||||
|
let para_header_number = 5;
|
||||||
|
let relay_header_number = 1;
|
||||||
|
|
||||||
|
prepare_configuration();
|
||||||
|
|
||||||
|
// start with bridged relay chain block#0
|
||||||
|
helpers::initialize_bridge_grandpa_pallet::<Runtime, GPI>(
|
||||||
|
test_data::initialization_data::<Runtime, GPI>(0),
|
||||||
|
);
|
||||||
|
|
||||||
|
// generate bridged relay chain finality, parachain heads and message proofs,
|
||||||
|
// to be submitted by relayer to this chain.
|
||||||
|
let (
|
||||||
|
relay_chain_header,
|
||||||
|
grandpa_justification,
|
||||||
|
parachain_head,
|
||||||
|
parachain_heads,
|
||||||
|
para_heads_proof,
|
||||||
|
message_proof,
|
||||||
|
) = test_data::from_parachain::make_complex_relayer_delivery_proofs::<
|
||||||
|
<Runtime as pallet_bridge_grandpa::Config<GPI>>::BridgedChain,
|
||||||
|
MB,
|
||||||
|
(),
|
||||||
|
>(
|
||||||
|
lane_id,
|
||||||
|
xcm.into(),
|
||||||
|
message_nonce,
|
||||||
|
message_destination,
|
||||||
|
para_header_number,
|
||||||
|
relay_header_number,
|
||||||
|
bridged_para_id,
|
||||||
|
);
|
||||||
|
|
||||||
|
let parachain_head_hash = parachain_head.hash();
|
||||||
|
let relay_chain_header_hash = relay_chain_header.hash();
|
||||||
|
let relay_chain_header_number = *relay_chain_header.number();
|
||||||
|
vec![(
|
||||||
|
pallet_utility::Call::<Runtime>::batch_all {
|
||||||
|
calls: vec![
|
||||||
|
pallet_bridge_grandpa::Call::<Runtime, GPI>::submit_finality_proof {
|
||||||
|
finality_target: Box::new(relay_chain_header),
|
||||||
|
justification: grandpa_justification,
|
||||||
|
}.into(),
|
||||||
|
pallet_bridge_parachains::Call::<Runtime, PPI>::submit_parachain_heads {
|
||||||
|
at_relay_block: (relay_chain_header_number, relay_chain_header_hash),
|
||||||
|
parachains: parachain_heads,
|
||||||
|
parachain_heads_proof: para_heads_proof,
|
||||||
|
}.into(),
|
||||||
|
pallet_bridge_messages::Call::<Runtime, MPI>::receive_messages_proof {
|
||||||
|
relayer_id_at_bridged_chain,
|
||||||
|
proof: message_proof,
|
||||||
|
messages_count: 1,
|
||||||
|
dispatch_weight: Weight::from_parts(1000000000, 0),
|
||||||
|
}.into(),
|
||||||
|
],
|
||||||
|
}.into(),
|
||||||
|
Box::new((
|
||||||
|
helpers::VerifySubmitGrandpaFinalityProofOutcome::<Runtime, GPI>::expect_best_header_hash(relay_chain_header_hash),
|
||||||
|
helpers::VerifySubmitParachainHeaderProofOutcome::<Runtime, PPI>::expect_best_header_hash(bridged_para_id, parachain_head_hash),
|
||||||
|
helpers::VerifySubmitMessagesProofOutcome::<Runtime, MPI>::expect_last_delivered_nonce(lane_id, 1),
|
||||||
|
helpers::VerifyRelayerRewarded::<Runtime>::expect_relayer_reward(
|
||||||
|
relayer_id_at_this_chain,
|
||||||
|
RewardsAccountParams::new(
|
||||||
|
lane_id,
|
||||||
|
bridged_chain_id,
|
||||||
|
RewardsAccountOwner::ThisChain,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
)]
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Estimates transaction fee for default message delivery transaction (batched with required
|
||||||
|
/// proofs) from bridged parachain.
|
||||||
|
pub fn can_calculate_fee_for_complex_message_delivery_transaction<Runtime, GPI, PPI, MPI, MB>(
|
||||||
|
collator_session_key: CollatorSessionKeys<Runtime>,
|
||||||
|
compute_extrinsic_fee: fn(pallet_utility::Call::<Runtime>) -> u128,
|
||||||
|
) -> u128
|
||||||
|
where
|
||||||
|
Runtime: frame_system::Config
|
||||||
|
+ pallet_balances::Config
|
||||||
|
+ pallet_session::Config
|
||||||
|
+ pallet_xcm::Config
|
||||||
|
+ parachain_info::Config
|
||||||
|
+ pallet_collator_selection::Config
|
||||||
|
+ cumulus_pallet_parachain_system::Config
|
||||||
|
+ pallet_bridge_grandpa::Config<GPI>
|
||||||
|
+ pallet_bridge_parachains::Config<PPI>
|
||||||
|
+ pallet_bridge_messages::Config<MPI, InboundPayload = XcmAsPlainPayload>
|
||||||
|
+ pallet_utility::Config,
|
||||||
|
GPI: 'static,
|
||||||
|
PPI: 'static,
|
||||||
|
MPI: 'static,
|
||||||
|
MB: MessageBridge,
|
||||||
|
<MB as MessageBridge>::BridgedChain: Send + Sync + 'static,
|
||||||
|
<MB as MessageBridge>::ThisChain: Send + Sync + 'static,
|
||||||
|
UnderlyingChainOf<MessageBridgedChain<MB>>: bp_runtime::Chain<Hash = ParaHash> + Parachain,
|
||||||
|
ValidatorIdOf<Runtime>: From<AccountIdOf<Runtime>>,
|
||||||
|
<<Runtime as pallet_bridge_messages::Config<MPI>>::SourceHeaderChain as SourceHeaderChain>::MessagesProof:
|
||||||
|
From<FromBridgedChainMessagesProof<ParaHash>>,
|
||||||
|
<Runtime as pallet_bridge_grandpa::Config<GPI>>::BridgedChain: bp_runtime::Chain<Hash = RelayBlockHash, BlockNumber = RelayBlockNumber>,
|
||||||
|
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>,
|
||||||
|
<Runtime as pallet_utility::Config>::RuntimeCall:
|
||||||
|
From<pallet_bridge_grandpa::Call<Runtime, GPI>>
|
||||||
|
+ From<pallet_bridge_parachains::Call<Runtime, PPI>>
|
||||||
|
+ From<pallet_bridge_messages::Call<Runtime, MPI>>,
|
||||||
|
{
|
||||||
|
run_test::<Runtime, _>(collator_session_key, 1000, vec![], || {
|
||||||
|
// generate bridged relay chain finality, parachain heads and message proofs,
|
||||||
|
// to be submitted by relayer to this chain.
|
||||||
|
//
|
||||||
|
// we don't care about parameter values here, apart from the XCM message size. But we
|
||||||
|
// do not need to have a large message here, because we're charging for every byte of
|
||||||
|
// the message additionally
|
||||||
|
let (
|
||||||
|
relay_chain_header,
|
||||||
|
grandpa_justification,
|
||||||
|
_,
|
||||||
|
parachain_heads,
|
||||||
|
para_heads_proof,
|
||||||
|
message_proof,
|
||||||
|
) = test_data::from_parachain::make_complex_relayer_delivery_proofs::<
|
||||||
|
<Runtime as pallet_bridge_grandpa::Config<GPI>>::BridgedChain,
|
||||||
|
MB,
|
||||||
|
(),
|
||||||
|
>(
|
||||||
|
LaneId::default(),
|
||||||
|
vec![xcm::v3::Instruction::<()>::ClearOrigin; 1_024].into(),
|
||||||
|
1,
|
||||||
|
X2(GlobalConsensus(Polkadot), Parachain(1_000)),
|
||||||
|
1,
|
||||||
|
5,
|
||||||
|
1_000,
|
||||||
|
);
|
||||||
|
|
||||||
|
// generate batch call that provides finality for bridged relay and parachains + message
|
||||||
|
// proof
|
||||||
|
let batch = test_data::from_parachain::make_complex_relayer_delivery_batch::<
|
||||||
|
Runtime,
|
||||||
|
GPI,
|
||||||
|
PPI,
|
||||||
|
MPI,
|
||||||
|
>(
|
||||||
|
relay_chain_header,
|
||||||
|
grandpa_justification,
|
||||||
|
parachain_heads,
|
||||||
|
para_heads_proof,
|
||||||
|
message_proof,
|
||||||
|
Dave.public().into(),
|
||||||
|
);
|
||||||
|
let estimated_fee = compute_extrinsic_fee(batch);
|
||||||
|
|
||||||
|
log::error!(
|
||||||
|
target: "bridges::estimate",
|
||||||
|
"Estimate fee: {:?} for single message delivery for runtime: {:?}",
|
||||||
|
estimated_fee,
|
||||||
|
Runtime::Version::get(),
|
||||||
|
);
|
||||||
|
|
||||||
|
estimated_fee
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Estimates transaction fee for default message confirmation transaction (batched with required
|
||||||
|
/// proofs) from bridged parachain.
|
||||||
|
pub fn can_calculate_fee_for_complex_message_confirmation_transaction<Runtime, GPI, PPI, MPI, MB>(
|
||||||
|
collator_session_key: CollatorSessionKeys<Runtime>,
|
||||||
|
compute_extrinsic_fee: fn(pallet_utility::Call::<Runtime>) -> u128,
|
||||||
|
) -> u128
|
||||||
|
where
|
||||||
|
Runtime: frame_system::Config
|
||||||
|
+ pallet_balances::Config
|
||||||
|
+ pallet_session::Config
|
||||||
|
+ pallet_xcm::Config
|
||||||
|
+ parachain_info::Config
|
||||||
|
+ pallet_collator_selection::Config
|
||||||
|
+ cumulus_pallet_parachain_system::Config
|
||||||
|
+ pallet_bridge_grandpa::Config<GPI>
|
||||||
|
+ pallet_bridge_parachains::Config<PPI>
|
||||||
|
+ pallet_bridge_messages::Config<MPI, OutboundPayload = XcmAsPlainPayload>
|
||||||
|
+ pallet_utility::Config,
|
||||||
|
GPI: 'static,
|
||||||
|
PPI: 'static,
|
||||||
|
MPI: 'static,
|
||||||
|
MB: MessageBridge,
|
||||||
|
<MB as MessageBridge>::BridgedChain: Send + Sync + 'static,
|
||||||
|
<MB as MessageBridge>::ThisChain: Send + Sync + 'static,
|
||||||
|
<<MB as MessageBridge>::ThisChain as bp_runtime::Chain>::AccountId: From<AccountId32>,
|
||||||
|
UnderlyingChainOf<MessageBridgedChain<MB>>: bp_runtime::Chain<Hash = ParaHash> + Parachain,
|
||||||
|
ValidatorIdOf<Runtime>: From<AccountIdOf<Runtime>>,
|
||||||
|
<<Runtime as pallet_bridge_messages::Config<MPI>>::SourceHeaderChain as SourceHeaderChain>::MessagesProof:
|
||||||
|
From<FromBridgedChainMessagesProof<ParaHash>>,
|
||||||
|
<Runtime as pallet_bridge_grandpa::Config<GPI>>::BridgedChain: bp_runtime::Chain<Hash = RelayBlockHash, BlockNumber = RelayBlockNumber>,
|
||||||
|
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>,
|
||||||
|
<<Runtime as pallet_bridge_messages::Config<MPI>>::TargetHeaderChain as TargetHeaderChain<
|
||||||
|
XcmAsPlainPayload,
|
||||||
|
Runtime::AccountId,
|
||||||
|
>>::MessagesDeliveryProof: From<FromBridgedChainMessagesDeliveryProof<ParaHash>>,
|
||||||
|
<Runtime as pallet_utility::Config>::RuntimeCall:
|
||||||
|
From<pallet_bridge_grandpa::Call<Runtime, GPI>>
|
||||||
|
+ From<pallet_bridge_parachains::Call<Runtime, PPI>>
|
||||||
|
+ From<pallet_bridge_messages::Call<Runtime, MPI>>,
|
||||||
|
{
|
||||||
|
run_test::<Runtime, _>(collator_session_key, 1000, vec![], || {
|
||||||
|
// generate bridged relay chain finality, parachain heads and message proofs,
|
||||||
|
// to be submitted by relayer to this chain.
|
||||||
|
let unrewarded_relayers = UnrewardedRelayersState {
|
||||||
|
unrewarded_relayer_entries: 1,
|
||||||
|
total_messages: 1,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
let (
|
||||||
|
relay_chain_header,
|
||||||
|
grandpa_justification,
|
||||||
|
_,
|
||||||
|
parachain_heads,
|
||||||
|
para_heads_proof,
|
||||||
|
message_delivery_proof,
|
||||||
|
) = test_data::from_parachain::make_complex_relayer_confirmation_proofs::<
|
||||||
|
<Runtime as pallet_bridge_grandpa::Config<GPI>>::BridgedChain,
|
||||||
|
MB,
|
||||||
|
(),
|
||||||
|
>(LaneId::default(), 1, 5, 1_000, Alice.public().into(), unrewarded_relayers.clone());
|
||||||
|
|
||||||
|
// generate batch call that provides finality for bridged relay and parachains + message
|
||||||
|
// proof
|
||||||
|
let batch = test_data::from_parachain::make_complex_relayer_confirmation_batch::<
|
||||||
|
Runtime,
|
||||||
|
GPI,
|
||||||
|
PPI,
|
||||||
|
MPI,
|
||||||
|
>(
|
||||||
|
relay_chain_header,
|
||||||
|
grandpa_justification,
|
||||||
|
parachain_heads,
|
||||||
|
para_heads_proof,
|
||||||
|
message_delivery_proof,
|
||||||
|
unrewarded_relayers,
|
||||||
|
);
|
||||||
|
let estimated_fee = compute_extrinsic_fee(batch);
|
||||||
|
|
||||||
|
log::error!(
|
||||||
|
target: "bridges::estimate",
|
||||||
|
"Estimate fee: {:?} for single message confirmation for runtime: {:?}",
|
||||||
|
estimated_fee,
|
||||||
|
Runtime::Version::get(),
|
||||||
|
);
|
||||||
|
|
||||||
|
estimated_fee
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,340 @@
|
|||||||
|
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Cumulus.
|
||||||
|
|
||||||
|
// Cumulus 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.
|
||||||
|
|
||||||
|
// Cumulus 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 Cumulus. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//! Module contains tests code, that is shared by all types of bridges
|
||||||
|
|
||||||
|
use crate::test_cases::{run_test, RuntimeHelper};
|
||||||
|
|
||||||
|
use asset_test_utils::BasicParachainRuntime;
|
||||||
|
use bp_messages::{LaneId, MessageNonce};
|
||||||
|
use bp_polkadot_core::parachains::{ParaHash, ParaId};
|
||||||
|
use bp_relayers::RewardsAccountParams;
|
||||||
|
use frame_support::{
|
||||||
|
assert_ok,
|
||||||
|
traits::{OnFinalize, OnInitialize, PalletInfoAccess},
|
||||||
|
};
|
||||||
|
use frame_system::pallet_prelude::BlockNumberFor;
|
||||||
|
use pallet_bridge_grandpa::{BridgedBlockHash, BridgedHeader};
|
||||||
|
use parachains_common::AccountId;
|
||||||
|
use parachains_runtimes_test_utils::{
|
||||||
|
mock_open_hrmp_channel, AccountIdOf, CollatorSessionKeys, ValidatorIdOf,
|
||||||
|
};
|
||||||
|
use sp_core::Get;
|
||||||
|
use sp_keyring::AccountKeyring::*;
|
||||||
|
use sp_runtime::AccountId32;
|
||||||
|
use sp_std::marker::PhantomData;
|
||||||
|
use xcm::latest::prelude::*;
|
||||||
|
|
||||||
|
#[impl_trait_for_tuples::impl_for_tuples(30)]
|
||||||
|
pub trait VerifyTransactionOutcome {
|
||||||
|
fn verify_outcome(&self);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VerifyTransactionOutcome for Box<dyn VerifyTransactionOutcome> {
|
||||||
|
fn verify_outcome(&self) {
|
||||||
|
VerifyTransactionOutcome::verify_outcome(&**self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks that the best finalized header hash in the bridge GRANDPA pallet equals to given one.
|
||||||
|
pub struct VerifySubmitGrandpaFinalityProofOutcome<Runtime, GPI>
|
||||||
|
where
|
||||||
|
Runtime: pallet_bridge_grandpa::Config<GPI>,
|
||||||
|
GPI: 'static,
|
||||||
|
{
|
||||||
|
expected_best_hash: BridgedBlockHash<Runtime, GPI>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Runtime, GPI> VerifySubmitGrandpaFinalityProofOutcome<Runtime, GPI>
|
||||||
|
where
|
||||||
|
Runtime: pallet_bridge_grandpa::Config<GPI>,
|
||||||
|
GPI: 'static,
|
||||||
|
{
|
||||||
|
/// Expect given header hash to be the best after transaction.
|
||||||
|
pub fn expect_best_header_hash(
|
||||||
|
expected_best_hash: BridgedBlockHash<Runtime, GPI>,
|
||||||
|
) -> Box<dyn VerifyTransactionOutcome> {
|
||||||
|
Box::new(Self { expected_best_hash })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Runtime, GPI> VerifyTransactionOutcome
|
||||||
|
for VerifySubmitGrandpaFinalityProofOutcome<Runtime, GPI>
|
||||||
|
where
|
||||||
|
Runtime: pallet_bridge_grandpa::Config<GPI>,
|
||||||
|
GPI: 'static,
|
||||||
|
{
|
||||||
|
fn verify_outcome(&self) {
|
||||||
|
assert_eq!(
|
||||||
|
pallet_bridge_grandpa::BestFinalized::<Runtime, GPI>::get().unwrap().1,
|
||||||
|
self.expected_best_hash
|
||||||
|
);
|
||||||
|
assert!(pallet_bridge_grandpa::ImportedHeaders::<Runtime, GPI>::contains_key(
|
||||||
|
self.expected_best_hash
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks that the best parachain header hash in the bridge parachains pallet equals to given one.
|
||||||
|
pub struct VerifySubmitParachainHeaderProofOutcome<Runtime, PPI> {
|
||||||
|
bridged_para_id: u32,
|
||||||
|
expected_best_hash: ParaHash,
|
||||||
|
_marker: PhantomData<(Runtime, PPI)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Runtime, PPI> VerifySubmitParachainHeaderProofOutcome<Runtime, PPI>
|
||||||
|
where
|
||||||
|
Runtime: pallet_bridge_parachains::Config<PPI>,
|
||||||
|
PPI: 'static,
|
||||||
|
{
|
||||||
|
/// Expect given header hash to be the best after transaction.
|
||||||
|
pub fn expect_best_header_hash(
|
||||||
|
bridged_para_id: u32,
|
||||||
|
expected_best_hash: ParaHash,
|
||||||
|
) -> Box<dyn VerifyTransactionOutcome> {
|
||||||
|
Box::new(Self { bridged_para_id, expected_best_hash, _marker: PhantomData })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Runtime, PPI> VerifyTransactionOutcome
|
||||||
|
for VerifySubmitParachainHeaderProofOutcome<Runtime, PPI>
|
||||||
|
where
|
||||||
|
Runtime: pallet_bridge_parachains::Config<PPI>,
|
||||||
|
PPI: 'static,
|
||||||
|
{
|
||||||
|
fn verify_outcome(&self) {
|
||||||
|
assert_eq!(
|
||||||
|
pallet_bridge_parachains::ParasInfo::<Runtime, PPI>::get(ParaId(self.bridged_para_id))
|
||||||
|
.map(|info| info.best_head_hash.head_hash),
|
||||||
|
Some(self.expected_best_hash),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks that the latest delivered nonce in the bridge messages pallet equals to given one.
|
||||||
|
pub struct VerifySubmitMessagesProofOutcome<Runtime, MPI> {
|
||||||
|
lane: LaneId,
|
||||||
|
expected_nonce: MessageNonce,
|
||||||
|
_marker: PhantomData<(Runtime, MPI)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Runtime, MPI> VerifySubmitMessagesProofOutcome<Runtime, MPI>
|
||||||
|
where
|
||||||
|
Runtime: pallet_bridge_messages::Config<MPI>,
|
||||||
|
MPI: 'static,
|
||||||
|
{
|
||||||
|
/// Expect given delivered nonce to be the latest after transaction.
|
||||||
|
pub fn expect_last_delivered_nonce(
|
||||||
|
lane: LaneId,
|
||||||
|
expected_nonce: MessageNonce,
|
||||||
|
) -> Box<dyn VerifyTransactionOutcome> {
|
||||||
|
Box::new(Self { lane, expected_nonce, _marker: PhantomData })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Runtime, MPI> VerifyTransactionOutcome for VerifySubmitMessagesProofOutcome<Runtime, MPI>
|
||||||
|
where
|
||||||
|
Runtime: pallet_bridge_messages::Config<MPI>,
|
||||||
|
MPI: 'static,
|
||||||
|
{
|
||||||
|
fn verify_outcome(&self) {
|
||||||
|
assert_eq!(
|
||||||
|
pallet_bridge_messages::InboundLanes::<Runtime, MPI>::get(self.lane)
|
||||||
|
.last_delivered_nonce(),
|
||||||
|
self.expected_nonce,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Verifies that relayer is rewarded at this chain.
|
||||||
|
pub struct VerifyRelayerRewarded<Runtime: frame_system::Config> {
|
||||||
|
relayer: Runtime::AccountId,
|
||||||
|
reward_params: RewardsAccountParams,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Runtime> VerifyRelayerRewarded<Runtime>
|
||||||
|
where
|
||||||
|
Runtime: pallet_bridge_relayers::Config,
|
||||||
|
{
|
||||||
|
/// Expect given delivered nonce to be the latest after transaction.
|
||||||
|
pub fn expect_relayer_reward(
|
||||||
|
relayer: Runtime::AccountId,
|
||||||
|
reward_params: RewardsAccountParams,
|
||||||
|
) -> Box<dyn VerifyTransactionOutcome> {
|
||||||
|
Box::new(Self { relayer, reward_params })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Runtime> VerifyTransactionOutcome for VerifyRelayerRewarded<Runtime>
|
||||||
|
where
|
||||||
|
Runtime: pallet_bridge_relayers::Config,
|
||||||
|
{
|
||||||
|
fn verify_outcome(&self) {
|
||||||
|
assert!(pallet_bridge_relayers::RelayerRewards::<Runtime>::get(
|
||||||
|
&self.relayer,
|
||||||
|
&self.reward_params,
|
||||||
|
)
|
||||||
|
.is_some());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initialize bridge GRANDPA pallet.
|
||||||
|
pub(crate) fn initialize_bridge_grandpa_pallet<Runtime, GPI>(
|
||||||
|
init_data: bp_header_chain::InitializationData<BridgedHeader<Runtime, GPI>>,
|
||||||
|
) where
|
||||||
|
Runtime: pallet_bridge_grandpa::Config<GPI>,
|
||||||
|
{
|
||||||
|
pallet_bridge_grandpa::Pallet::<Runtime, GPI>::initialize(
|
||||||
|
RuntimeHelper::<Runtime>::root_origin(),
|
||||||
|
init_data,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Runtime calls and their verifiers.
|
||||||
|
pub type CallsAndVerifiers<Runtime> =
|
||||||
|
Vec<(<Runtime as frame_system::Config>::RuntimeCall, Box<dyn VerifyTransactionOutcome>)>;
|
||||||
|
|
||||||
|
/// Test-case makes sure that Runtime can dispatch XCM messages submitted by relayer,
|
||||||
|
/// with proofs (finality, message) independently submitted.
|
||||||
|
pub fn relayed_incoming_message_works<Runtime, AllPalletsWithoutSystem, HrmpChannelOpener, MPI>(
|
||||||
|
collator_session_key: CollatorSessionKeys<Runtime>,
|
||||||
|
runtime_para_id: u32,
|
||||||
|
sibling_parachain_id: u32,
|
||||||
|
local_relay_chain_id: NetworkId,
|
||||||
|
construct_and_apply_extrinsic: fn(
|
||||||
|
sp_keyring::AccountKeyring,
|
||||||
|
<Runtime as frame_system::Config>::RuntimeCall,
|
||||||
|
) -> sp_runtime::DispatchOutcome,
|
||||||
|
prepare_message_proof_import: impl FnOnce(
|
||||||
|
Runtime::AccountId,
|
||||||
|
Runtime::InboundRelayer,
|
||||||
|
InteriorMultiLocation,
|
||||||
|
MessageNonce,
|
||||||
|
Xcm<()>,
|
||||||
|
) -> CallsAndVerifiers<Runtime>,
|
||||||
|
) where
|
||||||
|
Runtime: BasicParachainRuntime
|
||||||
|
+ cumulus_pallet_xcmp_queue::Config
|
||||||
|
+ pallet_bridge_messages::Config<MPI>,
|
||||||
|
AllPalletsWithoutSystem:
|
||||||
|
OnInitialize<BlockNumberFor<Runtime>> + OnFinalize<BlockNumberFor<Runtime>>,
|
||||||
|
HrmpChannelOpener: frame_support::inherent::ProvideInherent<
|
||||||
|
Call = cumulus_pallet_parachain_system::Call<Runtime>,
|
||||||
|
>,
|
||||||
|
MPI: 'static,
|
||||||
|
ValidatorIdOf<Runtime>: From<AccountIdOf<Runtime>>,
|
||||||
|
AccountIdOf<Runtime>: From<AccountId32> + From<sp_core::sr25519::Public>,
|
||||||
|
<Runtime as pallet_bridge_messages::Config<MPI>>::InboundRelayer: From<AccountId32>,
|
||||||
|
{
|
||||||
|
let relayer_at_target = Bob;
|
||||||
|
let relayer_id_on_target: AccountId32 = relayer_at_target.public().into();
|
||||||
|
let relayer_at_source = Dave;
|
||||||
|
let relayer_id_on_source: AccountId32 = relayer_at_source.public().into();
|
||||||
|
|
||||||
|
assert_ne!(runtime_para_id, sibling_parachain_id);
|
||||||
|
|
||||||
|
run_test::<Runtime, _>(
|
||||||
|
collator_session_key,
|
||||||
|
runtime_para_id,
|
||||||
|
vec![(
|
||||||
|
relayer_id_on_target.clone().into(),
|
||||||
|
Runtime::ExistentialDeposit::get() * 100000u32.into(),
|
||||||
|
)],
|
||||||
|
|| {
|
||||||
|
let mut alice = [0u8; 32];
|
||||||
|
alice[0] = 1;
|
||||||
|
|
||||||
|
let included_head = RuntimeHelper::<Runtime, AllPalletsWithoutSystem>::run_to_block(
|
||||||
|
2,
|
||||||
|
AccountId::from(alice).into(),
|
||||||
|
);
|
||||||
|
mock_open_hrmp_channel::<Runtime, HrmpChannelOpener>(
|
||||||
|
runtime_para_id.into(),
|
||||||
|
sibling_parachain_id.into(),
|
||||||
|
included_head,
|
||||||
|
&alice,
|
||||||
|
);
|
||||||
|
|
||||||
|
// set up relayer details and proofs
|
||||||
|
|
||||||
|
let message_destination =
|
||||||
|
X2(GlobalConsensus(local_relay_chain_id), Parachain(sibling_parachain_id));
|
||||||
|
// some random numbers (checked by test)
|
||||||
|
let message_nonce = 1;
|
||||||
|
|
||||||
|
let xcm = vec![xcm::v3::Instruction::<()>::ClearOrigin; 42];
|
||||||
|
let expected_dispatch = xcm::latest::Xcm::<()>({
|
||||||
|
let mut expected_instructions = xcm.clone();
|
||||||
|
// dispatch prepends bridge pallet instance
|
||||||
|
expected_instructions.insert(
|
||||||
|
0,
|
||||||
|
DescendOrigin(X1(PalletInstance(
|
||||||
|
<pallet_bridge_messages::Pallet<Runtime, MPI> as PalletInfoAccess>::index()
|
||||||
|
as u8,
|
||||||
|
))),
|
||||||
|
);
|
||||||
|
expected_instructions
|
||||||
|
});
|
||||||
|
|
||||||
|
execute_and_verify_calls::<Runtime>(
|
||||||
|
relayer_at_target,
|
||||||
|
construct_and_apply_extrinsic,
|
||||||
|
prepare_message_proof_import(
|
||||||
|
relayer_id_on_target.clone().into(),
|
||||||
|
relayer_id_on_source.clone().into(),
|
||||||
|
message_destination,
|
||||||
|
message_nonce,
|
||||||
|
xcm.clone().into(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// verify that imported XCM contains original message
|
||||||
|
let imported_xcm =
|
||||||
|
RuntimeHelper::<cumulus_pallet_xcmp_queue::Pallet<Runtime>>::take_xcm(
|
||||||
|
sibling_parachain_id.into(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let dispatched = xcm::latest::Xcm::<()>::try_from(imported_xcm).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),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Execute every call and verify its outcome.
|
||||||
|
fn execute_and_verify_calls<Runtime: frame_system::Config>(
|
||||||
|
submitter: sp_keyring::AccountKeyring,
|
||||||
|
construct_and_apply_extrinsic: fn(
|
||||||
|
sp_keyring::AccountKeyring,
|
||||||
|
<Runtime as frame_system::Config>::RuntimeCall,
|
||||||
|
) -> sp_runtime::DispatchOutcome,
|
||||||
|
calls_and_verifiers: CallsAndVerifiers<Runtime>,
|
||||||
|
) {
|
||||||
|
for (call, verifier) in calls_and_verifiers {
|
||||||
|
let dispatch_outcome = construct_and_apply_extrinsic(submitter, call);
|
||||||
|
assert_ok!(dispatch_outcome);
|
||||||
|
verifier.verify_outcome();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,485 @@
|
|||||||
|
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Cumulus.
|
||||||
|
|
||||||
|
// Cumulus 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.
|
||||||
|
|
||||||
|
// Cumulus 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 Cumulus. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//! Module contains predefined test-case scenarios for `Runtime` with bridging capabilities.
|
||||||
|
//!
|
||||||
|
//! This file contains tests, suitable for all bridge runtimes. See `from_parachain` and
|
||||||
|
//! `from_grandpa_chain` submodules for tests, that are specific to the bridged chain type.
|
||||||
|
|
||||||
|
pub mod from_grandpa_chain;
|
||||||
|
pub mod from_parachain;
|
||||||
|
|
||||||
|
pub(crate) mod helpers;
|
||||||
|
|
||||||
|
use crate::test_data;
|
||||||
|
|
||||||
|
use asset_test_utils::BasicParachainRuntime;
|
||||||
|
use bp_messages::{
|
||||||
|
target_chain::{DispatchMessage, DispatchMessageData, MessageDispatch},
|
||||||
|
LaneId, MessageKey, OutboundLaneData,
|
||||||
|
};
|
||||||
|
use bridge_runtime_common::messages_xcm_extension::{
|
||||||
|
XcmAsPlainPayload, XcmBlobMessageDispatchResult,
|
||||||
|
};
|
||||||
|
use codec::Encode;
|
||||||
|
use frame_support::{
|
||||||
|
assert_ok,
|
||||||
|
traits::{Get, OnFinalize, OnInitialize, OriginTrait},
|
||||||
|
};
|
||||||
|
use frame_system::pallet_prelude::BlockNumberFor;
|
||||||
|
use parachains_common::AccountId;
|
||||||
|
use parachains_runtimes_test_utils::{
|
||||||
|
mock_open_hrmp_channel, AccountIdOf, BalanceOf, CollatorSessionKeys, ExtBuilder, ValidatorIdOf,
|
||||||
|
XcmReceivedFrom,
|
||||||
|
};
|
||||||
|
use sp_runtime::{traits::Zero, AccountId32};
|
||||||
|
use xcm::{latest::prelude::*, AlwaysLatest};
|
||||||
|
use xcm_builder::DispatchBlobError;
|
||||||
|
use xcm_executor::{
|
||||||
|
traits::{TransactAsset, WeightBounds},
|
||||||
|
XcmExecutor,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Re-export test_case from assets
|
||||||
|
pub use asset_test_utils::include_teleports_for_native_asset_works;
|
||||||
|
|
||||||
|
pub type RuntimeHelper<Runtime, AllPalletsWithoutSystem = ()> =
|
||||||
|
parachains_runtimes_test_utils::RuntimeHelper<Runtime, AllPalletsWithoutSystem>;
|
||||||
|
|
||||||
|
// Re-export test_case from `parachains-runtimes-test-utils`
|
||||||
|
pub use parachains_runtimes_test_utils::test_cases::change_storage_constant_by_governance_works;
|
||||||
|
|
||||||
|
/// Prepare default runtime storage and run test within this context.
|
||||||
|
pub fn run_test<Runtime, T>(
|
||||||
|
collator_session_key: CollatorSessionKeys<Runtime>,
|
||||||
|
runtime_para_id: u32,
|
||||||
|
balances: Vec<(Runtime::AccountId, Runtime::Balance)>,
|
||||||
|
test: impl FnOnce() -> T,
|
||||||
|
) -> T
|
||||||
|
where
|
||||||
|
Runtime: BasicParachainRuntime,
|
||||||
|
ValidatorIdOf<Runtime>: From<AccountIdOf<Runtime>>,
|
||||||
|
{
|
||||||
|
ExtBuilder::<Runtime>::default()
|
||||||
|
.with_collators(collator_session_key.collators())
|
||||||
|
.with_session_keys(collator_session_key.session_keys())
|
||||||
|
.with_safe_xcm_version(XCM_VERSION)
|
||||||
|
.with_para_id(runtime_para_id.into())
|
||||||
|
.with_balances(balances)
|
||||||
|
.with_tracing()
|
||||||
|
.build()
|
||||||
|
.execute_with(|| test())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Test-case makes sure that `Runtime` can process bridging initialize via governance-like call
|
||||||
|
pub fn initialize_bridge_by_governance_works<Runtime, GrandpaPalletInstance>(
|
||||||
|
collator_session_key: CollatorSessionKeys<Runtime>,
|
||||||
|
runtime_para_id: u32,
|
||||||
|
runtime_call_encode: Box<
|
||||||
|
dyn Fn(pallet_bridge_grandpa::Call<Runtime, GrandpaPalletInstance>) -> Vec<u8>,
|
||||||
|
>,
|
||||||
|
) where
|
||||||
|
Runtime: BasicParachainRuntime + pallet_bridge_grandpa::Config<GrandpaPalletInstance>,
|
||||||
|
GrandpaPalletInstance: 'static,
|
||||||
|
ValidatorIdOf<Runtime>: From<AccountIdOf<Runtime>>,
|
||||||
|
{
|
||||||
|
run_test::<Runtime, _>(collator_session_key, runtime_para_id, vec![], || {
|
||||||
|
// check mode before
|
||||||
|
assert_eq!(
|
||||||
|
pallet_bridge_grandpa::PalletOperatingMode::<Runtime, GrandpaPalletInstance>::try_get(),
|
||||||
|
Err(())
|
||||||
|
);
|
||||||
|
|
||||||
|
// encode `initialize` call
|
||||||
|
let initialize_call = runtime_call_encode(pallet_bridge_grandpa::Call::<
|
||||||
|
Runtime,
|
||||||
|
GrandpaPalletInstance,
|
||||||
|
>::initialize {
|
||||||
|
init_data: test_data::initialization_data::<Runtime, GrandpaPalletInstance>(12345),
|
||||||
|
});
|
||||||
|
|
||||||
|
// overestimate - check weight for `pallet_bridge_grandpa::Pallet::initialize()` call
|
||||||
|
let require_weight_at_most =
|
||||||
|
<Runtime as frame_system::Config>::DbWeight::get().reads_writes(7, 7);
|
||||||
|
|
||||||
|
// execute XCM with Transacts to `initialize bridge` as governance does
|
||||||
|
assert_ok!(RuntimeHelper::<Runtime>::execute_as_governance(
|
||||||
|
initialize_call,
|
||||||
|
require_weight_at_most
|
||||||
|
)
|
||||||
|
.ensure_complete());
|
||||||
|
|
||||||
|
// check mode after
|
||||||
|
assert_eq!(
|
||||||
|
pallet_bridge_grandpa::PalletOperatingMode::<Runtime, GrandpaPalletInstance>::try_get(),
|
||||||
|
Ok(bp_runtime::BasicOperatingMode::Normal)
|
||||||
|
);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Test-case makes sure that `Runtime` can handle xcm `ExportMessage`:
|
||||||
|
/// Checks if received XCM messages is correctly added to the message outbound queue for delivery.
|
||||||
|
/// For SystemParachains we expect unpaid execution.
|
||||||
|
pub fn handle_export_message_from_system_parachain_to_outbound_queue_works<
|
||||||
|
Runtime,
|
||||||
|
XcmConfig,
|
||||||
|
MessagesPalletInstance,
|
||||||
|
>(
|
||||||
|
collator_session_key: CollatorSessionKeys<Runtime>,
|
||||||
|
runtime_para_id: u32,
|
||||||
|
sibling_parachain_id: u32,
|
||||||
|
unwrap_pallet_bridge_messages_event: Box<
|
||||||
|
dyn Fn(Vec<u8>) -> Option<pallet_bridge_messages::Event<Runtime, MessagesPalletInstance>>,
|
||||||
|
>,
|
||||||
|
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: BasicParachainRuntime + pallet_bridge_messages::Config<MessagesPalletInstance>,
|
||||||
|
XcmConfig: xcm_executor::Config,
|
||||||
|
MessagesPalletInstance: 'static,
|
||||||
|
ValidatorIdOf<Runtime>: From<AccountIdOf<Runtime>>,
|
||||||
|
{
|
||||||
|
assert_ne!(runtime_para_id, sibling_parachain_id);
|
||||||
|
let sibling_parachain_location = MultiLocation::new(1, Parachain(sibling_parachain_id));
|
||||||
|
|
||||||
|
run_test::<Runtime, _>(collator_session_key, runtime_para_id, vec![], || {
|
||||||
|
prepare_configuration();
|
||||||
|
|
||||||
|
// check queue before
|
||||||
|
assert_eq!(
|
||||||
|
pallet_bridge_messages::OutboundLanes::<Runtime, MessagesPalletInstance>::try_get(
|
||||||
|
expected_lane_id
|
||||||
|
),
|
||||||
|
Err(())
|
||||||
|
);
|
||||||
|
|
||||||
|
// prepare `ExportMessage`
|
||||||
|
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,
|
||||||
|
Some(&XcmContext::with_message_id([0; 32])),
|
||||||
|
)
|
||||||
|
.expect("deposited ed");
|
||||||
|
}
|
||||||
|
// deposit fee to origin
|
||||||
|
XcmConfig::AssetTransactor::deposit_asset(
|
||||||
|
&fee,
|
||||||
|
&sibling_parachain_location,
|
||||||
|
Some(&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);
|
||||||
|
assert_ok!(XcmExecutor::<XcmConfig>::execute_xcm(
|
||||||
|
sibling_parachain_location,
|
||||||
|
xcm,
|
||||||
|
hash,
|
||||||
|
RuntimeHelper::<Runtime>::xcm_max_weight(XcmReceivedFrom::Sibling),
|
||||||
|
)
|
||||||
|
.ensure_complete());
|
||||||
|
|
||||||
|
// check queue after
|
||||||
|
assert_eq!(
|
||||||
|
pallet_bridge_messages::OutboundLanes::<Runtime, MessagesPalletInstance>::try_get(
|
||||||
|
expected_lane_id
|
||||||
|
),
|
||||||
|
Ok(OutboundLaneData {
|
||||||
|
oldest_unpruned_nonce: 1,
|
||||||
|
latest_received_nonce: 0,
|
||||||
|
latest_generated_nonce: 1,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
// check events
|
||||||
|
let mut events = <frame_system::Pallet<Runtime>>::events()
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|e| unwrap_pallet_bridge_messages_event(e.event.encode()));
|
||||||
|
assert!(events.any(|e| matches!(e, pallet_bridge_messages::Event::MessageAccepted { .. })));
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Test-case makes sure that Runtime can route XCM messages received in inbound queue,
|
||||||
|
/// We just test here `MessageDispatch` configuration.
|
||||||
|
/// We expect that runtime can route messages:
|
||||||
|
/// 1. to Parent (relay chain)
|
||||||
|
/// 2. to Sibling parachain
|
||||||
|
pub fn message_dispatch_routing_works<
|
||||||
|
Runtime,
|
||||||
|
AllPalletsWithoutSystem,
|
||||||
|
XcmConfig,
|
||||||
|
HrmpChannelOpener,
|
||||||
|
MessagesPalletInstance,
|
||||||
|
RuntimeNetwork,
|
||||||
|
BridgedNetwork,
|
||||||
|
NetworkDistanceAsParentCount,
|
||||||
|
>(
|
||||||
|
collator_session_key: CollatorSessionKeys<Runtime>,
|
||||||
|
runtime_para_id: u32,
|
||||||
|
sibling_parachain_id: u32,
|
||||||
|
unwrap_cumulus_pallet_parachain_system_event: Box<
|
||||||
|
dyn Fn(Vec<u8>) -> Option<cumulus_pallet_parachain_system::Event<Runtime>>,
|
||||||
|
>,
|
||||||
|
unwrap_cumulus_pallet_xcmp_queue_event: Box<
|
||||||
|
dyn Fn(Vec<u8>) -> Option<cumulus_pallet_xcmp_queue::Event<Runtime>>,
|
||||||
|
>,
|
||||||
|
expected_lane_id: LaneId,
|
||||||
|
prepare_configuration: impl Fn(),
|
||||||
|
) where
|
||||||
|
Runtime: BasicParachainRuntime
|
||||||
|
+ cumulus_pallet_xcmp_queue::Config
|
||||||
|
+ pallet_bridge_messages::Config<MessagesPalletInstance, InboundPayload = XcmAsPlainPayload>,
|
||||||
|
AllPalletsWithoutSystem:
|
||||||
|
OnInitialize<BlockNumberFor<Runtime>> + OnFinalize<BlockNumberFor<Runtime>>,
|
||||||
|
<Runtime as frame_system::Config>::AccountId:
|
||||||
|
Into<<<Runtime as frame_system::Config>::RuntimeOrigin as OriginTrait>::AccountId>,
|
||||||
|
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>,
|
||||||
|
>,
|
||||||
|
RuntimeNetwork: Get<NetworkId>,
|
||||||
|
BridgedNetwork: Get<NetworkId>,
|
||||||
|
NetworkDistanceAsParentCount: Get<u8>,
|
||||||
|
{
|
||||||
|
struct NetworkWithParentCount<N, C>(core::marker::PhantomData<(N, C)>);
|
||||||
|
impl<N: Get<NetworkId>, C: Get<u8>> Get<MultiLocation> for NetworkWithParentCount<N, C> {
|
||||||
|
fn get() -> MultiLocation {
|
||||||
|
MultiLocation { parents: C::get(), interior: X1(GlobalConsensus(N::get())) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_ne!(runtime_para_id, sibling_parachain_id);
|
||||||
|
|
||||||
|
run_test::<Runtime, _>(collator_session_key, runtime_para_id, vec![], || {
|
||||||
|
prepare_configuration();
|
||||||
|
|
||||||
|
let mut alice = [0u8; 32];
|
||||||
|
alice[0] = 1;
|
||||||
|
|
||||||
|
let included_head = RuntimeHelper::<Runtime, AllPalletsWithoutSystem>::run_to_block(
|
||||||
|
2,
|
||||||
|
AccountId::from(alice).into(),
|
||||||
|
);
|
||||||
|
// 1. this message is sent from other global consensus with destination of this Runtime
|
||||||
|
// relay chain (UMP)
|
||||||
|
let bridging_message = test_data::simulate_message_exporter_on_bridged_chain::<
|
||||||
|
BridgedNetwork,
|
||||||
|
NetworkWithParentCount<RuntimeNetwork, NetworkDistanceAsParentCount>,
|
||||||
|
AlwaysLatest,
|
||||||
|
>((RuntimeNetwork::get(), Here));
|
||||||
|
let result = <<Runtime as pallet_bridge_messages::Config<MessagesPalletInstance>>::MessageDispatch>::dispatch(
|
||||||
|
test_data::dispatch_message(expected_lane_id, 1, bridging_message)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
format!("{:?}", result.dispatch_level_result),
|
||||||
|
format!("{:?}", XcmBlobMessageDispatchResult::Dispatched)
|
||||||
|
);
|
||||||
|
|
||||||
|
// check events - UpwardMessageSent
|
||||||
|
let mut events = <frame_system::Pallet<Runtime>>::events()
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|e| unwrap_cumulus_pallet_parachain_system_event(e.event.encode()));
|
||||||
|
assert!(events.any(|e| matches!(
|
||||||
|
e,
|
||||||
|
cumulus_pallet_parachain_system::Event::UpwardMessageSent { .. }
|
||||||
|
)));
|
||||||
|
|
||||||
|
// 2. this message is sent from other global consensus with destination of this Runtime
|
||||||
|
// sibling parachain (HRMP)
|
||||||
|
let bridging_message = test_data::simulate_message_exporter_on_bridged_chain::<
|
||||||
|
BridgedNetwork,
|
||||||
|
NetworkWithParentCount<RuntimeNetwork, NetworkDistanceAsParentCount>,
|
||||||
|
AlwaysLatest,
|
||||||
|
>((RuntimeNetwork::get(), X1(Parachain(sibling_parachain_id))));
|
||||||
|
|
||||||
|
// 2.1. WITHOUT opened hrmp channel -> RoutingError
|
||||||
|
let result =
|
||||||
|
<<Runtime as pallet_bridge_messages::Config<MessagesPalletInstance>>::MessageDispatch>::dispatch(
|
||||||
|
DispatchMessage {
|
||||||
|
key: MessageKey { lane_id: expected_lane_id, nonce: 1 },
|
||||||
|
data: DispatchMessageData { payload: Ok(bridging_message.clone()) },
|
||||||
|
}
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
format!("{:?}", result.dispatch_level_result),
|
||||||
|
format!(
|
||||||
|
"{:?}",
|
||||||
|
XcmBlobMessageDispatchResult::NotDispatched(Some(DispatchBlobError::RoutingError))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
// check events - no XcmpMessageSent
|
||||||
|
assert_eq!(
|
||||||
|
<frame_system::Pallet<Runtime>>::events()
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|e| unwrap_cumulus_pallet_xcmp_queue_event(e.event.encode()))
|
||||||
|
.count(),
|
||||||
|
0
|
||||||
|
);
|
||||||
|
|
||||||
|
// 2.1. WITH hrmp channel -> Ok
|
||||||
|
mock_open_hrmp_channel::<Runtime, HrmpChannelOpener>(
|
||||||
|
runtime_para_id.into(),
|
||||||
|
sibling_parachain_id.into(),
|
||||||
|
included_head,
|
||||||
|
&alice,
|
||||||
|
);
|
||||||
|
let result = <<Runtime as pallet_bridge_messages::Config<MessagesPalletInstance>>::MessageDispatch>::dispatch(
|
||||||
|
DispatchMessage {
|
||||||
|
key: MessageKey { lane_id: expected_lane_id, nonce: 1 },
|
||||||
|
data: DispatchMessageData { payload: Ok(bridging_message) },
|
||||||
|
}
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
format!("{:?}", result.dispatch_level_result),
|
||||||
|
format!("{:?}", XcmBlobMessageDispatchResult::Dispatched)
|
||||||
|
);
|
||||||
|
|
||||||
|
// check events - XcmpMessageSent
|
||||||
|
let mut events = <frame_system::Pallet<Runtime>>::events()
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|e| unwrap_cumulus_pallet_xcmp_queue_event(e.event.encode()));
|
||||||
|
assert!(
|
||||||
|
events.any(|e| matches!(e, cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. }))
|
||||||
|
);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Estimates XCM execution 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,
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
},
|
||||||
|
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()
|
||||||
|
}
|
||||||
+244
@@ -0,0 +1,244 @@
|
|||||||
|
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Cumulus.
|
||||||
|
|
||||||
|
// Cumulus 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.
|
||||||
|
|
||||||
|
// Cumulus 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 Cumulus. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//! Generating test data for bridges with remote GRANDPA chains.
|
||||||
|
|
||||||
|
use crate::test_data::prepare_inbound_xcm;
|
||||||
|
|
||||||
|
use bp_messages::{
|
||||||
|
source_chain::TargetHeaderChain, target_chain::SourceHeaderChain, LaneId, MessageNonce,
|
||||||
|
UnrewardedRelayersState,
|
||||||
|
};
|
||||||
|
use bp_runtime::{AccountIdOf, BlockNumberOf, HeaderOf, StorageProofSize, UnderlyingChainOf};
|
||||||
|
use bp_test_utils::make_default_justification;
|
||||||
|
use bridge_runtime_common::{
|
||||||
|
messages::{
|
||||||
|
source::FromBridgedChainMessagesDeliveryProof, target::FromBridgedChainMessagesProof,
|
||||||
|
BridgedChain as MessageBridgedChain, MessageBridge, ThisChain as MessageThisChain,
|
||||||
|
},
|
||||||
|
messages_generation::{
|
||||||
|
encode_all_messages, encode_lane_data, prepare_message_delivery_storage_proof,
|
||||||
|
prepare_messages_storage_proof,
|
||||||
|
},
|
||||||
|
messages_xcm_extension::XcmAsPlainPayload,
|
||||||
|
};
|
||||||
|
use codec::Encode;
|
||||||
|
use pallet_bridge_grandpa::{BridgedChain, BridgedHeader};
|
||||||
|
use sp_runtime::traits::Header as HeaderT;
|
||||||
|
use xcm::latest::prelude::*;
|
||||||
|
|
||||||
|
use bp_header_chain::{justification::GrandpaJustification, ChainWithGrandpa};
|
||||||
|
use bp_messages::{DeliveredMessages, InboundLaneData, UnrewardedRelayer};
|
||||||
|
use bp_runtime::HashOf;
|
||||||
|
use sp_runtime::DigestItem;
|
||||||
|
|
||||||
|
/// Prepare a batch call with bridged GRANDPA finality and message proof.
|
||||||
|
pub fn make_complex_relayer_delivery_batch<Runtime, GPI, MPI>(
|
||||||
|
bridged_header: BridgedHeader<Runtime, GPI>,
|
||||||
|
bridged_justification: GrandpaJustification<BridgedHeader<Runtime, GPI>>,
|
||||||
|
message_proof: FromBridgedChainMessagesProof<HashOf<BridgedChain<Runtime, GPI>>>,
|
||||||
|
relayer_id_at_bridged_chain: AccountIdOf<BridgedChain<Runtime, GPI>>,
|
||||||
|
) -> pallet_utility::Call<Runtime>
|
||||||
|
where
|
||||||
|
Runtime: pallet_bridge_grandpa::Config<GPI>
|
||||||
|
+ pallet_bridge_messages::Config<
|
||||||
|
MPI,
|
||||||
|
InboundPayload = XcmAsPlainPayload,
|
||||||
|
InboundRelayer = AccountIdOf<BridgedChain<Runtime, GPI>>,
|
||||||
|
> + pallet_utility::Config,
|
||||||
|
GPI: 'static,
|
||||||
|
MPI: 'static,
|
||||||
|
<Runtime as pallet_bridge_messages::Config<MPI>>::SourceHeaderChain: SourceHeaderChain<
|
||||||
|
MessagesProof = FromBridgedChainMessagesProof<HashOf<BridgedChain<Runtime, GPI>>>,
|
||||||
|
>,
|
||||||
|
<Runtime as pallet_utility::Config>::RuntimeCall: From<pallet_bridge_grandpa::Call<Runtime, GPI>>
|
||||||
|
+ From<pallet_bridge_messages::Call<Runtime, MPI>>,
|
||||||
|
{
|
||||||
|
let submit_grandpa = pallet_bridge_grandpa::Call::<Runtime, GPI>::submit_finality_proof {
|
||||||
|
finality_target: Box::new(bridged_header),
|
||||||
|
justification: bridged_justification,
|
||||||
|
};
|
||||||
|
let submit_message = pallet_bridge_messages::Call::<Runtime, MPI>::receive_messages_proof {
|
||||||
|
relayer_id_at_bridged_chain,
|
||||||
|
proof: message_proof,
|
||||||
|
messages_count: 1,
|
||||||
|
dispatch_weight: Weight::from_parts(1000000000, 0),
|
||||||
|
};
|
||||||
|
pallet_utility::Call::<Runtime>::batch_all {
|
||||||
|
calls: vec![submit_grandpa.into(), submit_message.into()],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Prepare a batch call with bridged GRANDPA finality and message delivery proof.
|
||||||
|
pub fn make_complex_relayer_confirmation_batch<Runtime, GPI, MPI>(
|
||||||
|
bridged_header: BridgedHeader<Runtime, GPI>,
|
||||||
|
bridged_justification: GrandpaJustification<BridgedHeader<Runtime, GPI>>,
|
||||||
|
message_delivery_proof: FromBridgedChainMessagesDeliveryProof<
|
||||||
|
HashOf<BridgedChain<Runtime, GPI>>,
|
||||||
|
>,
|
||||||
|
relayers_state: UnrewardedRelayersState,
|
||||||
|
) -> pallet_utility::Call<Runtime>
|
||||||
|
where
|
||||||
|
Runtime: pallet_bridge_grandpa::Config<GPI>
|
||||||
|
+ pallet_bridge_messages::Config<MPI, OutboundPayload = XcmAsPlainPayload>
|
||||||
|
+ pallet_utility::Config,
|
||||||
|
GPI: 'static,
|
||||||
|
MPI: 'static,
|
||||||
|
<Runtime as pallet_bridge_messages::Config<MPI>>::TargetHeaderChain: TargetHeaderChain<
|
||||||
|
XcmAsPlainPayload,
|
||||||
|
Runtime::AccountId,
|
||||||
|
MessagesDeliveryProof = FromBridgedChainMessagesDeliveryProof<
|
||||||
|
HashOf<BridgedChain<Runtime, GPI>>,
|
||||||
|
>,
|
||||||
|
>,
|
||||||
|
<Runtime as pallet_utility::Config>::RuntimeCall: From<pallet_bridge_grandpa::Call<Runtime, GPI>>
|
||||||
|
+ From<pallet_bridge_messages::Call<Runtime, MPI>>,
|
||||||
|
{
|
||||||
|
let submit_grandpa = pallet_bridge_grandpa::Call::<Runtime, GPI>::submit_finality_proof {
|
||||||
|
finality_target: Box::new(bridged_header),
|
||||||
|
justification: bridged_justification,
|
||||||
|
};
|
||||||
|
let submit_message_delivery_proof =
|
||||||
|
pallet_bridge_messages::Call::<Runtime, MPI>::receive_messages_delivery_proof {
|
||||||
|
proof: message_delivery_proof,
|
||||||
|
relayers_state,
|
||||||
|
};
|
||||||
|
pallet_utility::Call::<Runtime>::batch_all {
|
||||||
|
calls: vec![submit_grandpa.into(), submit_message_delivery_proof.into()],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Prepare storage proofs of messages, stored at the (bridged) source GRANDPA chain.
|
||||||
|
pub fn make_complex_relayer_delivery_proofs<MB, InnerXcmRuntimeCall>(
|
||||||
|
lane_id: LaneId,
|
||||||
|
xcm_message: Xcm<InnerXcmRuntimeCall>,
|
||||||
|
message_nonce: MessageNonce,
|
||||||
|
message_destination: Junctions,
|
||||||
|
header_number: BlockNumberOf<MessageBridgedChain<MB>>,
|
||||||
|
) -> (
|
||||||
|
HeaderOf<MessageBridgedChain<MB>>,
|
||||||
|
GrandpaJustification<HeaderOf<MessageBridgedChain<MB>>>,
|
||||||
|
FromBridgedChainMessagesProof<HashOf<MessageBridgedChain<MB>>>,
|
||||||
|
)
|
||||||
|
where
|
||||||
|
MB: MessageBridge,
|
||||||
|
MessageBridgedChain<MB>: Send + Sync + 'static,
|
||||||
|
UnderlyingChainOf<MessageBridgedChain<MB>>: ChainWithGrandpa,
|
||||||
|
{
|
||||||
|
let message_payload = prepare_inbound_xcm(xcm_message, message_destination);
|
||||||
|
let message_size = StorageProofSize::Minimal(message_payload.len() as u32);
|
||||||
|
// prepare para storage proof containing message
|
||||||
|
let (state_root, storage_proof) = prepare_messages_storage_proof::<MB>(
|
||||||
|
lane_id,
|
||||||
|
message_nonce..=message_nonce,
|
||||||
|
None,
|
||||||
|
message_size,
|
||||||
|
message_payload,
|
||||||
|
encode_all_messages,
|
||||||
|
encode_lane_data,
|
||||||
|
);
|
||||||
|
|
||||||
|
let (header, justification) = make_complex_bridged_grandpa_header_proof::<
|
||||||
|
MessageBridgedChain<MB>,
|
||||||
|
>(state_root, header_number);
|
||||||
|
|
||||||
|
let message_proof = FromBridgedChainMessagesProof {
|
||||||
|
bridged_header_hash: header.hash(),
|
||||||
|
storage_proof,
|
||||||
|
lane: lane_id,
|
||||||
|
nonces_start: message_nonce,
|
||||||
|
nonces_end: message_nonce,
|
||||||
|
};
|
||||||
|
|
||||||
|
(header, justification, message_proof)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Prepare storage proofs of message confirmations, stored at the (bridged) target GRANDPA chain.
|
||||||
|
pub fn make_complex_relayer_confirmation_proofs<MB, InnerXcmRuntimeCall>(
|
||||||
|
lane_id: LaneId,
|
||||||
|
header_number: BlockNumberOf<MessageBridgedChain<MB>>,
|
||||||
|
relayer_id_at_this_chain: AccountIdOf<MessageThisChain<MB>>,
|
||||||
|
relayers_state: UnrewardedRelayersState,
|
||||||
|
) -> (
|
||||||
|
HeaderOf<MessageBridgedChain<MB>>,
|
||||||
|
GrandpaJustification<HeaderOf<MessageBridgedChain<MB>>>,
|
||||||
|
FromBridgedChainMessagesDeliveryProof<HashOf<MessageBridgedChain<MB>>>,
|
||||||
|
)
|
||||||
|
where
|
||||||
|
MB: MessageBridge,
|
||||||
|
MessageBridgedChain<MB>: Send + Sync + 'static,
|
||||||
|
MessageThisChain<MB>: Send + Sync + 'static,
|
||||||
|
UnderlyingChainOf<MessageBridgedChain<MB>>: ChainWithGrandpa,
|
||||||
|
{
|
||||||
|
// prepare storage proof containing message delivery proof
|
||||||
|
let (state_root, storage_proof) = prepare_message_delivery_storage_proof::<MB>(
|
||||||
|
lane_id,
|
||||||
|
InboundLaneData {
|
||||||
|
relayers: vec![
|
||||||
|
UnrewardedRelayer {
|
||||||
|
relayer: relayer_id_at_this_chain,
|
||||||
|
messages: DeliveredMessages::new(1)
|
||||||
|
};
|
||||||
|
relayers_state.unrewarded_relayer_entries as usize
|
||||||
|
]
|
||||||
|
.into(),
|
||||||
|
last_confirmed_nonce: 1,
|
||||||
|
},
|
||||||
|
StorageProofSize::Minimal(0),
|
||||||
|
);
|
||||||
|
|
||||||
|
let (header, justification) =
|
||||||
|
make_complex_bridged_grandpa_header_proof::<MB::BridgedChain>(state_root, header_number);
|
||||||
|
|
||||||
|
let message_delivery_proof = FromBridgedChainMessagesDeliveryProof {
|
||||||
|
bridged_header_hash: header.hash(),
|
||||||
|
storage_proof,
|
||||||
|
lane: lane_id,
|
||||||
|
};
|
||||||
|
|
||||||
|
(header, justification, message_delivery_proof)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Make bridged GRANDPA chain header with given state root.
|
||||||
|
pub fn make_complex_bridged_grandpa_header_proof<BridgedChain>(
|
||||||
|
state_root: HashOf<BridgedChain>,
|
||||||
|
header_number: BlockNumberOf<BridgedChain>,
|
||||||
|
) -> (HeaderOf<BridgedChain>, GrandpaJustification<HeaderOf<BridgedChain>>)
|
||||||
|
where
|
||||||
|
BridgedChain: ChainWithGrandpa,
|
||||||
|
{
|
||||||
|
let mut header = bp_test_utils::test_header_with_root::<HeaderOf<BridgedChain>>(
|
||||||
|
header_number.into(),
|
||||||
|
state_root.into(),
|
||||||
|
);
|
||||||
|
|
||||||
|
// to compute proper cost of GRANDPA call, let's add some dummy bytes to header, so that the
|
||||||
|
// `submit_finality_proof` call size would be close to maximal expected (and refundable)
|
||||||
|
let extra_bytes_required = maximal_expected_submit_finality_proof_call_size::<BridgedChain>()
|
||||||
|
.saturating_sub(header.encoded_size());
|
||||||
|
header.digest_mut().push(DigestItem::Other(vec![42; extra_bytes_required]));
|
||||||
|
|
||||||
|
let justification = make_default_justification(&header);
|
||||||
|
(header, justification)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Maximal expected `submit_finality_proof` call size.
|
||||||
|
pub fn maximal_expected_submit_finality_proof_call_size<BridgedChain: ChainWithGrandpa>() -> usize {
|
||||||
|
bp_header_chain::max_expected_submit_finality_proof_arguments_size::<BridgedChain>(
|
||||||
|
false,
|
||||||
|
BridgedChain::MAX_AUTHORITIES_COUNT * 2 / 3 + 1,
|
||||||
|
) as usize
|
||||||
|
}
|
||||||
@@ -0,0 +1,326 @@
|
|||||||
|
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Cumulus.
|
||||||
|
|
||||||
|
// Cumulus 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.
|
||||||
|
|
||||||
|
// Cumulus 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 Cumulus. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//! Generating test data for bridges with remote parachains.
|
||||||
|
|
||||||
|
use super::{from_grandpa_chain::make_complex_bridged_grandpa_header_proof, prepare_inbound_xcm};
|
||||||
|
|
||||||
|
use bp_messages::{
|
||||||
|
source_chain::TargetHeaderChain, target_chain::SourceHeaderChain, LaneId,
|
||||||
|
UnrewardedRelayersState, Weight,
|
||||||
|
};
|
||||||
|
use bp_runtime::{BlockNumberOf, HeaderOf, Parachain, StorageProofSize, UnderlyingChainOf};
|
||||||
|
use bp_test_utils::prepare_parachain_heads_proof;
|
||||||
|
use bridge_runtime_common::{
|
||||||
|
messages::{
|
||||||
|
source::FromBridgedChainMessagesDeliveryProof, target::FromBridgedChainMessagesProof,
|
||||||
|
BridgedChain as MessageBridgedChain, MessageBridge,
|
||||||
|
},
|
||||||
|
messages_generation::{
|
||||||
|
encode_all_messages, encode_lane_data, prepare_message_delivery_storage_proof,
|
||||||
|
prepare_messages_storage_proof,
|
||||||
|
},
|
||||||
|
messages_xcm_extension::XcmAsPlainPayload,
|
||||||
|
};
|
||||||
|
use codec::Encode;
|
||||||
|
use pallet_bridge_grandpa::BridgedHeader;
|
||||||
|
use pallet_bridge_parachains::{RelayBlockHash, RelayBlockNumber};
|
||||||
|
use sp_runtime::{traits::Header as HeaderT, AccountId32};
|
||||||
|
use xcm::latest::prelude::*;
|
||||||
|
|
||||||
|
use bp_header_chain::{justification::GrandpaJustification, ChainWithGrandpa};
|
||||||
|
use bp_messages::{DeliveredMessages, InboundLaneData, MessageNonce, UnrewardedRelayer};
|
||||||
|
use bp_polkadot_core::parachains::{ParaHash, ParaHead, ParaHeadsProof, ParaId};
|
||||||
|
use sp_runtime::SaturatedConversion;
|
||||||
|
|
||||||
|
/// Prepare a batch call with relay finality proof, parachain head proof and message proof.
|
||||||
|
pub fn make_complex_relayer_delivery_batch<Runtime, GPI, PPI, MPI>(
|
||||||
|
relay_chain_header: BridgedHeader<Runtime, GPI>,
|
||||||
|
grandpa_justification: GrandpaJustification<BridgedHeader<Runtime, GPI>>,
|
||||||
|
parachain_heads: Vec<(ParaId, ParaHash)>,
|
||||||
|
para_heads_proof: ParaHeadsProof,
|
||||||
|
message_proof: FromBridgedChainMessagesProof<ParaHash>,
|
||||||
|
relayer_id_at_bridged_chain: AccountId32,
|
||||||
|
) -> pallet_utility::Call<Runtime> where
|
||||||
|
Runtime:pallet_bridge_grandpa::Config<GPI>
|
||||||
|
+ pallet_bridge_parachains::Config<PPI>
|
||||||
|
+ pallet_bridge_messages::Config<MPI, InboundPayload = XcmAsPlainPayload>
|
||||||
|
+ pallet_utility::Config,
|
||||||
|
GPI: 'static,
|
||||||
|
PPI: 'static,
|
||||||
|
MPI: 'static,
|
||||||
|
ParaHash: From<<<Runtime as pallet_bridge_grandpa::Config<GPI>>::BridgedChain as bp_runtime::Chain>::Hash>,
|
||||||
|
<<Runtime as pallet_bridge_grandpa::Config<GPI>>::BridgedChain as bp_runtime::Chain>::Hash: From<ParaHash>,
|
||||||
|
<<Runtime as pallet_bridge_messages::Config<MPI>>::SourceHeaderChain as SourceHeaderChain>::MessagesProof:
|
||||||
|
From<FromBridgedChainMessagesProof<ParaHash>>,
|
||||||
|
<Runtime as pallet_bridge_messages::Config<MPI>>::InboundRelayer: From<AccountId32>,
|
||||||
|
<Runtime as pallet_utility::Config>::RuntimeCall:
|
||||||
|
From<pallet_bridge_grandpa::Call<Runtime, GPI>>
|
||||||
|
+ From<pallet_bridge_parachains::Call<Runtime, PPI>>
|
||||||
|
+ From<pallet_bridge_messages::Call<Runtime, MPI>>,
|
||||||
|
{
|
||||||
|
let relay_chain_header_hash = relay_chain_header.hash();
|
||||||
|
let relay_chain_header_number = *relay_chain_header.number();
|
||||||
|
let submit_grandpa = pallet_bridge_grandpa::Call::<Runtime, GPI>::submit_finality_proof {
|
||||||
|
finality_target: Box::new(relay_chain_header),
|
||||||
|
justification: grandpa_justification,
|
||||||
|
};
|
||||||
|
let submit_para_head = pallet_bridge_parachains::Call::<Runtime, PPI>::submit_parachain_heads {
|
||||||
|
at_relay_block: (
|
||||||
|
relay_chain_header_number.saturated_into(),
|
||||||
|
relay_chain_header_hash.into(),
|
||||||
|
),
|
||||||
|
parachains: parachain_heads,
|
||||||
|
parachain_heads_proof: para_heads_proof,
|
||||||
|
};
|
||||||
|
let submit_message = pallet_bridge_messages::Call::<Runtime, MPI>::receive_messages_proof {
|
||||||
|
relayer_id_at_bridged_chain: relayer_id_at_bridged_chain.into(),
|
||||||
|
proof: message_proof.into(),
|
||||||
|
messages_count: 1,
|
||||||
|
dispatch_weight: Weight::from_parts(1000000000, 0),
|
||||||
|
};
|
||||||
|
pallet_utility::Call::<Runtime>::batch_all {
|
||||||
|
calls: vec![submit_grandpa.into(), submit_para_head.into(), submit_message.into()],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Prepare a batch call with relay finality proof, parachain head proof and message delivery
|
||||||
|
/// proof.
|
||||||
|
pub fn make_complex_relayer_confirmation_batch<Runtime, GPI, PPI, MPI>(
|
||||||
|
relay_chain_header: BridgedHeader<Runtime, GPI>,
|
||||||
|
grandpa_justification: GrandpaJustification<BridgedHeader<Runtime, GPI>>,
|
||||||
|
parachain_heads: Vec<(ParaId, ParaHash)>,
|
||||||
|
para_heads_proof: ParaHeadsProof,
|
||||||
|
message_delivery_proof: FromBridgedChainMessagesDeliveryProof<ParaHash>,
|
||||||
|
relayers_state: UnrewardedRelayersState,
|
||||||
|
) -> pallet_utility::Call<Runtime>
|
||||||
|
where
|
||||||
|
Runtime: pallet_bridge_grandpa::Config<GPI>
|
||||||
|
+ pallet_bridge_parachains::Config<PPI>
|
||||||
|
+ pallet_bridge_messages::Config<MPI, OutboundPayload = XcmAsPlainPayload>
|
||||||
|
+ pallet_utility::Config,
|
||||||
|
GPI: 'static,
|
||||||
|
PPI: 'static,
|
||||||
|
MPI: 'static,
|
||||||
|
<Runtime as pallet_bridge_grandpa::Config<GPI>>::BridgedChain:
|
||||||
|
bp_runtime::Chain<Hash = RelayBlockHash, BlockNumber = RelayBlockNumber> + ChainWithGrandpa,
|
||||||
|
<<Runtime as pallet_bridge_messages::Config<MPI>>::TargetHeaderChain as TargetHeaderChain<
|
||||||
|
XcmAsPlainPayload,
|
||||||
|
Runtime::AccountId,
|
||||||
|
>>::MessagesDeliveryProof: From<FromBridgedChainMessagesDeliveryProof<ParaHash>>,
|
||||||
|
<Runtime as pallet_utility::Config>::RuntimeCall: From<pallet_bridge_grandpa::Call<Runtime, GPI>>
|
||||||
|
+ From<pallet_bridge_parachains::Call<Runtime, PPI>>
|
||||||
|
+ From<pallet_bridge_messages::Call<Runtime, MPI>>,
|
||||||
|
{
|
||||||
|
let relay_chain_header_hash = relay_chain_header.hash();
|
||||||
|
let relay_chain_header_number = *relay_chain_header.number();
|
||||||
|
let submit_grandpa = pallet_bridge_grandpa::Call::<Runtime, GPI>::submit_finality_proof {
|
||||||
|
finality_target: Box::new(relay_chain_header),
|
||||||
|
justification: grandpa_justification,
|
||||||
|
};
|
||||||
|
let submit_para_head = pallet_bridge_parachains::Call::<Runtime, PPI>::submit_parachain_heads {
|
||||||
|
at_relay_block: (
|
||||||
|
relay_chain_header_number.saturated_into(),
|
||||||
|
relay_chain_header_hash.into(),
|
||||||
|
),
|
||||||
|
parachains: parachain_heads,
|
||||||
|
parachain_heads_proof: para_heads_proof,
|
||||||
|
};
|
||||||
|
let submit_message_delivery_proof =
|
||||||
|
pallet_bridge_messages::Call::<Runtime, MPI>::receive_messages_delivery_proof {
|
||||||
|
proof: message_delivery_proof.into(),
|
||||||
|
relayers_state,
|
||||||
|
};
|
||||||
|
pallet_utility::Call::<Runtime>::batch_all {
|
||||||
|
calls: vec![
|
||||||
|
submit_grandpa.into(),
|
||||||
|
submit_para_head.into(),
|
||||||
|
submit_message_delivery_proof.into(),
|
||||||
|
],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Prepare storage proofs of messages, stored at the source chain.
|
||||||
|
pub fn make_complex_relayer_delivery_proofs<BridgedRelayChain, MB, InnerXcmRuntimeCall>(
|
||||||
|
lane_id: LaneId,
|
||||||
|
xcm_message: Xcm<InnerXcmRuntimeCall>,
|
||||||
|
message_nonce: MessageNonce,
|
||||||
|
message_destination: Junctions,
|
||||||
|
para_header_number: u32,
|
||||||
|
relay_header_number: u32,
|
||||||
|
bridged_para_id: u32,
|
||||||
|
) -> (
|
||||||
|
HeaderOf<BridgedRelayChain>,
|
||||||
|
GrandpaJustification<HeaderOf<BridgedRelayChain>>,
|
||||||
|
ParaHead,
|
||||||
|
Vec<(ParaId, ParaHash)>,
|
||||||
|
ParaHeadsProof,
|
||||||
|
FromBridgedChainMessagesProof<ParaHash>,
|
||||||
|
)
|
||||||
|
where
|
||||||
|
BridgedRelayChain:
|
||||||
|
bp_runtime::Chain<Hash = RelayBlockHash, BlockNumber = RelayBlockNumber> + ChainWithGrandpa,
|
||||||
|
MB: MessageBridge,
|
||||||
|
<MB as MessageBridge>::BridgedChain: Send + Sync + 'static,
|
||||||
|
<MB as MessageBridge>::ThisChain: Send + Sync + 'static,
|
||||||
|
UnderlyingChainOf<MessageBridgedChain<MB>>: bp_runtime::Chain<Hash = ParaHash> + Parachain,
|
||||||
|
{
|
||||||
|
let message_payload = prepare_inbound_xcm(xcm_message, message_destination);
|
||||||
|
let message_size = StorageProofSize::Minimal(message_payload.len() as u32);
|
||||||
|
// prepare para storage proof containing message
|
||||||
|
let (para_state_root, para_storage_proof) = prepare_messages_storage_proof::<MB>(
|
||||||
|
lane_id,
|
||||||
|
message_nonce..=message_nonce,
|
||||||
|
None,
|
||||||
|
message_size,
|
||||||
|
message_payload,
|
||||||
|
encode_all_messages,
|
||||||
|
encode_lane_data,
|
||||||
|
);
|
||||||
|
|
||||||
|
let (relay_chain_header, justification, bridged_para_head, parachain_heads, para_heads_proof) =
|
||||||
|
make_complex_bridged_parachain_heads_proof::<BridgedRelayChain, MB>(
|
||||||
|
para_state_root,
|
||||||
|
para_header_number,
|
||||||
|
relay_header_number,
|
||||||
|
bridged_para_id,
|
||||||
|
);
|
||||||
|
|
||||||
|
let message_proof = FromBridgedChainMessagesProof {
|
||||||
|
bridged_header_hash: bridged_para_head.hash(),
|
||||||
|
storage_proof: para_storage_proof,
|
||||||
|
lane: lane_id,
|
||||||
|
nonces_start: message_nonce,
|
||||||
|
nonces_end: message_nonce,
|
||||||
|
};
|
||||||
|
|
||||||
|
(
|
||||||
|
relay_chain_header,
|
||||||
|
justification,
|
||||||
|
bridged_para_head,
|
||||||
|
parachain_heads,
|
||||||
|
para_heads_proof,
|
||||||
|
message_proof,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Prepare storage proofs of message confirmations, stored at the target parachain.
|
||||||
|
pub fn make_complex_relayer_confirmation_proofs<BridgedRelayChain, MB, InnerXcmRuntimeCall>(
|
||||||
|
lane_id: LaneId,
|
||||||
|
para_header_number: u32,
|
||||||
|
relay_header_number: u32,
|
||||||
|
bridged_para_id: u32,
|
||||||
|
relayer_id_at_this_chain: AccountId32,
|
||||||
|
relayers_state: UnrewardedRelayersState,
|
||||||
|
) -> (
|
||||||
|
HeaderOf<BridgedRelayChain>,
|
||||||
|
GrandpaJustification<HeaderOf<BridgedRelayChain>>,
|
||||||
|
ParaHead,
|
||||||
|
Vec<(ParaId, ParaHash)>,
|
||||||
|
ParaHeadsProof,
|
||||||
|
FromBridgedChainMessagesDeliveryProof<ParaHash>,
|
||||||
|
)
|
||||||
|
where
|
||||||
|
BridgedRelayChain:
|
||||||
|
bp_runtime::Chain<Hash = RelayBlockHash, BlockNumber = RelayBlockNumber> + ChainWithGrandpa,
|
||||||
|
MB: MessageBridge,
|
||||||
|
<MB as MessageBridge>::BridgedChain: Send + Sync + 'static,
|
||||||
|
<MB as MessageBridge>::ThisChain: Send + Sync + 'static,
|
||||||
|
<<MB as MessageBridge>::ThisChain as bp_runtime::Chain>::AccountId: From<AccountId32>,
|
||||||
|
UnderlyingChainOf<MessageBridgedChain<MB>>: bp_runtime::Chain<Hash = ParaHash> + Parachain,
|
||||||
|
{
|
||||||
|
// prepare para storage proof containing message delivery proof
|
||||||
|
let (para_state_root, para_storage_proof) = prepare_message_delivery_storage_proof::<MB>(
|
||||||
|
lane_id,
|
||||||
|
InboundLaneData {
|
||||||
|
relayers: vec![
|
||||||
|
UnrewardedRelayer {
|
||||||
|
relayer: relayer_id_at_this_chain.into(),
|
||||||
|
messages: DeliveredMessages::new(1)
|
||||||
|
};
|
||||||
|
relayers_state.unrewarded_relayer_entries as usize
|
||||||
|
]
|
||||||
|
.into(),
|
||||||
|
last_confirmed_nonce: 1,
|
||||||
|
},
|
||||||
|
StorageProofSize::Minimal(0),
|
||||||
|
);
|
||||||
|
|
||||||
|
let (relay_chain_header, justification, bridged_para_head, parachain_heads, para_heads_proof) =
|
||||||
|
make_complex_bridged_parachain_heads_proof::<BridgedRelayChain, MB>(
|
||||||
|
para_state_root,
|
||||||
|
para_header_number,
|
||||||
|
relay_header_number,
|
||||||
|
bridged_para_id,
|
||||||
|
);
|
||||||
|
|
||||||
|
let message_delivery_proof = FromBridgedChainMessagesDeliveryProof {
|
||||||
|
bridged_header_hash: bridged_para_head.hash(),
|
||||||
|
storage_proof: para_storage_proof,
|
||||||
|
lane: lane_id,
|
||||||
|
};
|
||||||
|
|
||||||
|
(
|
||||||
|
relay_chain_header,
|
||||||
|
justification,
|
||||||
|
bridged_para_head,
|
||||||
|
parachain_heads,
|
||||||
|
para_heads_proof,
|
||||||
|
message_delivery_proof,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Make bridged parachain header with given state root and relay header that is finalizing it.
|
||||||
|
pub fn make_complex_bridged_parachain_heads_proof<BridgedRelayChain, MB>(
|
||||||
|
para_state_root: ParaHash,
|
||||||
|
para_header_number: u32,
|
||||||
|
relay_header_number: BlockNumberOf<BridgedRelayChain>,
|
||||||
|
bridged_para_id: u32,
|
||||||
|
) -> (
|
||||||
|
HeaderOf<BridgedRelayChain>,
|
||||||
|
GrandpaJustification<HeaderOf<BridgedRelayChain>>,
|
||||||
|
ParaHead,
|
||||||
|
Vec<(ParaId, ParaHash)>,
|
||||||
|
ParaHeadsProof,
|
||||||
|
)
|
||||||
|
where
|
||||||
|
BridgedRelayChain:
|
||||||
|
bp_runtime::Chain<Hash = RelayBlockHash, BlockNumber = RelayBlockNumber> + ChainWithGrandpa,
|
||||||
|
MB: MessageBridge,
|
||||||
|
<MB as MessageBridge>::BridgedChain: Send + Sync + 'static,
|
||||||
|
<MB as MessageBridge>::ThisChain: Send + Sync + 'static,
|
||||||
|
UnderlyingChainOf<MessageBridgedChain<MB>>: bp_runtime::Chain<Hash = ParaHash> + Parachain,
|
||||||
|
{
|
||||||
|
let bridged_para_head = ParaHead(
|
||||||
|
bp_test_utils::test_header_with_root::<HeaderOf<MB::BridgedChain>>(
|
||||||
|
para_header_number.into(),
|
||||||
|
para_state_root,
|
||||||
|
)
|
||||||
|
.encode(),
|
||||||
|
);
|
||||||
|
let (relay_state_root, para_heads_proof, parachain_heads) =
|
||||||
|
prepare_parachain_heads_proof::<HeaderOf<MB::BridgedChain>>(vec![(
|
||||||
|
bridged_para_id,
|
||||||
|
bridged_para_head.clone(),
|
||||||
|
)]);
|
||||||
|
assert_eq!(bridged_para_head.hash(), parachain_heads[0].1);
|
||||||
|
|
||||||
|
let (relay_chain_header, justification) = make_complex_bridged_grandpa_header_proof::<
|
||||||
|
BridgedRelayChain,
|
||||||
|
>(relay_state_root, relay_header_number);
|
||||||
|
|
||||||
|
(relay_chain_header, justification, bridged_para_head, parachain_heads, para_heads_proof)
|
||||||
|
}
|
||||||
@@ -0,0 +1,144 @@
|
|||||||
|
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Cumulus.
|
||||||
|
|
||||||
|
// Cumulus 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.
|
||||||
|
|
||||||
|
// Cumulus 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 Cumulus. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//! Generating test data, used by all tests.
|
||||||
|
|
||||||
|
pub mod from_grandpa_chain;
|
||||||
|
pub mod from_parachain;
|
||||||
|
|
||||||
|
use bp_messages::{
|
||||||
|
target_chain::{DispatchMessage, DispatchMessageData},
|
||||||
|
LaneId, MessageKey,
|
||||||
|
};
|
||||||
|
use codec::Encode;
|
||||||
|
use frame_support::traits::Get;
|
||||||
|
use pallet_bridge_grandpa::BridgedHeader;
|
||||||
|
use xcm::latest::prelude::*;
|
||||||
|
|
||||||
|
use bp_messages::MessageNonce;
|
||||||
|
use bp_runtime::BasicOperatingMode;
|
||||||
|
use bp_test_utils::authority_list;
|
||||||
|
use xcm::GetVersion;
|
||||||
|
use xcm_builder::{HaulBlob, HaulBlobError, HaulBlobExporter};
|
||||||
|
use xcm_executor::traits::{validate_export, ExportXcm};
|
||||||
|
|
||||||
|
pub fn prepare_inbound_xcm<InnerXcmRuntimeCall>(
|
||||||
|
xcm_message: Xcm<InnerXcmRuntimeCall>,
|
||||||
|
destination: InteriorMultiLocation,
|
||||||
|
) -> Vec<u8> {
|
||||||
|
let location = xcm::VersionedInteriorMultiLocation::V3(destination);
|
||||||
|
let xcm = xcm::VersionedXcm::<InnerXcmRuntimeCall>::V3(xcm_message);
|
||||||
|
// this is the `BridgeMessage` from polkadot xcm builder, but it has no constructor
|
||||||
|
// or public fields, so just tuple
|
||||||
|
// (double encoding, because `.encode()` is called on original Xcm BLOB when it is pushed
|
||||||
|
// to the storage)
|
||||||
|
(location, xcm).encode().encode()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Helper that creates InitializationData mock data, that can be used to initialize bridge
|
||||||
|
/// GRANDPA pallet
|
||||||
|
pub fn initialization_data<
|
||||||
|
Runtime: pallet_bridge_grandpa::Config<GrandpaPalletInstance>,
|
||||||
|
GrandpaPalletInstance: 'static,
|
||||||
|
>(
|
||||||
|
block_number: u32,
|
||||||
|
) -> bp_header_chain::InitializationData<BridgedHeader<Runtime, GrandpaPalletInstance>> {
|
||||||
|
bp_header_chain::InitializationData {
|
||||||
|
header: Box::new(bp_test_utils::test_header(block_number.into())),
|
||||||
|
authority_list: authority_list(),
|
||||||
|
set_id: 1,
|
||||||
|
operating_mode: BasicOperatingMode::Normal,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Dummy xcm
|
||||||
|
pub(crate) fn dummy_xcm() -> Xcm<()> {
|
||||||
|
vec![Trap(42)].into()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn dispatch_message(
|
||||||
|
lane_id: LaneId,
|
||||||
|
nonce: MessageNonce,
|
||||||
|
payload: Vec<u8>,
|
||||||
|
) -> DispatchMessage<Vec<u8>> {
|
||||||
|
DispatchMessage {
|
||||||
|
key: MessageKey { lane_id, nonce },
|
||||||
|
data: DispatchMessageData { payload: Ok(payload) },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Macro used for simulate_export_message and capturing bytes
|
||||||
|
macro_rules! grab_haul_blob (
|
||||||
|
($name:ident, $grabbed_payload:ident) => {
|
||||||
|
std::thread_local! {
|
||||||
|
static $grabbed_payload: std::cell::RefCell<Option<Vec<u8>>> = std::cell::RefCell::new(None);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct $name;
|
||||||
|
impl HaulBlob for $name {
|
||||||
|
fn haul_blob(blob: Vec<u8>) -> Result<(), HaulBlobError>{
|
||||||
|
$grabbed_payload.with(|rm| *rm.borrow_mut() = Some(blob));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Simulates `HaulBlobExporter` and all its wrapping and captures generated plain bytes,
|
||||||
|
/// which are transferred over bridge.
|
||||||
|
pub(crate) fn simulate_message_exporter_on_bridged_chain<
|
||||||
|
SourceNetwork: Get<NetworkId>,
|
||||||
|
DestinationNetwork: Get<MultiLocation>,
|
||||||
|
DestinationVersion: GetVersion,
|
||||||
|
>(
|
||||||
|
(destination_network, destination_junctions): (NetworkId, Junctions),
|
||||||
|
) -> Vec<u8> {
|
||||||
|
grab_haul_blob!(GrabbingHaulBlob, GRABBED_HAUL_BLOB_PAYLOAD);
|
||||||
|
|
||||||
|
// lets pretend that some parachain on bridged chain exported the message
|
||||||
|
let universal_source_on_bridged_chain =
|
||||||
|
X2(GlobalConsensus(SourceNetwork::get()), Parachain(5678));
|
||||||
|
let channel = 1_u32;
|
||||||
|
|
||||||
|
// simulate XCM message export
|
||||||
|
let (ticket, fee) = validate_export::<
|
||||||
|
HaulBlobExporter<GrabbingHaulBlob, DestinationNetwork, DestinationVersion, ()>,
|
||||||
|
>(
|
||||||
|
destination_network,
|
||||||
|
channel,
|
||||||
|
universal_source_on_bridged_chain,
|
||||||
|
destination_junctions,
|
||||||
|
dummy_xcm(),
|
||||||
|
)
|
||||||
|
.expect("validate_export to pass");
|
||||||
|
log::info!(
|
||||||
|
target: "simulate_message_exporter_on_bridged_chain",
|
||||||
|
"HaulBlobExporter::validate fee: {:?}",
|
||||||
|
fee
|
||||||
|
);
|
||||||
|
let xcm_hash =
|
||||||
|
HaulBlobExporter::<GrabbingHaulBlob, DestinationNetwork, DestinationVersion, ()>::deliver(
|
||||||
|
ticket,
|
||||||
|
)
|
||||||
|
.expect("deliver to pass");
|
||||||
|
log::info!(
|
||||||
|
target: "simulate_message_exporter_on_bridged_chain",
|
||||||
|
"HaulBlobExporter::deliver xcm_hash: {:?}",
|
||||||
|
xcm_hash
|
||||||
|
);
|
||||||
|
|
||||||
|
GRABBED_HAUL_BLOB_PAYLOAD.with(|r| r.take().expect("Encoded message should be here"))
|
||||||
|
}
|
||||||
@@ -114,14 +114,34 @@ impl<Runtime: frame_system::Config + pallet_balances::Config + pallet_session::C
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Basic builder based on balances, collators and pallet_sessopm
|
/// A set of traits for a minimal parachain runtime, that may be used in conjunction with the
|
||||||
pub struct ExtBuilder<
|
/// `ExtBuilder` and the `RuntimeHelper`.
|
||||||
Runtime: frame_system::Config
|
pub trait BasicParachainRuntime:
|
||||||
|
frame_system::Config
|
||||||
|
+ pallet_balances::Config
|
||||||
|
+ pallet_session::Config
|
||||||
|
+ pallet_xcm::Config
|
||||||
|
+ parachain_info::Config
|
||||||
|
+ pallet_collator_selection::Config
|
||||||
|
+ cumulus_pallet_parachain_system::Config
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> BasicParachainRuntime for T
|
||||||
|
where
|
||||||
|
T: frame_system::Config
|
||||||
+ pallet_balances::Config
|
+ pallet_balances::Config
|
||||||
+ pallet_session::Config
|
+ pallet_session::Config
|
||||||
+ pallet_xcm::Config
|
+ pallet_xcm::Config
|
||||||
+ parachain_info::Config,
|
+ parachain_info::Config
|
||||||
> {
|
+ pallet_collator_selection::Config
|
||||||
|
+ cumulus_pallet_parachain_system::Config,
|
||||||
|
ValidatorIdOf<T>: From<AccountIdOf<T>>,
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Basic builder based on balances, collators and pallet_session.
|
||||||
|
pub struct ExtBuilder<Runtime: BasicParachainRuntime> {
|
||||||
// endowed accounts with balances
|
// endowed accounts with balances
|
||||||
balances: Vec<(AccountIdOf<Runtime>, BalanceOf<Runtime>)>,
|
balances: Vec<(AccountIdOf<Runtime>, BalanceOf<Runtime>)>,
|
||||||
// collators to test block prod
|
// collators to test block prod
|
||||||
@@ -135,14 +155,7 @@ pub struct ExtBuilder<
|
|||||||
_runtime: PhantomData<Runtime>,
|
_runtime: PhantomData<Runtime>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<
|
impl<Runtime: BasicParachainRuntime> Default for ExtBuilder<Runtime> {
|
||||||
Runtime: frame_system::Config
|
|
||||||
+ pallet_balances::Config
|
|
||||||
+ pallet_session::Config
|
|
||||||
+ pallet_xcm::Config
|
|
||||||
+ parachain_info::Config,
|
|
||||||
> Default for ExtBuilder<Runtime>
|
|
||||||
{
|
|
||||||
fn default() -> ExtBuilder<Runtime> {
|
fn default() -> ExtBuilder<Runtime> {
|
||||||
ExtBuilder {
|
ExtBuilder {
|
||||||
balances: vec![],
|
balances: vec![],
|
||||||
@@ -155,14 +168,7 @@ impl<
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<
|
impl<Runtime: BasicParachainRuntime> ExtBuilder<Runtime> {
|
||||||
Runtime: frame_system::Config
|
|
||||||
+ pallet_balances::Config
|
|
||||||
+ pallet_session::Config
|
|
||||||
+ pallet_xcm::Config
|
|
||||||
+ parachain_info::Config,
|
|
||||||
> ExtBuilder<Runtime>
|
|
||||||
{
|
|
||||||
pub fn with_balances(
|
pub fn with_balances(
|
||||||
mut self,
|
mut self,
|
||||||
balances: Vec<(AccountIdOf<Runtime>, BalanceOf<Runtime>)>,
|
balances: Vec<(AccountIdOf<Runtime>, BalanceOf<Runtime>)>,
|
||||||
@@ -198,12 +204,7 @@ impl<
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build(self) -> sp_io::TestExternalities
|
pub fn build(self) -> sp_io::TestExternalities {
|
||||||
where
|
|
||||||
Runtime:
|
|
||||||
pallet_collator_selection::Config + pallet_balances::Config + pallet_session::Config,
|
|
||||||
ValidatorIdOf<Runtime>: From<AccountIdOf<Runtime>>,
|
|
||||||
{
|
|
||||||
let mut t = frame_system::GenesisConfig::<Runtime>::default().build_storage().unwrap();
|
let mut t = frame_system::GenesisConfig::<Runtime>::default().build_storage().unwrap();
|
||||||
|
|
||||||
pallet_xcm::GenesisConfig::<Runtime> {
|
pallet_xcm::GenesisConfig::<Runtime> {
|
||||||
|
|||||||
Reference in New Issue
Block a user