fix: Complete snowbridge pezpallet rebrand and critical bug fixes
- snowbridge-pezpallet-* → pezsnowbridge-pezpallet-* (201 refs) - pallet/ directories → pezpallet/ (4 locations) - Fixed pezpallet.rs self-include recursion bug - Fixed sc-chain-spec hardcoded crate name in derive macro - Reverted .pezpallet_by_name() to .pallet_by_name() (subxt API) - Added BizinikiwiConfig type alias for zombienet tests - Deleted obsolete session state files Verified: pezsnowbridge-pezpallet-*, pezpallet-staking, pezpallet-staking-async, pezframe-benchmarking-cli all pass cargo check
This commit is contained in:
@@ -0,0 +1,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,
|
||||
>;
|
||||
}
|
||||
@@ -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(®ISTER_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);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -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 {}
|
||||
Reference in New Issue
Block a user