Skip to content

Commit

Permalink
Add validator to dispatch precompile (polkadot-evm#1042)
Browse files Browse the repository at this point in the history
* Add dispatch filter

* Fix clippy

* Fix review
  • Loading branch information
boundless-forest authored and ashutoshvarma committed Jun 8, 2023
1 parent b478b87 commit 82371fa
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 15 deletions.
56 changes: 42 additions & 14 deletions frame/evm/precompile/dispatch/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,16 @@ use pallet_evm::{AddressMapping, GasWeightMapping};
// `DecodeLimit` specifies the max depth a call can use when decoding, as unbounded depth
// can be used to overflow the stack.
// Default value is 8, which is the same as in XCM call decoding.
pub struct Dispatch<T, DecodeLimit = ConstU32<8>> {
_marker: PhantomData<(T, DecodeLimit)>,
pub struct Dispatch<T, DispatchValidator = (), DecodeLimit = ConstU32<8>> {
_marker: PhantomData<(T, DispatchValidator, DecodeLimit)>,
}

impl<T, DecodeLimit> Precompile for Dispatch<T, DecodeLimit>
impl<T, DispatchValidator, DecodeLimit> Precompile for Dispatch<T, DispatchValidator, DecodeLimit>
where
T: pallet_evm::Config,
T::RuntimeCall: Dispatchable<PostInfo = PostDispatchInfo> + GetDispatchInfo + Decode,
<T::RuntimeCall as Dispatchable>::RuntimeOrigin: From<Option<T::AccountId>>,
DispatchValidator: DispatchValidateT<T>,
DecodeLimit: Get<u32>,
{
fn execute(handle: &mut impl PrecompileHandle) -> PrecompileResult {
Expand All @@ -64,13 +65,6 @@ where
})?;
let info = call.get_dispatch_info();

let valid_call = info.pays_fee == Pays::Yes && info.class == DispatchClass::Normal;
if !valid_call {
return Err(PrecompileFailure::Error {
exit_status: ExitError::Other("invalid call".into()),
});
}

if let Some(gas) = target_gas {
let valid_weight =
info.weight.ref_time() <= T::GasWeightMapping::gas_to_weight(gas, false).ref_time();
Expand All @@ -83,13 +77,19 @@ where

let origin = T::AddressMapping::into_account_id(context.caller);

if let Some(err) = DispatchValidator::validate_before_dispatch(&origin, &call) {
return Err(err);
}

match call.dispatch(Some(origin).into()) {
Ok(post_info) => {
let cost = T::GasWeightMapping::weight_to_gas(
post_info.actual_weight.unwrap_or(info.weight),
);
if post_info.pays_fee(&info) == Pays::Yes {
let cost = T::GasWeightMapping::weight_to_gas(
post_info.actual_weight.unwrap_or(info.weight),
);

handle.record_cost(cost)?;
handle.record_cost(cost)?;
}

Ok(PrecompileOutput {
exit_status: ExitSucceed::Stopped,
Expand All @@ -104,3 +104,31 @@ where
}
}
}

/// Dispatch validation trait.
pub trait DispatchValidateT<T: pallet_evm::Config> {
fn validate_before_dispatch(
origin: &T::AccountId,
call: &T::RuntimeCall,
) -> Option<PrecompileFailure>;
}

/// The default implementation of `DispatchValidateT`.
impl<T> DispatchValidateT<T> for ()
where
T: pallet_evm::Config,
T::RuntimeCall: GetDispatchInfo,
{
fn validate_before_dispatch(
_origin: &T::AccountId,
call: &T::RuntimeCall,
) -> Option<PrecompileFailure> {
let info = call.get_dispatch_info();
if !(info.pays_fee == Pays::Yes && info.class == DispatchClass::Normal) {
return Some(PrecompileFailure::Error {
exit_status: ExitError::Other("invalid call".into()),
});
}
None
}
}
2 changes: 1 addition & 1 deletion primitives/account/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ impl std::fmt::Display for AccountId20 {

acc
});
write!(f, "{}", checksum)
write!(f, "{checksum}")
}
}

Expand Down

0 comments on commit 82371fa

Please sign in to comment.