use crate::{
test_cases::{bridges_prelude::*, helpers, run_test},
test_data,
};
use alloc::{boxed::Box, vec};
use bp_header_chain::ChainWithGrandpa;
use bp_messages::UnrewardedRelayersState;
use bp_relayers::{RewardsAccountOwner, RewardsAccountParams};
use bp_xcm_bridge_hub::XcmAsPlainPayload;
use frame_support::traits::{OnFinalize, OnInitialize};
use frame_system::pallet_prelude::BlockNumberFor;
use pallet_bridge_messages::{BridgedChainOf, LaneIdOf, ThisChainOf};
use parachains_runtimes_test_utils::{
AccountIdOf, BasicParachainRuntime, CollatorSessionKeys, RuntimeCallOf, SlotDurations,
};
use sp_core::Get;
use sp_keyring::Sr25519Keyring::*;
use sp_runtime::{traits::Header as HeaderT, AccountId32};
use xcm::latest::prelude::*;
pub trait WithRemoteGrandpaChainHelper {
type Runtime: BasicParachainRuntime
+ cumulus_pallet_xcmp_queue::Config
+ BridgeGrandpaConfig<Self::GPI, BridgedChain = BridgedChainOf<Self::Runtime, Self::MPI>>
+ BridgeMessagesConfig<
Self::MPI,
InboundPayload = XcmAsPlainPayload,
OutboundPayload = XcmAsPlainPayload,
> + pallet_bridge_relayers::Config<Self::RPI, LaneId = LaneIdOf<Self::Runtime, Self::MPI>>;
type AllPalletsWithoutSystem: OnInitialize<BlockNumberFor<Self::Runtime>>
+ OnFinalize<BlockNumberFor<Self::Runtime>>;
type GPI: 'static;
type MPI: 'static;
type RPI: 'static;
}
pub struct WithRemoteGrandpaChainHelperAdapter<Runtime, AllPalletsWithoutSystem, GPI, MPI, RPI>(
core::marker::PhantomData<(Runtime, AllPalletsWithoutSystem, GPI, MPI, RPI)>,
);
impl<Runtime, AllPalletsWithoutSystem, GPI, MPI, RPI> WithRemoteGrandpaChainHelper
for WithRemoteGrandpaChainHelperAdapter<Runtime, AllPalletsWithoutSystem, GPI, MPI, RPI>
where
Runtime: BasicParachainRuntime
+ cumulus_pallet_xcmp_queue::Config
+ BridgeGrandpaConfig<GPI, BridgedChain = BridgedChainOf<Runtime, MPI>>
+ BridgeMessagesConfig<
MPI,
InboundPayload = XcmAsPlainPayload,
OutboundPayload = XcmAsPlainPayload,
> + pallet_bridge_relayers::Config<RPI, LaneId = LaneIdOf<Runtime, MPI>>,
AllPalletsWithoutSystem:
OnInitialize<BlockNumberFor<Runtime>> + OnFinalize<BlockNumberFor<Runtime>>,
GPI: 'static,
MPI: 'static,
RPI: 'static,
{
type Runtime = Runtime;
type AllPalletsWithoutSystem = AllPalletsWithoutSystem;
type GPI = GPI;
type MPI = MPI;
type RPI = RPI;
}
pub fn relayed_incoming_message_works<RuntimeHelper>(
collator_session_key: CollatorSessionKeys<RuntimeHelper::Runtime>,
slot_durations: SlotDurations,
runtime_para_id: u32,
sibling_parachain_id: u32,
local_relay_chain_id: NetworkId,
prepare_configuration: impl Fn() -> LaneIdOf<RuntimeHelper::Runtime, RuntimeHelper::MPI>,
construct_and_apply_extrinsic: fn(
sp_keyring::Sr25519Keyring,
RuntimeCallOf<RuntimeHelper::Runtime>,
) -> sp_runtime::DispatchOutcome,
expect_rewards: bool,
) where
RuntimeHelper: WithRemoteGrandpaChainHelper,
AccountIdOf<RuntimeHelper::Runtime>: From<AccountId32>,
RuntimeCallOf<RuntimeHelper::Runtime>: From<BridgeGrandpaCall<RuntimeHelper::Runtime, RuntimeHelper::GPI>>
+ From<BridgeMessagesCall<RuntimeHelper::Runtime, RuntimeHelper::MPI>>,
BridgedChainOf<RuntimeHelper::Runtime, RuntimeHelper::MPI>: ChainWithGrandpa,
{
helpers::relayed_incoming_message_works::<
RuntimeHelper::Runtime,
RuntimeHelper::AllPalletsWithoutSystem,
RuntimeHelper::MPI,
>(
collator_session_key,
slot_durations,
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,
bridged_chain_id| {
let relay_header_number = 5u32.into();
let lane_id = prepare_configuration();
helpers::initialize_bridge_grandpa_pallet::<RuntimeHelper::Runtime, RuntimeHelper::GPI>(
test_data::initialization_data::<RuntimeHelper::Runtime, RuntimeHelper::GPI>(0),
);
let (relay_chain_header, grandpa_justification, message_proof) =
test_data::from_grandpa_chain::make_complex_relayer_delivery_proofs::<
BridgedChainOf<RuntimeHelper::Runtime, RuntimeHelper::MPI>,
ThisChainOf<RuntimeHelper::Runtime, RuntimeHelper::MPI>,
LaneIdOf<RuntimeHelper::Runtime, RuntimeHelper::MPI>,
>(
lane_id,
xcm.into(),
message_nonce,
message_destination,
relay_header_number,
false,
);
let relay_chain_header_hash = relay_chain_header.hash();
vec![
(
BridgeGrandpaCall::<RuntimeHelper::Runtime, RuntimeHelper::GPI>::submit_finality_proof {
finality_target: Box::new(relay_chain_header),
justification: grandpa_justification,
}.into(),
helpers::VerifySubmitGrandpaFinalityProofOutcome::<RuntimeHelper::Runtime, RuntimeHelper::GPI>::expect_best_header_hash(
relay_chain_header_hash,
),
),
(
BridgeMessagesCall::<RuntimeHelper::Runtime, RuntimeHelper::MPI>::receive_messages_proof {
relayer_id_at_bridged_chain,
proof: Box::new(message_proof),
messages_count: 1,
dispatch_weight: Weight::from_parts(1000000000, 0),
}.into(),
Box::new((
helpers::VerifySubmitMessagesProofOutcome::<RuntimeHelper::Runtime, RuntimeHelper::MPI>::expect_last_delivered_nonce(
lane_id,
1,
),
if expect_rewards {
helpers::VerifyRelayerRewarded::<RuntimeHelper::Runtime, RuntimeHelper::RPI>::expect_relayer_reward(
relayer_id_at_this_chain,
RewardsAccountParams::new(
lane_id,
bridged_chain_id,
RewardsAccountOwner::ThisChain,
),
)
} else {
Box::new(())
}
)),
),
]
},
);
}
pub fn free_relay_extrinsic_works<RuntimeHelper>(
collator_session_key: CollatorSessionKeys<RuntimeHelper::Runtime>,
slot_durations: SlotDurations,
runtime_para_id: u32,
sibling_parachain_id: u32,
local_relay_chain_id: NetworkId,
prepare_configuration: impl Fn() -> LaneIdOf<RuntimeHelper::Runtime, RuntimeHelper::MPI>,
construct_and_apply_extrinsic: fn(
sp_keyring::Sr25519Keyring,
RuntimeCallOf<RuntimeHelper::Runtime>,
) -> sp_runtime::DispatchOutcome,
expect_rewards: bool,
) where
RuntimeHelper: WithRemoteGrandpaChainHelper,
RuntimeHelper::Runtime: pallet_balances::Config,
AccountIdOf<RuntimeHelper::Runtime>: From<AccountId32>,
RuntimeCallOf<RuntimeHelper::Runtime>: From<BridgeGrandpaCall<RuntimeHelper::Runtime, RuntimeHelper::GPI>>
+ From<BridgeMessagesCall<RuntimeHelper::Runtime, RuntimeHelper::MPI>>,
BridgedChainOf<RuntimeHelper::Runtime, RuntimeHelper::MPI>: ChainWithGrandpa,
{
let free_headers_interval = <RuntimeHelper::Runtime as BridgeGrandpaConfig<
RuntimeHelper::GPI,
>>::FreeHeadersInterval::get()
.expect("this test requires runtime, configured to accept headers for free; qed");
helpers::relayed_incoming_message_works::<
RuntimeHelper::Runtime,
RuntimeHelper::AllPalletsWithoutSystem,
RuntimeHelper::MPI,
>(
collator_session_key,
slot_durations,
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,
bridged_chain_id| {
let lane_id = prepare_configuration();
let initial_block_number = 0;
helpers::initialize_bridge_grandpa_pallet::<RuntimeHelper::Runtime, RuntimeHelper::GPI>(
test_data::initialization_data::<RuntimeHelper::Runtime, RuntimeHelper::GPI>(
initial_block_number,
),
);
let relay_header_number = initial_block_number + free_headers_interval;
let initial_relayer_balance =
pallet_balances::Pallet::<RuntimeHelper::Runtime>::free_balance(
relayer_id_at_this_chain.clone(),
);
pallet_bridge_grandpa::Pallet::<RuntimeHelper::Runtime, RuntimeHelper::GPI>::on_initialize(
0u32.into(),
);
let (relay_chain_header, grandpa_justification, message_proof) =
test_data::from_grandpa_chain::make_complex_relayer_delivery_proofs::<
BridgedChainOf<RuntimeHelper::Runtime, RuntimeHelper::MPI>,
ThisChainOf<RuntimeHelper::Runtime, RuntimeHelper::MPI>,
LaneIdOf<RuntimeHelper::Runtime, RuntimeHelper::MPI>,
>(
lane_id,
xcm.into(),
message_nonce,
message_destination,
relay_header_number.into(),
true,
);
let relay_chain_header_hash = relay_chain_header.hash();
vec![
(
BridgeGrandpaCall::<RuntimeHelper::Runtime, RuntimeHelper::GPI>::submit_finality_proof {
finality_target: Box::new(relay_chain_header),
justification: grandpa_justification,
}.into(),
Box::new((
helpers::VerifySubmitGrandpaFinalityProofOutcome::<RuntimeHelper::Runtime, RuntimeHelper::GPI>::expect_best_header_hash(
relay_chain_header_hash,
),
helpers::VerifyRelayerBalance::<RuntimeHelper::Runtime>::expect_relayer_balance(
relayer_id_at_this_chain.clone(),
initial_relayer_balance,
),
))
),
(
BridgeMessagesCall::<RuntimeHelper::Runtime, RuntimeHelper::MPI>::receive_messages_proof {
relayer_id_at_bridged_chain,
proof: Box::new(message_proof),
messages_count: 1,
dispatch_weight: Weight::from_parts(1000000000, 0),
}.into(),
Box::new((
helpers::VerifySubmitMessagesProofOutcome::<RuntimeHelper::Runtime, RuntimeHelper::MPI>::expect_last_delivered_nonce(
lane_id,
1,
),
if expect_rewards {
helpers::VerifyRelayerRewarded::<RuntimeHelper::Runtime, RuntimeHelper::RPI>::expect_relayer_reward(
relayer_id_at_this_chain,
RewardsAccountParams::new(
lane_id,
bridged_chain_id,
RewardsAccountOwner::ThisChain,
),
)
} else {
Box::new(())
}
)),
),
]
},
);
}
pub fn complex_relay_extrinsic_works<RuntimeHelper>(
collator_session_key: CollatorSessionKeys<RuntimeHelper::Runtime>,
slot_durations: SlotDurations,
runtime_para_id: u32,
sibling_parachain_id: u32,
local_relay_chain_id: NetworkId,
prepare_configuration: impl Fn() -> LaneIdOf<RuntimeHelper::Runtime, RuntimeHelper::MPI>,
construct_and_apply_extrinsic: fn(
sp_keyring::Sr25519Keyring,
RuntimeCallOf<RuntimeHelper::Runtime>,
) -> sp_runtime::DispatchOutcome,
) where
RuntimeHelper: WithRemoteGrandpaChainHelper,
RuntimeHelper::Runtime:
pallet_utility::Config<RuntimeCall = RuntimeCallOf<RuntimeHelper::Runtime>>,
AccountIdOf<RuntimeHelper::Runtime>: From<AccountId32>,
RuntimeCallOf<RuntimeHelper::Runtime>: From<BridgeGrandpaCall<RuntimeHelper::Runtime, RuntimeHelper::GPI>>
+ From<BridgeMessagesCall<RuntimeHelper::Runtime, RuntimeHelper::MPI>>
+ From<pallet_utility::Call<RuntimeHelper::Runtime>>,
BridgedChainOf<RuntimeHelper::Runtime, RuntimeHelper::MPI>: ChainWithGrandpa,
{
helpers::relayed_incoming_message_works::<
RuntimeHelper::Runtime,
RuntimeHelper::AllPalletsWithoutSystem,
RuntimeHelper::MPI,
>(
collator_session_key,
slot_durations,
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,
bridged_chain_id| {
let relay_header_number = 1u32.into();
let lane_id = prepare_configuration();
helpers::initialize_bridge_grandpa_pallet::<RuntimeHelper::Runtime, RuntimeHelper::GPI>(
test_data::initialization_data::<RuntimeHelper::Runtime, RuntimeHelper::GPI>(0),
);
let (relay_chain_header, grandpa_justification, message_proof) =
test_data::from_grandpa_chain::make_complex_relayer_delivery_proofs::<
BridgedChainOf<RuntimeHelper::Runtime, RuntimeHelper::MPI>,
ThisChainOf<RuntimeHelper::Runtime, RuntimeHelper::MPI>,
LaneIdOf<RuntimeHelper::Runtime, RuntimeHelper::MPI>,
>(
lane_id,
xcm.into(),
message_nonce,
message_destination,
relay_header_number,
false,
);
let relay_chain_header_hash = relay_chain_header.hash();
vec![
(
pallet_utility::Call::<RuntimeHelper::Runtime>::batch_all {
calls: vec![
BridgeGrandpaCall::<RuntimeHelper::Runtime, RuntimeHelper::GPI>::submit_finality_proof {
finality_target: Box::new(relay_chain_header),
justification: grandpa_justification,
}.into(),
BridgeMessagesCall::<RuntimeHelper::Runtime, RuntimeHelper::MPI>::receive_messages_proof {
relayer_id_at_bridged_chain,
proof: Box::new(message_proof),
messages_count: 1,
dispatch_weight: Weight::from_parts(1000000000, 0),
}.into(),
],
}
.into(),
Box::new(
(
helpers::VerifySubmitGrandpaFinalityProofOutcome::<
RuntimeHelper::Runtime,
RuntimeHelper::GPI,
>::expect_best_header_hash(relay_chain_header_hash),
helpers::VerifySubmitMessagesProofOutcome::<
RuntimeHelper::Runtime,
RuntimeHelper::MPI,
>::expect_last_delivered_nonce(lane_id, 1),
helpers::VerifyRelayerRewarded::<
RuntimeHelper::Runtime,
RuntimeHelper::RPI,
>::expect_relayer_reward(
relayer_id_at_this_chain,
RewardsAccountParams::new(
lane_id,
bridged_chain_id,
RewardsAccountOwner::ThisChain,
),
),
),
),
),
]
},
);
}
pub fn can_calculate_fee_for_complex_message_delivery_transaction<RuntimeHelper>(
collator_session_key: CollatorSessionKeys<RuntimeHelper::Runtime>,
compute_extrinsic_fee: fn(pallet_utility::Call<RuntimeHelper::Runtime>) -> u128,
) -> u128
where
RuntimeHelper: WithRemoteGrandpaChainHelper,
RuntimeHelper::Runtime:
pallet_utility::Config<RuntimeCall = RuntimeCallOf<RuntimeHelper::Runtime>>,
RuntimeCallOf<RuntimeHelper::Runtime>: From<BridgeGrandpaCall<RuntimeHelper::Runtime, RuntimeHelper::GPI>>
+ From<BridgeMessagesCall<RuntimeHelper::Runtime, RuntimeHelper::MPI>>,
BridgedChainOf<RuntimeHelper::Runtime, RuntimeHelper::MPI>: ChainWithGrandpa,
{
run_test::<RuntimeHelper::Runtime, _>(collator_session_key, 1000, vec![], || {
let (relay_chain_header, grandpa_justification, message_proof) =
test_data::from_grandpa_chain::make_complex_relayer_delivery_proofs::<
BridgedChainOf<RuntimeHelper::Runtime, RuntimeHelper::MPI>,
ThisChainOf<RuntimeHelper::Runtime, RuntimeHelper::MPI>,
LaneIdOf<RuntimeHelper::Runtime, RuntimeHelper::MPI>,
>(
LaneIdOf::<RuntimeHelper::Runtime, RuntimeHelper::MPI>::default(),
vec![Instruction::<()>::ClearOrigin; 1_024].into(),
1,
[GlobalConsensus(Polkadot), Parachain(1_000)].into(),
1u32.into(),
false,
);
let batch = test_data::from_grandpa_chain::make_complex_relayer_delivery_batch::<
RuntimeHelper::Runtime,
RuntimeHelper::GPI,
RuntimeHelper::MPI,
>(
relay_chain_header,
grandpa_justification,
message_proof,
helpers::relayer_id_at_bridged_chain::<RuntimeHelper::Runtime, RuntimeHelper::MPI>(),
);
compute_extrinsic_fee(batch)
})
}
pub fn can_calculate_fee_for_complex_message_confirmation_transaction<RuntimeHelper>(
collator_session_key: CollatorSessionKeys<RuntimeHelper::Runtime>,
compute_extrinsic_fee: fn(pallet_utility::Call<RuntimeHelper::Runtime>) -> u128,
) -> u128
where
RuntimeHelper: WithRemoteGrandpaChainHelper,
AccountIdOf<RuntimeHelper::Runtime>: From<AccountId32>,
RuntimeHelper::Runtime:
pallet_utility::Config<RuntimeCall = RuntimeCallOf<RuntimeHelper::Runtime>>,
ThisChainOf<RuntimeHelper::Runtime, RuntimeHelper::MPI>:
bp_runtime::Chain<AccountId = AccountIdOf<RuntimeHelper::Runtime>>,
RuntimeCallOf<RuntimeHelper::Runtime>: From<BridgeGrandpaCall<RuntimeHelper::Runtime, RuntimeHelper::GPI>>
+ From<BridgeMessagesCall<RuntimeHelper::Runtime, RuntimeHelper::MPI>>,
BridgedChainOf<RuntimeHelper::Runtime, RuntimeHelper::MPI>: ChainWithGrandpa,
{
run_test::<RuntimeHelper::Runtime, _>(collator_session_key, 1000, vec![], || {
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::<
BridgedChainOf<RuntimeHelper::Runtime, RuntimeHelper::MPI>,
ThisChainOf<RuntimeHelper::Runtime, RuntimeHelper::MPI>,
(),
LaneIdOf<RuntimeHelper::Runtime, RuntimeHelper::MPI>,
>(
LaneIdOf::<RuntimeHelper::Runtime, RuntimeHelper::MPI>::default(),
1u32.into(),
AccountId32::from(Alice.public()).into(),
unrewarded_relayers.clone(),
);
let batch = test_data::from_grandpa_chain::make_complex_relayer_confirmation_batch::<
RuntimeHelper::Runtime,
RuntimeHelper::GPI,
RuntimeHelper::MPI,
>(
relay_chain_header,
grandpa_justification,
message_delivery_proof,
unrewarded_relayers,
);
compute_extrinsic_fee(batch)
})
}
pub fn can_calculate_fee_for_standalone_message_delivery_transaction<RuntimeHelper>(
collator_session_key: CollatorSessionKeys<RuntimeHelper::Runtime>,
compute_extrinsic_fee: fn(
<RuntimeHelper::Runtime as frame_system::Config>::RuntimeCall,
) -> u128,
) -> u128
where
RuntimeHelper: WithRemoteGrandpaChainHelper,
RuntimeCallOf<RuntimeHelper::Runtime>:
From<BridgeMessagesCall<RuntimeHelper::Runtime, RuntimeHelper::MPI>>,
BridgedChainOf<RuntimeHelper::Runtime, RuntimeHelper::MPI>: ChainWithGrandpa,
{
run_test::<RuntimeHelper::Runtime, _>(collator_session_key, 1000, vec![], || {
let (_, _, message_proof) =
test_data::from_grandpa_chain::make_complex_relayer_delivery_proofs::<
BridgedChainOf<RuntimeHelper::Runtime, RuntimeHelper::MPI>,
ThisChainOf<RuntimeHelper::Runtime, RuntimeHelper::MPI>,
LaneIdOf<RuntimeHelper::Runtime, RuntimeHelper::MPI>,
>(
LaneIdOf::<RuntimeHelper::Runtime, RuntimeHelper::MPI>::default(),
vec![Instruction::<()>::ClearOrigin; 1_024].into(),
1,
[GlobalConsensus(Polkadot), Parachain(1_000)].into(),
1u32.into(),
false,
);
let call = test_data::from_grandpa_chain::make_standalone_relayer_delivery_call::<
RuntimeHelper::Runtime,
RuntimeHelper::GPI,
RuntimeHelper::MPI,
>(
message_proof,
helpers::relayer_id_at_bridged_chain::<RuntimeHelper::Runtime, RuntimeHelper::MPI>(),
);
compute_extrinsic_fee(call)
})
}
pub fn can_calculate_fee_for_standalone_message_confirmation_transaction<RuntimeHelper>(
collator_session_key: CollatorSessionKeys<RuntimeHelper::Runtime>,
compute_extrinsic_fee: fn(
<RuntimeHelper::Runtime as frame_system::Config>::RuntimeCall,
) -> u128,
) -> u128
where
RuntimeHelper: WithRemoteGrandpaChainHelper,
AccountIdOf<RuntimeHelper::Runtime>: From<AccountId32>,
ThisChainOf<RuntimeHelper::Runtime, RuntimeHelper::MPI>:
bp_runtime::Chain<AccountId = AccountIdOf<RuntimeHelper::Runtime>>,
RuntimeCallOf<RuntimeHelper::Runtime>:
From<BridgeMessagesCall<RuntimeHelper::Runtime, RuntimeHelper::MPI>>,
BridgedChainOf<RuntimeHelper::Runtime, RuntimeHelper::MPI>: ChainWithGrandpa,
{
run_test::<RuntimeHelper::Runtime, _>(collator_session_key, 1000, vec![], || {
let unrewarded_relayers = UnrewardedRelayersState {
unrewarded_relayer_entries: 1,
total_messages: 1,
..Default::default()
};
let (_, _, message_delivery_proof) =
test_data::from_grandpa_chain::make_complex_relayer_confirmation_proofs::<
BridgedChainOf<RuntimeHelper::Runtime, RuntimeHelper::MPI>,
ThisChainOf<RuntimeHelper::Runtime, RuntimeHelper::MPI>,
(),
LaneIdOf<RuntimeHelper::Runtime, RuntimeHelper::MPI>,
>(
LaneIdOf::<RuntimeHelper::Runtime, RuntimeHelper::MPI>::default(),
1u32.into(),
AccountId32::from(Alice.public()).into(),
unrewarded_relayers.clone(),
);
let call = test_data::from_grandpa_chain::make_standalone_relayer_confirmation_call::<
RuntimeHelper::Runtime,
RuntimeHelper::GPI,
RuntimeHelper::MPI,
>(message_delivery_proof, unrewarded_relayers);
compute_extrinsic_fee(call)
})
}