Skip to content

Commit

Permalink
added FreeParachainUpdateForFreeRelayHeader
Browse files Browse the repository at this point in the history
  • Loading branch information
svyatonik committed Mar 13, 2024
1 parent 48bce25 commit 8003f8e
Show file tree
Hide file tree
Showing 2 changed files with 125 additions and 34 deletions.
41 changes: 7 additions & 34 deletions bin/runtime-common/src/extensions/refund_relayer_extension.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,15 @@
//! with calls that are: delivering new messsage and all necessary underlying headers
//! (parachain or relay chain).
use crate::messages_call_ext::{
CallHelper as MessagesCallHelper, CallInfo as MessagesCallInfo, MessagesCallSubType,
use crate::{
messages_call_ext::{
CallHelper as MessagesCallHelper, CallInfo as MessagesCallInfo, MessagesCallSubType,
},
RefundableParachainId,
};
use bp_messages::{LaneId, MessageNonce};
use bp_relayers::{ExplicitOrAccountParams, RewardsAccountOwner, RewardsAccountParams};
use bp_runtime::{Parachain, ParachainIdOf, RangeInclusiveExt, StaticStrProvider};
use bp_runtime::{RangeInclusiveExt, StaticStrProvider};
use codec::{Codec, Decode, Encode};
use frame_support::{
dispatch::{CallableCallFor, DispatchInfo, PostDispatchInfo},
Expand Down Expand Up @@ -64,37 +67,6 @@ type BalanceOf<R> =
<<R as TransactionPaymentConfig>::OnChargeTransaction as OnChargeTransaction<R>>::Balance;
type CallOf<R> = <R as frame_system::Config>::RuntimeCall;

/// Trait identifying a bridged parachain. A relayer might be refunded for delivering messages
/// coming from this parachain.
pub trait RefundableParachainId {
/// The instance of the bridge parachains pallet.
type Instance;
/// The parachain Id.
type Id: Get<u32>;
}

/// Default implementation of `RefundableParachainId`.
pub struct DefaultRefundableParachainId<Instance, Id>(PhantomData<(Instance, Id)>);

impl<Instance, Id> RefundableParachainId for DefaultRefundableParachainId<Instance, Id>
where
Id: Get<u32>,
{
type Instance = Instance;
type Id = Id;
}

/// Implementation of `RefundableParachainId` for `trait Parachain`.
pub struct RefundableParachain<Instance, Para>(PhantomData<(Instance, Para)>);

impl<Instance, Para> RefundableParachainId for RefundableParachain<Instance, Para>
where
Para: Parachain,
{
type Instance = Instance;
type Id = ParachainIdOf<Para>;
}

/// Trait identifying a bridged messages lane. A relayer might be refunded for delivering messages
/// coming from this lane.
pub trait RefundableMessagesLaneId {
Expand Down Expand Up @@ -970,6 +942,7 @@ pub(crate) mod tests {
UnrewardedRelayerOccupation,
},
mock::*,
DefaultRefundableParachainId,
};
use bp_messages::{
DeliveredMessages, InboundLaneData, MessageNonce, MessagesOperatingMode, OutboundLaneData,
Expand Down
118 changes: 118 additions & 0 deletions bin/runtime-common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@
#![warn(missing_docs)]
#![cfg_attr(not(feature = "std"), no_std)]

use bp_polkadot_core::parachains::{ParaHash, ParaId};
use bp_runtime::{Parachain, ParachainIdOf};
use pallet_bridge_grandpa::Config as GrandpaConfig;
use pallet_bridge_parachains::{
Config as ParachainsConfig, ParachainHeadsUpdateFilter, RelayBlockHash, RelayBlockNumber,
};
use sp_runtime::traits::{Get, PhantomData};

pub mod extensions;
pub mod messages;
pub mod messages_api;
Expand All @@ -34,3 +42,113 @@ mod mock;
pub mod integrity;

const LOG_TARGET_BRIDGE_DISPATCH: &str = "runtime::bridge-dispatch";

/// Trait identifying a bridged parachain. A relayer might be refunded for delivering messages
/// coming from this parachain.
pub trait RefundableParachainId {
/// The instance of the bridge parachains pallet.
type Instance: 'static;
/// The parachain Id.
type Id: Get<u32>;
}

/// Default implementation of `RefundableParachainId`.
pub struct DefaultRefundableParachainId<Instance, Id>(PhantomData<(Instance, Id)>);

impl<Instance, Id> RefundableParachainId for DefaultRefundableParachainId<Instance, Id>
where
Instance: 'static,
Id: Get<u32>,
{
type Instance = Instance;
type Id = Id;
}

/// Implementation of `RefundableParachainId` for `trait Parachain`.
pub struct RefundableParachain<Instance, Para>(PhantomData<(Instance, Para)>);

impl<Instance, Para> RefundableParachainId for RefundableParachain<Instance, Para>
where
Instance: 'static,
Para: Parachain,
{
type Instance = Instance;
type Id = ParachainIdOf<Para>;
}

/// A filter that allows one free parachain head submissions for every free
/// relay chain header. It DOES NOT refund for parachains, finalized at
/// mandatory relay chain blocks.
///
/// The number of free submissions is implicitly limited by the
/// `T::MaxFreeHeadersPerBlock` - there can be at most one parachain head
/// submission for every free relay chain header. And since number of free
/// relay chain headers is limited by this parameter, free parachain head
/// updates is also limited.
pub struct FreeParachainUpdateForFreeRelayHeader<T, GI, P>(PhantomData<(T, GI, P)>);

impl<T, GI, P> ParachainHeadsUpdateFilter for FreeParachainUpdateForFreeRelayHeader<T, GI, P>
where
T: GrandpaConfig<GI> + ParachainsConfig<P::Instance>,
GI: 'static,
P: RefundableParachainId,
{
fn is_free(
at_relay_block: (RelayBlockNumber, RelayBlockHash),
parachains: &[(ParaId, ParaHash)],
) -> bool {
// just one parachain that we are interested in
if parachains.len() != 1 || parachains[0].0 .0 != P::Id::get() {
return false;
}

// we only refund for parachains, finalized at free relay chain blocks
let Some(free_headers_interval) = <T as GrandpaConfig<GI>>::FreeHeadersInterval::get()
else {
return false
};
if at_relay_block.0 != 0 && at_relay_block.0 % free_headers_interval == 0 {
return true
}

false
}
}

#[cfg(test)]
mod tests {
use super::*;
use mock::*;

type RefundableParachain = super::RefundableParachain<(), BridgedUnderlyingParachain>;
type FreeBridgedParachainUpdate =
FreeParachainUpdateForFreeRelayHeader<TestRuntime, (), RefundableParachain>;

#[test]
fn free_parachain_update_for_free_relay_header_works() {
let free_interval = <TestRuntime as GrandpaConfig<()>>::FreeHeadersInterval::get();
// not free when there are multiple parachains
assert!(!FreeBridgedParachainUpdate::is_free(
(free_interval, Default::default()),
&[
(ParaId(BridgedUnderlyingParachain::PARACHAIN_ID), Default::default()),
(ParaId(BridgedUnderlyingParachain::PARACHAIN_ID + 1), Default::default()),
],
));
// not free when finalized at non-free relay chain header
assert!(!FreeBridgedParachainUpdate::is_free(
(free_interval + 1, Default::default()),
&[(ParaId(BridgedUnderlyingParachain::PARACHAIN_ID), Default::default()),],
));
// not free when finalized at relay chain genesis
assert!(!FreeBridgedParachainUpdate::is_free(
(0, Default::default()),
&[(ParaId(BridgedUnderlyingParachain::PARACHAIN_ID), Default::default()),],
));
// free when finalized at free relay chain header
assert!(FreeBridgedParachainUpdate::is_free(
(free_interval, Default::default()),
&[(ParaId(BridgedUnderlyingParachain::PARACHAIN_ID), Default::default()),],
));
}
}

0 comments on commit 8003f8e

Please sign in to comment.