fix: Complete snowbridge pezpallet rebrand and critical bug fixes
- snowbridge-pezpallet-* → pezsnowbridge-pezpallet-* (201 refs) - pallet/ directories → pezpallet/ (4 locations) - Fixed pezpallet.rs self-include recursion bug - Fixed sc-chain-spec hardcoded crate name in derive macro - Reverted .pezpallet_by_name() to .pallet_by_name() (subxt API) - Added BizinikiwiConfig type alias for zombienet tests - Deleted obsolete session state files Verified: pezsnowbridge-pezpallet-*, pezpallet-staking, pezpallet-staking-async, pezframe-benchmarking-cli all pass cargo check
This commit is contained in:
@@ -0,0 +1,849 @@
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity Bridges Common.
|
||||
|
||||
// Parity Bridges Common 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.
|
||||
|
||||
// Parity Bridges Common 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 Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Transaction extension that rejects bridge-related transactions, that include
|
||||
//! obsolete (duplicated) data or do not pass some additional pezpallet-specific
|
||||
//! checks.
|
||||
|
||||
use bp_relayers::ExplicitOrAccountParams;
|
||||
use pezbp_runtime::Teyrchain;
|
||||
use bp_teyrchains::SubmitTeyrchainHeadsInfo;
|
||||
use pezpallet_bridge_grandpa::{
|
||||
BridgedBlockNumber, CallSubType as GrandpaCallSubType, SubmitFinalityProofHelper,
|
||||
};
|
||||
use pezpallet_bridge_messages::CallSubType as MessagesCallSubType;
|
||||
use pezpallet_bridge_relayers::Pezpallet as RelayersPallet;
|
||||
use pezpallet_bridge_teyrchains::{CallSubType as TeyrchainsCallSubtype, SubmitTeyrchainHeadsHelper};
|
||||
use pezsp_runtime::{
|
||||
traits::{Get, UniqueSaturatedInto},
|
||||
transaction_validity::{TransactionPriority, TransactionValidity, ValidTransactionBuilder},
|
||||
};
|
||||
use pezsp_std::marker::PhantomData;
|
||||
|
||||
// Re-export to avoid include tuplex dependency everywhere.
|
||||
#[doc(hidden)]
|
||||
pub mod __private {
|
||||
pub use tuplex;
|
||||
}
|
||||
|
||||
/// A duplication of the `FilterCall` trait.
|
||||
///
|
||||
/// We need this trait in order to be able to implement it for the messages pezpallet,
|
||||
/// since the implementation is done outside of the pezpallet crate.
|
||||
pub trait BridgeRuntimeFilterCall<AccountId, Call> {
|
||||
/// Data that may be passed from the validate to `post_dispatch`.
|
||||
type ToPostDispatch;
|
||||
/// Called during validation. Needs to checks whether a runtime call, submitted
|
||||
/// by the `who` is valid. Transactions not signed are not validated.
|
||||
fn validate(who: &AccountId, call: &Call) -> (Self::ToPostDispatch, TransactionValidity);
|
||||
/// Called after transaction is dispatched.
|
||||
fn post_dispatch(_who: &AccountId, _has_failed: bool, _to_post_dispatch: Self::ToPostDispatch) {
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrapper for the bridge GRANDPA pezpallet that checks calls for obsolete submissions
|
||||
/// and also boosts transaction priority if it has submitted by registered relayer.
|
||||
/// The boost is computed as
|
||||
/// `(BundledHeaderNumber - 1 - BestFinalizedHeaderNumber) * Priority::get()`.
|
||||
/// The boost is only applied if submitter has active registration in the relayers
|
||||
/// pezpallet.
|
||||
pub struct CheckAndBoostBridgeGrandpaTransactions<T, I, Priority, SlashAccount>(
|
||||
PhantomData<(T, I, Priority, SlashAccount)>,
|
||||
);
|
||||
|
||||
impl<T, I: 'static, Priority: Get<TransactionPriority>, SlashAccount: Get<T::AccountId>>
|
||||
BridgeRuntimeFilterCall<T::AccountId, T::RuntimeCall>
|
||||
for CheckAndBoostBridgeGrandpaTransactions<T, I, Priority, SlashAccount>
|
||||
where
|
||||
T: pezpallet_bridge_relayers::Config + pezpallet_bridge_grandpa::Config<I>,
|
||||
T::RuntimeCall: GrandpaCallSubType<T, I>,
|
||||
{
|
||||
// bridged header number, bundled in transaction
|
||||
type ToPostDispatch = Option<BridgedBlockNumber<T, I>>;
|
||||
|
||||
fn validate(
|
||||
who: &T::AccountId,
|
||||
call: &T::RuntimeCall,
|
||||
) -> (Self::ToPostDispatch, TransactionValidity) {
|
||||
match GrandpaCallSubType::<T, I>::check_obsolete_submit_finality_proof(call) {
|
||||
Ok(Some(our_tx)) => {
|
||||
let to_post_dispatch = Some(our_tx.base.block_number);
|
||||
let total_priority_boost =
|
||||
compute_priority_boost::<T, _, Priority>(who, our_tx.improved_by);
|
||||
(
|
||||
to_post_dispatch,
|
||||
ValidTransactionBuilder::default().priority(total_priority_boost).build(),
|
||||
)
|
||||
},
|
||||
Ok(None) => (None, ValidTransactionBuilder::default().build()),
|
||||
Err(e) => (None, Err(e)),
|
||||
}
|
||||
}
|
||||
|
||||
fn post_dispatch(
|
||||
relayer: &T::AccountId,
|
||||
has_failed: bool,
|
||||
bundled_block_number: Self::ToPostDispatch,
|
||||
) {
|
||||
// we are only interested in associated pezpallet submissions
|
||||
let Some(bundled_block_number) = bundled_block_number else { return };
|
||||
// we are only interested in failed or unneeded transactions
|
||||
let has_failed =
|
||||
has_failed || !SubmitFinalityProofHelper::<T, I>::was_successful(bundled_block_number);
|
||||
|
||||
if !has_failed {
|
||||
return;
|
||||
}
|
||||
|
||||
// let's slash registered relayer
|
||||
RelayersPallet::<T>::slash_and_deregister(
|
||||
relayer,
|
||||
ExplicitOrAccountParams::Explicit::<_, ()>(SlashAccount::get()),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrapper for the bridge teyrchains pezpallet that checks calls for obsolete submissions
|
||||
/// and also boosts transaction priority if it has submitted by registered relayer.
|
||||
/// The boost is computed as
|
||||
/// `(BundledHeaderNumber - 1 - BestKnownHeaderNumber) * Priority::get()`.
|
||||
/// The boost is only applied if submitter has active registration in the relayers
|
||||
/// pezpallet.
|
||||
pub struct CheckAndBoostBridgeTeyrchainsTransactions<
|
||||
T,
|
||||
TeyrchainsInstance,
|
||||
Para,
|
||||
Priority,
|
||||
SlashAccount,
|
||||
>(PhantomData<(T, TeyrchainsInstance, Para, Priority, SlashAccount)>);
|
||||
|
||||
impl<
|
||||
T,
|
||||
TeyrchainsInstance,
|
||||
Para,
|
||||
Priority: Get<TransactionPriority>,
|
||||
SlashAccount: Get<T::AccountId>,
|
||||
> BridgeRuntimeFilterCall<T::AccountId, T::RuntimeCall>
|
||||
for CheckAndBoostBridgeTeyrchainsTransactions<T, TeyrchainsInstance, Para, Priority, SlashAccount>
|
||||
where
|
||||
T: pezpallet_bridge_relayers::Config + pezpallet_bridge_teyrchains::Config<TeyrchainsInstance>,
|
||||
TeyrchainsInstance: 'static,
|
||||
Para: Teyrchain,
|
||||
T::RuntimeCall: TeyrchainsCallSubtype<T, TeyrchainsInstance>,
|
||||
{
|
||||
// bridged header number, bundled in transaction
|
||||
type ToPostDispatch = Option<SubmitTeyrchainHeadsInfo>;
|
||||
|
||||
fn validate(
|
||||
who: &T::AccountId,
|
||||
call: &T::RuntimeCall,
|
||||
) -> (Self::ToPostDispatch, TransactionValidity) {
|
||||
match TeyrchainsCallSubtype::<T, TeyrchainsInstance>::check_obsolete_submit_teyrchain_heads(
|
||||
call,
|
||||
) {
|
||||
Ok(Some(our_tx)) if our_tx.base.para_id.0 == Para::TEYRCHAIN_ID => {
|
||||
let to_post_dispatch = Some(our_tx.base);
|
||||
let total_priority_boost =
|
||||
compute_priority_boost::<T, _, Priority>(&who, our_tx.improved_by);
|
||||
(
|
||||
to_post_dispatch,
|
||||
ValidTransactionBuilder::default().priority(total_priority_boost).build(),
|
||||
)
|
||||
},
|
||||
Ok(_) => (None, ValidTransactionBuilder::default().build()),
|
||||
Err(e) => (None, Err(e)),
|
||||
}
|
||||
}
|
||||
|
||||
fn post_dispatch(relayer: &T::AccountId, has_failed: bool, maybe_update: Self::ToPostDispatch) {
|
||||
// we are only interested in associated pezpallet submissions
|
||||
let Some(update) = maybe_update else { return };
|
||||
// we are only interested in failed or unneeded transactions
|
||||
let has_failed = has_failed ||
|
||||
!SubmitTeyrchainHeadsHelper::<T, TeyrchainsInstance>::was_successful(&update);
|
||||
|
||||
if !has_failed {
|
||||
return;
|
||||
}
|
||||
|
||||
// let's slash registered relayer
|
||||
RelayersPallet::<T>::slash_and_deregister(
|
||||
relayer,
|
||||
ExplicitOrAccountParams::Explicit::<_, ()>(SlashAccount::get()),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, I: 'static> BridgeRuntimeFilterCall<T::AccountId, T::RuntimeCall>
|
||||
for pezpallet_bridge_grandpa::Pezpallet<T, I>
|
||||
where
|
||||
T: pezpallet_bridge_grandpa::Config<I>,
|
||||
T::RuntimeCall: GrandpaCallSubType<T, I>,
|
||||
{
|
||||
type ToPostDispatch = ();
|
||||
fn validate(_who: &T::AccountId, call: &T::RuntimeCall) -> ((), TransactionValidity) {
|
||||
(
|
||||
(),
|
||||
GrandpaCallSubType::<T, I>::check_obsolete_submit_finality_proof(call)
|
||||
.and_then(|_| ValidTransactionBuilder::default().build()),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, I: 'static> BridgeRuntimeFilterCall<T::AccountId, T::RuntimeCall>
|
||||
for pezpallet_bridge_teyrchains::Pezpallet<T, I>
|
||||
where
|
||||
T: pezpallet_bridge_teyrchains::Config<I>,
|
||||
T::RuntimeCall: TeyrchainsCallSubtype<T, I>,
|
||||
{
|
||||
type ToPostDispatch = ();
|
||||
fn validate(_who: &T::AccountId, call: &T::RuntimeCall) -> ((), TransactionValidity) {
|
||||
(
|
||||
(),
|
||||
TeyrchainsCallSubtype::<T, I>::check_obsolete_submit_teyrchain_heads(call)
|
||||
.and_then(|_| ValidTransactionBuilder::default().build()),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: pezpallet_bridge_messages::Config<I>, I: 'static>
|
||||
BridgeRuntimeFilterCall<T::AccountId, T::RuntimeCall> for pezpallet_bridge_messages::Pezpallet<T, I>
|
||||
where
|
||||
T::RuntimeCall: MessagesCallSubType<T, I>,
|
||||
{
|
||||
type ToPostDispatch = ();
|
||||
/// Validate messages in order to avoid "mining" messages delivery and delivery confirmation
|
||||
/// transactions, that are delivering outdated messages/confirmations. Without this validation,
|
||||
/// even honest relayers may lose their funds if there are multiple relays running and
|
||||
/// submitting the same messages/confirmations.
|
||||
fn validate(_who: &T::AccountId, call: &T::RuntimeCall) -> ((), TransactionValidity) {
|
||||
((), call.check_obsolete_call())
|
||||
}
|
||||
}
|
||||
|
||||
/// Computes priority boost that improved known header by `improved_by`
|
||||
fn compute_priority_boost<T, N, Priority>(
|
||||
relayer: &T::AccountId,
|
||||
improved_by: N,
|
||||
) -> TransactionPriority
|
||||
where
|
||||
T: pezpallet_bridge_relayers::Config,
|
||||
N: UniqueSaturatedInto<TransactionPriority>,
|
||||
Priority: Get<TransactionPriority>,
|
||||
{
|
||||
// we only boost priority if relayer has staked required balance
|
||||
let is_relayer_registration_active = RelayersPallet::<T>::is_registration_active(relayer);
|
||||
// if tx improves by just one, there's no need to bump its priority
|
||||
let improved_by: TransactionPriority = improved_by.unique_saturated_into().saturating_sub(1);
|
||||
// if relayer is registered, for every skipped header we improve by `Priority`
|
||||
let boost_per_header = if is_relayer_registration_active { Priority::get() } else { 0 };
|
||||
improved_by.saturating_mul(boost_per_header)
|
||||
}
|
||||
|
||||
/// Declares a runtime-specific `BridgeRejectObsoleteHeadersAndMessages` signed extension.
|
||||
///
|
||||
/// ## Example
|
||||
///
|
||||
/// ```nocompile
|
||||
/// generate_bridge_reject_obsolete_headers_and_messages!{
|
||||
/// Call, AccountId
|
||||
/// BridgePezkuwichainGrandpa, BridgePezkuwichainMessages,
|
||||
/// BridgePezkuwichainTeyrchains
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// The goal of this extension is to avoid "mining" transactions that provide outdated bridged
|
||||
/// headers and messages. Without that extension, even honest relayers may lose their funds if
|
||||
/// there are multiple relays running and submitting the same information.
|
||||
#[macro_export]
|
||||
macro_rules! generate_bridge_reject_obsolete_headers_and_messages {
|
||||
($call:ty, $account_id:ty, $($filter_call:ty),*) => {
|
||||
#[derive(Clone, codec::Decode, codec::DecodeWithMemTracking, Default, codec::Encode, Eq, PartialEq, pezsp_runtime::RuntimeDebug, scale_info::TypeInfo)]
|
||||
pub struct BridgeRejectObsoleteHeadersAndMessages;
|
||||
impl pezsp_runtime::traits::TransactionExtension<$call> for BridgeRejectObsoleteHeadersAndMessages {
|
||||
const IDENTIFIER: &'static str = "BridgeRejectObsoleteHeadersAndMessages";
|
||||
type Implicit = ();
|
||||
type Val = Option<(
|
||||
$account_id,
|
||||
( $(
|
||||
<$filter_call as $crate::extensions::BridgeRuntimeFilterCall<
|
||||
$account_id,
|
||||
$call,
|
||||
>>::ToPostDispatch,
|
||||
)* ),
|
||||
)>;
|
||||
type Pre = Self::Val;
|
||||
|
||||
fn weight(&self, _: &$call) -> pezframe_support::pezpallet_prelude::Weight {
|
||||
pezframe_support::pezpallet_prelude::Weight::zero()
|
||||
}
|
||||
|
||||
fn validate(
|
||||
&self,
|
||||
origin: <$call as pezsp_runtime::traits::Dispatchable>::RuntimeOrigin,
|
||||
call: &$call,
|
||||
_info: &pezsp_runtime::traits::DispatchInfoOf<$call>,
|
||||
_len: usize,
|
||||
_self_implicit: Self::Implicit,
|
||||
_inherited_implication: &impl codec::Encode,
|
||||
_source: pezsp_runtime::transaction_validity::TransactionSource,
|
||||
) -> Result<
|
||||
(
|
||||
pezsp_runtime::transaction_validity::ValidTransaction,
|
||||
Self::Val,
|
||||
<$call as pezsp_runtime::traits::Dispatchable>::RuntimeOrigin,
|
||||
), pezsp_runtime::transaction_validity::TransactionValidityError
|
||||
> {
|
||||
use $crate::extensions::__private::tuplex::PushBack;
|
||||
use pezsp_runtime::traits::AsSystemOriginSigner;
|
||||
|
||||
let Some(who) = origin.as_system_origin_signer() else {
|
||||
return Ok((Default::default(), None, origin));
|
||||
};
|
||||
|
||||
let to_post_dispatch = ();
|
||||
let tx_validity = pezsp_runtime::transaction_validity::ValidTransaction::default();
|
||||
$(
|
||||
let (from_validate, call_filter_validity) = <
|
||||
$filter_call as
|
||||
$crate::extensions::BridgeRuntimeFilterCall<
|
||||
$account_id,
|
||||
$call,
|
||||
>>::validate(who, call);
|
||||
let to_post_dispatch = to_post_dispatch.push_back(from_validate);
|
||||
let tx_validity = tx_validity.combine_with(call_filter_validity?);
|
||||
)*
|
||||
Ok((tx_validity, Some((who.clone(), to_post_dispatch)), origin))
|
||||
}
|
||||
|
||||
fn prepare(
|
||||
self,
|
||||
val: Self::Val,
|
||||
_origin: &<$call as pezsp_runtime::traits::Dispatchable>::RuntimeOrigin,
|
||||
_call: &$call,
|
||||
_info: &pezsp_runtime::traits::DispatchInfoOf<$call>,
|
||||
_len: usize,
|
||||
) -> Result<Self::Pre, pezsp_runtime::transaction_validity::TransactionValidityError> {
|
||||
Ok(val)
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn post_dispatch_details(
|
||||
to_post_dispatch: Self::Pre,
|
||||
info: &pezsp_runtime::traits::DispatchInfoOf<$call>,
|
||||
post_info: &pezsp_runtime::traits::PostDispatchInfoOf<$call>,
|
||||
len: usize,
|
||||
result: &pezsp_runtime::DispatchResult,
|
||||
) -> Result<pezframe_support::pezpallet_prelude::Weight, pezsp_runtime::transaction_validity::TransactionValidityError> {
|
||||
use $crate::extensions::__private::tuplex::PopFront;
|
||||
|
||||
let Some((relayer, to_post_dispatch)) = to_post_dispatch else {
|
||||
return Ok(pezframe_support::pezpallet_prelude::Weight::zero())
|
||||
};
|
||||
|
||||
let has_failed = result.is_err();
|
||||
$(
|
||||
let (item, to_post_dispatch) = to_post_dispatch.pop_front();
|
||||
<
|
||||
$filter_call as
|
||||
$crate::extensions::BridgeRuntimeFilterCall<
|
||||
$account_id,
|
||||
$call,
|
||||
>>::post_dispatch(&relayer, has_failed, item);
|
||||
)*
|
||||
Ok(pezframe_support::pezpallet_prelude::Weight::zero())
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::mock::*;
|
||||
use bp_header_pez_chain::StoredHeaderDataBuilder;
|
||||
use bp_messages::{InboundLaneData, MessageNonce, OutboundLaneData};
|
||||
use bp_pezkuwi_core::teyrchains::{ParaHeadsProof, ParaId};
|
||||
use bp_relayers::{RewardsAccountOwner, RewardsAccountParams};
|
||||
use pezbp_runtime::HeaderId;
|
||||
use bp_test_utils::{make_default_justification, test_keyring, TEST_GRANDPA_SET_ID};
|
||||
use bp_teyrchains::{BestParaHeadHash, ParaInfo};
|
||||
use codec::{Decode, Encode, MaxEncodedLen};
|
||||
use pezframe_support::{assert_err, assert_ok, traits::fungible::Mutate};
|
||||
use pezpallet_bridge_grandpa::{Call as GrandpaCall, StoredAuthoritySet};
|
||||
use pezpallet_bridge_teyrchains::Call as TeyrchainsCall;
|
||||
use scale_info::TypeInfo;
|
||||
use pezsp_runtime::{
|
||||
traits::{
|
||||
parameter_types, AsSystemOriginSigner, AsTransactionAuthorizedOrigin, ConstU64,
|
||||
DispatchTransaction, Header as _, TransactionExtension,
|
||||
},
|
||||
transaction_validity::{
|
||||
InvalidTransaction, TransactionSource::External, TransactionValidity, ValidTransaction,
|
||||
},
|
||||
DispatchError,
|
||||
};
|
||||
|
||||
parameter_types! {
|
||||
pub MsgProofsRewardsAccount: RewardsAccountParams<TestLaneIdType> = RewardsAccountParams::new(
|
||||
test_lane_id(),
|
||||
TEST_BRIDGED_CHAIN_ID,
|
||||
RewardsAccountOwner::ThisChain,
|
||||
);
|
||||
pub MsgDeliveryProofsRewardsAccount: RewardsAccountParams<TestLaneIdType> = RewardsAccountParams::new(
|
||||
test_lane_id(),
|
||||
TEST_BRIDGED_CHAIN_ID,
|
||||
RewardsAccountOwner::BridgedChain,
|
||||
);
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Encode, Decode, TypeInfo, MaxEncodedLen)]
|
||||
pub struct MockCall {
|
||||
data: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Encode, Decode, TypeInfo, MaxEncodedLen)]
|
||||
pub struct MockOrigin(pub u64);
|
||||
|
||||
impl AsSystemOriginSigner<u64> for MockOrigin {
|
||||
fn as_system_origin_signer(&self) -> Option<&u64> {
|
||||
Some(&self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsTransactionAuthorizedOrigin for MockOrigin {
|
||||
fn is_transaction_authorized(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u64> for MockOrigin {
|
||||
fn from(o: u64) -> Self {
|
||||
Self(o)
|
||||
}
|
||||
}
|
||||
|
||||
impl pezsp_runtime::traits::Dispatchable for MockCall {
|
||||
type RuntimeOrigin = MockOrigin;
|
||||
type Config = ();
|
||||
type Info = ();
|
||||
type PostInfo = ();
|
||||
|
||||
fn dispatch(
|
||||
self,
|
||||
_origin: Self::RuntimeOrigin,
|
||||
) -> pezsp_runtime::DispatchResultWithInfo<Self::PostInfo> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FirstFilterCall;
|
||||
impl FirstFilterCall {
|
||||
fn post_dispatch_called_with(success: bool) {
|
||||
pezframe_support::storage::unhashed::put(&[1], &success);
|
||||
}
|
||||
|
||||
fn verify_post_dispatch_called_with(success: bool) {
|
||||
assert_eq!(pezframe_support::storage::unhashed::get::<bool>(&[1]), Some(success));
|
||||
}
|
||||
}
|
||||
|
||||
impl BridgeRuntimeFilterCall<u64, MockCall> for FirstFilterCall {
|
||||
type ToPostDispatch = u64;
|
||||
fn validate(_who: &u64, call: &MockCall) -> (u64, TransactionValidity) {
|
||||
if call.data <= 1 {
|
||||
return (1, InvalidTransaction::Custom(1).into());
|
||||
}
|
||||
|
||||
(1, Ok(ValidTransaction { priority: 1, ..Default::default() }))
|
||||
}
|
||||
|
||||
fn post_dispatch(_who: &u64, has_failed: bool, to_post_dispatch: Self::ToPostDispatch) {
|
||||
Self::post_dispatch_called_with(!has_failed);
|
||||
assert_eq!(to_post_dispatch, 1);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SecondFilterCall;
|
||||
|
||||
impl SecondFilterCall {
|
||||
fn post_dispatch_called_with(success: bool) {
|
||||
pezframe_support::storage::unhashed::put(&[2], &success);
|
||||
}
|
||||
|
||||
fn verify_post_dispatch_called_with(success: bool) {
|
||||
assert_eq!(pezframe_support::storage::unhashed::get::<bool>(&[2]), Some(success));
|
||||
}
|
||||
}
|
||||
|
||||
impl BridgeRuntimeFilterCall<u64, MockCall> for SecondFilterCall {
|
||||
type ToPostDispatch = u64;
|
||||
fn validate(_who: &u64, call: &MockCall) -> (u64, TransactionValidity) {
|
||||
if call.data <= 2 {
|
||||
return (2, InvalidTransaction::Custom(2).into());
|
||||
}
|
||||
|
||||
(2, Ok(ValidTransaction { priority: 2, ..Default::default() }))
|
||||
}
|
||||
|
||||
fn post_dispatch(_who: &u64, has_failed: bool, to_post_dispatch: Self::ToPostDispatch) {
|
||||
Self::post_dispatch_called_with(!has_failed);
|
||||
assert_eq!(to_post_dispatch, 2);
|
||||
}
|
||||
}
|
||||
|
||||
fn initial_balance_of_relayer_account_at_this_chain() -> ThisChainBalance {
|
||||
let test_stake: ThisChainBalance = TestStake::get();
|
||||
ExistentialDeposit::get().saturating_add(test_stake * 100)
|
||||
}
|
||||
|
||||
// in tests, the following accounts are equal (because of how `into_sub_account_truncating`
|
||||
// works)
|
||||
|
||||
fn delivery_rewards_account() -> ThisChainAccountId {
|
||||
TestPaymentProcedure::rewards_account(MsgProofsRewardsAccount::get())
|
||||
}
|
||||
|
||||
fn confirmation_rewards_account() -> ThisChainAccountId {
|
||||
TestPaymentProcedure::rewards_account(MsgDeliveryProofsRewardsAccount::get())
|
||||
}
|
||||
|
||||
fn relayer_account_at_this_chain() -> ThisChainAccountId {
|
||||
0
|
||||
}
|
||||
|
||||
fn initialize_environment(
|
||||
best_relay_header_number: BridgedChainBlockNumber,
|
||||
teyrchain_head_at_relay_header_number: BridgedChainBlockNumber,
|
||||
best_message: MessageNonce,
|
||||
) {
|
||||
let authorities = test_keyring().into_iter().map(|(a, w)| (a.into(), w)).collect();
|
||||
let best_relay_header = HeaderId(best_relay_header_number, BridgedChainHash::default());
|
||||
pezpallet_bridge_grandpa::CurrentAuthoritySet::<TestRuntime>::put(
|
||||
StoredAuthoritySet::try_new(authorities, TEST_GRANDPA_SET_ID).unwrap(),
|
||||
);
|
||||
pezpallet_bridge_grandpa::BestFinalized::<TestRuntime>::put(best_relay_header);
|
||||
pezpallet_bridge_grandpa::ImportedHeaders::<TestRuntime>::insert(
|
||||
best_relay_header.hash(),
|
||||
bp_test_utils::test_header::<BridgedChainHeader>(0).build(),
|
||||
);
|
||||
|
||||
let para_id = ParaId(BridgedUnderlyingTeyrchain::TEYRCHAIN_ID);
|
||||
let para_info = ParaInfo {
|
||||
best_head_hash: BestParaHeadHash {
|
||||
at_relay_block_number: teyrchain_head_at_relay_header_number,
|
||||
head_hash: [teyrchain_head_at_relay_header_number as u8; 32].into(),
|
||||
},
|
||||
next_imported_hash_position: 0,
|
||||
};
|
||||
pezpallet_bridge_teyrchains::ParasInfo::<TestRuntime>::insert(para_id, para_info);
|
||||
|
||||
let lane_id = test_lane_id();
|
||||
let in_lane_data =
|
||||
InboundLaneData { last_confirmed_nonce: best_message, ..Default::default() };
|
||||
pezpallet_bridge_messages::InboundLanes::<TestRuntime>::insert(lane_id, in_lane_data);
|
||||
|
||||
let out_lane_data =
|
||||
OutboundLaneData { latest_received_nonce: best_message, ..Default::default() };
|
||||
pezpallet_bridge_messages::OutboundLanes::<TestRuntime>::insert(lane_id, out_lane_data);
|
||||
|
||||
Balances::mint_into(&delivery_rewards_account(), ExistentialDeposit::get()).unwrap();
|
||||
Balances::mint_into(&confirmation_rewards_account(), ExistentialDeposit::get()).unwrap();
|
||||
Balances::mint_into(
|
||||
&relayer_account_at_this_chain(),
|
||||
initial_balance_of_relayer_account_at_this_chain(),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
fn submit_relay_header_call(relay_header_number: BridgedChainBlockNumber) -> RuntimeCall {
|
||||
let relay_header = BridgedChainHeader::new(
|
||||
relay_header_number,
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
);
|
||||
let relay_justification = make_default_justification(&relay_header);
|
||||
|
||||
RuntimeCall::BridgeGrandpa(GrandpaCall::submit_finality_proof {
|
||||
finality_target: Box::new(relay_header),
|
||||
justification: relay_justification,
|
||||
})
|
||||
}
|
||||
|
||||
fn submit_teyrchain_head_call(
|
||||
teyrchain_head_at_relay_header_number: BridgedChainBlockNumber,
|
||||
) -> RuntimeCall {
|
||||
RuntimeCall::BridgeTeyrchains(TeyrchainsCall::submit_teyrchain_heads {
|
||||
at_relay_block: (teyrchain_head_at_relay_header_number, BridgedChainHash::default()),
|
||||
teyrchains: vec![(
|
||||
ParaId(BridgedUnderlyingTeyrchain::TEYRCHAIN_ID),
|
||||
[teyrchain_head_at_relay_header_number as u8; 32].into(),
|
||||
)],
|
||||
teyrchain_heads_proof: ParaHeadsProof { storage_proof: Default::default() },
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_generated_obsolete_extension() {
|
||||
generate_bridge_reject_obsolete_headers_and_messages!(
|
||||
MockCall,
|
||||
u64,
|
||||
FirstFilterCall,
|
||||
SecondFilterCall
|
||||
);
|
||||
|
||||
run_test(|| {
|
||||
assert_err!(
|
||||
BridgeRejectObsoleteHeadersAndMessages.validate_only(
|
||||
42u64.into(),
|
||||
&MockCall { data: 1 },
|
||||
&(),
|
||||
0,
|
||||
External,
|
||||
0,
|
||||
),
|
||||
InvalidTransaction::Custom(1)
|
||||
);
|
||||
assert_err!(
|
||||
BridgeRejectObsoleteHeadersAndMessages.validate_and_prepare(
|
||||
42u64.into(),
|
||||
&MockCall { data: 1 },
|
||||
&(),
|
||||
0,
|
||||
0,
|
||||
),
|
||||
InvalidTransaction::Custom(1)
|
||||
);
|
||||
|
||||
assert_err!(
|
||||
BridgeRejectObsoleteHeadersAndMessages.validate_only(
|
||||
42u64.into(),
|
||||
&MockCall { data: 2 },
|
||||
&(),
|
||||
0,
|
||||
External,
|
||||
0,
|
||||
),
|
||||
InvalidTransaction::Custom(2)
|
||||
);
|
||||
assert_err!(
|
||||
BridgeRejectObsoleteHeadersAndMessages.validate_and_prepare(
|
||||
42u64.into(),
|
||||
&MockCall { data: 2 },
|
||||
&(),
|
||||
0,
|
||||
0,
|
||||
),
|
||||
InvalidTransaction::Custom(2)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
BridgeRejectObsoleteHeadersAndMessages
|
||||
.validate_only(42u64.into(), &MockCall { data: 3 }, &(), 0, External, 0)
|
||||
.unwrap()
|
||||
.0,
|
||||
ValidTransaction { priority: 3, ..Default::default() },
|
||||
);
|
||||
assert_eq!(
|
||||
BridgeRejectObsoleteHeadersAndMessages
|
||||
.validate_and_prepare(42u64.into(), &MockCall { data: 3 }, &(), 0, 0)
|
||||
.unwrap()
|
||||
.0
|
||||
.unwrap(),
|
||||
(42, (1, 2)),
|
||||
);
|
||||
|
||||
// when post_dispatch is called with `Ok(())`, it is propagated to all "nested"
|
||||
// extensions
|
||||
assert_ok!(BridgeRejectObsoleteHeadersAndMessages::post_dispatch_details(
|
||||
Some((0, (1, 2))),
|
||||
&(),
|
||||
&(),
|
||||
0,
|
||||
&Ok(()),
|
||||
));
|
||||
FirstFilterCall::verify_post_dispatch_called_with(true);
|
||||
SecondFilterCall::verify_post_dispatch_called_with(true);
|
||||
|
||||
// when post_dispatch is called with `Err(())`, it is propagated to all "nested"
|
||||
// extensions
|
||||
assert_ok!(BridgeRejectObsoleteHeadersAndMessages::post_dispatch_details(
|
||||
Some((0, (1, 2))),
|
||||
&(),
|
||||
&(),
|
||||
0,
|
||||
&Err(DispatchError::BadOrigin),
|
||||
));
|
||||
FirstFilterCall::verify_post_dispatch_called_with(false);
|
||||
SecondFilterCall::verify_post_dispatch_called_with(false);
|
||||
});
|
||||
}
|
||||
|
||||
pezframe_support::parameter_types! {
|
||||
pub SlashDestination: ThisChainAccountId = 42;
|
||||
}
|
||||
|
||||
type BridgeGrandpaWrapper =
|
||||
CheckAndBoostBridgeGrandpaTransactions<TestRuntime, (), ConstU64<1_000>, SlashDestination>;
|
||||
|
||||
#[test]
|
||||
fn grandpa_wrapper_does_not_boost_extensions_for_unregistered_relayer() {
|
||||
run_test(|| {
|
||||
initialize_environment(100, 100, 100);
|
||||
|
||||
let priority_boost = BridgeGrandpaWrapper::validate(
|
||||
&relayer_account_at_this_chain(),
|
||||
&submit_relay_header_call(200),
|
||||
)
|
||||
.1
|
||||
.unwrap()
|
||||
.priority;
|
||||
assert_eq!(priority_boost, 0);
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn grandpa_wrapper_boosts_extensions_for_registered_relayer() {
|
||||
run_test(|| {
|
||||
initialize_environment(100, 100, 100);
|
||||
BridgeRelayers::register(RuntimeOrigin::signed(relayer_account_at_this_chain()), 1000)
|
||||
.unwrap();
|
||||
|
||||
let priority_boost = BridgeGrandpaWrapper::validate(
|
||||
&relayer_account_at_this_chain(),
|
||||
&submit_relay_header_call(200),
|
||||
)
|
||||
.1
|
||||
.unwrap()
|
||||
.priority;
|
||||
assert_eq!(priority_boost, 99_000);
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn grandpa_wrapper_slashes_registered_relayer_if_transaction_fails() {
|
||||
run_test(|| {
|
||||
initialize_environment(100, 100, 100);
|
||||
BridgeRelayers::register(RuntimeOrigin::signed(relayer_account_at_this_chain()), 1000)
|
||||
.unwrap();
|
||||
|
||||
assert!(BridgeRelayers::is_registration_active(&relayer_account_at_this_chain()));
|
||||
BridgeGrandpaWrapper::post_dispatch(&relayer_account_at_this_chain(), true, Some(150));
|
||||
assert!(!BridgeRelayers::is_registration_active(&relayer_account_at_this_chain()));
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn grandpa_wrapper_does_not_slash_registered_relayer_if_transaction_succeeds() {
|
||||
run_test(|| {
|
||||
initialize_environment(100, 100, 100);
|
||||
BridgeRelayers::register(RuntimeOrigin::signed(relayer_account_at_this_chain()), 1000)
|
||||
.unwrap();
|
||||
|
||||
assert!(BridgeRelayers::is_registration_active(&relayer_account_at_this_chain()));
|
||||
BridgeGrandpaWrapper::post_dispatch(&relayer_account_at_this_chain(), false, Some(100));
|
||||
assert!(BridgeRelayers::is_registration_active(&relayer_account_at_this_chain()));
|
||||
})
|
||||
}
|
||||
|
||||
type BridgeTeyrchainsWrapper = CheckAndBoostBridgeTeyrchainsTransactions<
|
||||
TestRuntime,
|
||||
(),
|
||||
BridgedUnderlyingTeyrchain,
|
||||
ConstU64<1_000>,
|
||||
SlashDestination,
|
||||
>;
|
||||
|
||||
#[test]
|
||||
fn teyrchains_wrapper_does_not_boost_extensions_for_unregistered_relayer() {
|
||||
run_test(|| {
|
||||
initialize_environment(100, 100, 100);
|
||||
|
||||
let priority_boost = BridgeTeyrchainsWrapper::validate(
|
||||
&relayer_account_at_this_chain(),
|
||||
&submit_teyrchain_head_call(200),
|
||||
)
|
||||
.1
|
||||
.unwrap()
|
||||
.priority;
|
||||
assert_eq!(priority_boost, 0);
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn teyrchains_wrapper_boosts_extensions_for_registered_relayer() {
|
||||
run_test(|| {
|
||||
initialize_environment(100, 100, 100);
|
||||
BridgeRelayers::register(RuntimeOrigin::signed(relayer_account_at_this_chain()), 1000)
|
||||
.unwrap();
|
||||
|
||||
let priority_boost = BridgeTeyrchainsWrapper::validate(
|
||||
&relayer_account_at_this_chain(),
|
||||
&submit_teyrchain_head_call(200),
|
||||
)
|
||||
.1
|
||||
.unwrap()
|
||||
.priority;
|
||||
assert_eq!(priority_boost, 99_000);
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn teyrchains_wrapper_slashes_registered_relayer_if_transaction_fails() {
|
||||
run_test(|| {
|
||||
initialize_environment(100, 100, 100);
|
||||
BridgeRelayers::register(RuntimeOrigin::signed(relayer_account_at_this_chain()), 1000)
|
||||
.unwrap();
|
||||
|
||||
assert!(BridgeRelayers::is_registration_active(&relayer_account_at_this_chain()));
|
||||
BridgeTeyrchainsWrapper::post_dispatch(
|
||||
&relayer_account_at_this_chain(),
|
||||
true,
|
||||
Some(SubmitTeyrchainHeadsInfo {
|
||||
at_relay_block: HeaderId(150, Default::default()),
|
||||
para_id: ParaId(BridgedUnderlyingTeyrchain::TEYRCHAIN_ID),
|
||||
para_head_hash: [150u8; 32].into(),
|
||||
is_free_execution_expected: false,
|
||||
}),
|
||||
);
|
||||
assert!(!BridgeRelayers::is_registration_active(&relayer_account_at_this_chain()));
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn teyrchains_wrapper_does_not_slash_registered_relayer_if_transaction_succeeds() {
|
||||
run_test(|| {
|
||||
initialize_environment(100, 100, 100);
|
||||
BridgeRelayers::register(RuntimeOrigin::signed(relayer_account_at_this_chain()), 1000)
|
||||
.unwrap();
|
||||
|
||||
assert!(BridgeRelayers::is_registration_active(&relayer_account_at_this_chain()));
|
||||
BridgeTeyrchainsWrapper::post_dispatch(
|
||||
&relayer_account_at_this_chain(),
|
||||
false,
|
||||
Some(SubmitTeyrchainHeadsInfo {
|
||||
at_relay_block: HeaderId(100, Default::default()),
|
||||
para_id: ParaId(BridgedUnderlyingTeyrchain::TEYRCHAIN_ID),
|
||||
para_head_hash: [100u8; 32].into(),
|
||||
is_free_execution_expected: false,
|
||||
}),
|
||||
);
|
||||
assert!(BridgeRelayers::is_registration_active(&relayer_account_at_this_chain()));
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,397 @@
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity Bridges Common.
|
||||
|
||||
// Parity Bridges Common 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.
|
||||
|
||||
// Parity Bridges Common 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 Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Integrity tests for chain constants and pallets configuration.
|
||||
//!
|
||||
//! Most of the tests in this module assume that the bridge is using standard (see `crate::messages`
|
||||
//! module for details) configuration.
|
||||
|
||||
use bp_header_pez_chain::ChainWithGrandpa;
|
||||
use bp_messages::{ChainWithMessages, InboundLaneData, MessageNonce};
|
||||
use pezbp_runtime::{AccountIdOf, Chain};
|
||||
use codec::Encode;
|
||||
use pezframe_support::{storage::generator::StorageValue, traits::Get, weights::Weight};
|
||||
use pezframe_system::limits;
|
||||
use pezpallet_bridge_messages::{ThisChainOf, WeightInfoExt as _};
|
||||
|
||||
// Re-export to avoid include all dependencies everywhere.
|
||||
#[doc(hidden)]
|
||||
pub mod __private {
|
||||
pub use static_assertions;
|
||||
}
|
||||
|
||||
/// Macro that ensures that the runtime configuration and chain primitives crate are sharing
|
||||
/// the same types (nonce, block number, hash, hasher, account id and header).
|
||||
#[macro_export]
|
||||
macro_rules! assert_chain_types(
|
||||
( runtime: $r:path, this_chain: $this:path ) => {
|
||||
{
|
||||
use pezframe_system::{Config as SystemConfig, pezpallet_prelude::{BlockNumberFor, HeaderFor}};
|
||||
use $crate::integrity::__private::static_assertions::assert_type_eq_all;
|
||||
|
||||
// if one of asserts fail, then either bridge isn't configured properly (or alternatively - non-standard
|
||||
// configuration is used), or something has broke existing configuration (meaning that all bridged chains
|
||||
// and relays will stop functioning)
|
||||
|
||||
assert_type_eq_all!(<$r as SystemConfig>::Nonce, pezbp_runtime::NonceOf<$this>);
|
||||
assert_type_eq_all!(BlockNumberFor<$r>, pezbp_runtime::BlockNumberOf<$this>);
|
||||
assert_type_eq_all!(<$r as SystemConfig>::Hash, pezbp_runtime::HashOf<$this>);
|
||||
assert_type_eq_all!(<$r as SystemConfig>::Hashing, pezbp_runtime::HasherOf<$this>);
|
||||
assert_type_eq_all!(<$r as SystemConfig>::AccountId, pezbp_runtime::AccountIdOf<$this>);
|
||||
assert_type_eq_all!(HeaderFor<$r>, pezbp_runtime::HeaderOf<$this>);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
/// Macro that ensures that the bridge messages pezpallet is configured properly to bridge using given
|
||||
/// configuration.
|
||||
#[macro_export]
|
||||
macro_rules! assert_bridge_messages_pallet_types(
|
||||
(
|
||||
runtime: $r:path,
|
||||
with_bridged_chain_messages_instance: $i:path,
|
||||
this_chain: $this:path,
|
||||
bridged_chain: $bridged:path,
|
||||
expected_payload_type: $payload:path,
|
||||
) => {
|
||||
{
|
||||
use $crate::integrity::__private::static_assertions::assert_type_eq_all;
|
||||
use bp_messages::ChainWithMessages;
|
||||
use pezbp_runtime::Chain;
|
||||
use pezpallet_bridge_messages::Config as BridgeMessagesConfig;
|
||||
|
||||
// if one of asserts fail, then either bridge isn't configured properly (or alternatively - non-standard
|
||||
// configuration is used), or something has broke existing configuration (meaning that all bridged chains
|
||||
// and relays will stop functioning)
|
||||
|
||||
assert_type_eq_all!(<$r as BridgeMessagesConfig<$i>>::ThisChain, $this);
|
||||
assert_type_eq_all!(<$r as BridgeMessagesConfig<$i>>::BridgedChain, $bridged);
|
||||
|
||||
assert_type_eq_all!(<$r as BridgeMessagesConfig<$i>>::OutboundPayload, $payload);
|
||||
assert_type_eq_all!(<$r as BridgeMessagesConfig<$i>>::InboundPayload, $payload);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
/// Macro that combines four other macro calls - `assert_chain_types`, `assert_bridge_types`,
|
||||
/// and `assert_bridge_messages_pallet_types`. It may be used
|
||||
/// at the chain that is implementing standard messages bridge with messages pallets deployed.
|
||||
#[macro_export]
|
||||
macro_rules! assert_complete_bridge_types(
|
||||
(
|
||||
runtime: $r:path,
|
||||
with_bridged_chain_messages_instance: $mi:path,
|
||||
this_chain: $this:path,
|
||||
bridged_chain: $bridged:path,
|
||||
expected_payload_type: $payload:path,
|
||||
) => {
|
||||
$crate::assert_chain_types!(runtime: $r, this_chain: $this);
|
||||
$crate::assert_bridge_messages_pallet_types!(
|
||||
runtime: $r,
|
||||
with_bridged_chain_messages_instance: $mi,
|
||||
this_chain: $this,
|
||||
bridged_chain: $bridged,
|
||||
expected_payload_type: $payload,
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
/// Parameters for asserting chain-related constants.
|
||||
#[derive(Debug)]
|
||||
pub struct AssertChainConstants {
|
||||
/// Block length limits of the chain.
|
||||
pub block_length: limits::BlockLength,
|
||||
/// Block weight limits of the chain.
|
||||
pub block_weights: limits::BlockWeights,
|
||||
}
|
||||
|
||||
/// Test that our hardcoded, chain-related constants, are matching chain runtime configuration.
|
||||
///
|
||||
/// In particular, this test ensures that:
|
||||
///
|
||||
/// 1) block weight limits are matching;
|
||||
/// 2) block size limits are matching.
|
||||
pub fn assert_chain_constants<R>(params: AssertChainConstants)
|
||||
where
|
||||
R: pezframe_system::Config,
|
||||
{
|
||||
// we don't check runtime version here, because in our case we'll be building relay from one
|
||||
// repo and runtime will live in another repo, along with outdated relay version. To avoid
|
||||
// unneeded commits, let's not raise an error in case of version mismatch.
|
||||
|
||||
// if one of following assert fails, it means that we may need to upgrade bridged chain and
|
||||
// relay to use updated constants. If constants are now smaller than before, it may lead to
|
||||
// undeliverable messages.
|
||||
|
||||
// `BlockLength` struct is not implementing `PartialEq`, so we compare encoded values here.
|
||||
assert_eq!(
|
||||
R::BlockLength::get().encode(),
|
||||
params.block_length.encode(),
|
||||
"BlockLength from runtime ({:?}) differ from hardcoded: {:?}",
|
||||
R::BlockLength::get(),
|
||||
params.block_length,
|
||||
);
|
||||
// `BlockWeights` struct is not implementing `PartialEq`, so we compare encoded values here
|
||||
assert_eq!(
|
||||
R::BlockWeights::get().encode(),
|
||||
params.block_weights.encode(),
|
||||
"BlockWeights from runtime ({:?}) differ from hardcoded: {:?}",
|
||||
R::BlockWeights::get(),
|
||||
params.block_weights,
|
||||
);
|
||||
}
|
||||
|
||||
/// Test that the constants, used in GRANDPA pezpallet configuration are valid.
|
||||
pub fn assert_bridge_grandpa_pallet_constants<R, GI>()
|
||||
where
|
||||
R: pezpallet_bridge_grandpa::Config<GI>,
|
||||
GI: 'static,
|
||||
{
|
||||
assert!(
|
||||
R::HeadersToKeep::get() > 0,
|
||||
"HeadersToKeep ({}) must be larger than zero",
|
||||
R::HeadersToKeep::get(),
|
||||
);
|
||||
}
|
||||
|
||||
/// Test that the constants, used in messages pezpallet configuration are valid.
|
||||
pub fn assert_bridge_messages_pallet_constants<R, MI>()
|
||||
where
|
||||
R: pezpallet_bridge_messages::Config<MI>,
|
||||
MI: 'static,
|
||||
{
|
||||
assert!(
|
||||
pezpallet_bridge_messages::BridgedChainOf::<R, MI>::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX
|
||||
<= pezpallet_bridge_messages::BridgedChainOf::<R, MI>::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX,
|
||||
"MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX ({}) of {:?} is larger than \
|
||||
its MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX ({}). This makes \
|
||||
no sense",
|
||||
pezpallet_bridge_messages::BridgedChainOf::<R, MI>::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX,
|
||||
pezpallet_bridge_messages::BridgedChainOf::<R, MI>::ID,
|
||||
pezpallet_bridge_messages::BridgedChainOf::<R, MI>::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX,
|
||||
);
|
||||
}
|
||||
|
||||
/// Parameters for asserting bridge GRANDPA pezpallet names.
|
||||
#[derive(Debug)]
|
||||
struct AssertBridgeGrandpaPalletNames<'a> {
|
||||
/// Name of the GRANDPA pezpallet, deployed at this chain and used to bridge with the bridged
|
||||
/// chain.
|
||||
pub with_bridged_chain_grandpa_pallet_name: &'a str,
|
||||
}
|
||||
|
||||
/// Tests that bridge pezpallet names used in `construct_runtime!()` macro call are matching constants
|
||||
/// from chain primitives crates.
|
||||
fn assert_bridge_grandpa_pallet_names<R, GI>(params: AssertBridgeGrandpaPalletNames)
|
||||
where
|
||||
R: pezpallet_bridge_grandpa::Config<GI>,
|
||||
GI: 'static,
|
||||
{
|
||||
// check that the bridge GRANDPA pezpallet has required name
|
||||
assert_eq!(
|
||||
pezpallet_bridge_grandpa::PalletOwner::<R, GI>::storage_value_final_key().to_vec(),
|
||||
pezbp_runtime::storage_value_key(
|
||||
params.with_bridged_chain_grandpa_pallet_name,
|
||||
"PalletOwner",
|
||||
)
|
||||
.0,
|
||||
);
|
||||
assert_eq!(
|
||||
pezpallet_bridge_grandpa::PalletOperatingMode::<R, GI>::storage_value_final_key().to_vec(),
|
||||
pezbp_runtime::storage_value_key(
|
||||
params.with_bridged_chain_grandpa_pallet_name,
|
||||
"PalletOperatingMode",
|
||||
)
|
||||
.0,
|
||||
);
|
||||
}
|
||||
|
||||
/// Parameters for asserting bridge messages pezpallet names.
|
||||
#[derive(Debug)]
|
||||
struct AssertBridgeMessagesPalletNames<'a> {
|
||||
/// Name of the messages pezpallet, deployed at this chain and used to bridge with the bridged
|
||||
/// chain.
|
||||
pub with_bridged_chain_messages_pallet_name: &'a str,
|
||||
}
|
||||
|
||||
/// Tests that bridge pezpallet names used in `construct_runtime!()` macro call are matching constants
|
||||
/// from chain primitives crates.
|
||||
fn assert_bridge_messages_pallet_names<R, MI>(params: AssertBridgeMessagesPalletNames)
|
||||
where
|
||||
R: pezpallet_bridge_messages::Config<MI>,
|
||||
MI: 'static,
|
||||
{
|
||||
// check that the bridge messages pezpallet has required name
|
||||
assert_eq!(
|
||||
pezpallet_bridge_messages::PalletOwner::<R, MI>::storage_value_final_key().to_vec(),
|
||||
pezbp_runtime::storage_value_key(
|
||||
params.with_bridged_chain_messages_pallet_name,
|
||||
"PalletOwner",
|
||||
)
|
||||
.0,
|
||||
);
|
||||
assert_eq!(
|
||||
pezpallet_bridge_messages::PalletOperatingMode::<R, MI>::storage_value_final_key().to_vec(),
|
||||
pezbp_runtime::storage_value_key(
|
||||
params.with_bridged_chain_messages_pallet_name,
|
||||
"PalletOperatingMode",
|
||||
)
|
||||
.0,
|
||||
);
|
||||
}
|
||||
|
||||
/// Parameters for asserting complete standard messages bridge.
|
||||
#[derive(Debug)]
|
||||
pub struct AssertCompleteBridgeConstants {
|
||||
/// Parameters to assert this chain constants.
|
||||
pub this_chain_constants: AssertChainConstants,
|
||||
}
|
||||
|
||||
/// All bridge-related constants tests for the complete standard relay-chain messages bridge
|
||||
/// (i.e. with bridge GRANDPA and messages pallets deployed).
|
||||
pub fn assert_complete_with_relay_chain_bridge_constants<R, GI, MI>(
|
||||
params: AssertCompleteBridgeConstants,
|
||||
) where
|
||||
R: pezframe_system::Config
|
||||
+ pezpallet_bridge_grandpa::Config<GI>
|
||||
+ pezpallet_bridge_messages::Config<MI>,
|
||||
GI: 'static,
|
||||
MI: 'static,
|
||||
{
|
||||
assert_chain_constants::<R>(params.this_chain_constants);
|
||||
assert_bridge_grandpa_pallet_constants::<R, GI>();
|
||||
assert_bridge_messages_pallet_constants::<R, MI>();
|
||||
assert_bridge_grandpa_pallet_names::<R, GI>(AssertBridgeGrandpaPalletNames {
|
||||
with_bridged_chain_grandpa_pallet_name:
|
||||
<R as pezpallet_bridge_grandpa::Config<GI>>::BridgedChain::WITH_CHAIN_GRANDPA_PALLET_NAME,
|
||||
});
|
||||
assert_bridge_messages_pallet_names::<R, MI>(AssertBridgeMessagesPalletNames {
|
||||
with_bridged_chain_messages_pallet_name:
|
||||
<R as pezpallet_bridge_messages::Config<MI>>::BridgedChain::WITH_CHAIN_MESSAGES_PALLET_NAME,
|
||||
});
|
||||
}
|
||||
|
||||
/// All bridge-related constants tests for the complete standard teyrchain messages bridge
|
||||
/// (i.e. with bridge GRANDPA, teyrchains and messages pallets deployed).
|
||||
pub fn assert_complete_with_teyrchain_bridge_constants<R, PI, MI>(
|
||||
params: AssertCompleteBridgeConstants,
|
||||
) where
|
||||
R: pezframe_system::Config
|
||||
+ pezpallet_bridge_teyrchains::Config<PI>
|
||||
+ pezpallet_bridge_messages::Config<MI>,
|
||||
<R as pezpallet_bridge_teyrchains::BoundedBridgeGrandpaConfig<R::BridgesGrandpaPalletInstance>>::BridgedRelayChain: ChainWithGrandpa,
|
||||
PI: 'static,
|
||||
MI: 'static,
|
||||
{
|
||||
assert_chain_constants::<R>(params.this_chain_constants);
|
||||
assert_bridge_grandpa_pallet_constants::<R, R::BridgesGrandpaPalletInstance>();
|
||||
assert_bridge_messages_pallet_constants::<R, MI>();
|
||||
assert_bridge_grandpa_pallet_names::<R, R::BridgesGrandpaPalletInstance>(
|
||||
AssertBridgeGrandpaPalletNames {
|
||||
with_bridged_chain_grandpa_pallet_name:
|
||||
<<R as pezpallet_bridge_teyrchains::BoundedBridgeGrandpaConfig<
|
||||
R::BridgesGrandpaPalletInstance,
|
||||
>>::BridgedRelayChain>::WITH_CHAIN_GRANDPA_PALLET_NAME,
|
||||
},
|
||||
);
|
||||
assert_bridge_messages_pallet_names::<R, MI>(AssertBridgeMessagesPalletNames {
|
||||
with_bridged_chain_messages_pallet_name:
|
||||
<R as pezpallet_bridge_messages::Config<MI>>::BridgedChain::WITH_CHAIN_MESSAGES_PALLET_NAME,
|
||||
});
|
||||
}
|
||||
|
||||
/// All bridge-related constants tests for the standalone messages bridge deployment (only with
|
||||
/// messages pallets deployed).
|
||||
pub fn assert_standalone_messages_bridge_constants<R, MI>(params: AssertCompleteBridgeConstants)
|
||||
where
|
||||
R: pezframe_system::Config + pezpallet_bridge_messages::Config<MI>,
|
||||
MI: 'static,
|
||||
{
|
||||
assert_chain_constants::<R>(params.this_chain_constants);
|
||||
assert_bridge_messages_pallet_constants::<R, MI>();
|
||||
assert_bridge_messages_pallet_names::<R, MI>(AssertBridgeMessagesPalletNames {
|
||||
with_bridged_chain_messages_pallet_name:
|
||||
<R as pezpallet_bridge_messages::Config<MI>>::BridgedChain::WITH_CHAIN_MESSAGES_PALLET_NAME,
|
||||
});
|
||||
}
|
||||
|
||||
/// Check that the message lane weights are correct.
|
||||
pub fn check_message_lane_weights<
|
||||
C: ChainWithMessages,
|
||||
T: pezframe_system::Config + pezpallet_bridge_messages::Config<MessagesPalletInstance>,
|
||||
MessagesPalletInstance: 'static,
|
||||
>(
|
||||
bridged_chain_extra_storage_proof_size: u32,
|
||||
this_chain_max_unrewarded_relayers: MessageNonce,
|
||||
this_chain_max_unconfirmed_messages: MessageNonce,
|
||||
// whether `RefundBridgedTeyrchainMessages` extension is deployed at runtime and is used for
|
||||
// refunding this bridge transactions?
|
||||
//
|
||||
// in other words: pass true for all known production chains
|
||||
runtime_includes_refund_extension: bool,
|
||||
) {
|
||||
type Weights<T, MI> = <T as pezpallet_bridge_messages::Config<MI>>::WeightInfo;
|
||||
|
||||
// check basic weight assumptions
|
||||
pezpallet_bridge_messages::ensure_weights_are_correct::<Weights<T, MessagesPalletInstance>>();
|
||||
|
||||
// check that the maximal message dispatch weight is below hardcoded limit
|
||||
pezpallet_bridge_messages::ensure_maximal_message_dispatch::<Weights<T, MessagesPalletInstance>>(
|
||||
C::maximal_incoming_message_size(),
|
||||
C::maximal_incoming_message_dispatch_weight(),
|
||||
);
|
||||
|
||||
// check that weights allow us to receive messages
|
||||
let max_incoming_message_proof_size =
|
||||
bridged_chain_extra_storage_proof_size.saturating_add(C::maximal_incoming_message_size());
|
||||
pezpallet_bridge_messages::ensure_able_to_receive_message::<Weights<T, MessagesPalletInstance>>(
|
||||
C::max_extrinsic_size(),
|
||||
C::max_extrinsic_weight(),
|
||||
max_incoming_message_proof_size,
|
||||
C::maximal_incoming_message_dispatch_weight(),
|
||||
);
|
||||
|
||||
// check that weights allow us to receive delivery confirmations
|
||||
let max_incoming_inbound_lane_data_proof_size = InboundLaneData::<
|
||||
AccountIdOf<ThisChainOf<T, MessagesPalletInstance>>,
|
||||
>::encoded_size_hint_u32(
|
||||
this_chain_max_unrewarded_relayers as _
|
||||
);
|
||||
pezpallet_bridge_messages::ensure_able_to_receive_confirmation::<Weights<T, MessagesPalletInstance>>(
|
||||
C::max_extrinsic_size(),
|
||||
C::max_extrinsic_weight(),
|
||||
max_incoming_inbound_lane_data_proof_size,
|
||||
this_chain_max_unrewarded_relayers,
|
||||
this_chain_max_unconfirmed_messages,
|
||||
);
|
||||
|
||||
// check that extra weights of delivery/confirmation transactions include the weight
|
||||
// of `RefundBridgedTeyrchainMessages` operations. This signed extension assumes the worst case
|
||||
// (i.e. slashing if delivery transaction was invalid) and refunds some weight if
|
||||
// assumption was wrong (i.e. if we did refund instead of slashing). This check
|
||||
// ensures the extension will not refund weight when it doesn't need to (i.e. if pezpallet
|
||||
// weights do not account weights of refund extension).
|
||||
if runtime_includes_refund_extension {
|
||||
assert_ne!(
|
||||
Weights::<T, MessagesPalletInstance>::receive_messages_proof_overhead_from_runtime(),
|
||||
Weight::zero()
|
||||
);
|
||||
assert_ne!(
|
||||
Weights::<T, MessagesPalletInstance>::receive_messages_delivery_proof_overhead_from_runtime(),
|
||||
Weight::zero()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity Bridges Common.
|
||||
|
||||
// Parity Bridges Common 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.
|
||||
|
||||
// Parity Bridges Common 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 Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Common types/functions that may be used by runtimes of all bridged chains.
|
||||
|
||||
#![warn(missing_docs)]
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
pub mod extensions;
|
||||
pub mod messages_api;
|
||||
pub mod messages_benchmarking;
|
||||
pub mod teyrchains_benchmarking;
|
||||
|
||||
mod mock;
|
||||
|
||||
#[cfg(feature = "integrity-test")]
|
||||
pub mod integrity;
|
||||
@@ -0,0 +1,64 @@
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity Bridges Common.
|
||||
|
||||
// Parity Bridges Common 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.
|
||||
|
||||
// Parity Bridges Common 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 Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Helpers for implementing various message-related runtime API methods.
|
||||
|
||||
use bp_messages::{InboundMessageDetails, MessageNonce, MessagePayload, OutboundMessageDetails};
|
||||
use pezsp_std::vec::Vec;
|
||||
|
||||
/// Implementation of the `To*OutboundLaneApi::message_details`.
|
||||
pub fn outbound_message_details<Runtime, MessagesPalletInstance>(
|
||||
lane: Runtime::LaneId,
|
||||
begin: MessageNonce,
|
||||
end: MessageNonce,
|
||||
) -> Vec<OutboundMessageDetails>
|
||||
where
|
||||
Runtime: pezpallet_bridge_messages::Config<MessagesPalletInstance>,
|
||||
MessagesPalletInstance: 'static,
|
||||
{
|
||||
(begin..=end)
|
||||
.filter_map(|nonce| {
|
||||
let message_data =
|
||||
pezpallet_bridge_messages::Pezpallet::<Runtime, MessagesPalletInstance>::outbound_message_data(lane, nonce)?;
|
||||
Some(OutboundMessageDetails {
|
||||
nonce,
|
||||
// dispatch message weight is always zero at the source chain, since we're paying for
|
||||
// dispatch at the target chain
|
||||
dispatch_weight: pezframe_support::weights::Weight::zero(),
|
||||
size: message_data.len() as _,
|
||||
})
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Implementation of the `To*InboundLaneApi::message_details`.
|
||||
pub fn inbound_message_details<Runtime, MessagesPalletInstance>(
|
||||
lane: Runtime::LaneId,
|
||||
messages: Vec<(MessagePayload, OutboundMessageDetails)>,
|
||||
) -> Vec<InboundMessageDetails>
|
||||
where
|
||||
Runtime: pezpallet_bridge_messages::Config<MessagesPalletInstance>,
|
||||
MessagesPalletInstance: 'static,
|
||||
{
|
||||
messages
|
||||
.into_iter()
|
||||
.map(|(payload, details)| {
|
||||
pezpallet_bridge_messages::Pezpallet::<Runtime, MessagesPalletInstance>::inbound_message_data(
|
||||
lane, payload, details,
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
@@ -0,0 +1,326 @@
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity Bridges Common.
|
||||
|
||||
// Parity Bridges Common 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.
|
||||
|
||||
// Parity Bridges Common 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 Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Everything required to run benchmarks of messages module, based on
|
||||
//! `pezbridge_runtime_common::messages` implementation.
|
||||
|
||||
#![cfg(feature = "runtime-benchmarks")]
|
||||
|
||||
use bp_messages::{
|
||||
source_chain::FromBridgedChainMessagesDeliveryProof,
|
||||
target_chain::FromBridgedChainMessagesProof, MessagePayload,
|
||||
};
|
||||
use bp_pezkuwi_core::teyrchains::ParaHash;
|
||||
use pezbp_runtime::{AccountIdOf, Chain, HashOf, Teyrchain};
|
||||
use codec::Encode;
|
||||
use pezframe_support::weights::Weight;
|
||||
use pezpallet_bridge_messages::{
|
||||
benchmarking::{MessageDeliveryProofParams, MessageProofParams},
|
||||
messages_generation::{
|
||||
encode_all_messages, encode_lane_data, prepare_message_delivery_storage_proof,
|
||||
prepare_messages_storage_proof,
|
||||
},
|
||||
BridgedChainOf, LaneIdOf, ThisChainOf,
|
||||
};
|
||||
use pezsp_runtime::traits::{Header, Zero};
|
||||
use pezsp_std::prelude::*;
|
||||
use xcm::latest::prelude::*;
|
||||
|
||||
/// Prepare inbound bridge message according to given message proof parameters.
|
||||
fn prepare_inbound_message<LaneId>(
|
||||
params: &MessageProofParams<LaneId>,
|
||||
successful_dispatch_message_generator: impl Fn(usize) -> MessagePayload,
|
||||
) -> MessagePayload {
|
||||
let expected_size = params.proof_params.db_size.unwrap_or(0) as usize;
|
||||
|
||||
// if we don't need a correct message, then we may just return some random blob
|
||||
if !params.is_successful_dispatch_expected {
|
||||
return vec![0u8; expected_size];
|
||||
}
|
||||
|
||||
// else let's prepare successful message.
|
||||
let msg = successful_dispatch_message_generator(expected_size);
|
||||
assert!(
|
||||
msg.len() >= expected_size,
|
||||
"msg.len(): {} does not match expected_size: {}",
|
||||
expected_size,
|
||||
msg.len()
|
||||
);
|
||||
msg
|
||||
}
|
||||
|
||||
/// Prepare proof of messages for the `receive_messages_proof` call.
|
||||
///
|
||||
/// In addition to returning valid messages proof, environment is prepared to verify this message
|
||||
/// proof.
|
||||
///
|
||||
/// This method is intended to be used when benchmarking pezpallet, linked to the chain that
|
||||
/// uses GRANDPA finality. For teyrchains, please use the `prepare_message_proof_from_teyrchain`
|
||||
/// function.
|
||||
pub fn prepare_message_proof_from_grandpa_chain<R, FI, MI>(
|
||||
params: MessageProofParams<LaneIdOf<R, MI>>,
|
||||
message_generator: impl Fn(usize) -> MessagePayload,
|
||||
) -> (FromBridgedChainMessagesProof<HashOf<BridgedChainOf<R, MI>>, LaneIdOf<R, MI>>, Weight)
|
||||
where
|
||||
R: pezpallet_bridge_grandpa::Config<FI, BridgedChain = BridgedChainOf<R, MI>>
|
||||
+ pezpallet_bridge_messages::Config<
|
||||
MI,
|
||||
BridgedHeaderChain = pezpallet_bridge_grandpa::Pezpallet<R, FI>,
|
||||
>,
|
||||
FI: 'static,
|
||||
MI: 'static,
|
||||
{
|
||||
// prepare storage proof
|
||||
let (state_root, storage_proof) = prepare_messages_storage_proof::<
|
||||
BridgedChainOf<R, MI>,
|
||||
ThisChainOf<R, MI>,
|
||||
LaneIdOf<R, MI>,
|
||||
>(
|
||||
params.lane,
|
||||
params.message_nonces.clone(),
|
||||
params.outbound_lane_data.clone(),
|
||||
params.proof_params,
|
||||
|_| prepare_inbound_message(¶ms, &message_generator),
|
||||
encode_all_messages,
|
||||
encode_lane_data,
|
||||
false,
|
||||
false,
|
||||
);
|
||||
|
||||
// update runtime storage
|
||||
let (_, bridged_header_hash) = insert_header_to_grandpa_pallet::<R, FI>(state_root);
|
||||
|
||||
(
|
||||
FromBridgedChainMessagesProof {
|
||||
bridged_header_hash,
|
||||
storage_proof,
|
||||
lane: params.lane,
|
||||
nonces_start: *params.message_nonces.start(),
|
||||
nonces_end: *params.message_nonces.end(),
|
||||
},
|
||||
Weight::MAX / 1000,
|
||||
)
|
||||
}
|
||||
|
||||
/// Prepare proof of messages for the `receive_messages_proof` call.
|
||||
///
|
||||
/// In addition to returning valid messages proof, environment is prepared to verify this message
|
||||
/// proof.
|
||||
///
|
||||
/// This method is intended to be used when benchmarking pezpallet, linked to the chain that
|
||||
/// uses teyrchain finality. For GRANDPA chains, please use the
|
||||
/// `prepare_message_proof_from_grandpa_chain` function.
|
||||
pub fn prepare_message_proof_from_teyrchain<R, PI, MI>(
|
||||
params: MessageProofParams<LaneIdOf<R, MI>>,
|
||||
message_generator: impl Fn(usize) -> MessagePayload,
|
||||
) -> (FromBridgedChainMessagesProof<HashOf<BridgedChainOf<R, MI>>, LaneIdOf<R, MI>>, Weight)
|
||||
where
|
||||
R: pezpallet_bridge_teyrchains::Config<PI> + pezpallet_bridge_messages::Config<MI>,
|
||||
PI: 'static,
|
||||
MI: 'static,
|
||||
BridgedChainOf<R, MI>: Chain<Hash = ParaHash> + Teyrchain,
|
||||
{
|
||||
// prepare storage proof
|
||||
let (state_root, storage_proof) = prepare_messages_storage_proof::<
|
||||
BridgedChainOf<R, MI>,
|
||||
ThisChainOf<R, MI>,
|
||||
LaneIdOf<R, MI>,
|
||||
>(
|
||||
params.lane,
|
||||
params.message_nonces.clone(),
|
||||
params.outbound_lane_data.clone(),
|
||||
params.proof_params,
|
||||
|_| prepare_inbound_message(¶ms, &message_generator),
|
||||
encode_all_messages,
|
||||
encode_lane_data,
|
||||
false,
|
||||
false,
|
||||
);
|
||||
|
||||
// update runtime storage
|
||||
let (_, bridged_header_hash) =
|
||||
insert_header_to_teyrchains_pallet::<R, PI, BridgedChainOf<R, MI>>(state_root);
|
||||
|
||||
(
|
||||
FromBridgedChainMessagesProof {
|
||||
bridged_header_hash,
|
||||
storage_proof,
|
||||
lane: params.lane,
|
||||
nonces_start: *params.message_nonces.start(),
|
||||
nonces_end: *params.message_nonces.end(),
|
||||
},
|
||||
Weight::MAX / 1000,
|
||||
)
|
||||
}
|
||||
|
||||
/// Prepare proof of messages delivery for the `receive_messages_delivery_proof` call.
|
||||
///
|
||||
/// This method is intended to be used when benchmarking pezpallet, linked to the chain that
|
||||
/// uses GRANDPA finality. For teyrchains, please use the
|
||||
/// `prepare_message_delivery_proof_from_teyrchain` function.
|
||||
pub fn prepare_message_delivery_proof_from_grandpa_chain<R, FI, MI>(
|
||||
params: MessageDeliveryProofParams<AccountIdOf<ThisChainOf<R, MI>>, LaneIdOf<R, MI>>,
|
||||
) -> FromBridgedChainMessagesDeliveryProof<HashOf<BridgedChainOf<R, MI>>, LaneIdOf<R, MI>>
|
||||
where
|
||||
R: pezpallet_bridge_grandpa::Config<FI, BridgedChain = BridgedChainOf<R, MI>>
|
||||
+ pezpallet_bridge_messages::Config<
|
||||
MI,
|
||||
BridgedHeaderChain = pezpallet_bridge_grandpa::Pezpallet<R, FI>,
|
||||
>,
|
||||
FI: 'static,
|
||||
MI: 'static,
|
||||
{
|
||||
// prepare storage proof
|
||||
let lane = params.lane;
|
||||
let (state_root, storage_proof) = prepare_message_delivery_storage_proof::<
|
||||
BridgedChainOf<R, MI>,
|
||||
ThisChainOf<R, MI>,
|
||||
LaneIdOf<R, MI>,
|
||||
>(params.lane, params.inbound_lane_data, params.proof_params);
|
||||
|
||||
// update runtime storage
|
||||
let (_, bridged_header_hash) = insert_header_to_grandpa_pallet::<R, FI>(state_root);
|
||||
|
||||
FromBridgedChainMessagesDeliveryProof {
|
||||
bridged_header_hash: bridged_header_hash.into(),
|
||||
storage_proof,
|
||||
lane,
|
||||
}
|
||||
}
|
||||
|
||||
/// Prepare proof of messages delivery for the `receive_messages_delivery_proof` call.
|
||||
///
|
||||
/// This method is intended to be used when benchmarking pezpallet, linked to the chain that
|
||||
/// uses teyrchain finality. For GRANDPA chains, please use the
|
||||
/// `prepare_message_delivery_proof_from_grandpa_chain` function.
|
||||
pub fn prepare_message_delivery_proof_from_teyrchain<R, PI, MI>(
|
||||
params: MessageDeliveryProofParams<AccountIdOf<ThisChainOf<R, MI>>, LaneIdOf<R, MI>>,
|
||||
) -> FromBridgedChainMessagesDeliveryProof<HashOf<BridgedChainOf<R, MI>>, LaneIdOf<R, MI>>
|
||||
where
|
||||
R: pezpallet_bridge_teyrchains::Config<PI> + pezpallet_bridge_messages::Config<MI>,
|
||||
PI: 'static,
|
||||
MI: 'static,
|
||||
BridgedChainOf<R, MI>: Chain<Hash = ParaHash> + Teyrchain,
|
||||
{
|
||||
// prepare storage proof
|
||||
let lane = params.lane;
|
||||
let (state_root, storage_proof) = prepare_message_delivery_storage_proof::<
|
||||
BridgedChainOf<R, MI>,
|
||||
ThisChainOf<R, MI>,
|
||||
LaneIdOf<R, MI>,
|
||||
>(params.lane, params.inbound_lane_data, params.proof_params);
|
||||
|
||||
// update runtime storage
|
||||
let (_, bridged_header_hash) =
|
||||
insert_header_to_teyrchains_pallet::<R, PI, BridgedChainOf<R, MI>>(state_root);
|
||||
|
||||
FromBridgedChainMessagesDeliveryProof {
|
||||
bridged_header_hash: bridged_header_hash.into(),
|
||||
storage_proof,
|
||||
lane,
|
||||
}
|
||||
}
|
||||
|
||||
/// Insert header to the bridge GRANDPA pezpallet.
|
||||
pub(crate) fn insert_header_to_grandpa_pallet<R, GI>(
|
||||
state_root: pezbp_runtime::HashOf<R::BridgedChain>,
|
||||
) -> (pezbp_runtime::BlockNumberOf<R::BridgedChain>, pezbp_runtime::HashOf<R::BridgedChain>)
|
||||
where
|
||||
R: pezpallet_bridge_grandpa::Config<GI>,
|
||||
GI: 'static,
|
||||
R::BridgedChain: pezbp_runtime::Chain,
|
||||
{
|
||||
let bridged_block_number = Zero::zero();
|
||||
let bridged_header = pezbp_runtime::HeaderOf::<R::BridgedChain>::new(
|
||||
bridged_block_number,
|
||||
Default::default(),
|
||||
state_root,
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
);
|
||||
let bridged_header_hash = bridged_header.hash();
|
||||
pezpallet_bridge_grandpa::initialize_for_benchmarks::<R, GI>(bridged_header);
|
||||
(bridged_block_number, bridged_header_hash)
|
||||
}
|
||||
|
||||
/// Insert header to the bridge teyrchains pezpallet.
|
||||
pub(crate) fn insert_header_to_teyrchains_pallet<R, PI, PC>(
|
||||
state_root: pezbp_runtime::HashOf<PC>,
|
||||
) -> (pezbp_runtime::BlockNumberOf<PC>, pezbp_runtime::HashOf<PC>)
|
||||
where
|
||||
R: pezpallet_bridge_teyrchains::Config<PI>,
|
||||
PI: 'static,
|
||||
PC: Chain<Hash = ParaHash> + Teyrchain,
|
||||
{
|
||||
let bridged_block_number = Zero::zero();
|
||||
let bridged_header = pezbp_runtime::HeaderOf::<PC>::new(
|
||||
bridged_block_number,
|
||||
Default::default(),
|
||||
state_root,
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
);
|
||||
let bridged_header_hash = bridged_header.hash();
|
||||
pezpallet_bridge_teyrchains::initialize_for_benchmarks::<R, PI, PC>(bridged_header);
|
||||
(bridged_block_number, bridged_header_hash)
|
||||
}
|
||||
|
||||
/// Returns callback which generates `BridgeMessage` from Pezkuwi XCM builder based on
|
||||
/// `expected_message_size` for benchmark.
|
||||
pub fn generate_xcm_builder_bridge_message_sample(
|
||||
destination: InteriorLocation,
|
||||
) -> impl Fn(usize) -> MessagePayload {
|
||||
move |expected_message_size| -> MessagePayload {
|
||||
// For XCM bridge hubs, it is the message that
|
||||
// will be pushed further to some XCM queue (XCMP/UMP)
|
||||
let location = xcm::VersionedInteriorLocation::from(destination.clone());
|
||||
let location_encoded_size = location.encoded_size();
|
||||
|
||||
// we don't need to be super-precise with `expected_size` here
|
||||
let xcm_size = expected_message_size.saturating_sub(location_encoded_size);
|
||||
let xcm_data_size = xcm_size.saturating_sub(
|
||||
// minus empty instruction size
|
||||
Instruction::<()>::ExpectPallet {
|
||||
index: 0,
|
||||
name: vec![],
|
||||
module_name: vec![],
|
||||
crate_major: 0,
|
||||
min_crate_minor: 0,
|
||||
}
|
||||
.encoded_size(),
|
||||
);
|
||||
|
||||
tracing::trace!(
|
||||
target: "runtime::bridge-benchmarks",
|
||||
%expected_message_size, %location_encoded_size, %xcm_size, %xcm_data_size,
|
||||
"generate_xcm_builder_bridge_message_sample"
|
||||
);
|
||||
|
||||
let xcm = xcm::VersionedXcm::<()>::from(Xcm(vec![Instruction::<()>::ExpectPallet {
|
||||
index: 0,
|
||||
name: vec![42; xcm_data_size],
|
||||
module_name: vec![],
|
||||
crate_major: 0,
|
||||
min_crate_minor: 0,
|
||||
}]));
|
||||
|
||||
// this is the `BridgeMessage` from pezkuwi 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()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,361 @@
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity Bridges Common.
|
||||
|
||||
// Parity Bridges Common 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.
|
||||
|
||||
// Parity Bridges Common 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 Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! A mock runtime for testing different stuff in the crate.
|
||||
|
||||
#![cfg(test)]
|
||||
|
||||
use bp_header_pez_chain::ChainWithGrandpa;
|
||||
use bp_messages::{
|
||||
target_chain::{DispatchMessage, MessageDispatch},
|
||||
ChainWithMessages, HashedLaneId, LaneIdType, MessageNonce,
|
||||
};
|
||||
use bp_relayers::{PayRewardFromAccount, RewardsAccountParams};
|
||||
use pezbp_runtime::{messages::MessageDispatchResult, Chain, ChainId, Teyrchain};
|
||||
use bp_teyrchains::SingleParaStoredHeaderDataBuilder;
|
||||
use codec::Encode;
|
||||
use pezframe_support::{
|
||||
derive_impl, parameter_types,
|
||||
weights::{ConstantMultiplier, IdentityFee, RuntimeDbWeight, Weight},
|
||||
};
|
||||
use pezpallet_transaction_payment::Multiplier;
|
||||
use pezsp_runtime::{
|
||||
testing::H256,
|
||||
traits::{BlakeTwo256, ConstU32, ConstU64, ConstU8},
|
||||
FixedPointNumber, Perquintill, StateVersion,
|
||||
};
|
||||
|
||||
/// Account identifier at `ThisChain`.
|
||||
pub type ThisChainAccountId = u64;
|
||||
/// Balance at `ThisChain`.
|
||||
pub type ThisChainBalance = u64;
|
||||
/// Block number at `ThisChain`.
|
||||
pub type ThisChainBlockNumber = u32;
|
||||
/// Hash at `ThisChain`.
|
||||
pub type ThisChainHash = H256;
|
||||
/// Hasher at `ThisChain`.
|
||||
pub type ThisChainHasher = BlakeTwo256;
|
||||
/// Runtime call at `ThisChain`.
|
||||
pub type ThisChainRuntimeCall = RuntimeCall;
|
||||
/// Header of `ThisChain`.
|
||||
pub type ThisChainHeader = pezsp_runtime::generic::Header<ThisChainBlockNumber, ThisChainHasher>;
|
||||
/// Block of `ThisChain`.
|
||||
pub type ThisChainBlock = pezframe_system::mocking::MockBlockU32<TestRuntime>;
|
||||
|
||||
/// Account identifier at the `BridgedChain`.
|
||||
pub type BridgedChainAccountId = u128;
|
||||
/// Balance at the `BridgedChain`.
|
||||
pub type BridgedChainBalance = u128;
|
||||
/// Block number at the `BridgedChain`.
|
||||
pub type BridgedChainBlockNumber = u32;
|
||||
/// Hash at the `BridgedChain`.
|
||||
pub type BridgedChainHash = H256;
|
||||
/// Hasher at the `BridgedChain`.
|
||||
pub type BridgedChainHasher = BlakeTwo256;
|
||||
/// Header of the `BridgedChain`.
|
||||
pub type BridgedChainHeader =
|
||||
pezsp_runtime::generic::Header<BridgedChainBlockNumber, BridgedChainHasher>;
|
||||
|
||||
/// Rewards payment procedure.
|
||||
pub type TestPaymentProcedure =
|
||||
PayRewardFromAccount<Balances, ThisChainAccountId, TestLaneIdType, RewardBalance>;
|
||||
/// Stake that we are using in tests.
|
||||
pub type TestStake = ConstU64<5_000>;
|
||||
/// Stake and slash mechanism to use in tests.
|
||||
pub type TestStakeAndSlash = pezpallet_bridge_relayers::StakeAndSlashNamed<
|
||||
ThisChainAccountId,
|
||||
ThisChainBlockNumber,
|
||||
Balances,
|
||||
ReserveId,
|
||||
TestStake,
|
||||
ConstU32<8>,
|
||||
>;
|
||||
|
||||
/// Lane identifier type used for tests.
|
||||
pub type TestLaneIdType = HashedLaneId;
|
||||
/// Lane that we're using in tests.
|
||||
pub fn test_lane_id() -> TestLaneIdType {
|
||||
TestLaneIdType::try_new(1, 2).unwrap()
|
||||
}
|
||||
/// Reward measurement type.
|
||||
pub type RewardBalance = u32;
|
||||
|
||||
/// Bridged chain id used in tests.
|
||||
pub const TEST_BRIDGED_CHAIN_ID: ChainId = *b"brdg";
|
||||
/// Maximal extrinsic size at the `BridgedChain`.
|
||||
pub const BRIDGED_CHAIN_MAX_EXTRINSIC_SIZE: u32 = 1024;
|
||||
|
||||
pezframe_support::construct_runtime! {
|
||||
pub enum TestRuntime
|
||||
{
|
||||
System: pezframe_system::{Pezpallet, Call, Config<T>, Storage, Event<T>},
|
||||
Utility: pezpallet_utility,
|
||||
Balances: pezpallet_balances::{Pezpallet, Call, Storage, Config<T>, Event<T>},
|
||||
TransactionPayment: pezpallet_transaction_payment::{Pezpallet, Storage, Event<T>},
|
||||
BridgeRelayers: pezpallet_bridge_relayers::{Pezpallet, Call, Storage, Event<T>},
|
||||
BridgeGrandpa: pezpallet_bridge_grandpa::{Pezpallet, Call, Storage, Event<T>},
|
||||
BridgeTeyrchains: pezpallet_bridge_teyrchains::{Pezpallet, Call, Storage, Event<T>},
|
||||
BridgeMessages: pezpallet_bridge_messages::{Pezpallet, Call, Storage, Event<T>, Config<T>},
|
||||
}
|
||||
}
|
||||
|
||||
crate::generate_bridge_reject_obsolete_headers_and_messages! {
|
||||
ThisChainRuntimeCall, ThisChainAccountId,
|
||||
BridgeGrandpa, BridgeTeyrchains, BridgeMessages
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
pub const BridgedParasPalletName: &'static str = "Paras";
|
||||
pub const ExistentialDeposit: ThisChainBalance = 500;
|
||||
pub const DbWeight: RuntimeDbWeight = RuntimeDbWeight { read: 1, write: 2 };
|
||||
pub const TargetBlockFullness: Perquintill = Perquintill::from_percent(25);
|
||||
pub const TransactionBaseFee: ThisChainBalance = 0;
|
||||
pub const TransactionByteFee: ThisChainBalance = 1;
|
||||
pub AdjustmentVariable: Multiplier = Multiplier::saturating_from_rational(3, 100_000);
|
||||
pub MinimumMultiplier: Multiplier = Multiplier::saturating_from_rational(1, 1_000_000u128);
|
||||
pub MaximumMultiplier: Multiplier = pezsp_runtime::traits::Bounded::max_value();
|
||||
pub const ReserveId: [u8; 8] = *b"brdgrlrs";
|
||||
}
|
||||
|
||||
#[derive_impl(pezframe_system::config_preludes::TestDefaultConfig)]
|
||||
impl pezframe_system::Config for TestRuntime {
|
||||
type Hash = ThisChainHash;
|
||||
type Hashing = ThisChainHasher;
|
||||
type AccountId = ThisChainAccountId;
|
||||
type Block = ThisChainBlock;
|
||||
type AccountData = pezpallet_balances::AccountData<ThisChainBalance>;
|
||||
}
|
||||
|
||||
impl pezpallet_utility::Config for TestRuntime {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
type RuntimeCall = RuntimeCall;
|
||||
type PalletsOrigin = OriginCaller;
|
||||
type WeightInfo = ();
|
||||
}
|
||||
|
||||
#[derive_impl(pezpallet_balances::config_preludes::TestDefaultConfig)]
|
||||
impl pezpallet_balances::Config for TestRuntime {
|
||||
type ReserveIdentifier = [u8; 8];
|
||||
type AccountStore = System;
|
||||
}
|
||||
|
||||
#[derive_impl(pezpallet_transaction_payment::config_preludes::TestDefaultConfig)]
|
||||
impl pezpallet_transaction_payment::Config for TestRuntime {
|
||||
type OnChargeTransaction = pezpallet_transaction_payment::FungibleAdapter<Balances, ()>;
|
||||
type OperationalFeeMultiplier = ConstU8<5>;
|
||||
type WeightToFee = IdentityFee<ThisChainBalance>;
|
||||
type LengthToFee = ConstantMultiplier<ThisChainBalance, TransactionByteFee>;
|
||||
type FeeMultiplierUpdate = pezpallet_transaction_payment::TargetedFeeAdjustment<
|
||||
TestRuntime,
|
||||
TargetBlockFullness,
|
||||
AdjustmentVariable,
|
||||
MinimumMultiplier,
|
||||
MaximumMultiplier,
|
||||
>;
|
||||
}
|
||||
|
||||
impl pezpallet_bridge_grandpa::Config for TestRuntime {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
type BridgedChain = BridgedUnderlyingChain;
|
||||
type MaxFreeHeadersPerBlock = ConstU32<4>;
|
||||
type FreeHeadersInterval = ConstU32<1_024>;
|
||||
type HeadersToKeep = ConstU32<8>;
|
||||
type WeightInfo = pezpallet_bridge_grandpa::weights::BridgeWeight<TestRuntime>;
|
||||
}
|
||||
|
||||
impl pezpallet_bridge_teyrchains::Config for TestRuntime {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
type BridgesGrandpaPalletInstance = ();
|
||||
type ParasPalletName = BridgedParasPalletName;
|
||||
type ParaStoredHeaderDataBuilder =
|
||||
SingleParaStoredHeaderDataBuilder<BridgedUnderlyingTeyrchain>;
|
||||
type HeadsToKeep = ConstU32<8>;
|
||||
type MaxParaHeadDataSize = ConstU32<1024>;
|
||||
type WeightInfo = pezpallet_bridge_teyrchains::weights::BridgeWeight<TestRuntime>;
|
||||
type OnNewHead = ();
|
||||
}
|
||||
|
||||
impl pezpallet_bridge_messages::Config for TestRuntime {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
type WeightInfo = pezpallet_bridge_messages::weights::BridgeWeight<TestRuntime>;
|
||||
|
||||
type OutboundPayload = Vec<u8>;
|
||||
type InboundPayload = Vec<u8>;
|
||||
type LaneId = TestLaneIdType;
|
||||
|
||||
type DeliveryPayments = ();
|
||||
type DeliveryConfirmationPayments = pezpallet_bridge_relayers::DeliveryConfirmationPaymentsAdapter<
|
||||
TestRuntime,
|
||||
(),
|
||||
(),
|
||||
ConstU32<100_000>,
|
||||
>;
|
||||
type OnMessagesDelivered = ();
|
||||
|
||||
type MessageDispatch = DummyMessageDispatch;
|
||||
|
||||
type ThisChain = ThisUnderlyingChain;
|
||||
type BridgedChain = BridgedUnderlyingChain;
|
||||
type BridgedHeaderChain = BridgeGrandpa;
|
||||
}
|
||||
|
||||
impl pezpallet_bridge_relayers::Config for TestRuntime {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
type RewardBalance = RewardBalance;
|
||||
type Reward = RewardsAccountParams<pezpallet_bridge_messages::LaneIdOf<TestRuntime, ()>>;
|
||||
type PaymentProcedure = TestPaymentProcedure;
|
||||
type StakeAndSlash = TestStakeAndSlash;
|
||||
type Balance = ThisChainBalance;
|
||||
type WeightInfo = ();
|
||||
}
|
||||
|
||||
/// Dummy message dispatcher.
|
||||
pub struct DummyMessageDispatch;
|
||||
|
||||
impl DummyMessageDispatch {
|
||||
pub fn deactivate(lane: TestLaneIdType) {
|
||||
pezframe_support::storage::unhashed::put(&(b"inactive", lane).encode()[..], &false);
|
||||
}
|
||||
}
|
||||
|
||||
impl MessageDispatch for DummyMessageDispatch {
|
||||
type DispatchPayload = Vec<u8>;
|
||||
type DispatchLevelResult = ();
|
||||
type LaneId = TestLaneIdType;
|
||||
|
||||
fn is_active(lane: Self::LaneId) -> bool {
|
||||
pezframe_support::storage::unhashed::take::<bool>(&(b"inactive", lane).encode()[..]) !=
|
||||
Some(false)
|
||||
}
|
||||
|
||||
fn dispatch_weight(
|
||||
_message: &mut DispatchMessage<Self::DispatchPayload, Self::LaneId>,
|
||||
) -> Weight {
|
||||
Weight::zero()
|
||||
}
|
||||
|
||||
fn dispatch(
|
||||
_: DispatchMessage<Self::DispatchPayload, Self::LaneId>,
|
||||
) -> MessageDispatchResult<Self::DispatchLevelResult> {
|
||||
MessageDispatchResult { unspent_weight: Weight::zero(), dispatch_level_result: () }
|
||||
}
|
||||
}
|
||||
|
||||
/// Underlying chain of `ThisChain`.
|
||||
pub struct ThisUnderlyingChain;
|
||||
|
||||
impl Chain for ThisUnderlyingChain {
|
||||
const ID: ChainId = *b"tuch";
|
||||
|
||||
type BlockNumber = ThisChainBlockNumber;
|
||||
type Hash = ThisChainHash;
|
||||
type Hasher = ThisChainHasher;
|
||||
type Header = ThisChainHeader;
|
||||
type AccountId = ThisChainAccountId;
|
||||
type Balance = ThisChainBalance;
|
||||
type Nonce = u32;
|
||||
type Signature = pezsp_runtime::MultiSignature;
|
||||
|
||||
const STATE_VERSION: StateVersion = StateVersion::V1;
|
||||
|
||||
fn max_extrinsic_size() -> u32 {
|
||||
BRIDGED_CHAIN_MAX_EXTRINSIC_SIZE
|
||||
}
|
||||
|
||||
fn max_extrinsic_weight() -> Weight {
|
||||
Weight::zero()
|
||||
}
|
||||
}
|
||||
|
||||
impl ChainWithMessages for ThisUnderlyingChain {
|
||||
const WITH_CHAIN_MESSAGES_PALLET_NAME: &'static str = "";
|
||||
|
||||
const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce = 16;
|
||||
const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = 1000;
|
||||
}
|
||||
|
||||
/// Underlying chain of `BridgedChain`.
|
||||
pub struct BridgedUnderlyingChain;
|
||||
/// Some teyrchain under `BridgedChain` consensus.
|
||||
pub struct BridgedUnderlyingTeyrchain;
|
||||
|
||||
impl Chain for BridgedUnderlyingChain {
|
||||
const ID: ChainId = TEST_BRIDGED_CHAIN_ID;
|
||||
|
||||
type BlockNumber = BridgedChainBlockNumber;
|
||||
type Hash = BridgedChainHash;
|
||||
type Hasher = BridgedChainHasher;
|
||||
type Header = BridgedChainHeader;
|
||||
type AccountId = BridgedChainAccountId;
|
||||
type Balance = BridgedChainBalance;
|
||||
type Nonce = u32;
|
||||
type Signature = pezsp_runtime::MultiSignature;
|
||||
|
||||
const STATE_VERSION: StateVersion = StateVersion::V1;
|
||||
|
||||
fn max_extrinsic_size() -> u32 {
|
||||
BRIDGED_CHAIN_MAX_EXTRINSIC_SIZE
|
||||
}
|
||||
fn max_extrinsic_weight() -> Weight {
|
||||
Weight::zero()
|
||||
}
|
||||
}
|
||||
|
||||
impl ChainWithGrandpa for BridgedUnderlyingChain {
|
||||
const WITH_CHAIN_GRANDPA_PALLET_NAME: &'static str = "";
|
||||
const MAX_AUTHORITIES_COUNT: u32 = 16;
|
||||
const REASONABLE_HEADERS_IN_JUSTIFICATION_ANCESTRY: u32 = 8;
|
||||
const MAX_MANDATORY_HEADER_SIZE: u32 = 256;
|
||||
const AVERAGE_HEADER_SIZE: u32 = 64;
|
||||
}
|
||||
|
||||
impl ChainWithMessages for BridgedUnderlyingChain {
|
||||
const WITH_CHAIN_MESSAGES_PALLET_NAME: &'static str = "";
|
||||
const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce = 16;
|
||||
const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = 1000;
|
||||
}
|
||||
|
||||
impl Chain for BridgedUnderlyingTeyrchain {
|
||||
const ID: ChainId = *b"bupc";
|
||||
|
||||
type BlockNumber = BridgedChainBlockNumber;
|
||||
type Hash = BridgedChainHash;
|
||||
type Hasher = BridgedChainHasher;
|
||||
type Header = BridgedChainHeader;
|
||||
type AccountId = BridgedChainAccountId;
|
||||
type Balance = BridgedChainBalance;
|
||||
type Nonce = u32;
|
||||
type Signature = pezsp_runtime::MultiSignature;
|
||||
|
||||
const STATE_VERSION: StateVersion = StateVersion::V1;
|
||||
|
||||
fn max_extrinsic_size() -> u32 {
|
||||
BRIDGED_CHAIN_MAX_EXTRINSIC_SIZE
|
||||
}
|
||||
fn max_extrinsic_weight() -> Weight {
|
||||
Weight::zero()
|
||||
}
|
||||
}
|
||||
|
||||
impl Teyrchain for BridgedUnderlyingTeyrchain {
|
||||
const TEYRCHAIN_ID: u32 = 42;
|
||||
const MAX_HEADER_SIZE: u32 = 1_024;
|
||||
}
|
||||
|
||||
/// Run test within test externalities.
|
||||
pub fn run_test(test: impl FnOnce()) {
|
||||
pezsp_io::TestExternalities::new(Default::default()).execute_with(test)
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity Bridges Common.
|
||||
|
||||
// Parity Bridges Common 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.
|
||||
|
||||
// Parity Bridges Common 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 Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Everything required to run benchmarks of teyrchains finality module.
|
||||
|
||||
#![cfg(feature = "runtime-benchmarks")]
|
||||
|
||||
use crate::messages_benchmarking::insert_header_to_grandpa_pallet;
|
||||
|
||||
use bp_pezkuwi_core::teyrchains::{ParaHash, ParaHead, ParaHeadsProof, ParaId};
|
||||
use pezbp_runtime::{grow_storage_value, record_all_trie_keys, Chain, UnverifiedStorageProofParams};
|
||||
use bp_teyrchains::{
|
||||
teyrchain_head_storage_key_at_source, RelayBlockHash, RelayBlockHasher, RelayBlockNumber,
|
||||
};
|
||||
use codec::Encode;
|
||||
use pezframe_support::traits::Get;
|
||||
use pezsp_std::prelude::*;
|
||||
use pezsp_trie::{trie_types::TrieDBMutBuilderV1, LayoutV1, MemoryDB, TrieMut};
|
||||
|
||||
/// Prepare proof of messages for the `receive_messages_proof` call.
|
||||
///
|
||||
/// In addition to returning valid messages proof, environment is prepared to verify this message
|
||||
/// proof.
|
||||
pub fn prepare_teyrchain_heads_proof<R, PI>(
|
||||
teyrchains: &[ParaId],
|
||||
teyrchain_head_size: u32,
|
||||
proof_params: UnverifiedStorageProofParams,
|
||||
) -> (RelayBlockNumber, RelayBlockHash, ParaHeadsProof, Vec<(ParaId, ParaHash)>)
|
||||
where
|
||||
R: pezpallet_bridge_teyrchains::Config<PI>
|
||||
+ pezpallet_bridge_grandpa::Config<R::BridgesGrandpaPalletInstance>,
|
||||
PI: 'static,
|
||||
<R as pezpallet_bridge_grandpa::Config<R::BridgesGrandpaPalletInstance>>::BridgedChain:
|
||||
Chain<BlockNumber = RelayBlockNumber, Hash = RelayBlockHash>,
|
||||
{
|
||||
let teyrchain_head = ParaHead(vec![0u8; teyrchain_head_size as usize]);
|
||||
|
||||
// insert all heads to the trie
|
||||
let mut teyrchain_heads = Vec::with_capacity(teyrchains.len());
|
||||
let mut storage_keys = Vec::with_capacity(teyrchains.len());
|
||||
let mut state_root = Default::default();
|
||||
let mut mdb = MemoryDB::default();
|
||||
{
|
||||
let mut trie =
|
||||
TrieDBMutBuilderV1::<RelayBlockHasher>::new(&mut mdb, &mut state_root).build();
|
||||
|
||||
// insert teyrchain heads
|
||||
for (i, teyrchain) in teyrchains.into_iter().enumerate() {
|
||||
let storage_key =
|
||||
teyrchain_head_storage_key_at_source(R::ParasPalletName::get(), *teyrchain);
|
||||
let leaf_data = if i == 0 {
|
||||
grow_storage_value(teyrchain_head.encode(), &proof_params)
|
||||
} else {
|
||||
teyrchain_head.encode()
|
||||
};
|
||||
trie.insert(&storage_key.0, &leaf_data)
|
||||
.map_err(|_| "TrieMut::insert has failed")
|
||||
.expect("TrieMut::insert should not fail in benchmarks");
|
||||
storage_keys.push(storage_key);
|
||||
teyrchain_heads.push((*teyrchain, teyrchain_head.hash()))
|
||||
}
|
||||
}
|
||||
|
||||
// generate heads storage proof
|
||||
let proof = record_all_trie_keys::<LayoutV1<RelayBlockHasher>, _>(&mdb, &state_root)
|
||||
.map_err(|_| "record_all_trie_keys has failed")
|
||||
.expect("record_all_trie_keys should not fail in benchmarks");
|
||||
|
||||
let (relay_block_number, relay_block_hash) =
|
||||
insert_header_to_grandpa_pallet::<R, R::BridgesGrandpaPalletInstance>(state_root);
|
||||
|
||||
(relay_block_number, relay_block_hash, ParaHeadsProof { storage_proof: proof }, teyrchain_heads)
|
||||
}
|
||||
Reference in New Issue
Block a user