From 82371fada0bf3a6a451dc391c4f6657c02cf2ba6 Mon Sep 17 00:00:00 2001 From: bear Date: Thu, 20 Apr 2023 02:19:49 +0800 Subject: [PATCH] Add validator to dispatch precompile (#1042) * Add dispatch filter * Fix clippy * Fix review --- frame/evm/precompile/dispatch/src/lib.rs | 56 ++++++++++++++++++------ primitives/account/src/lib.rs | 2 +- 2 files changed, 43 insertions(+), 15 deletions(-) diff --git a/frame/evm/precompile/dispatch/src/lib.rs b/frame/evm/precompile/dispatch/src/lib.rs index 82aee787e7..790e95809c 100644 --- a/frame/evm/precompile/dispatch/src/lib.rs +++ b/frame/evm/precompile/dispatch/src/lib.rs @@ -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> { - _marker: PhantomData<(T, DecodeLimit)>, +pub struct Dispatch> { + _marker: PhantomData<(T, DispatchValidator, DecodeLimit)>, } -impl Precompile for Dispatch +impl Precompile for Dispatch where T: pallet_evm::Config, T::RuntimeCall: Dispatchable + GetDispatchInfo + Decode, ::RuntimeOrigin: From>, + DispatchValidator: DispatchValidateT, DecodeLimit: Get, { fn execute(handle: &mut impl PrecompileHandle) -> PrecompileResult { @@ -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(); @@ -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, @@ -104,3 +104,31 @@ where } } } + +/// Dispatch validation trait. +pub trait DispatchValidateT { + fn validate_before_dispatch( + origin: &T::AccountId, + call: &T::RuntimeCall, + ) -> Option; +} + +/// The default implementation of `DispatchValidateT`. +impl DispatchValidateT for () +where + T: pallet_evm::Config, + T::RuntimeCall: GetDispatchInfo, +{ + fn validate_before_dispatch( + _origin: &T::AccountId, + call: &T::RuntimeCall, + ) -> Option { + 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 + } +} diff --git a/primitives/account/src/lib.rs b/primitives/account/src/lib.rs index d1be0e8e29..acbf9a6b82 100644 --- a/primitives/account/src/lib.rs +++ b/primitives/account/src/lib.rs @@ -67,7 +67,7 @@ impl std::fmt::Display for AccountId20 { acc }); - write!(f, "{}", checksum) + write!(f, "{checksum}") } }