Skip to content
Merged
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
17 changes: 8 additions & 9 deletions frame/evm/precompile/dispatch/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ where
T: pallet_evm::Config,
T::RuntimeCall: Dispatchable<PostInfo = PostDispatchInfo> + GetDispatchInfo + Decode,
<T::RuntimeCall as Dispatchable>::RuntimeOrigin: From<Option<T::AccountId>>,
DispatchValidator: DispatchValidateT<T>,
DispatchValidator: DispatchValidateT<T::AccountId, T::RuntimeCall>,
DecodeLimit: Get<u32>,
{
fn execute(handle: &mut impl PrecompileHandle) -> PrecompileResult {
Expand Down Expand Up @@ -106,22 +106,21 @@ where
}

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

/// The default implementation of `DispatchValidateT`.
impl<T> DispatchValidateT<T> for ()
impl<AccountId, RuntimeCall> DispatchValidateT<AccountId, RuntimeCall> for ()
where
T: pallet_evm::Config,
T::RuntimeCall: GetDispatchInfo,
RuntimeCall: GetDispatchInfo,
{
fn validate_before_dispatch(
_origin: &T::AccountId,
call: &T::RuntimeCall,
_origin: &AccountId,
call: &RuntimeCall,
) -> Option<PrecompileFailure> {
let info = call.get_dispatch_info();
if !(info.pays_fee == Pays::Yes && info.class == DispatchClass::Normal) {
Expand Down
95 changes: 44 additions & 51 deletions frame/evm/precompile/dispatch/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,62 +20,16 @@
use super::*;
use crate::mock::*;

use fp_evm::{Context, GenesisAccount};
use frame_support::{assert_ok, traits::GenesisBuild};
use fp_evm::Context;
use frame_support::{assert_err, assert_ok};
use scale_codec::Encode;
use sp_core::{H160, U256};
use std::{collections::BTreeMap, str::FromStr};

pub fn new_test_ext() -> sp_io::TestExternalities {
let mut t = frame_system::GenesisConfig::default()
frame_system::GenesisConfig::default()
.build_storage::<Test>()
.unwrap();

let mut accounts = BTreeMap::new();
accounts.insert(
H160::from_str("1000000000000000000000000000000000000001").unwrap(),
GenesisAccount {
nonce: U256::from(1),
balance: U256::from(1000000),
storage: Default::default(),
code: vec![
0x00, // STOP
],
},
);
accounts.insert(
H160::from_str("1000000000000000000000000000000000000002").unwrap(),
GenesisAccount {
nonce: U256::from(1),
balance: U256::from(1000000),
storage: Default::default(),
code: vec![
0xff, // INVALID
],
},
);
accounts.insert(
H160::default(), // root
GenesisAccount {
nonce: U256::from(1),
balance: U256::max_value(),
storage: Default::default(),
code: vec![],
},
);

pallet_balances::GenesisConfig::<Test> {
// Create the block author account with some balance.
balances: vec![(
H160::from_str("0x1234500000000000000000000000000000000000").unwrap(),
12345,
)],
}
.assimilate_storage(&mut t)
.expect("Pallet balances storage can be assimilated");
GenesisBuild::<Test>::assimilate_storage(&pallet_evm::GenesisConfig { accounts }, &mut t)
.unwrap();
t.into()
.unwrap()
.into()
}

#[test]
Expand Down Expand Up @@ -135,3 +89,42 @@ fn decode_limit_ok() {
assert_ok!(Dispatch::<Test>::execute(&mut handle));
});
}

#[test]
fn dispatch_validator_works_well() {
new_test_ext().execute_with(|| {
let call = RuntimeCall::System(frame_system::Call::remark { remark: Vec::new() });
let mut handle = MockHandle {
input: call.encode(),
context: Context {
address: H160::default(),
caller: H160::default(),
apparent_value: U256::default(),
},
};
assert_ok!(Dispatch::<Test>::execute(&mut handle));

pub struct MockValidator;
impl DispatchValidateT<H160, RuntimeCall> for MockValidator {
fn validate_before_dispatch(
_origin: &H160,
call: &RuntimeCall,
) -> Option<PrecompileFailure> {
match call {
RuntimeCall::System(frame_system::Call::remark { remark: _ }) => {
return Some(PrecompileFailure::Error {
exit_status: ExitError::Other("This call is not allowed".into()),
})
}
_ => None,
}
}
}
assert_err!(
Dispatch::<Test, MockValidator>::execute(&mut handle),
PrecompileFailure::Error {
exit_status: ExitError::Other("This call is not allowed".into()),
}
);
});
}