From 1ed00e339a5edbeab0d0ed5db7e26f2c2cfb8170 Mon Sep 17 00:00:00 2001 From: bear Date: Mon, 17 Apr 2023 16:43:51 +0800 Subject: [PATCH 1/3] Add dispatch filter --- frame/evm/precompile/dispatch/src/lib.rs | 44 ++++++++++++++++-------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/frame/evm/precompile/dispatch/src/lib.rs b/frame/evm/precompile/dispatch/src/lib.rs index 82aee787e7..fe23622179 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, DispatchFilter, DecodeLimit)>, } -impl Precompile for Dispatch +impl Precompile for Dispatch where T: pallet_evm::Config, T::RuntimeCall: Dispatchable + GetDispatchInfo + Decode, ::RuntimeOrigin: From>, + DispatchFilter: DispatchFilterT, DecodeLimit: Get, { fn execute(handle: &mut impl PrecompileHandle) -> PrecompileResult { @@ -64,32 +65,33 @@ 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(); if !valid_weight { return Err(PrecompileFailure::Error { - exit_status: ExitError::OutOfGas, + exit_status: ExitError::Other("decode failed".into()), }); } } let origin = T::AddressMapping::into_account_id(context.caller); + if !DispatchFilter::allow(&origin, &call) { + return Err(PrecompileFailure::Error { + exit_status: ExitError::Other("call not allowed".into()), + }); + } + 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 +106,15 @@ where } } } + +/// Dispatch filter trait. +pub trait DispatchFilterT { + fn allow(origin: &T::AccountId, call: &T::RuntimeCall) -> bool; +} + +/// The default implementation of `DispatchFilterT`. +impl DispatchFilterT for () { + fn allow(_origin: &T::AccountId, _call: &T::RuntimeCall) -> bool { + true + } +} From 12662ba4d169c58d9313c65eadc11a7a0a915679 Mon Sep 17 00:00:00 2001 From: bear Date: Mon, 17 Apr 2023 16:46:44 +0800 Subject: [PATCH 2/3] Fix clippy --- frame/evm/precompile/dispatch/src/lib.rs | 4 ++-- primitives/account/src/lib.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/frame/evm/precompile/dispatch/src/lib.rs b/frame/evm/precompile/dispatch/src/lib.rs index fe23622179..934ba3fdaa 100644 --- a/frame/evm/precompile/dispatch/src/lib.rs +++ b/frame/evm/precompile/dispatch/src/lib.rs @@ -34,7 +34,7 @@ use fp_evm::{ }; use frame_support::{ codec::{Decode, DecodeLimit as _}, - dispatch::{DispatchClass, Dispatchable, GetDispatchInfo, Pays, PostDispatchInfo}, + dispatch::{Dispatchable, GetDispatchInfo, Pays, PostDispatchInfo}, traits::{ConstU32, Get}, }; use pallet_evm::{AddressMapping, GasWeightMapping}; @@ -70,7 +70,7 @@ where info.weight.ref_time() <= T::GasWeightMapping::gas_to_weight(gas, false).ref_time(); if !valid_weight { return Err(PrecompileFailure::Error { - exit_status: ExitError::Other("decode failed".into()), + exit_status: ExitError::OutOfGas, }); } } 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}") } } From 35bc1c8d7c0d2674ad9311dfed6827ec5dd9c0ad Mon Sep 17 00:00:00 2001 From: bear Date: Wed, 19 Apr 2023 18:10:17 +0800 Subject: [PATCH 3/3] Fix review --- frame/evm/precompile/dispatch/src/lib.rs | 46 +++++++++++++++--------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/frame/evm/precompile/dispatch/src/lib.rs b/frame/evm/precompile/dispatch/src/lib.rs index 934ba3fdaa..790e95809c 100644 --- a/frame/evm/precompile/dispatch/src/lib.rs +++ b/frame/evm/precompile/dispatch/src/lib.rs @@ -34,7 +34,7 @@ use fp_evm::{ }; use frame_support::{ codec::{Decode, DecodeLimit as _}, - dispatch::{Dispatchable, GetDispatchInfo, Pays, PostDispatchInfo}, + dispatch::{DispatchClass, Dispatchable, GetDispatchInfo, Pays, PostDispatchInfo}, traits::{ConstU32, Get}, }; use pallet_evm::{AddressMapping, GasWeightMapping}; @@ -42,16 +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, DispatchFilter, 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>, - DispatchFilter: DispatchFilterT, + DispatchValidator: DispatchValidateT, DecodeLimit: Get, { fn execute(handle: &mut impl PrecompileHandle) -> PrecompileResult { @@ -77,10 +77,8 @@ where let origin = T::AddressMapping::into_account_id(context.caller); - if !DispatchFilter::allow(&origin, &call) { - return Err(PrecompileFailure::Error { - exit_status: ExitError::Other("call not allowed".into()), - }); + if let Some(err) = DispatchValidator::validate_before_dispatch(&origin, &call) { + return Err(err); } match call.dispatch(Some(origin).into()) { @@ -107,14 +105,30 @@ where } } -/// Dispatch filter trait. -pub trait DispatchFilterT { - fn allow(origin: &T::AccountId, call: &T::RuntimeCall) -> bool; +/// Dispatch validation trait. +pub trait DispatchValidateT { + fn validate_before_dispatch( + origin: &T::AccountId, + call: &T::RuntimeCall, + ) -> Option; } -/// The default implementation of `DispatchFilterT`. -impl DispatchFilterT for () { - fn allow(_origin: &T::AccountId, _call: &T::RuntimeCall) -> bool { - true +/// 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 } }