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:
2025-12-16 09:57:23 +03:00
parent eea003e14d
commit 3139ffa25e
3022 changed files with 42157 additions and 23579 deletions
@@ -0,0 +1,198 @@
// 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/>.
//! Benchmarks for the relayers Pezpallet.
#![cfg(feature = "runtime-benchmarks")]
use crate::*;
use pezframe_benchmarking::v2::*;
use pezframe_support::{assert_ok, weights::Weight};
use pezframe_system::RawOrigin;
use pezsp_runtime::traits::One;
/// Reward amount that is (hopefully) is larger than existential deposit across all chains.
const REWARD_AMOUNT: u32 = u32::MAX;
/// Pezpallet we're benchmarking here.
pub struct Pezpallet<T: Config<I>, I: 'static = ()>(crate::Pezpallet<T, I>);
/// Trait that must be implemented by runtime.
pub trait Config<I: 'static = ()>: crate::Config<I> {
/// `T::Reward` to use in benchmarks.
fn bench_reward() -> Self::Reward;
/// Prepare environment for paying given reward for serving given lane.
fn prepare_rewards_account(
reward_kind: Self::Reward,
reward: Self::RewardBalance,
) -> Option<BeneficiaryOf<Self, I>>;
/// Give enough balance to given account.
fn deposit_account(account: Self::AccountId, balance: Self::Balance);
}
fn assert_last_event<T: Config<I>, I: 'static>(
generic_event: <T as pezpallet::Config<I>>::RuntimeEvent,
) {
pezframe_system::Pezpallet::<T>::assert_last_event(generic_event.into());
}
#[instance_benchmarks(
where
BeneficiaryOf<T, I>: From<<T as pezframe_system::Config>::AccountId>,
)]
mod benchmarks {
use super::*;
#[benchmark]
fn claim_rewards() {
let relayer: T::AccountId = whitelisted_caller();
let reward_kind = T::bench_reward();
let reward_balance = T::RewardBalance::from(REWARD_AMOUNT);
let _ = T::prepare_rewards_account(reward_kind, reward_balance);
RelayerRewards::<T, I>::insert(&relayer, reward_kind, reward_balance);
#[extrinsic_call]
_(RawOrigin::Signed(relayer.clone()), reward_kind);
// we can't check anything here, because `PaymentProcedure` is responsible for
// payment logic, so we assume that if call has succeeded, the procedure has
// also completed successfully
assert_last_event::<T, I>(
Event::RewardPaid {
relayer: relayer.clone(),
reward_kind,
reward_balance,
beneficiary: relayer.into(),
}
.into(),
);
}
#[benchmark]
fn claim_rewards_to() -> Result<(), BenchmarkError> {
let relayer: T::AccountId = whitelisted_caller();
let reward_kind = T::bench_reward();
let reward_balance = T::RewardBalance::from(REWARD_AMOUNT);
let Some(alternative_beneficiary) = T::prepare_rewards_account(reward_kind, reward_balance)
else {
return Err(BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)));
};
RelayerRewards::<T, I>::insert(&relayer, reward_kind, reward_balance);
#[extrinsic_call]
_(RawOrigin::Signed(relayer.clone()), reward_kind, alternative_beneficiary.clone());
// we can't check anything here, because `PaymentProcedure` is responsible for
// payment logic, so we assume that if call has succeeded, the procedure has
// also completed successfully
assert_last_event::<T, I>(
Event::RewardPaid {
relayer: relayer.clone(),
reward_kind,
reward_balance,
beneficiary: alternative_beneficiary,
}
.into(),
);
Ok(())
}
#[benchmark]
fn register() {
let relayer: T::AccountId = whitelisted_caller();
let valid_till = pezframe_system::Pezpallet::<T>::block_number()
.saturating_add(crate::Pezpallet::<T, I>::required_registration_lease())
.saturating_add(One::one())
.saturating_add(One::one());
T::deposit_account(relayer.clone(), crate::Pezpallet::<T, I>::required_stake());
#[extrinsic_call]
_(RawOrigin::Signed(relayer.clone()), valid_till);
assert!(crate::Pezpallet::<T, I>::is_registration_active(&relayer));
}
#[benchmark]
fn deregister() {
let relayer: T::AccountId = whitelisted_caller();
let valid_till = pezframe_system::Pezpallet::<T>::block_number()
.saturating_add(crate::Pezpallet::<T, I>::required_registration_lease())
.saturating_add(One::one())
.saturating_add(One::one());
T::deposit_account(relayer.clone(), crate::Pezpallet::<T, I>::required_stake());
crate::Pezpallet::<T, I>::register(RawOrigin::Signed(relayer.clone()).into(), valid_till)
.unwrap();
pezframe_system::Pezpallet::<T>::set_block_number(valid_till.saturating_add(One::one()));
#[extrinsic_call]
_(RawOrigin::Signed(relayer.clone()));
assert!(!crate::Pezpallet::<T, I>::is_registration_active(&relayer));
}
// Benchmark `slash_and_deregister` method of the pezpallet. We are adding this weight to
// the weight of message delivery call if `BridgeRelayersTransactionExtension` signed extension
// is deployed at runtime level.
#[benchmark]
fn slash_and_deregister() {
// prepare and register relayer account
let relayer: T::AccountId = whitelisted_caller();
let valid_till = pezframe_system::Pezpallet::<T>::block_number()
.saturating_add(crate::Pezpallet::<T, I>::required_registration_lease())
.saturating_add(One::one())
.saturating_add(One::one());
T::deposit_account(relayer.clone(), crate::Pezpallet::<T, I>::required_stake());
assert_ok!(crate::Pezpallet::<T, I>::register(
RawOrigin::Signed(relayer.clone()).into(),
valid_till
));
// create slash destination account
let slash_destination: T::AccountId = whitelisted_caller();
T::deposit_account(slash_destination.clone(), Zero::zero());
#[block]
{
crate::Pezpallet::<T, I>::slash_and_deregister(
&relayer,
bp_relayers::ExplicitOrAccountParams::Explicit::<_, ()>(slash_destination),
);
}
assert!(!crate::Pezpallet::<T, I>::is_registration_active(&relayer));
}
// Benchmark `register_relayer_reward` method of the pezpallet. We are adding this weight to
// the weight of message delivery call if `BridgeRelayersTransactionExtension` signed extension
// is deployed at runtime level.
#[benchmark]
fn register_relayer_reward() {
let reward_kind = T::bench_reward();
let relayer: T::AccountId = whitelisted_caller();
#[block]
{
crate::Pezpallet::<T, I>::register_relayer_reward(reward_kind, &relayer, One::one());
}
assert_eq!(RelayerRewards::<T, I>::get(relayer, &reward_kind), Some(One::one()));
}
impl_benchmark_test_suite!(Pezpallet, crate::mock::new_test_ext(), crate::mock::TestRuntime);
}
@@ -0,0 +1,182 @@
// 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/>.
//! Adapter that allows using `pezpallet-bridge-relayers` as a signed extension in the
//! bridge with remote GRANDPA chain.
use crate::{
extension::verify_messages_call_succeeded, Config as BridgeRelayersConfig, LOG_TARGET,
};
use bp_relayers::{BatchCallUnpacker, ExtensionCallData, ExtensionCallInfo, ExtensionConfig};
use pezbp_runtime::{Chain, StaticStrProvider};
use core::marker::PhantomData;
use pezframe_support::dispatch::{DispatchInfo, PostDispatchInfo};
use pezframe_system::Config as SystemConfig;
use pezpallet_bridge_grandpa::{
CallSubType as BridgeGrandpaCallSubtype, Config as BridgeGrandpaConfig,
SubmitFinalityProofHelper,
};
use pezpallet_bridge_messages::{
CallSubType as BridgeMessagesCallSubType, Config as BridgeMessagesConfig, LaneIdOf,
};
use pezsp_runtime::{
traits::{Dispatchable, Get},
transaction_validity::{TransactionPriority, TransactionValidityError},
Saturating,
};
/// Adapter to be used in signed extension configuration, when bridging with remote
/// chains that are using GRANDPA finality.
pub struct WithGrandpaChainExtensionConfig<
// signed extension identifier
IdProvider,
// runtime that implements `BridgeMessagesConfig<BridgeMessagesPalletInstance>`, which
// uses `BridgeGrandpaConfig<BridgeGrandpaPalletInstance>` to receive messages and
// confirmations from the remote chain.
Runtime,
// batch call unpacker
BatchCallUnpacker,
// instance of the `pezpallet-bridge-grandpa`, tracked by this extension
BridgeGrandpaPalletInstance,
// instance of BridgedChain `pezpallet-bridge-messages`, tracked by this extension
BridgeMessagesPalletInstance,
// instance of `pezpallet-bridge-relayers`, tracked by this extension
BridgeRelayersPalletInstance,
// message delivery transaction priority boost for every additional message
PriorityBoostPerMessage,
>(
PhantomData<(
IdProvider,
Runtime,
BatchCallUnpacker,
BridgeGrandpaPalletInstance,
BridgeMessagesPalletInstance,
BridgeRelayersPalletInstance,
PriorityBoostPerMessage,
)>,
);
impl<ID, R, BCU, GI, MI, RI, P> ExtensionConfig
for WithGrandpaChainExtensionConfig<ID, R, BCU, GI, MI, RI, P>
where
ID: StaticStrProvider,
R: BridgeRelayersConfig<RI>
+ BridgeMessagesConfig<MI, BridgedChain = pezpallet_bridge_grandpa::BridgedChain<R, GI>>
+ BridgeGrandpaConfig<GI>,
BCU: BatchCallUnpacker<R>,
GI: 'static,
MI: 'static,
RI: 'static,
P: Get<TransactionPriority>,
R::RuntimeCall: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo>
+ BridgeGrandpaCallSubtype<R, GI>
+ BridgeMessagesCallSubType<R, MI>,
{
type IdProvider = ID;
type Runtime = R;
type BridgeMessagesPalletInstance = MI;
type BridgeRelayersPalletInstance = RI;
type PriorityBoostPerMessage = P;
type RemoteGrandpaChainBlockNumber = pezpallet_bridge_grandpa::BridgedBlockNumber<R, GI>;
type LaneId = LaneIdOf<R, Self::BridgeMessagesPalletInstance>;
fn parse_and_check_for_obsolete_call(
call: &R::RuntimeCall,
) -> Result<
Option<ExtensionCallInfo<Self::RemoteGrandpaChainBlockNumber, Self::LaneId>>,
TransactionValidityError,
> {
let calls = BCU::unpack(call, 2);
let total_calls = calls.len();
let mut calls = calls.into_iter().map(Self::check_obsolete_parsed_call).rev();
let msgs_call = calls.next().transpose()?.and_then(|c| c.call_info());
let relay_finality_call =
calls.next().transpose()?.and_then(|c| c.submit_finality_proof_info());
Ok(match (total_calls, relay_finality_call, msgs_call) {
(2, Some(relay_finality_call), Some(msgs_call)) =>
Some(ExtensionCallInfo::RelayFinalityAndMsgs(relay_finality_call, msgs_call)),
(1, None, Some(msgs_call)) => Some(ExtensionCallInfo::Msgs(msgs_call)),
_ => None,
})
}
fn check_obsolete_parsed_call(
call: &R::RuntimeCall,
) -> Result<&R::RuntimeCall, TransactionValidityError> {
call.check_obsolete_submit_finality_proof()?;
call.check_obsolete_call()?;
Ok(call)
}
fn check_call_result(
call_info: &ExtensionCallInfo<Self::RemoteGrandpaChainBlockNumber, Self::LaneId>,
call_data: &mut ExtensionCallData,
relayer: &R::AccountId,
) -> bool {
verify_submit_finality_proof_succeeded::<Self, GI>(call_info, call_data, relayer) &&
verify_messages_call_succeeded::<Self>(call_info, call_data, relayer)
}
}
/// If the batch call contains the GRANDPA chain state update call, verify that it
/// has been successful.
///
/// Only returns false when GRANDPA chain state update call has failed.
pub(crate) fn verify_submit_finality_proof_succeeded<C, GI>(
call_info: &ExtensionCallInfo<C::RemoteGrandpaChainBlockNumber, C::LaneId>,
call_data: &mut ExtensionCallData,
relayer: &<C::Runtime as SystemConfig>::AccountId,
) -> bool
where
C: ExtensionConfig,
GI: 'static,
C::Runtime: BridgeGrandpaConfig<GI>,
<C::Runtime as BridgeGrandpaConfig<GI>>::BridgedChain:
Chain<BlockNumber = C::RemoteGrandpaChainBlockNumber>,
{
let Some(finality_proof_info) = call_info.submit_finality_proof_info() else { return true };
if !SubmitFinalityProofHelper::<C::Runtime, GI>::was_successful(
finality_proof_info.block_number,
) {
// we only refund relayer if all calls have updated chain state
tracing::trace!(
target: LOG_TARGET,
id_provider=%C::IdProvider::STR,
lane_id=?call_info.messages_call_info().lane_id(),
?relayer,
"Relayer has submitted invalid GRANDPA chain finality proof"
);
return false;
}
// there's a conflict between how bridge GRANDPA pezpallet works and a `utility.batchAll`
// transaction. If relay chain header is mandatory, the GRANDPA pezpallet returns
// `Pays::No`, because such transaction is mandatory for operating the bridge. But
// `utility.batchAll` transaction always requires payment. But in both cases we'll
// refund relayer - either explicitly here, or using `Pays::No` if he's choosing
// to submit dedicated transaction.
// submitter has means to include extra weight/bytes in the `submit_finality_proof`
// call, so let's subtract extra weight/size to avoid refunding for this extra stuff
call_data.extra_weight.saturating_accrue(finality_proof_info.extra_weight);
call_data.extra_size.saturating_accrue(finality_proof_info.extra_size);
true
}
@@ -0,0 +1,99 @@
// 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/>.
//! Adapter that allows using `pezpallet-bridge-relayers` as a signed extension in the
//! bridge with any remote chain. This adapter does not refund any finality transactions.
use crate::{extension::verify_messages_call_succeeded, Config as BridgeRelayersConfig};
use bp_relayers::{ExtensionCallData, ExtensionCallInfo, ExtensionConfig};
use pezbp_runtime::StaticStrProvider;
use core::marker::PhantomData;
use pezframe_support::dispatch::{DispatchInfo, PostDispatchInfo};
use pezpallet_bridge_messages::{
CallSubType as BridgeMessagesCallSubType, Config as BridgeMessagesConfig, LaneIdOf,
};
use pezsp_runtime::{
traits::{Dispatchable, Get},
transaction_validity::{TransactionPriority, TransactionValidityError},
};
/// Transaction extension that refunds a relayer for standalone messages delivery and confirmation
/// transactions. Finality transactions are not refunded.
pub struct WithMessagesExtensionConfig<
IdProvider,
Runtime,
BridgeMessagesPalletInstance,
BridgeRelayersPalletInstance,
PriorityBoostPerMessage,
>(
PhantomData<(
// signed extension identifier
IdProvider,
// runtime with `pezpallet-bridge-messages` pezpallet deployed
Runtime,
// instance of BridgedChain `pezpallet-bridge-messages`, tracked by this extension
BridgeMessagesPalletInstance,
// instance of `pezpallet-bridge-relayers`, tracked by this extension
BridgeRelayersPalletInstance,
// message delivery transaction priority boost for every additional message
PriorityBoostPerMessage,
)>,
);
impl<ID, R, MI, RI, P> ExtensionConfig for WithMessagesExtensionConfig<ID, R, MI, RI, P>
where
ID: StaticStrProvider,
R: BridgeRelayersConfig<RI> + BridgeMessagesConfig<MI>,
MI: 'static,
RI: 'static,
P: Get<TransactionPriority>,
R::RuntimeCall: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo>
+ BridgeMessagesCallSubType<R, MI>,
{
type IdProvider = ID;
type Runtime = R;
type BridgeMessagesPalletInstance = MI;
type BridgeRelayersPalletInstance = RI;
type PriorityBoostPerMessage = P;
type RemoteGrandpaChainBlockNumber = ();
type LaneId = LaneIdOf<R, Self::BridgeMessagesPalletInstance>;
fn parse_and_check_for_obsolete_call(
call: &R::RuntimeCall,
) -> Result<
Option<ExtensionCallInfo<Self::RemoteGrandpaChainBlockNumber, Self::LaneId>>,
TransactionValidityError,
> {
let call = Self::check_obsolete_parsed_call(call)?;
Ok(call.call_info().map(ExtensionCallInfo::Msgs))
}
fn check_obsolete_parsed_call(
call: &R::RuntimeCall,
) -> Result<&R::RuntimeCall, TransactionValidityError> {
call.check_obsolete_call()?;
Ok(call)
}
fn check_call_result(
call_info: &ExtensionCallInfo<Self::RemoteGrandpaChainBlockNumber, Self::LaneId>,
call_data: &mut ExtensionCallData,
relayer: &R::AccountId,
) -> bool {
verify_messages_call_succeeded::<Self>(call_info, call_data, relayer)
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,431 @@
// 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/>.
//! Bridge transaction priority calculator.
//!
//! We want to prioritize message delivery transactions with more messages over
//! transactions with less messages. That's because we reject delivery transactions
//! if it contains already delivered message. And if some transaction delivers
//! single message with nonce `N`, then the transaction with nonces `N..=N+100` will
//! be rejected. This can lower bridge throughput down to one message per block.
use pezframe_support::traits::Get;
use pezsp_runtime::transaction_validity::TransactionPriority;
// reexport everything from `integrity_tests` module
#[allow(unused_imports)]
pub use integrity_tests::*;
/// We'll deal with different bridge items here - messages, headers, ...
/// To avoid being too verbose with generic code, let's just define a separate alias.
pub type ItemCount = u64;
/// Compute priority boost for transaction that brings given number of bridge
/// items (messages, headers, ...), when every additional item adds `PriorityBoostPerItem`
/// to transaction priority.
pub fn compute_priority_boost<PriorityBoostPerItem>(n_items: ItemCount) -> TransactionPriority
where
PriorityBoostPerItem: Get<TransactionPriority>,
{
// we don't want any boost for transaction with single (additional) item => minus one
PriorityBoostPerItem::get().saturating_mul(n_items.saturating_sub(1))
}
#[cfg(not(feature = "integrity-test"))]
mod integrity_tests {}
#[cfg(feature = "integrity-test")]
mod integrity_tests {
use super::{compute_priority_boost, ItemCount};
use bp_messages::MessageNonce;
use pezbp_runtime::PreComputedSize;
use pezframe_support::{
dispatch::{DispatchClass, DispatchInfo, Pays, PostDispatchInfo},
traits::Get,
};
use pezpallet_transaction_payment::OnChargeTransaction;
use pezsp_runtime::{
traits::{Dispatchable, UniqueSaturatedInto, Zero},
transaction_validity::TransactionPriority,
FixedPointOperand, SaturatedConversion, Saturating,
};
type BalanceOf<T> =
<<T as pezpallet_transaction_payment::Config>::OnChargeTransaction as OnChargeTransaction<
T,
>>::Balance;
/// Ensures that the value of `PriorityBoostPerItem` matches the value of
/// `tip_boost_per_item`.
///
/// We want two transactions, `TX1` with `N` items and `TX2` with `N+1` items, have almost
/// the same priority if we'll add `tip_boost_per_item` tip to the `TX1`. We want to be sure
/// that if we add plain `PriorityBoostPerItem` priority to `TX1`, the priority will be close
/// to `TX2` as well.
fn ensure_priority_boost_is_sane<PriorityBoostPerItem, Balance>(
param_name: &str,
max_items: ItemCount,
tip_boost_per_item: Balance,
estimate_priority: impl Fn(ItemCount, Balance) -> TransactionPriority,
) where
PriorityBoostPerItem: Get<TransactionPriority>,
ItemCount: UniqueSaturatedInto<Balance>,
Balance: FixedPointOperand + Zero,
{
let priority_boost_per_item = PriorityBoostPerItem::get();
for n_items in 1..=max_items {
let base_priority = estimate_priority(n_items, Zero::zero());
let priority_boost = compute_priority_boost::<PriorityBoostPerItem>(n_items);
let priority_with_boost = base_priority
.checked_add(priority_boost)
.expect("priority overflow: try lowering `max_items` or `tip_boost_per_item`?");
let tip = tip_boost_per_item.saturating_mul((n_items - 1).unique_saturated_into());
let priority_with_tip = estimate_priority(1, tip);
const ERROR_MARGIN: TransactionPriority = 5; // 5%
if priority_with_boost.abs_diff(priority_with_tip).saturating_mul(100) /
priority_with_tip >
ERROR_MARGIN
{
panic!(
"The {param_name} value ({}) must be fixed to: {}",
priority_boost_per_item,
compute_priority_boost_per_item(
max_items,
tip_boost_per_item,
estimate_priority
),
);
}
}
}
/// Compute priority boost that we give to bridge transaction for every
/// additional bridge item.
#[cfg(feature = "integrity-test")]
fn compute_priority_boost_per_item<Balance>(
max_items: ItemCount,
tip_boost_per_item: Balance,
estimate_priority: impl Fn(ItemCount, Balance) -> TransactionPriority,
) -> TransactionPriority
where
ItemCount: UniqueSaturatedInto<Balance>,
Balance: FixedPointOperand + Zero,
{
// estimate priority of transaction that delivers one item and has large tip
let small_with_tip_priority =
estimate_priority(1, tip_boost_per_item.saturating_mul(max_items.saturated_into()));
// estimate priority of transaction that delivers maximal number of items, but has no tip
let large_without_tip_priority = estimate_priority(max_items, Zero::zero());
small_with_tip_priority
.saturating_sub(large_without_tip_priority)
.saturating_div(max_items - 1)
}
/// Computations, specific to bridge relay chains transactions.
pub mod per_relay_header {
use super::*;
use bp_header_pez_chain::{
max_expected_submit_finality_proof_arguments_size, ChainWithGrandpa,
};
use pezpallet_bridge_grandpa::WeightInfoExt;
/// Ensures that the value of `PriorityBoostPerHeader` matches the value of
/// `tip_boost_per_header`.
///
/// We want two transactions, `TX1` with `N` headers and `TX2` with `N+1` headers, have
/// almost the same priority if we'll add `tip_boost_per_header` tip to the `TX1`. We want
/// to be sure that if we add plain `PriorityBoostPerHeader` priority to `TX1`, the priority
/// will be close to `TX2` as well.
pub fn ensure_priority_boost_is_sane<Runtime, GrandpaInstance, PriorityBoostPerHeader>(
tip_boost_per_header: BalanceOf<Runtime>,
) where
Runtime:
pezpallet_transaction_payment::Config + pezpallet_bridge_grandpa::Config<GrandpaInstance>,
GrandpaInstance: 'static,
PriorityBoostPerHeader: Get<TransactionPriority>,
Runtime::RuntimeCall: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo>,
BalanceOf<Runtime>: Send + Sync + FixedPointOperand,
{
// the meaning of `max_items` here is different when comparing with message
// transactions - with messages we have a strict limit on maximal number of
// messages we can fit into a single transaction. With headers, current best
// header may be improved by any "number of items". But this number is only
// used to verify priority boost, so it should be fine to select this arbitrary
// value - it SHALL NOT affect any value, it just adds more tests for the value.
let maximal_improved_by = 4_096;
super::ensure_priority_boost_is_sane::<PriorityBoostPerHeader, BalanceOf<Runtime>>(
"PriorityBoostPerRelayHeader",
maximal_improved_by,
tip_boost_per_header,
|_n_headers, tip| {
estimate_relay_header_submit_transaction_priority::<Runtime, GrandpaInstance>(
tip,
)
},
);
}
/// Estimate relay header delivery transaction priority.
#[cfg(feature = "integrity-test")]
fn estimate_relay_header_submit_transaction_priority<Runtime, GrandpaInstance>(
tip: BalanceOf<Runtime>,
) -> TransactionPriority
where
Runtime:
pezpallet_transaction_payment::Config + pezpallet_bridge_grandpa::Config<GrandpaInstance>,
GrandpaInstance: 'static,
Runtime::RuntimeCall: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo>,
BalanceOf<Runtime>: Send + Sync + FixedPointOperand,
{
// just an estimation of extra transaction bytes that are added to every transaction
// (including signature, signed extensions extra and etc + in our case it includes
// all call arguments except the proof itself)
let base_tx_size = 512;
// let's say we are relaying largest relay chain headers
let tx_call_size = max_expected_submit_finality_proof_arguments_size::<
Runtime::BridgedChain,
>(true, Runtime::BridgedChain::MAX_AUTHORITIES_COUNT * 2 / 3 + 1);
// finally we are able to estimate transaction size and weight
let transaction_size = base_tx_size.saturating_add(tx_call_size);
let transaction_weight = <Runtime as ::pezpallet_bridge_grandpa::Config<
GrandpaInstance,
>>::WeightInfo::submit_finality_proof_weight(
Runtime::BridgedChain::MAX_AUTHORITIES_COUNT * 2 / 3 + 1,
Runtime::BridgedChain::REASONABLE_HEADERS_IN_JUSTIFICATION_ANCESTRY,
);
pezpallet_transaction_payment::ChargeTransactionPayment::<Runtime>::get_priority(
&DispatchInfo {
call_weight: transaction_weight,
extension_weight: Default::default(),
class: DispatchClass::Normal,
pays_fee: Pays::Yes,
},
transaction_size as _,
tip,
Zero::zero(),
)
}
}
/// Computations, specific to bridge teyrchains transactions.
pub mod per_teyrchain_header {
use super::*;
use pezbp_runtime::Teyrchain;
use pezpallet_bridge_teyrchains::WeightInfoExt;
/// Ensures that the value of `PriorityBoostPerHeader` matches the value of
/// `tip_boost_per_header`.
///
/// We want two transactions, `TX1` with `N` headers and `TX2` with `N+1` headers, have
/// almost the same priority if we'll add `tip_boost_per_header` tip to the `TX1`. We want
/// to be sure that if we add plain `PriorityBoostPerHeader` priority to `TX1`, the priority
/// will be close to `TX2` as well.
pub fn ensure_priority_boost_is_sane<
Runtime,
TeyrchainsInstance,
Para,
PriorityBoostPerHeader,
>(
tip_boost_per_header: BalanceOf<Runtime>,
) where
Runtime: pezpallet_transaction_payment::Config
+ pezpallet_bridge_teyrchains::Config<TeyrchainsInstance>,
TeyrchainsInstance: 'static,
Para: Teyrchain,
PriorityBoostPerHeader: Get<TransactionPriority>,
Runtime::RuntimeCall: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo>,
BalanceOf<Runtime>: Send + Sync + FixedPointOperand,
{
// the meaning of `max_items` here is different when comparing with message
// transactions - with messages we have a strict limit on maximal number of
// messages we can fit into a single transaction. With headers, current best
// header may be improved by any "number of items". But this number is only
// used to verify priority boost, so it should be fine to select this arbitrary
// value - it SHALL NOT affect any value, it just adds more tests for the value.
let maximal_improved_by = 4_096;
super::ensure_priority_boost_is_sane::<PriorityBoostPerHeader, BalanceOf<Runtime>>(
"PriorityBoostPerTeyrchainHeader",
maximal_improved_by,
tip_boost_per_header,
|_n_headers, tip| {
estimate_teyrchain_header_submit_transaction_priority::<
Runtime,
TeyrchainsInstance,
Para,
>(tip)
},
);
}
/// Estimate teyrchain header delivery transaction priority.
#[cfg(feature = "integrity-test")]
fn estimate_teyrchain_header_submit_transaction_priority<
Runtime,
TeyrchainsInstance,
Para,
>(
tip: BalanceOf<Runtime>,
) -> TransactionPriority
where
Runtime: pezpallet_transaction_payment::Config
+ pezpallet_bridge_teyrchains::Config<TeyrchainsInstance>,
TeyrchainsInstance: 'static,
Para: Teyrchain,
Runtime::RuntimeCall: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo>,
BalanceOf<Runtime>: Send + Sync + FixedPointOperand,
{
// just an estimation of extra transaction bytes that are added to every transaction
// (including signature, signed extensions extra and etc + in our case it includes
// all call arguments except the proof itself)
let base_tx_size = 512;
// let's say we are relaying largest teyrchain headers and proof takes some more bytes
let tx_call_size = <Runtime as pezpallet_bridge_teyrchains::Config<
TeyrchainsInstance,
>>::WeightInfo::expected_extra_storage_proof_size()
.saturating_add(Para::MAX_HEADER_SIZE);
// finally we are able to estimate transaction size and weight
let transaction_size = base_tx_size.saturating_add(tx_call_size);
let transaction_weight = <Runtime as pezpallet_bridge_teyrchains::Config<
TeyrchainsInstance,
>>::WeightInfo::submit_teyrchain_heads_weight(
Runtime::DbWeight::get(),
&PreComputedSize(transaction_size as _),
// just one teyrchain - all other submissions won't receive any boost
1,
);
pezpallet_transaction_payment::ChargeTransactionPayment::<Runtime>::get_priority(
&DispatchInfo {
call_weight: transaction_weight,
extension_weight: Default::default(),
class: DispatchClass::Normal,
pays_fee: Pays::Yes,
},
transaction_size as _,
tip,
Zero::zero(),
)
}
}
/// Computations, specific to bridge messages transactions.
pub mod per_message {
use super::*;
use bp_messages::ChainWithMessages;
use pezpallet_bridge_messages::WeightInfoExt;
/// Ensures that the value of `PriorityBoostPerMessage` matches the value of
/// `tip_boost_per_message`.
///
/// We want two transactions, `TX1` with `N` messages and `TX2` with `N+1` messages, have
/// almost the same priority if we'll add `tip_boost_per_message` tip to the `TX1`. We want
/// to be sure that if we add plain `PriorityBoostPerMessage` priority to `TX1`, the
/// priority will be close to `TX2` as well.
pub fn ensure_priority_boost_is_sane<Runtime, MessagesInstance, PriorityBoostPerMessage>(
tip_boost_per_message: BalanceOf<Runtime>,
) where
Runtime: pezpallet_transaction_payment::Config
+ pezpallet_bridge_messages::Config<MessagesInstance>,
MessagesInstance: 'static,
PriorityBoostPerMessage: Get<TransactionPriority>,
Runtime::RuntimeCall: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo>,
BalanceOf<Runtime>: Send + Sync + FixedPointOperand,
{
let maximal_messages_in_delivery_transaction =
Runtime::BridgedChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX;
super::ensure_priority_boost_is_sane::<PriorityBoostPerMessage, BalanceOf<Runtime>>(
"PriorityBoostPerMessage",
maximal_messages_in_delivery_transaction,
tip_boost_per_message,
|n_messages, tip| {
estimate_message_delivery_transaction_priority::<Runtime, MessagesInstance>(
n_messages, tip,
)
},
);
}
/// Estimate message delivery transaction priority.
#[cfg(feature = "integrity-test")]
fn estimate_message_delivery_transaction_priority<Runtime, MessagesInstance>(
messages: MessageNonce,
tip: BalanceOf<Runtime>,
) -> TransactionPriority
where
Runtime: pezpallet_transaction_payment::Config
+ pezpallet_bridge_messages::Config<MessagesInstance>,
MessagesInstance: 'static,
Runtime::RuntimeCall: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo>,
BalanceOf<Runtime>: Send + Sync + FixedPointOperand,
{
// just an estimation of extra transaction bytes that are added to every transaction
// (including signature, signed extensions extra and etc + in our case it includes
// all call arguments except the proof itself)
let base_tx_size = 512;
// let's say we are relaying similar small messages and for every message we add more
// trie nodes to the proof (x0.5 because we expect some nodes to be reused)
let estimated_message_size = 512;
// let's say all our messages have the same dispatch weight
let estimated_message_dispatch_weight = <Runtime as pezpallet_bridge_messages::Config<
MessagesInstance,
>>::WeightInfo::message_dispatch_weight(
estimated_message_size
);
// messages proof argument size is (for every message) messages size + some additional
// trie nodes. Some of them are reused by different messages, so let's take 2/3 of
// default "overhead" constant
let messages_proof_size = <Runtime as pezpallet_bridge_messages::Config<
MessagesInstance,
>>::WeightInfo::expected_extra_storage_proof_size()
.saturating_mul(2)
.saturating_div(3)
.saturating_add(estimated_message_size)
.saturating_mul(messages as _);
// finally we are able to estimate transaction size and weight
let transaction_size = base_tx_size.saturating_add(messages_proof_size);
let transaction_weight = <Runtime as pezpallet_bridge_messages::Config<
MessagesInstance,
>>::WeightInfo::receive_messages_proof_weight(
&PreComputedSize(transaction_size as _),
messages as _,
estimated_message_dispatch_weight.saturating_mul(messages),
);
pezpallet_transaction_payment::ChargeTransactionPayment::<Runtime>::get_priority(
&DispatchInfo {
call_weight: transaction_weight,
extension_weight: Default::default(),
class: DispatchClass::Normal,
pays_fee: Pays::Yes,
},
transaction_size as _,
tip,
Zero::zero(),
)
}
}
}
@@ -0,0 +1,188 @@
// 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/>.
//! Adapter that allows using `pezpallet-bridge-relayers` as a signed extension in the
//! bridge with remote teyrchain.
use crate::{
extension::{
grandpa_adapter::verify_submit_finality_proof_succeeded, verify_messages_call_succeeded,
},
Config as BridgeRelayersConfig, LOG_TARGET,
};
use bp_relayers::{BatchCallUnpacker, ExtensionCallData, ExtensionCallInfo, ExtensionConfig};
use pezbp_runtime::{StaticStrProvider, Teyrchain};
use core::marker::PhantomData;
use pezframe_support::dispatch::{DispatchInfo, PostDispatchInfo};
use pezframe_system::Config as SystemConfig;
use pezpallet_bridge_grandpa::{
CallSubType as BridgeGrandpaCallSubtype, Config as BridgeGrandpaConfig,
};
use pezpallet_bridge_messages::{
CallSubType as BridgeMessagesCallSubType, Config as BridgeMessagesConfig, LaneIdOf,
};
use pezpallet_bridge_teyrchains::{
CallSubType as BridgeTeyrchainsCallSubtype, Config as BridgeTeyrchainsConfig,
SubmitTeyrchainHeadsHelper,
};
use pezsp_runtime::{
traits::{Dispatchable, Get},
transaction_validity::{TransactionPriority, TransactionValidityError},
};
/// Adapter to be used in signed extension configuration, when bridging with remote teyrchains.
pub struct WithTeyrchainExtensionConfig<
// signed extension identifier
IdProvider,
// runtime that implements `BridgeMessagesConfig<BridgeMessagesPalletInstance>`, which
// uses `BridgeTeyrchainsConfig<BridgeTeyrchainsPalletInstance>` to receive messages and
// confirmations from the remote chain.
Runtime,
// batch call unpacker
BatchCallUnpacker,
// instance of the `pezpallet-bridge-teyrchains`, tracked by this extension
BridgeTeyrchainsPalletInstance,
// instance of BridgedChain `pezpallet-bridge-messages`, tracked by this extension
BridgeMessagesPalletInstance,
// instance of `pezpallet-bridge-relayers`, tracked by this extension
BridgeRelayersPalletInstance,
// message delivery transaction priority boost for every additional message
PriorityBoostPerMessage,
>(
PhantomData<(
IdProvider,
Runtime,
BatchCallUnpacker,
BridgeTeyrchainsPalletInstance,
BridgeMessagesPalletInstance,
BridgeRelayersPalletInstance,
PriorityBoostPerMessage,
)>,
);
impl<ID, R, BCU, PI, MI, RI, P> ExtensionConfig
for WithTeyrchainExtensionConfig<ID, R, BCU, PI, MI, RI, P>
where
ID: StaticStrProvider,
R: BridgeRelayersConfig<RI>
+ BridgeMessagesConfig<MI>
+ BridgeTeyrchainsConfig<PI>
+ BridgeGrandpaConfig<R::BridgesGrandpaPalletInstance>,
BCU: BatchCallUnpacker<R>,
PI: 'static,
MI: 'static,
RI: 'static,
P: Get<TransactionPriority>,
R::RuntimeCall: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo>
+ BridgeGrandpaCallSubtype<R, R::BridgesGrandpaPalletInstance>
+ BridgeTeyrchainsCallSubtype<R, PI>
+ BridgeMessagesCallSubType<R, MI>,
<R as BridgeMessagesConfig<MI>>::BridgedChain: Teyrchain,
{
type IdProvider = ID;
type Runtime = R;
type BridgeMessagesPalletInstance = MI;
type BridgeRelayersPalletInstance = RI;
type PriorityBoostPerMessage = P;
type RemoteGrandpaChainBlockNumber =
pezpallet_bridge_grandpa::BridgedBlockNumber<R, R::BridgesGrandpaPalletInstance>;
type LaneId = LaneIdOf<R, Self::BridgeMessagesPalletInstance>;
fn parse_and_check_for_obsolete_call(
call: &R::RuntimeCall,
) -> Result<
Option<ExtensionCallInfo<Self::RemoteGrandpaChainBlockNumber, Self::LaneId>>,
TransactionValidityError,
> {
let calls = BCU::unpack(call, 3);
let total_calls = calls.len();
let mut calls = calls.into_iter().map(Self::check_obsolete_parsed_call).rev();
let msgs_call = calls.next().transpose()?.and_then(|c| c.call_info());
let para_finality_call = calls.next().transpose()?.and_then(|c| {
let r = c.submit_teyrchain_heads_info_for(
<R as BridgeMessagesConfig<Self::BridgeMessagesPalletInstance>>::BridgedChain::TEYRCHAIN_ID,
);
r
});
let relay_finality_call =
calls.next().transpose()?.and_then(|c| c.submit_finality_proof_info());
Ok(match (total_calls, relay_finality_call, para_finality_call, msgs_call) {
(3, Some(relay_finality_call), Some(para_finality_call), Some(msgs_call)) =>
Some(ExtensionCallInfo::AllFinalityAndMsgs(
relay_finality_call,
para_finality_call,
msgs_call,
)),
(2, None, Some(para_finality_call), Some(msgs_call)) =>
Some(ExtensionCallInfo::TeyrchainFinalityAndMsgs(para_finality_call, msgs_call)),
(1, None, None, Some(msgs_call)) => Some(ExtensionCallInfo::Msgs(msgs_call)),
_ => None,
})
}
fn check_obsolete_parsed_call(
call: &R::RuntimeCall,
) -> Result<&R::RuntimeCall, TransactionValidityError> {
call.check_obsolete_submit_finality_proof()?;
call.check_obsolete_submit_teyrchain_heads()?;
call.check_obsolete_call()?;
Ok(call)
}
fn check_call_result(
call_info: &ExtensionCallInfo<Self::RemoteGrandpaChainBlockNumber, Self::LaneId>,
call_data: &mut ExtensionCallData,
relayer: &R::AccountId,
) -> bool {
verify_submit_finality_proof_succeeded::<Self, R::BridgesGrandpaPalletInstance>(
call_info, call_data, relayer,
) && verify_submit_teyrchain_head_succeeded::<Self, PI>(call_info, call_data, relayer) &&
verify_messages_call_succeeded::<Self>(call_info, call_data, relayer)
}
}
/// If the batch call contains the teyrchain state update call, verify that it
/// has been successful.
///
/// Only returns false when teyrchain state update call has failed.
pub(crate) fn verify_submit_teyrchain_head_succeeded<C, PI>(
call_info: &ExtensionCallInfo<C::RemoteGrandpaChainBlockNumber, C::LaneId>,
_call_data: &mut ExtensionCallData,
relayer: &<C::Runtime as SystemConfig>::AccountId,
) -> bool
where
C: ExtensionConfig,
PI: 'static,
C::Runtime: BridgeTeyrchainsConfig<PI>,
{
let Some(para_proof_info) = call_info.submit_teyrchain_heads_info() else { return true };
if !SubmitTeyrchainHeadsHelper::<C::Runtime, PI>::was_successful(para_proof_info) {
// we only refund relayer if all calls have updated chain state
tracing::trace!(
target: LOG_TARGET,
id_provider=%C::IdProvider::STR,
lane_id=?call_info.messages_call_info().lane_id(),
?relayer,
"Relayer has submitted invalid teyrchain finality proof"
);
return false;
}
true
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,451 @@
// 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 module that is responsible for migration of storage.
use alloc::vec::Vec;
use pezframe_support::{
traits::{Get, StorageVersion},
weights::Weight,
};
/// The in-code storage version.
pub const STORAGE_VERSION: StorageVersion = StorageVersion::new(2);
/// This module contains data structures that are valid for the initial state of `0`.
/// (used with v1 migration).
pub mod v0 {
use crate::{Config, Pezpallet};
use bp_relayers::RewardsAccountOwner;
use pezbp_runtime::{ChainId, StorageDoubleMapKeyProvider};
use codec::{Codec, Decode, Encode, EncodeLike, MaxEncodedLen};
use core::marker::PhantomData;
use pezframe_support::{pezpallet_prelude::OptionQuery, Blake2_128Concat, Identity};
use scale_info::TypeInfo;
use pezsp_runtime::traits::AccountIdConversion;
/// Structure used to identify the account that pays a reward to the relayer.
#[derive(Copy, Clone, Debug, Decode, Encode, Eq, PartialEq, TypeInfo, MaxEncodedLen)]
pub struct RewardsAccountParams<LaneId> {
/// lane_id
pub lane_id: LaneId,
/// bridged_chain_id
pub bridged_chain_id: ChainId,
/// owner
pub owner: RewardsAccountOwner,
}
impl<LaneId: Decode + Encode> RewardsAccountParams<LaneId> {
/// Create a new instance of `RewardsAccountParams`.
pub const fn new(
lane_id: LaneId,
bridged_chain_id: ChainId,
owner: RewardsAccountOwner,
) -> Self {
Self { lane_id, bridged_chain_id, owner }
}
}
impl<LaneId> pezsp_runtime::TypeId for RewardsAccountParams<LaneId> {
const TYPE_ID: [u8; 4] = *b"brap";
}
pub(crate) struct RelayerRewardsKeyProvider<AccountId, RewardBalance, LaneId>(
PhantomData<(AccountId, RewardBalance, LaneId)>,
);
impl<AccountId, RewardBalance, LaneId> StorageDoubleMapKeyProvider
for RelayerRewardsKeyProvider<AccountId, RewardBalance, LaneId>
where
AccountId: 'static + Codec + EncodeLike + Send + Sync,
RewardBalance: 'static + Codec + EncodeLike + Send + Sync,
LaneId: Codec + EncodeLike + Send + Sync,
{
const MAP_NAME: &'static str = "RelayerRewards";
type Hasher1 = Blake2_128Concat;
type Key1 = AccountId;
type Hasher2 = Identity;
type Key2 = RewardsAccountParams<LaneId>;
type Value = RewardBalance;
}
pub(crate) type RelayerRewardsKeyProviderOf<T, I, LaneId> = RelayerRewardsKeyProvider<
<T as pezframe_system::Config>::AccountId,
<T as Config<I>>::RewardBalance,
LaneId,
>;
#[pezframe_support::storage_alias]
pub(crate) type RelayerRewards<T: Config<I>, I: 'static, LaneId> = StorageDoubleMap<
Pezpallet<T, I>,
<RelayerRewardsKeyProviderOf<T, I, LaneId> as StorageDoubleMapKeyProvider>::Hasher1,
<RelayerRewardsKeyProviderOf<T, I, LaneId> as StorageDoubleMapKeyProvider>::Key1,
<RelayerRewardsKeyProviderOf<T, I, LaneId> as StorageDoubleMapKeyProvider>::Hasher2,
<RelayerRewardsKeyProviderOf<T, I, LaneId> as StorageDoubleMapKeyProvider>::Key2,
<RelayerRewardsKeyProviderOf<T, I, LaneId> as StorageDoubleMapKeyProvider>::Value,
OptionQuery,
>;
/// Reward account generator for `v0`.
pub struct PayRewardFromAccount<Account, LaneId>(PhantomData<(Account, LaneId)>);
impl<Account, LaneId> PayRewardFromAccount<Account, LaneId>
where
Account: Decode + Encode,
LaneId: Decode + Encode,
{
/// Return account that pays rewards based on the provided parameters.
pub fn rewards_account(params: RewardsAccountParams<LaneId>) -> Account {
params.into_sub_account_truncating(b"rewards-account")
}
}
}
/// This migration updates `RelayerRewards` where `RewardsAccountParams` was used as the key with
/// `lane_id` as the first attribute, which affects `into_sub_account_truncating`. We are migrating
/// this key to use the new `RewardsAccountParams` where `lane_id` is the last attribute.
pub mod v1 {
use super::*;
use crate::{Config, Pezpallet};
use bp_messages::LaneIdType;
use bp_relayers::RewardsAccountParams;
use pezbp_runtime::StorageDoubleMapKeyProvider;
use codec::{Codec, EncodeLike};
use core::marker::PhantomData;
use pezframe_support::{
pezpallet_prelude::OptionQuery, traits::UncheckedOnRuntimeUpgrade, Blake2_128Concat, Identity,
};
use pezsp_arithmetic::traits::Zero;
pub(crate) struct RelayerRewardsKeyProvider<AccountId, RewardBalance, LaneId>(
PhantomData<(AccountId, RewardBalance, LaneId)>,
);
impl<AccountId, RewardBalance, LaneId> StorageDoubleMapKeyProvider
for RelayerRewardsKeyProvider<AccountId, RewardBalance, LaneId>
where
AccountId: 'static + Codec + EncodeLike + Send + Sync,
RewardBalance: 'static + Codec + EncodeLike + Send + Sync,
LaneId: Codec + EncodeLike + Send + Sync,
{
const MAP_NAME: &'static str = "RelayerRewards";
type Hasher1 = Blake2_128Concat;
type Key1 = AccountId;
type Hasher2 = Identity;
type Key2 = v1::RewardsAccountParams<LaneId>;
type Value = RewardBalance;
}
pub(crate) type RelayerRewardsKeyProviderOf<T, I, LaneId> = RelayerRewardsKeyProvider<
<T as pezframe_system::Config>::AccountId,
<T as Config<I>>::RewardBalance,
LaneId,
>;
#[pezframe_support::storage_alias]
pub(crate) type RelayerRewards<T: Config<I>, I: 'static, LaneId> = StorageDoubleMap<
Pezpallet<T, I>,
<RelayerRewardsKeyProviderOf<T, I, LaneId> as StorageDoubleMapKeyProvider>::Hasher1,
<RelayerRewardsKeyProviderOf<T, I, LaneId> as StorageDoubleMapKeyProvider>::Key1,
<RelayerRewardsKeyProviderOf<T, I, LaneId> as StorageDoubleMapKeyProvider>::Hasher2,
<RelayerRewardsKeyProviderOf<T, I, LaneId> as StorageDoubleMapKeyProvider>::Key2,
<RelayerRewardsKeyProviderOf<T, I, LaneId> as StorageDoubleMapKeyProvider>::Value,
OptionQuery,
>;
// Copy of `Pezpallet::<T, I>::register_relayer_reward` compatible with v1.
fn register_relayer_reward_for_v1<
T: Config<I>,
I: 'static,
LaneId: LaneIdType + Send + Sync,
>(
rewards_account_params: v1::RewardsAccountParams<LaneId>,
relayer: &T::AccountId,
reward_balance: T::RewardBalance,
) {
use pezsp_runtime::Saturating;
if reward_balance.is_zero() {
return;
}
v1::RelayerRewards::<T, I, LaneId>::mutate(
relayer,
rewards_account_params,
|old_reward: &mut Option<T::RewardBalance>| {
let new_reward =
old_reward.unwrap_or_else(Zero::zero).saturating_add(reward_balance);
*old_reward = Some(new_reward);
tracing::trace!(
target: crate::LOG_TARGET,
?relayer,
?rewards_account_params,
?new_reward,
"Relayer can now claim reward"
);
},
);
}
/// Migrates the pezpallet storage to v1.
pub struct UncheckedMigrationV0ToV1<T, I, LaneId>(PhantomData<(T, I, LaneId)>);
#[cfg(feature = "try-runtime")]
const LOG_TARGET: &str = "runtime::bridge-relayers-migration";
impl<T: Config<I>, I: 'static, LaneId: LaneIdType + Send + Sync> UncheckedOnRuntimeUpgrade
for UncheckedMigrationV0ToV1<T, I, LaneId>
{
fn on_runtime_upgrade() -> Weight {
let mut weight = T::DbWeight::get().reads(1);
// list all rewards (we cannot do this as one step because of `drain` limitation)
let mut rewards_to_migrate =
Vec::with_capacity(v0::RelayerRewards::<T, I, LaneId>::iter().count());
for (key1, key2, reward) in v0::RelayerRewards::<T, I, LaneId>::drain() {
rewards_to_migrate.push((key1, key2, reward));
weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1));
}
// re-register rewards with new format of `RewardsAccountParams`.
for (key1, key2, reward) in rewards_to_migrate {
// expand old key
let v0::RewardsAccountParams { owner, lane_id, bridged_chain_id } = key2;
// re-register reward
register_relayer_reward_for_v1::<T, I, LaneId>(
v1::RewardsAccountParams::new(lane_id, bridged_chain_id, owner),
&key1,
reward,
);
weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1));
}
weight
}
#[cfg(feature = "try-runtime")]
fn pre_upgrade() -> Result<Vec<u8>, pezsp_runtime::DispatchError> {
use codec::Encode;
use pezframe_support::BoundedBTreeMap;
use pezsp_runtime::traits::ConstU32;
// collect actual rewards
let mut rewards: BoundedBTreeMap<
(T::AccountId, LaneId),
T::RewardBalance,
ConstU32<{ u32::MAX }>,
> = BoundedBTreeMap::new();
for (key1, key2, reward) in v0::RelayerRewards::<T, I, LaneId>::iter() {
tracing::info!(target: LOG_TARGET, ?key1, ?key2, ?reward, "Reward to migrate");
rewards = rewards
.try_mutate(|inner| {
inner
.entry((key1.clone(), key2.lane_id))
.and_modify(|value| *value += reward)
.or_insert(reward);
})
.unwrap();
}
tracing::info!(target: LOG_TARGET, ?rewards, "Found total rewards to migrate");
Ok(rewards.encode())
}
#[cfg(feature = "try-runtime")]
fn post_upgrade(state: Vec<u8>) -> Result<(), pezsp_runtime::DispatchError> {
use codec::Decode;
use pezframe_support::BoundedBTreeMap;
use pezsp_runtime::traits::ConstU32;
let rewards_before: BoundedBTreeMap<
(T::AccountId, LaneId),
T::RewardBalance,
ConstU32<{ u32::MAX }>,
> = Decode::decode(&mut &state[..]).unwrap();
// collect migrated rewards
let mut rewards_after: BoundedBTreeMap<
(T::AccountId, LaneId),
T::RewardBalance,
ConstU32<{ u32::MAX }>,
> = BoundedBTreeMap::new();
for (key1, key2, reward) in v1::RelayerRewards::<T, I, LaneId>::iter() {
tracing::info!(target: LOG_TARGET, ?key1, ?key2, ?reward, "Migrated rewards");
rewards_after = rewards_after
.try_mutate(|inner| {
inner
.entry((key1.clone(), *key2.lane_id()))
.and_modify(|value| *value += reward)
.or_insert(reward);
})
.unwrap();
}
tracing::info!(target: LOG_TARGET, ?rewards_after, "Found total migrated rewards");
pezframe_support::ensure!(
rewards_before == rewards_after,
"The rewards were not migrated correctly!."
);
tracing::info!(target: LOG_TARGET, "migrated all.");
Ok(())
}
}
/// [`UncheckedMigrationV0ToV1`] wrapped in a
/// [`VersionedMigration`](pezframe_support::migrations::VersionedMigration), ensuring the
/// migration is only performed when on-chain version is 0.
pub type MigrationToV1<T, I, LaneId> = pezframe_support::migrations::VersionedMigration<
0,
1,
UncheckedMigrationV0ToV1<T, I, LaneId>,
Pezpallet<T, I>,
<T as pezframe_system::Config>::DbWeight,
>;
}
/// The pezpallet in version 1 only supported rewards collected under the key of
/// `RewardsAccountParams`. This migration essentially converts existing `RewardsAccountParams` keys
/// to the generic type `T::Reward`.
pub mod v2 {
use super::*;
#[cfg(feature = "try-runtime")]
use crate::RelayerRewards;
use crate::{Config, Pezpallet};
use bp_messages::LaneIdType;
use bp_relayers::RewardsAccountParams;
use core::marker::PhantomData;
use pezframe_support::traits::UncheckedOnRuntimeUpgrade;
/// Migrates the pezpallet storage to v2.
pub struct UncheckedMigrationV1ToV2<T, I, LaneId>(PhantomData<(T, I, LaneId)>);
#[cfg(feature = "try-runtime")]
const LOG_TARGET: &str = "runtime::bridge-relayers-migration";
impl<T: Config<I>, I: 'static, LaneId: LaneIdType + Send + Sync> UncheckedOnRuntimeUpgrade
for UncheckedMigrationV1ToV2<T, I, LaneId>
where
<T as Config<I>>::Reward: From<RewardsAccountParams<LaneId>>,
{
fn on_runtime_upgrade() -> Weight {
let mut weight = T::DbWeight::get().reads(1);
// list all rewards (we cannot do this as one step because of `drain` limitation)
let mut rewards_to_migrate =
Vec::with_capacity(v1::RelayerRewards::<T, I, LaneId>::iter().count());
for (key1, key2, reward) in v1::RelayerRewards::<T, I, LaneId>::drain() {
rewards_to_migrate.push((key1, key2, reward));
weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1));
}
// re-register rewards with new format.
for (key1, key2, reward) in rewards_to_migrate {
// convert old key to the new
let new_key2: T::Reward = key2.into();
// re-register reward (drained above)
Pezpallet::<T, I>::register_relayer_reward(new_key2, &key1, reward);
weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1));
}
weight
}
#[cfg(feature = "try-runtime")]
fn pre_upgrade() -> Result<Vec<u8>, pezsp_runtime::DispatchError> {
use codec::Encode;
use pezframe_support::BoundedBTreeMap;
use pezsp_runtime::traits::ConstU32;
// collect actual rewards
let mut rewards: BoundedBTreeMap<
(T::AccountId, Vec<u8>),
T::RewardBalance,
ConstU32<{ u32::MAX }>,
> = BoundedBTreeMap::new();
for (key1, key2, reward) in v1::RelayerRewards::<T, I, LaneId>::iter() {
let new_key2: T::Reward = key2.into();
tracing::info!(target: LOG_TARGET, ?key1, ?key2, ?new_key2, ?reward, "Reward to migrate");
rewards = rewards
.try_mutate(|inner| {
inner
.entry((key1.clone(), new_key2.encode()))
.and_modify(|value| *value += reward)
.or_insert(reward);
})
.unwrap();
}
tracing::info!(target: LOG_TARGET, ?rewards, "Found total rewards to migrate");
Ok(rewards.encode())
}
#[cfg(feature = "try-runtime")]
fn post_upgrade(state: Vec<u8>) -> Result<(), pezsp_runtime::DispatchError> {
use codec::{Decode, Encode};
use pezframe_support::BoundedBTreeMap;
use pezsp_runtime::traits::ConstU32;
let rewards_before: BoundedBTreeMap<
(T::AccountId, Vec<u8>),
T::RewardBalance,
ConstU32<{ u32::MAX }>,
> = Decode::decode(&mut &state[..]).unwrap();
// collect migrated rewards
let mut rewards_after: BoundedBTreeMap<
(T::AccountId, Vec<u8>),
T::RewardBalance,
ConstU32<{ u32::MAX }>,
> = BoundedBTreeMap::new();
for (key1, key2, reward) in v2::RelayerRewards::<T, I>::iter() {
tracing::info!(target: LOG_TARGET, ?key1, ?key2, ?reward, "Migrated rewards");
rewards_after = rewards_after
.try_mutate(|inner| {
inner
.entry((key1.clone(), key2.encode()))
.and_modify(|value| *value += reward)
.or_insert(reward);
})
.unwrap();
}
tracing::info!(target: LOG_TARGET, ?rewards_after, "Found total migrated rewards");
pezframe_support::ensure!(
rewards_before == rewards_after,
"The rewards were not migrated correctly!."
);
tracing::info!(target: LOG_TARGET, "migrated all.");
Ok(())
}
}
/// [`UncheckedMigrationV1ToV2`] wrapped in a
/// [`VersionedMigration`](pezframe_support::migrations::VersionedMigration), ensuring the
/// migration is only performed when on-chain version is 1.
pub type MigrationToV2<T, I, LaneId> = pezframe_support::migrations::VersionedMigration<
1,
2,
UncheckedMigrationV1ToV2<T, I, LaneId>,
Pezpallet<T, I>,
<T as pezframe_system::Config>::DbWeight,
>;
}
+423
View File
@@ -0,0 +1,423 @@
// 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/>.
#![cfg(test)]
use crate as pezpallet_bridge_relayers;
use bp_header_pez_chain::ChainWithGrandpa;
use bp_messages::{
target_chain::{DispatchMessage, MessageDispatch},
ChainWithMessages, HashedLaneId, LaneIdType, MessageNonce,
};
use bp_relayers::{
PayRewardFromAccount, PaymentProcedure, RewardsAccountOwner, RewardsAccountParams,
};
use pezbp_runtime::{messages::MessageDispatchResult, Chain, ChainId, Teyrchain};
use bp_teyrchains::SingleParaStoredHeaderDataBuilder;
use codec::Encode;
use pezframe_support::{
derive_impl, parameter_types,
traits::fungible::Mutate,
weights::{ConstantMultiplier, IdentityFee, RuntimeDbWeight, Weight},
};
use pezpallet_transaction_payment::Multiplier;
use pezsp_core::H256;
use pezsp_runtime::{
traits::{BlakeTwo256, ConstU32, ConstU64, ConstU8},
BuildStorage, 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;
/// 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>;
/// 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;
/// 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 = u64;
/// 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 BridgedUnderlyingTeyrchain;
impl Chain for BridgedUnderlyingTeyrchain {
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 BridgedUnderlyingTeyrchain {
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 BridgedUnderlyingTeyrchain {
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 Teyrchain for BridgedUnderlyingTeyrchain {
const TEYRCHAIN_ID: u32 = 42;
const MAX_HEADER_SIZE: u32 = 1_024;
}
pub type TestStakeAndSlash = pezpallet_bridge_relayers::StakeAndSlashNamed<
ThisChainAccountId,
ThisChainBlockNumber,
Balances,
ReserveId,
Stake,
Lease,
>;
pezframe_support::construct_runtime! {
pub enum TestRuntime
{
System: pezframe_system,
Utility: pezpallet_utility,
Balances: pezpallet_balances,
TransactionPayment: pezpallet_transaction_payment,
BridgeRelayers: pezpallet_bridge_relayers,
BridgeGrandpa: pezpallet_bridge_grandpa,
BridgeTeyrchains: pezpallet_bridge_teyrchains,
BridgeMessages: pezpallet_bridge_messages,
}
}
parameter_types! {
pub const BridgedParasPalletName: &'static str = "Paras";
pub const DbWeight: RuntimeDbWeight = RuntimeDbWeight { read: 1, write: 2 };
pub const ExistentialDeposit: ThisChainBalance = 1;
pub const ReserveId: [u8; 8] = *b"brdgrlrs";
pub const Stake: ThisChainBalance = 1_000;
pub const Lease: ThisChainBlockNumber = 8;
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();
}
#[derive_impl(pezframe_system::config_preludes::TestDefaultConfig)]
impl pezframe_system::Config for TestRuntime {
type Block = ThisChainBlock;
// TODO: remove when https://github.com/pezkuwichain/kurdistan-sdk/issues/120 merged
type BlockHashCount = ConstU32<10>;
type AccountData = pezpallet_balances::AccountData<ThisChainBalance>;
type DbWeight = DbWeight;
}
#[derive_impl(pezpallet_balances::config_preludes::TestDefaultConfig)]
impl pezpallet_balances::Config for TestRuntime {
type ReserveIdentifier = [u8; 8];
type AccountStore = System;
}
impl pezpallet_utility::Config for TestRuntime {
type RuntimeEvent = RuntimeEvent;
type RuntimeCall = RuntimeCall;
type PalletsOrigin = OriginCaller;
type WeightInfo = ();
}
#[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,
>;
type RuntimeEvent = RuntimeEvent;
}
impl pezpallet_bridge_grandpa::Config for TestRuntime {
type RuntimeEvent = RuntimeEvent;
type BridgedChain = BridgedUnderlyingTeyrchain;
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,
(),
(),
ConstU64<100_000>,
>;
type OnMessagesDelivered = ();
type MessageDispatch = DummyMessageDispatch;
type ThisChain = ThisUnderlyingChain;
type BridgedChain = BridgedUnderlyingTeyrchain;
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 = ();
}
#[cfg(feature = "runtime-benchmarks")]
impl pezpallet_bridge_relayers::benchmarking::Config for TestRuntime {
fn bench_reward() -> Self::Reward {
RewardsAccountParams::new(
TestLaneIdType::default(),
*b"test",
RewardsAccountOwner::ThisChain,
)
}
fn prepare_rewards_account(
account_params: RewardsAccountParams<TestLaneIdType>,
reward: Self::RewardBalance,
) -> Option<ThisChainAccountId> {
let rewards_account = PayRewardFromAccount::<
Balances,
ThisChainAccountId,
TestLaneIdType,
RewardBalance,
>::rewards_account(account_params);
Self::deposit_account(rewards_account, reward.into());
Some(REGULAR_RELAYER2)
}
fn deposit_account(account: Self::AccountId, balance: Self::Balance) {
pezframe_support::assert_ok!(Balances::mint_into(
&account,
balance.saturating_add(ExistentialDeposit::get())
));
}
}
/// Regular relayer that may receive rewards.
pub const REGULAR_RELAYER: ThisChainAccountId = 1;
/// Regular relayer that may receive rewards.
pub const REGULAR_RELAYER2: ThisChainAccountId = 3;
/// Relayer that can't receive rewards.
pub const FAILING_RELAYER: ThisChainAccountId = 2;
/// Relayer that is able to register.
pub const REGISTER_RELAYER: ThisChainAccountId = 42;
/// Payment procedure that rejects payments to the `FAILING_RELAYER`.
pub struct TestPaymentProcedure;
impl TestPaymentProcedure {
pub fn rewards_account(params: RewardsAccountParams<TestLaneIdType>) -> ThisChainAccountId {
PayRewardFromAccount::<(), ThisChainAccountId, TestLaneIdType, RewardBalance>::rewards_account(
params,
)
}
}
impl PaymentProcedure<ThisChainAccountId, RewardsAccountParams<TestLaneIdType>, RewardBalance>
for TestPaymentProcedure
{
type Error = ();
type Beneficiary = ThisChainAccountId;
fn pay_reward(
relayer: &ThisChainAccountId,
_reward_kind: RewardsAccountParams<TestLaneIdType>,
_reward: RewardBalance,
_beneficiary: Self::Beneficiary,
) -> Result<(), Self::Error> {
match *relayer {
FAILING_RELAYER => Err(()),
_ => Ok(()),
}
}
}
/// 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: () }
}
}
/// Reward account params that we are using in tests.
pub fn test_reward_account_param() -> RewardsAccountParams<TestLaneIdType> {
RewardsAccountParams::new(
TestLaneIdType::try_new(1, 2).unwrap(),
*b"test",
RewardsAccountOwner::ThisChain,
)
}
/// Return test externalities to use in tests.
pub fn new_test_ext() -> pezsp_io::TestExternalities {
let t = pezframe_system::GenesisConfig::<TestRuntime>::default().build_storage().unwrap();
pezsp_io::TestExternalities::new(t)
}
/// Run pezpallet test.
pub fn run_test<T>(test: impl FnOnce() -> T) -> T {
new_test_ext().execute_with(|| {
Balances::mint_into(&REGISTER_RELAYER, ExistentialDeposit::get() + 10 * Stake::get())
.unwrap();
test()
})
}
@@ -0,0 +1,226 @@
// 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/>.
//! Code that allows relayers pezpallet to be used as a payment mechanism for
//! the `pezpallet-bridge-messages` pezpallet using `RewardsAccountParams`.
use crate::{Config, Pezpallet};
use alloc::collections::vec_deque::VecDeque;
use bp_messages::{
source_chain::{DeliveryConfirmationPayments, RelayersRewards},
MessageNonce,
};
pub use bp_relayers::PayRewardFromAccount;
use bp_relayers::{RewardsAccountOwner, RewardsAccountParams};
use pezbp_runtime::Chain;
use core::{marker::PhantomData, ops::RangeInclusive};
use pezframe_support::{pezsp_runtime::SaturatedConversion, traits::Get};
use pezpallet_bridge_messages::LaneIdOf;
use pezsp_arithmetic::traits::{Saturating, Zero};
/// Adapter that allows relayers pezpallet to be used as a delivery+dispatch payment mechanism
/// for the `pezpallet-bridge-messages` pezpallet and using `RewardsAccountParams`.
pub struct DeliveryConfirmationPaymentsAdapter<T, MI, RI, DeliveryReward>(
PhantomData<(T, MI, RI, DeliveryReward)>,
);
impl<T, MI, RI, DeliveryReward> DeliveryConfirmationPayments<T::AccountId, LaneIdOf<T, MI>>
for DeliveryConfirmationPaymentsAdapter<T, MI, RI, DeliveryReward>
where
T: Config<RI> + pezpallet_bridge_messages::Config<MI>,
MI: 'static,
RI: 'static,
DeliveryReward: Get<T::RewardBalance>,
<T as Config<RI>>::Reward: From<RewardsAccountParams<LaneIdOf<T, MI>>>,
{
type Error = &'static str;
fn pay_reward(
lane_id: LaneIdOf<T, MI>,
pez_messages_relayers: VecDeque<bp_messages::UnrewardedRelayer<T::AccountId>>,
confirmation_relayer: &T::AccountId,
received_range: &RangeInclusive<bp_messages::MessageNonce>,
) -> MessageNonce {
let relayers_rewards =
bp_messages::calc_relayers_rewards::<T::AccountId>(pez_messages_relayers, received_range);
let rewarded_relayers = relayers_rewards.len();
register_relayers_rewards::<T, RI, MI>(
confirmation_relayer,
relayers_rewards,
RewardsAccountParams::new(
lane_id,
T::BridgedChain::ID,
RewardsAccountOwner::BridgedChain,
),
DeliveryReward::get(),
);
rewarded_relayers as _
}
}
// Update rewards to given relayers, optionally rewarding confirmation relayer.
fn register_relayers_rewards<
T: Config<RI> + pezpallet_bridge_messages::Config<MI>,
RI: 'static,
MI: 'static,
>(
confirmation_relayer: &T::AccountId,
relayers_rewards: RelayersRewards<T::AccountId>,
lane_id: RewardsAccountParams<LaneIdOf<T, MI>>,
delivery_fee: T::RewardBalance,
) where
<T as Config<RI>>::Reward: From<RewardsAccountParams<LaneIdOf<T, MI>>>,
{
// reward every relayer except `confirmation_relayer`
let mut confirmation_relayer_reward = T::RewardBalance::zero();
for (relayer, messages) in relayers_rewards {
// sane runtime configurations guarantee that the number of messages will be below
// `u32::MAX`
let relayer_reward =
T::RewardBalance::saturated_from(messages).saturating_mul(delivery_fee);
if relayer != *confirmation_relayer {
Pezpallet::<T, RI>::register_relayer_reward(lane_id.into(), &relayer, relayer_reward);
} else {
confirmation_relayer_reward =
confirmation_relayer_reward.saturating_add(relayer_reward);
}
}
// finally - pay reward to confirmation relayer
Pezpallet::<T, RI>::register_relayer_reward(
lane_id.into(),
confirmation_relayer,
confirmation_relayer_reward,
);
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{mock::*, RelayerRewards};
use bp_messages::LaneIdType;
use bp_relayers::PaymentProcedure;
use pezframe_support::{
assert_ok,
traits::fungible::{Inspect, Mutate},
};
const RELAYER_1: ThisChainAccountId = 1;
const RELAYER_2: ThisChainAccountId = 2;
const RELAYER_3: ThisChainAccountId = 3;
fn relayers_rewards() -> RelayersRewards<ThisChainAccountId> {
vec![(RELAYER_1, 2), (RELAYER_2, 3)].into_iter().collect()
}
#[test]
fn confirmation_relayer_is_rewarded_if_it_has_also_delivered_messages() {
run_test(|| {
register_relayers_rewards::<TestRuntime, (), ()>(
&RELAYER_2,
relayers_rewards(),
test_reward_account_param(),
50,
);
assert_eq!(
RelayerRewards::<TestRuntime>::get(RELAYER_1, test_reward_account_param()),
Some(100)
);
assert_eq!(
RelayerRewards::<TestRuntime>::get(RELAYER_2, test_reward_account_param()),
Some(150)
);
});
}
#[test]
fn confirmation_relayer_is_not_rewarded_if_it_has_not_delivered_any_messages() {
run_test(|| {
register_relayers_rewards::<TestRuntime, (), ()>(
&RELAYER_3,
relayers_rewards(),
test_reward_account_param(),
50,
);
assert_eq!(
RelayerRewards::<TestRuntime>::get(RELAYER_1, test_reward_account_param()),
Some(100)
);
assert_eq!(
RelayerRewards::<TestRuntime>::get(RELAYER_2, test_reward_account_param()),
Some(150)
);
assert_eq!(
RelayerRewards::<TestRuntime>::get(RELAYER_3, test_reward_account_param()),
None
);
});
}
#[test]
fn pay_reward_from_account_actually_pays_reward() {
type Balances = pezpallet_balances::Pezpallet<TestRuntime>;
type PayLaneRewardFromAccount =
PayRewardFromAccount<Balances, ThisChainAccountId, TestLaneIdType, RewardBalance>;
run_test(|| {
let in_lane_0 = RewardsAccountParams::new(
TestLaneIdType::try_new(1, 2).unwrap(),
*b"test",
RewardsAccountOwner::ThisChain,
);
let out_lane_1 = RewardsAccountParams::new(
TestLaneIdType::try_new(1, 3).unwrap(),
*b"test",
RewardsAccountOwner::BridgedChain,
);
let in_lane0_rewards_account = PayLaneRewardFromAccount::rewards_account(in_lane_0);
let out_lane1_rewards_account = PayLaneRewardFromAccount::rewards_account(out_lane_1);
assert_ok!(Balances::mint_into(&in_lane0_rewards_account, 200));
assert_ok!(Balances::mint_into(&out_lane1_rewards_account, 100));
assert_eq!(Balances::balance(&in_lane0_rewards_account), 200);
assert_eq!(Balances::balance(&out_lane1_rewards_account), 100);
assert_eq!(Balances::balance(&1), 0);
assert_eq!(Balances::balance(&2), 0);
assert_ok!(PayLaneRewardFromAccount::pay_reward(&1, in_lane_0, 100, 1_u64));
assert_eq!(Balances::balance(&in_lane0_rewards_account), 100);
assert_eq!(Balances::balance(&out_lane1_rewards_account), 100);
assert_eq!(Balances::balance(&1), 100);
assert_eq!(Balances::balance(&2), 0);
assert_ok!(PayLaneRewardFromAccount::pay_reward(&1, out_lane_1, 100, 1_u64));
assert_eq!(Balances::balance(&in_lane0_rewards_account), 100);
assert_eq!(Balances::balance(&out_lane1_rewards_account), 0);
assert_eq!(Balances::balance(&1), 200);
assert_eq!(Balances::balance(&2), 0);
assert_ok!(PayLaneRewardFromAccount::pay_reward(&1, in_lane_0, 100, 2_u64));
assert_eq!(Balances::balance(&in_lane0_rewards_account), 0);
assert_eq!(Balances::balance(&out_lane1_rewards_account), 0);
assert_eq!(Balances::balance(&1), 200);
assert_eq!(Balances::balance(&2), 100);
});
}
}
@@ -0,0 +1,203 @@
// 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/>.
//! Code that allows `NamedReservableCurrency` to be used as a `StakeAndSlash`
//! mechanism of the relayers pezpallet.
use bp_relayers::StakeAndSlash;
use codec::Codec;
use core::{fmt::Debug, marker::PhantomData};
use pezframe_support::traits::{tokens::BalanceStatus, NamedReservableCurrency};
use pezsp_runtime::{traits::Get, DispatchError, DispatchResult};
/// `StakeAndSlash` that works with `NamedReservableCurrency` and uses named
/// reservations.
///
/// **WARNING**: this implementation assumes that the relayers pezpallet is configured to
/// use the [`bp_relayers::PayRewardFromAccount`] as its relayers payment scheme.
pub struct StakeAndSlashNamed<AccountId, BlockNumber, Currency, ReserveId, Stake, Lease>(
PhantomData<(AccountId, BlockNumber, Currency, ReserveId, Stake, Lease)>,
);
impl<AccountId, BlockNumber, Currency, ReserveId, Stake, Lease>
StakeAndSlash<AccountId, BlockNumber, Currency::Balance>
for StakeAndSlashNamed<AccountId, BlockNumber, Currency, ReserveId, Stake, Lease>
where
AccountId: Codec + Debug,
Currency: NamedReservableCurrency<AccountId>,
ReserveId: Get<Currency::ReserveIdentifier>,
Stake: Get<Currency::Balance>,
Lease: Get<BlockNumber>,
{
type RequiredStake = Stake;
type RequiredRegistrationLease = Lease;
fn reserve(relayer: &AccountId, amount: Currency::Balance) -> DispatchResult {
Currency::reserve_named(&ReserveId::get(), relayer, amount)
}
fn unreserve(relayer: &AccountId, amount: Currency::Balance) -> Currency::Balance {
Currency::unreserve_named(&ReserveId::get(), relayer, amount)
}
fn repatriate_reserved(
relayer: &AccountId,
beneficiary: &AccountId,
amount: Currency::Balance,
) -> Result<Currency::Balance, DispatchError> {
Currency::repatriate_reserved_named(
&ReserveId::get(),
relayer,
&beneficiary,
amount,
BalanceStatus::Free,
)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::mock::*;
use bp_relayers::ExplicitOrAccountParams;
use pezframe_support::traits::fungible::Mutate;
use pezsp_runtime::traits::IdentifyAccount;
fn test_stake() -> ThisChainBalance {
Stake::get()
}
#[test]
fn reserve_works() {
run_test(|| {
assert!(TestStakeAndSlash::reserve(&1, test_stake()).is_err());
assert_eq!(Balances::free_balance(1), 0);
assert_eq!(Balances::reserved_balance(1), 0);
Balances::mint_into(&2, test_stake() - 1).unwrap();
assert!(TestStakeAndSlash::reserve(&2, test_stake()).is_err());
assert_eq!(Balances::free_balance(2), test_stake() - 1);
assert_eq!(Balances::reserved_balance(2), 0);
Balances::mint_into(&3, test_stake() * 2).unwrap();
assert_eq!(TestStakeAndSlash::reserve(&3, test_stake()), Ok(()));
assert_eq!(Balances::free_balance(3), test_stake());
assert_eq!(Balances::reserved_balance(3), test_stake());
})
}
#[test]
fn unreserve_works() {
run_test(|| {
assert_eq!(TestStakeAndSlash::unreserve(&1, test_stake()), test_stake());
assert_eq!(Balances::free_balance(1), 0);
assert_eq!(Balances::reserved_balance(1), 0);
Balances::mint_into(&2, test_stake() * 2).unwrap();
TestStakeAndSlash::reserve(&2, test_stake() / 3).unwrap();
assert_eq!(
TestStakeAndSlash::unreserve(&2, test_stake()),
test_stake() - test_stake() / 3
);
assert_eq!(Balances::free_balance(2), test_stake() * 2);
assert_eq!(Balances::reserved_balance(2), 0);
Balances::mint_into(&3, test_stake() * 2).unwrap();
TestStakeAndSlash::reserve(&3, test_stake()).unwrap();
assert_eq!(TestStakeAndSlash::unreserve(&3, test_stake()), 0);
assert_eq!(Balances::free_balance(3), test_stake() * 2);
assert_eq!(Balances::reserved_balance(3), 0);
})
}
#[test]
fn repatriate_reserved_works() {
run_test(|| {
let beneficiary = test_reward_account_param();
let beneficiary_account = TestPaymentProcedure::rewards_account(beneficiary);
let mut expected_balance = ExistentialDeposit::get();
Balances::mint_into(&beneficiary_account, expected_balance).unwrap();
assert_eq!(
TestStakeAndSlash::repatriate_reserved(
&1,
&(ExplicitOrAccountParams::Params(beneficiary).into_account()),
test_stake()
),
Ok(test_stake())
);
assert_eq!(Balances::free_balance(1), 0);
assert_eq!(Balances::reserved_balance(1), 0);
assert_eq!(Balances::free_balance(beneficiary_account), expected_balance);
assert_eq!(Balances::reserved_balance(beneficiary_account), 0);
expected_balance += test_stake() / 3;
Balances::mint_into(&2, test_stake() * 2).unwrap();
TestStakeAndSlash::reserve(&2, test_stake() / 3).unwrap();
assert_eq!(
TestStakeAndSlash::repatriate_reserved(
&2,
&(ExplicitOrAccountParams::Params(beneficiary).into_account()),
test_stake()
),
Ok(test_stake() - test_stake() / 3)
);
assert_eq!(Balances::free_balance(2), test_stake() * 2 - test_stake() / 3);
assert_eq!(Balances::reserved_balance(2), 0);
assert_eq!(Balances::free_balance(beneficiary_account), expected_balance);
assert_eq!(Balances::reserved_balance(beneficiary_account), 0);
expected_balance += test_stake();
Balances::mint_into(&3, test_stake() * 2).unwrap();
TestStakeAndSlash::reserve(&3, test_stake()).unwrap();
assert_eq!(
TestStakeAndSlash::repatriate_reserved(
&3,
&(ExplicitOrAccountParams::Params(beneficiary).into_account()),
test_stake()
),
Ok(0)
);
assert_eq!(Balances::free_balance(3), test_stake());
assert_eq!(Balances::reserved_balance(3), 0);
assert_eq!(Balances::free_balance(beneficiary_account), expected_balance);
assert_eq!(Balances::reserved_balance(beneficiary_account), 0);
})
}
#[test]
fn repatriate_reserved_doesnt_work_when_beneficiary_account_is_missing() {
run_test(|| {
let beneficiary = test_reward_account_param();
let beneficiary_account = TestPaymentProcedure::rewards_account(beneficiary);
Balances::mint_into(&3, test_stake() * 2).unwrap();
TestStakeAndSlash::reserve(&3, test_stake()).unwrap();
assert!(TestStakeAndSlash::repatriate_reserved(
&3,
&(ExplicitOrAccountParams::Params(beneficiary).into_account()),
test_stake()
)
.is_err());
assert_eq!(Balances::free_balance(3), test_stake());
assert_eq!(Balances::reserved_balance(3), test_stake());
assert_eq!(Balances::free_balance(beneficiary_account), 0);
assert_eq!(Balances::reserved_balance(beneficiary_account), 0);
});
}
}
+306
View File
@@ -0,0 +1,306 @@
// 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/>.
//! Autogenerated weights for pezpallet_bridge_relayers
//!
//! THIS FILE WAS AUTO-GENERATED USING THE BIZINIKIWI BENCHMARK CLI VERSION 4.0.0-dev
//! DATE: 2023-04-28, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
//! WORST CASE MAP SIZE: `1000000`
//! HOSTNAME: `covid`, CPU: `11th Gen Intel(R) Core(TM) i7-11800H @ 2.30GHz`
//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024
// Executed Command:
// target/release/rip-bridge-node
// benchmark
// pezpallet
// --chain=dev
// --steps=50
// --repeat=20
// --pezpallet=pezpallet_bridge_relayers
// --extrinsic=*
// --execution=wasm
// --wasm-execution=Compiled
// --heap-pages=4096
// --output=./modules/relayers/src/weights.rs
// --template=./.maintain/bridge-weight-template.hbs
#![allow(clippy::all)]
#![allow(unused_parens)]
#![allow(unused_imports)]
#![allow(missing_docs)]
use core::marker::PhantomData;
use pezframe_support::{
traits::Get,
weights::{constants::RocksDbWeight, Weight},
};
/// Weight functions needed for pezpallet_bridge_relayers.
pub trait WeightInfo {
fn claim_rewards() -> Weight;
fn claim_rewards_to() -> Weight;
fn register() -> Weight;
fn deregister() -> Weight;
fn slash_and_deregister() -> Weight;
fn register_relayer_reward() -> Weight;
}
/// Weights for `pezpallet_bridge_relayers` that are generated using one of the Bridge testnets.
///
/// Those weights are test only and must never be used in production.
pub struct BridgeWeight<T>(PhantomData<T>);
impl<T: pezframe_system::Config> WeightInfo for BridgeWeight<T> {
/// Storage: BridgeRelayers RelayerRewards (r:1 w:1)
///
/// Proof: BridgeRelayers RelayerRewards (max_values: None, max_size: Some(65), added: 2540,
/// mode: MaxEncodedLen)
///
/// Storage: Balances TotalIssuance (r:1 w:0)
///
/// Proof: Balances TotalIssuance (max_values: Some(1), max_size: Some(8), added: 503, mode:
/// MaxEncodedLen)
///
/// Storage: System Account (r:1 w:1)
///
/// Proof: System Account (max_values: None, max_size: Some(104), added: 2579, mode:
/// MaxEncodedLen)
fn claim_rewards() -> Weight {
// Proof Size summary in bytes:
// Measured: `294`
// Estimated: `8592`
// Minimum execution time: 77_614 nanoseconds.
Weight::from_parts(79_987_000, 8592)
.saturating_add(T::DbWeight::get().reads(3_u64))
.saturating_add(T::DbWeight::get().writes(2_u64))
}
/// Storage: BridgeRelayers RelayerRewards (r:1 w:1)
///
/// Proof: BridgeRelayers RelayerRewards (max_values: None, max_size: Some(65), added: 2540,
/// mode: MaxEncodedLen)
///
/// Storage: Balances TotalIssuance (r:1 w:0)
///
/// Proof: Balances TotalIssuance (max_values: Some(1), max_size: Some(8), added: 503, mode:
/// MaxEncodedLen)
///
/// Storage: System Account (r:1 w:1)
///
/// Proof: System Account (max_values: None, max_size: Some(104), added: 2579, mode:
/// MaxEncodedLen)
fn claim_rewards_to() -> Weight {
// Proof Size summary in bytes:
// Measured: `294`
// Estimated: `8592`
// Minimum execution time: 77_614 nanoseconds.
Weight::from_parts(79_987_000, 8592)
.saturating_add(T::DbWeight::get().reads(3_u64))
.saturating_add(T::DbWeight::get().writes(2_u64))
}
/// Storage: BridgeRelayers RegisteredRelayers (r:1 w:1)
///
/// Proof: BridgeRelayers RegisteredRelayers (max_values: None, max_size: Some(64), added: 2539,
/// mode: MaxEncodedLen)
///
/// Storage: Balances Reserves (r:1 w:1)
///
/// Proof: Balances Reserves (max_values: None, max_size: Some(849), added: 3324, mode:
/// MaxEncodedLen)
fn register() -> Weight {
// Proof Size summary in bytes:
// Measured: `87`
// Estimated: `7843`
// Minimum execution time: 39_590 nanoseconds.
Weight::from_parts(40_546_000, 7843)
.saturating_add(T::DbWeight::get().reads(2_u64))
.saturating_add(T::DbWeight::get().writes(2_u64))
}
/// Storage: BridgeRelayers RegisteredRelayers (r:1 w:1)
///
/// Proof: BridgeRelayers RegisteredRelayers (max_values: None, max_size: Some(64), added: 2539,
/// mode: MaxEncodedLen)
///
/// Storage: Balances Reserves (r:1 w:1)
///
/// Proof: Balances Reserves (max_values: None, max_size: Some(849), added: 3324, mode:
/// MaxEncodedLen)
fn deregister() -> Weight {
// Proof Size summary in bytes:
// Measured: `264`
// Estimated: `7843`
// Minimum execution time: 43_332 nanoseconds.
Weight::from_parts(45_087_000, 7843)
.saturating_add(T::DbWeight::get().reads(2_u64))
.saturating_add(T::DbWeight::get().writes(2_u64))
}
/// Storage: BridgeRelayers RegisteredRelayers (r:1 w:1)
///
/// Proof: BridgeRelayers RegisteredRelayers (max_values: None, max_size: Some(64), added: 2539,
/// mode: MaxEncodedLen)
///
/// Storage: Balances Reserves (r:1 w:1)
///
/// Proof: Balances Reserves (max_values: None, max_size: Some(849), added: 3324, mode:
/// MaxEncodedLen)
///
/// Storage: System Account (r:1 w:1)
///
/// Proof: System Account (max_values: None, max_size: Some(104), added: 2579, mode:
/// MaxEncodedLen)
fn slash_and_deregister() -> Weight {
// Proof Size summary in bytes:
// Measured: `380`
// Estimated: `11412`
// Minimum execution time: 42_358 nanoseconds.
Weight::from_parts(43_539_000, 11412)
.saturating_add(T::DbWeight::get().reads(3_u64))
.saturating_add(T::DbWeight::get().writes(3_u64))
}
/// Storage: BridgeRelayers RelayerRewards (r:1 w:1)
///
/// Proof: BridgeRelayers RelayerRewards (max_values: None, max_size: Some(65), added: 2540,
/// mode: MaxEncodedLen)
fn register_relayer_reward() -> Weight {
// Proof Size summary in bytes:
// Measured: `12`
// Estimated: `3530`
// Minimum execution time: 6_338 nanoseconds.
Weight::from_parts(6_526_000, 3530)
.saturating_add(T::DbWeight::get().reads(1_u64))
.saturating_add(T::DbWeight::get().writes(1_u64))
}
}
// For backwards compatibility and tests
impl WeightInfo for () {
/// Storage: BridgeRelayers RelayerRewards (r:1 w:1)
///
/// Proof: BridgeRelayers RelayerRewards (max_values: None, max_size: Some(65), added: 2540,
/// mode: MaxEncodedLen)
///
/// Storage: Balances TotalIssuance (r:1 w:0)
///
/// Proof: Balances TotalIssuance (max_values: Some(1), max_size: Some(8), added: 503, mode:
/// MaxEncodedLen)
///
/// Storage: System Account (r:1 w:1)
///
/// Proof: System Account (max_values: None, max_size: Some(104), added: 2579, mode:
/// MaxEncodedLen)
fn claim_rewards() -> Weight {
// Proof Size summary in bytes:
// Measured: `294`
// Estimated: `8592`
// Minimum execution time: 77_614 nanoseconds.
Weight::from_parts(79_987_000, 8592)
.saturating_add(RocksDbWeight::get().reads(3_u64))
.saturating_add(RocksDbWeight::get().writes(2_u64))
}
/// Storage: BridgeRelayers RelayerRewards (r:1 w:1)
///
/// Proof: BridgeRelayers RelayerRewards (max_values: None, max_size: Some(65), added: 2540,
/// mode: MaxEncodedLen)
///
/// Storage: Balances TotalIssuance (r:1 w:0)
///
/// Proof: Balances TotalIssuance (max_values: Some(1), max_size: Some(8), added: 503, mode:
/// MaxEncodedLen)
///
/// Storage: System Account (r:1 w:1)
///
/// Proof: System Account (max_values: None, max_size: Some(104), added: 2579, mode:
/// MaxEncodedLen)
fn claim_rewards_to() -> Weight {
// Proof Size summary in bytes:
// Measured: `294`
// Estimated: `8592`
// Minimum execution time: 77_614 nanoseconds.
Weight::from_parts(79_987_000, 8592)
.saturating_add(RocksDbWeight::get().reads(3_u64))
.saturating_add(RocksDbWeight::get().writes(2_u64))
}
/// Storage: BridgeRelayers RegisteredRelayers (r:1 w:1)
///
/// Proof: BridgeRelayers RegisteredRelayers (max_values: None, max_size: Some(64), added: 2539,
/// mode: MaxEncodedLen)
///
/// Storage: Balances Reserves (r:1 w:1)
///
/// Proof: Balances Reserves (max_values: None, max_size: Some(849), added: 3324, mode:
/// MaxEncodedLen)
fn register() -> Weight {
// Proof Size summary in bytes:
// Measured: `87`
// Estimated: `7843`
// Minimum execution time: 39_590 nanoseconds.
Weight::from_parts(40_546_000, 7843)
.saturating_add(RocksDbWeight::get().reads(2_u64))
.saturating_add(RocksDbWeight::get().writes(2_u64))
}
/// Storage: BridgeRelayers RegisteredRelayers (r:1 w:1)
///
/// Proof: BridgeRelayers RegisteredRelayers (max_values: None, max_size: Some(64), added: 2539,
/// mode: MaxEncodedLen)
///
/// Storage: Balances Reserves (r:1 w:1)
///
/// Proof: Balances Reserves (max_values: None, max_size: Some(849), added: 3324, mode:
/// MaxEncodedLen)
fn deregister() -> Weight {
// Proof Size summary in bytes:
// Measured: `264`
// Estimated: `7843`
// Minimum execution time: 43_332 nanoseconds.
Weight::from_parts(45_087_000, 7843)
.saturating_add(RocksDbWeight::get().reads(2_u64))
.saturating_add(RocksDbWeight::get().writes(2_u64))
}
/// Storage: BridgeRelayers RegisteredRelayers (r:1 w:1)
///
/// Proof: BridgeRelayers RegisteredRelayers (max_values: None, max_size: Some(64), added: 2539,
/// mode: MaxEncodedLen)
///
/// Storage: Balances Reserves (r:1 w:1)
///
/// Proof: Balances Reserves (max_values: None, max_size: Some(849), added: 3324, mode:
/// MaxEncodedLen)
///
/// Storage: System Account (r:1 w:1)
///
/// Proof: System Account (max_values: None, max_size: Some(104), added: 2579, mode:
/// MaxEncodedLen)
fn slash_and_deregister() -> Weight {
// Proof Size summary in bytes:
// Measured: `380`
// Estimated: `11412`
// Minimum execution time: 42_358 nanoseconds.
Weight::from_parts(43_539_000, 11412)
.saturating_add(RocksDbWeight::get().reads(3_u64))
.saturating_add(RocksDbWeight::get().writes(3_u64))
}
/// Storage: BridgeRelayers RelayerRewards (r:1 w:1)
///
/// Proof: BridgeRelayers RelayerRewards (max_values: None, max_size: Some(65), added: 2540,
/// mode: MaxEncodedLen)
fn register_relayer_reward() -> Weight {
// Proof Size summary in bytes:
// Measured: `12`
// Estimated: `3530`
// Minimum execution time: 6_338 nanoseconds.
Weight::from_parts(6_526_000, 3530)
.saturating_add(RocksDbWeight::get().reads(1_u64))
.saturating_add(RocksDbWeight::get().writes(1_u64))
}
}
@@ -0,0 +1,49 @@
// 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/>.
//! Weight-related utilities.
use crate::weights::WeightInfo;
use pezframe_support::pezpallet_prelude::Weight;
/// Extended weight info.
pub trait WeightInfoExt: WeightInfo {
/// Returns weight, that needs to be added to the pre-dispatch weight of message delivery call,
/// if `BridgeRelayersTransactionExtension` signed extension is deployed at runtime level.
fn receive_messages_proof_overhead_from_runtime() -> Weight {
Self::slash_and_deregister().max(Self::register_relayer_reward())
}
/// Returns weight, that needs to be added to the pre-dispatch weight of message delivery
/// confirmation call, if `BridgeRelayersTransactionExtension` signed extension is deployed at
/// runtime level.
fn receive_messages_delivery_proof_overhead_from_runtime() -> Weight {
Self::register_relayer_reward()
}
/// Returns weight that we need to deduct from the message delivery call weight that has
/// completed successfully.
///
/// Usually, the weight of `slash_and_deregister` is larger than the weight of the
/// `register_relayer_reward`. So if relayer has been rewarded, we want to deduct the difference
/// to get the actual post-dispatch weight.
fn extra_weight_of_successful_receive_messages_proof_call() -> Weight {
Self::slash_and_deregister().saturating_sub(Self::register_relayer_reward())
}
}
impl<T: WeightInfo> WeightInfoExt for T {}