Skip to content

Commit 561dffa

Browse files
committed
define ethereum transaction validation
1 parent 9377029 commit 561dffa

File tree

2 files changed

+125
-0
lines changed

2 files changed

+125
-0
lines changed

frame/ethereum/src/extension.rs

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
//! Extensions for unsigned general extrinsic for ethereum pallet
2+
3+
use crate::pallet::Call as EthereumCall;
4+
use crate::{Config, Origin, Pallet as Ethereum, RawOrigin};
5+
use ethereum_types::H160;
6+
use fp_evm::TransactionValidationError;
7+
use frame_support::pallet_prelude::{PhantomData, TypeInfo};
8+
use frame_system::pallet_prelude::{OriginFor, RuntimeCallFor};
9+
use scale_codec::{Decode, Encode};
10+
use scale_info::prelude::fmt;
11+
use sp_runtime::impl_tx_ext_default;
12+
use sp_runtime::traits::{
13+
AsSystemOriginSigner, DispatchInfoOf, DispatchOriginOf, Dispatchable, Implication,
14+
TransactionExtension, ValidateResult,
15+
};
16+
use sp_runtime::transaction_validity::{
17+
InvalidTransaction, TransactionSource, TransactionValidityError, ValidTransaction,
18+
};
19+
20+
/// Trait to be implemented by the Runtime call for Ethereum call conversion and additional validations.
21+
pub trait EthereumTransactionHook<Runtime>
22+
where
23+
Runtime: Config,
24+
OriginFor<Runtime>: Into<Result<RawOrigin, OriginFor<Runtime>>>,
25+
{
26+
fn maybe_ethereum_call(&self) -> Option<&EthereumCall<Runtime>>;
27+
28+
fn additional_validation(
29+
&self,
30+
_signer: H160,
31+
_source: TransactionSource,
32+
) -> Result<(), TransactionValidityError> {
33+
Ok(())
34+
}
35+
}
36+
37+
/// Extensions for pallet-ethereum unsigned extrinsics.
38+
#[derive(Encode, Decode, Clone, Eq, PartialEq, TypeInfo)]
39+
pub struct EthereumExtension<Runtime>(PhantomData<Runtime>);
40+
41+
impl<Runtime> EthereumExtension<Runtime> {
42+
pub fn new() -> Self {
43+
Self(PhantomData)
44+
}
45+
}
46+
47+
impl<Runtime> Default for EthereumExtension<Runtime> {
48+
fn default() -> Self {
49+
Self::new()
50+
}
51+
}
52+
53+
impl<T: Config> fmt::Debug for EthereumExtension<T> {
54+
#[cfg(feature = "std")]
55+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
56+
write!(f, "EthereumExtension",)
57+
}
58+
59+
#[cfg(not(feature = "std"))]
60+
fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result {
61+
Ok(())
62+
}
63+
}
64+
65+
impl<Runtime> EthereumExtension<Runtime> where
66+
Runtime: Config + scale_info::TypeInfo + fmt::Debug + Send + Sync
67+
{
68+
}
69+
70+
impl<Runtime> TransactionExtension<RuntimeCallFor<Runtime>> for EthereumExtension<Runtime>
71+
where
72+
Runtime: Config + scale_info::TypeInfo + fmt::Debug + Send + Sync,
73+
<RuntimeCallFor<Runtime> as Dispatchable>::RuntimeOrigin:
74+
AsSystemOriginSigner<<Runtime as frame_system::Config>::AccountId> + From<Origin> + Clone,
75+
OriginFor<Runtime>: Into<Result<RawOrigin, OriginFor<Runtime>>>,
76+
RuntimeCallFor<Runtime>: EthereumTransactionHook<Runtime>,
77+
{
78+
const IDENTIFIER: &'static str = "EthereumExtension";
79+
type Implicit = ();
80+
type Val = ();
81+
type Pre = ();
82+
83+
fn validate(
84+
&self,
85+
origin: DispatchOriginOf<RuntimeCallFor<Runtime>>,
86+
call: &RuntimeCallFor<Runtime>,
87+
_info: &DispatchInfoOf<RuntimeCallFor<Runtime>>,
88+
_len: usize,
89+
_self_implicit: Self::Implicit,
90+
_inherited_implication: &impl Implication,
91+
source: TransactionSource,
92+
) -> ValidateResult<Self::Val, RuntimeCallFor<Runtime>> {
93+
// we only care about unsigned calls
94+
if origin.as_system_origin_signer().is_some() {
95+
return Ok((ValidTransaction::default(), (), origin));
96+
};
97+
98+
let transaction = match call.maybe_ethereum_call() {
99+
Some(EthereumCall::transact { transaction }) => transaction,
100+
_ => return Ok((ValidTransaction::default(), (), origin)),
101+
};
102+
103+
// check signer
104+
let signer = Ethereum::<Runtime>::recover_signer(transaction).ok_or(
105+
InvalidTransaction::Custom(TransactionValidationError::InvalidSignature as u8),
106+
)?;
107+
108+
// validation on transactions based on pre_dispatch or mempool validation.
109+
let pre_dispatch = source == TransactionSource::InBlock;
110+
let validity = if pre_dispatch {
111+
Ethereum::<Runtime>::validate_transaction_in_block(signer, transaction)
112+
.map(|_| ValidTransaction::default())
113+
} else {
114+
Ethereum::<Runtime>::validate_transaction_in_pool(signer, transaction)
115+
}?;
116+
117+
// do any additional validations
118+
call.additional_validation(signer, source)?;
119+
120+
Ok((validity, (), Origin::EthereumTransaction(signer).into()))
121+
}
122+
123+
impl_tx_ext_default!(RuntimeCallFor<Runtime>; prepare weight);
124+
}

frame/ethereum/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727

2828
extern crate alloc;
2929

30+
pub mod extension;
3031
#[cfg(all(feature = "std", test))]
3132
mod mock;
3233
#[cfg(all(feature = "std", test))]

0 commit comments

Comments
 (0)