Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP][Base on transaction extension] complete bridges extensions #5773

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 20 additions & 25 deletions bridges/bin/runtime-common/src/extensions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,7 @@ pub trait BridgeRuntimeFilterCall<AccountId, Call> {
/// Data that may be passed from the validate to `post_dispatch`.
type ToPostDispatch;
/// Called during validation. Needs to checks whether a runtime call, submitted
/// by the `who` is valid. `who` may be `None` if transaction is not signed
/// by a regular account.
/// by the `who` is valid.
fn validate(who: &AccountId, call: &Call) -> (Self::ToPostDispatch, TransactionValidity);
/// Called after transaction is dispatched.
fn post_dispatch(_who: &AccountId, _has_failed: bool, _to_post_dispatch: Self::ToPostDispatch) {
Expand Down Expand Up @@ -277,7 +276,7 @@ macro_rules! generate_bridge_reject_obsolete_headers_and_messages {
impl sp_runtime::traits::TransactionExtension<$call> for BridgeRejectObsoleteHeadersAndMessages {
const IDENTIFIER: &'static str = "BridgeRejectObsoleteHeadersAndMessages";
type Implicit = ();
type Pre = Option<(
type Val = Option<(
$account_id,
( $(
<$filter_call as $crate::extensions::BridgeRuntimeFilterCall<
Expand All @@ -286,7 +285,7 @@ macro_rules! generate_bridge_reject_obsolete_headers_and_messages {
>>::ToPostDispatch,
)* ),
)>;
type Val = ();
type Pre = Self::Val;

fn validate(
&self,
Expand All @@ -303,44 +302,37 @@ macro_rules! generate_bridge_reject_obsolete_headers_and_messages {
<$call as sp_runtime::traits::Dispatchable>::RuntimeOrigin,
), sp_runtime::transaction_validity::TransactionValidityError
> {
use $crate::extensions::__private::tuplex::PushBack;
use sp_runtime::traits::AsSystemOriginSigner;

let Some(who) = origin.as_system_origin_signer() else {
return Ok((Default::default(), None, origin));
};

let to_post_dispatch = ();
let tx_validity = sp_runtime::transaction_validity::ValidTransaction::default();
let who = origin.as_system_origin_signer().ok_or(sp_runtime::transaction_validity::InvalidTransaction::BadSigner)?;
$(
let (_from_validate, call_filter_validity) = <
let (from_validate, call_filter_validity) = <
$filter_call as
$crate::extensions::BridgeRuntimeFilterCall<
$account_id,
$call,
>>::validate(&who, call);
>>::validate(who, call);
let to_post_dispatch = to_post_dispatch.push_back(from_validate);
let tx_validity = tx_validity.combine_with(call_filter_validity?);
)*
Ok((tx_validity, (), origin))
Ok((tx_validity, Some((who.clone(), to_post_dispatch)), origin))
}

fn prepare(
self,
_val: Self::Val,
val: Self::Val,
origin: &<$call as sp_runtime::traits::Dispatchable>::RuntimeOrigin,
call: &$call,
_info: &sp_runtime::traits::DispatchInfoOf<$call>,
_len: usize,
) -> Result<Self::Pre, sp_runtime::transaction_validity::TransactionValidityError> {
use $crate::extensions::__private::tuplex::PushBack;
use sp_runtime::traits::AsSystemOriginSigner;

let to_post_dispatch = ();
let relayer = origin.as_system_origin_signer().ok_or(sp_runtime::transaction_validity::InvalidTransaction::BadSigner)?;
$(
let (from_validate, _call_filter_validity) = <
$filter_call as
$crate::extensions::BridgeRuntimeFilterCall<
$account_id,
$call,
>>::validate(&relayer, call);
let to_post_dispatch = to_post_dispatch.push_back(from_validate);
)*
Ok(Some((relayer.clone(), to_post_dispatch)))
Ok(val)
}

#[allow(unused_variables)]
Expand All @@ -353,7 +345,10 @@ macro_rules! generate_bridge_reject_obsolete_headers_and_messages {
) -> Result<frame_support::pallet_prelude::Weight, sp_runtime::transaction_validity::TransactionValidityError> {
use $crate::extensions::__private::tuplex::PopFront;

let Some((relayer, to_post_dispatch)) = to_post_dispatch else { return Ok(frame_support::pallet_prelude::Weight::zero()) };
let Some((relayer, to_post_dispatch)) = to_post_dispatch else {
return Ok(frame_support::pallet_prelude::Weight::zero())
};

let has_failed = result.is_err();
$(
let (item, to_post_dispatch) = to_post_dispatch.pop_front();
Expand Down
60 changes: 34 additions & 26 deletions bridges/modules/relayers/src/extension/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,13 +139,12 @@ where
/// virtually boosted. The relayer registration (we only boost priority for registered
/// relayer transactions) must be checked outside.
fn bundled_messages_for_priority_boost(
call_info: Option<&ExtensionCallInfo<C::RemoteGrandpaChainBlockNumber>>,
parsed_call: &ExtensionCallInfo<C::RemoteGrandpaChainBlockNumber>,
) -> Option<MessageNonce> {
// we only boost priority of message delivery transactions
let parsed_call = match call_info {
Some(parsed_call) if parsed_call.is_receive_messages_proof_call() => parsed_call,
_ => return None,
};
if !parsed_call.is_receive_messages_proof_call() {
return None;
}

// compute total number of messages in transaction
let bundled_messages = parsed_call.messages_call_info().bundled_messages().saturating_len();
Expand All @@ -163,15 +162,15 @@ where
/// Given post-dispatch information, analyze the outcome of relayer call and return
/// actions that need to be performed on relayer account.
fn analyze_call_result(
pre: Option<Option<PreDispatchData<R::AccountId, C::RemoteGrandpaChainBlockNumber>>>,
pre: Option<PreDispatchData<R::AccountId, C::RemoteGrandpaChainBlockNumber>>,
info: &DispatchInfo,
post_info: &PostDispatchInfo,
len: usize,
result: &DispatchResult,
) -> RelayerAccountAction<R::AccountId, R::Reward> {
// We don't refund anything for transactions that we don't support.
let (relayer, call_info) = match pre {
Some(Some(pre)) => (pre.relayer, pre.call_info),
Some(pre) => (pre.relayer, pre.call_info),
_ => return RelayerAccountAction::None,
};

Expand Down Expand Up @@ -201,7 +200,7 @@ where
// - when relayer is registered after `validate` is called and priority is not boosted:
// relayer should be ready for slashing after registration.
let may_slash_relayer =
Self::bundled_messages_for_priority_boost(Some(&call_info)).is_some();
Self::bundled_messages_for_priority_boost(&call_info).is_some();
let slash_relayer_if_delivery_result = may_slash_relayer
.then(|| RelayerAccountAction::Slash(relayer.clone(), reward_account_params))
.unwrap_or(RelayerAccountAction::None);
Expand Down Expand Up @@ -281,7 +280,7 @@ where
const IDENTIFIER: &'static str = C::IdProvider::STR;
type Implicit = ();
type Pre = Option<PreDispatchData<R::AccountId, C::RemoteGrandpaChainBlockNumber>>;
type Val = Option<ExtensionCallInfo<C::RemoteGrandpaChainBlockNumber>>;
type Val = Self::Pre;

fn validate(
&self,
Expand All @@ -292,26 +291,36 @@ where
_self_implicit: Self::Implicit,
_inherited_implication: &impl Encode,
) -> ValidateResult<Self::Val, R::RuntimeCall> {
let who = origin.as_system_origin_signer().ok_or(InvalidTransaction::BadSigner)?;
// this is the only relevant line of code for the `pre_dispatch`
//
// we're not calling `validate` from `pre_dispatch` directly because of performance
// reasons, so if you're adding some code that may fail here, please check if it needs
// to be added to the `pre_dispatch` as well
let parsed_call = C::parse_and_check_for_obsolete_call(call)?;
let parsed_call = match C::parse_and_check_for_obsolete_call(call)? {
Some(parsed_call) => parsed_call,
None => return Ok((Default::default(), None, origin)),
};

// Those calls are only for signed transactions.
let relayer = origin.as_system_origin_signer().ok_or(InvalidTransaction::BadSigner)?;

let data = PreDispatchData {
relayer: relayer.clone(),
call_info: parsed_call,
};

// the following code just plays with transaction priority and never returns an error

// we only boost priority of presumably correct message delivery transactions
let bundled_messages = match Self::bundled_messages_for_priority_boost(parsed_call.as_ref())
let bundled_messages = match Self::bundled_messages_for_priority_boost(&data.call_info)
{
Some(bundled_messages) => bundled_messages,
None => return Ok((Default::default(), parsed_call, origin)),
None => return Ok((Default::default(), Some(data), origin)),
};

// we only boost priority if relayer has staked required balance
if !RelayersPallet::<R>::is_registration_active(who) {
return Ok((Default::default(), parsed_call, origin))
if !RelayersPallet::<R>::is_registration_active(&data.relayer) {
return Ok((Default::default(), Some(data), origin))
}

// compute priority boost
Expand All @@ -324,34 +333,33 @@ where
"{}.{:?}: has boosted priority of message delivery transaction \
of relayer {:?}: {} messages -> {} priority",
Self::IDENTIFIER,
parsed_call.as_ref().map(|p| p.messages_call_info().lane_id()),
who,
data.call_info.messages_call_info().lane_id(),
data.relayer,
bundled_messages,
priority_boost,
);

let validity = valid_transaction.build()?;
Ok((validity, parsed_call, origin))
Ok((validity, Some(data), origin))
}

fn prepare(
self,
val: Self::Val,
origin: &<R::RuntimeCall as Dispatchable>::RuntimeOrigin,
_origin: &<R::RuntimeCall as Dispatchable>::RuntimeOrigin,
_call: &R::RuntimeCall,
_info: &DispatchInfoOf<R::RuntimeCall>,
_len: usize,
) -> Result<Self::Pre, TransactionValidityError> {
let who = origin.as_system_origin_signer().ok_or(InvalidTransaction::BadSigner)?;
Ok(val.map(|call_info| {
Ok(val.map(|data| {
log::trace!(
target: LOG_TARGET,
"{}.{:?}: parsed bridge transaction in pre-dispatch: {:?}",
"{}.{:?}: parsed bridge transaction in prepare: {:?}",
Self::IDENTIFIER,
call_info.messages_call_info().lane_id(),
call_info,
data.call_info.messages_call_info().lane_id(),
data.call_info,
);
PreDispatchData { relayer: who.clone(), call_info }
data
}))
}

Expand All @@ -363,7 +371,7 @@ where
result: &DispatchResult,
) -> Result<Weight, TransactionValidityError> {
let lane_id = pre.as_ref().map(|p| p.call_info.messages_call_info().lane_id());
let call_result = Self::analyze_call_result(Some(pre), info, post_info, len, result);
let call_result = Self::analyze_call_result(pre, info, post_info, len, result);

match call_result {
RelayerAccountAction::None => (),
Expand Down
2 changes: 1 addition & 1 deletion bridges/primitives/relayers/src/extension.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ pub trait ExtensionConfig {
/// GRANDPA chain, it must be it.
type RemoteGrandpaChainBlockNumber: Clone + Copy + Debug;

/// Given runtime call, check if it is supported by the signed extension. Additionally,
/// Given runtime call, check if it is supported by the transaction extension. Additionally,
/// check if call (or any of batched calls) are obsolete.
fn parse_and_check_for_obsolete_call(
call: &<Self::Runtime as SystemConfig>::RuntimeCall,
Expand Down
Loading