@@ -14,10 +14,9 @@ use crate::{
14
14
} ,
15
15
Context , ContextPrecompiles , FrameResult ,
16
16
} ;
17
- use core:: ops:: Mul ;
17
+ use core:: { cmp :: Ordering , ops:: Mul } ;
18
18
use revm_precompile:: PrecompileSpecId ;
19
- use std:: string:: ToString ;
20
- use std:: sync:: Arc ;
19
+ use std:: { boxed:: Box , string:: ToString , sync:: Arc } ;
21
20
22
21
use super :: l1block:: OPERATOR_FEE_RECIPIENT ;
23
22
@@ -41,6 +40,7 @@ pub fn optimism_handle_register<DB: Database, EXT>(handler: &mut EvmHandler<'_,
41
40
// In case of halt of deposit transaction return Error.
42
41
handler. post_execution. output = Arc :: new( output:: <SPEC , EXT , DB >) ;
43
42
handler. post_execution. end = Arc :: new( end:: <SPEC , EXT , DB >) ;
43
+ handler. post_execution. clear = Arc :: new( clear:: <EXT , DB >) ;
44
44
} ) ;
45
45
}
46
46
@@ -70,10 +70,113 @@ pub fn validate_env<SPEC: Spec, DB: Database>(env: &Env) -> Result<(), EVMError<
70
70
pub fn validate_tx_against_state < SPEC : Spec , EXT , DB : Database > (
71
71
context : & mut Context < EXT , DB > ,
72
72
) -> Result < ( ) , EVMError < DB :: Error > > {
73
- if context. evm . inner . env . tx . optimism . source_hash . is_some ( ) {
73
+ let env @ Env { cfg, tx, .. } = context. evm . inner . env . as_ref ( ) ;
74
+
75
+ // No validation is needed for deposit transactions, as they are pre-verified on L1.
76
+ if tx. optimism . source_hash . is_some ( ) {
74
77
return Ok ( ( ) ) ;
75
78
}
76
- mainnet:: validate_tx_against_state :: < SPEC , EXT , DB > ( context)
79
+
80
+ // load acc
81
+ let tx_caller = tx. caller ;
82
+ let account = context
83
+ . evm
84
+ . inner
85
+ . journaled_state
86
+ . load_code ( tx_caller, & mut context. evm . inner . db ) ?
87
+ . data ;
88
+
89
+ // EIP-3607: Reject transactions from senders with deployed code
90
+ // This EIP is introduced after london but there was no collision in past
91
+ // so we can leave it enabled always
92
+ if !cfg. is_eip3607_disabled ( ) {
93
+ let bytecode = & account. info . code . as_ref ( ) . unwrap ( ) ;
94
+ // allow EOAs whose code is a valid delegation designation,
95
+ // i.e. 0xef0100 || address, to continue to originate transactions.
96
+ if !bytecode. is_empty ( ) && !bytecode. is_eip7702 ( ) {
97
+ return Err ( EVMError :: Transaction (
98
+ InvalidTransaction :: RejectCallerWithCode ,
99
+ ) ) ;
100
+ }
101
+ }
102
+
103
+ // Check that the transaction's nonce is correct
104
+ if let Some ( tx) = tx. nonce {
105
+ let state = account. info . nonce ;
106
+ match tx. cmp ( & state) {
107
+ Ordering :: Greater => {
108
+ return Err ( EVMError :: Transaction ( InvalidTransaction :: NonceTooHigh {
109
+ tx,
110
+ state,
111
+ } ) ) ;
112
+ }
113
+ Ordering :: Less => {
114
+ return Err ( EVMError :: Transaction ( InvalidTransaction :: NonceTooLow {
115
+ tx,
116
+ state,
117
+ } ) ) ;
118
+ }
119
+ _ => { }
120
+ }
121
+ }
122
+
123
+ // get envelope
124
+ let Some ( enveloped_tx) = & tx. optimism . enveloped_tx else {
125
+ return Err ( EVMError :: Custom (
126
+ "[OPTIMISM] Failed to load enveloped transaction." . to_string ( ) ,
127
+ ) ) ;
128
+ } ;
129
+
130
+ // compute L1 cost
131
+ let tx_l1_cost = context
132
+ . evm
133
+ . inner
134
+ . l1_block_info
135
+ . as_mut ( )
136
+ . expect ( "L1BlockInfo should be loaded" )
137
+ . calculate_tx_l1_cost ( enveloped_tx, SPEC :: SPEC_ID ) ;
138
+
139
+ let gas_limit = U256 :: from ( tx. gas_limit ) ;
140
+ let operator_fee_charge = context
141
+ . evm
142
+ . inner
143
+ . l1_block_info
144
+ . as_ref ( )
145
+ . expect ( "L1BlockInfo should be loaded" )
146
+ . operator_fee_charge ( gas_limit, SPEC :: SPEC_ID ) ;
147
+
148
+ let mut balance_check = gas_limit
149
+ . checked_mul ( tx. gas_price )
150
+ . and_then ( |gas_cost| gas_cost. checked_add ( tx. value ) )
151
+ . and_then ( |total_cost| total_cost. checked_add ( tx_l1_cost) )
152
+ . and_then ( |total_cost| total_cost. checked_add ( operator_fee_charge) )
153
+ . ok_or ( InvalidTransaction :: OverflowPaymentInTransaction ) ?;
154
+
155
+ if SPEC :: enabled ( SpecId :: CANCUN ) {
156
+ // if the tx is not a blob tx, this will be None, so we add zero
157
+ let data_fee = env. calc_max_data_fee ( ) . unwrap_or_default ( ) ;
158
+ balance_check = balance_check
159
+ . checked_add ( U256 :: from ( data_fee) )
160
+ . ok_or ( InvalidTransaction :: OverflowPaymentInTransaction ) ?;
161
+ }
162
+
163
+ // Check if account has enough balance for gas_limit*gas_price and value transfer.
164
+ // Transfer will be done inside `*_inner` functions.
165
+ if balance_check > account. info . balance {
166
+ if cfg. is_balance_check_disabled ( ) {
167
+ // Add transaction cost to balance to ensure execution doesn't fail.
168
+ account. info . balance = balance_check;
169
+ } else {
170
+ return Err ( EVMError :: Transaction (
171
+ InvalidTransaction :: LackOfFundForMaxFee {
172
+ fee : Box :: new ( balance_check) ,
173
+ balance : Box :: new ( account. info . balance ) ,
174
+ } ,
175
+ ) ) ;
176
+ }
177
+ }
178
+
179
+ Ok ( ( ) )
77
180
}
78
181
79
182
/// Handle output of the transaction
@@ -266,17 +369,9 @@ pub fn deduct_caller<SPEC: Spec, EXT, DB: Database>(
266
369
. evm
267
370
. inner
268
371
. l1_block_info
269
- . as_ref ( )
372
+ . as_mut ( )
270
373
. expect ( "L1BlockInfo should be loaded" )
271
374
. calculate_tx_l1_cost ( enveloped_tx, SPEC :: SPEC_ID ) ;
272
- if tx_l1_cost. gt ( & caller_account. info . balance ) {
273
- return Err ( EVMError :: Transaction (
274
- InvalidTransaction :: LackOfFundForMaxFee {
275
- fee : tx_l1_cost. into ( ) ,
276
- balance : caller_account. info . balance . into ( ) ,
277
- } ,
278
- ) ) ;
279
- }
280
375
caller_account. info . balance = caller_account. info . balance . saturating_sub ( tx_l1_cost) ;
281
376
282
377
// Deduct the operator fee from the caller's account.
@@ -314,7 +409,7 @@ pub fn reward_beneficiary<SPEC: Spec, EXT, DB: Database>(
314
409
if !is_deposit {
315
410
// If the transaction is not a deposit transaction, fees are paid out
316
411
// to both the Base Fee Vault as well as the L1 Fee Vault.
317
- let Some ( l1_block_info) = & context. evm . inner . l1_block_info else {
412
+ let Some ( l1_block_info) = & mut context. evm . inner . l1_block_info else {
318
413
return Err ( EVMError :: Custom (
319
414
"[OPTIMISM] Failed to load L1 block information." . to_string ( ) ,
320
415
) ) ;
@@ -459,6 +554,16 @@ pub fn end<SPEC: Spec, EXT, DB: Database>(
459
554
} )
460
555
}
461
556
557
+ /// Clears cache OP l1 value.
558
+ #[ inline]
559
+ pub fn clear < EXT , DB : Database > ( context : & mut Context < EXT , DB > ) {
560
+ // clear error and journaled state.
561
+ mainnet:: clear ( context) ;
562
+ if let Some ( l1_block) = & mut context. evm . inner . l1_block_info {
563
+ l1_block. clear_tx_l1_cost ( ) ;
564
+ }
565
+ }
566
+
462
567
#[ cfg( test) ]
463
568
mod tests {
464
569
use revm_interpreter:: { CallOutcome , InterpreterResult } ;
@@ -714,7 +819,7 @@ mod tests {
714
819
context. evm . inner . env . tx . optimism . enveloped_tx = Some ( bytes ! ( "FACADE" ) ) ;
715
820
716
821
assert_eq ! (
717
- deduct_caller :: <RegolithSpec , ( ) , _>( & mut context) ,
822
+ validate_tx_against_state :: <RegolithSpec , ( ) , _>( & mut context) ,
718
823
Err ( EVMError :: Transaction (
719
824
InvalidTransaction :: LackOfFundForMaxFee {
720
825
fee: Box :: new( U256 :: from( 1048 ) ) ,
0 commit comments