1
- use crate :: { alloc:: vec:: Vec , SpecId , B160 , B256 , U256 } ;
1
+ use crate :: {
2
+ alloc:: vec:: Vec , Account , EVMError , InvalidTransaction , Spec , SpecId , B160 , B256 , KECCAK_EMPTY ,
3
+ MAX_INITCODE_SIZE , U256 ,
4
+ } ;
2
5
use bytes:: Bytes ;
3
- use core:: cmp:: min;
6
+ use core:: cmp:: { min, Ordering } ;
4
7
5
8
#[ derive( Clone , Debug , Default ) ]
6
9
#[ cfg_attr( feature = "serde" , derive( serde:: Serialize , serde:: Deserialize ) ) ]
@@ -78,10 +81,6 @@ pub enum CreateScheme {
78
81
pub struct CfgEnv {
79
82
pub chain_id : U256 ,
80
83
pub spec_id : SpecId ,
81
- /// If all precompiles have some balance we can skip initially fetching them from the database.
82
- /// This is is not really needed on mainnet, and defaults to false, but in most cases it is
83
- /// safe to be set to `true`, depending on the chain.
84
- pub perf_all_precompiles_have_balance : bool ,
85
84
/// Bytecode that is created with CREATE/CREATE2 is by default analysed and jumptable is created.
86
85
/// This is very benefitial for testing and speeds up execution of that bytecode if called multiple times.
87
86
///
@@ -121,6 +120,58 @@ pub struct CfgEnv {
121
120
pub disable_base_fee : bool ,
122
121
}
123
122
123
+ impl CfgEnv {
124
+ #[ cfg( feature = "optional_eip3607" ) ]
125
+ pub fn is_eip3607_disabled ( & self ) -> bool {
126
+ self . disable_eip3607
127
+ }
128
+
129
+ #[ cfg( not( feature = "optional_eip3607" ) ) ]
130
+ pub fn is_eip3607_disabled ( & self ) -> bool {
131
+ false
132
+ }
133
+
134
+ #[ cfg( feature = "optional_balance_check" ) ]
135
+ pub fn is_balance_check_disabled ( & self ) -> bool {
136
+ self . disable_balance_check
137
+ }
138
+
139
+ #[ cfg( not( feature = "optional_balance_check" ) ) ]
140
+ pub fn is_balance_check_disabled ( & self ) -> bool {
141
+ false
142
+ }
143
+
144
+ #[ cfg( feature = "optional_gas_refund" ) ]
145
+ pub fn is_gas_refund_disabled ( & self ) -> bool {
146
+ self . disable_gas_refund
147
+ }
148
+
149
+ #[ cfg( not( feature = "optional_gas_refund" ) ) ]
150
+ pub fn is_gas_refund_disabled ( & self ) -> bool {
151
+ false
152
+ }
153
+
154
+ #[ cfg( feature = "optional_no_base_fee" ) ]
155
+ pub fn is_base_fee_check_disabled ( & self ) -> bool {
156
+ self . disable_base_fee
157
+ }
158
+
159
+ #[ cfg( not( feature = "optional_no_base_fee" ) ) ]
160
+ pub fn is_base_fee_check_disabled ( & self ) -> bool {
161
+ false
162
+ }
163
+
164
+ #[ cfg( feature = "optional_block_gas_limit" ) ]
165
+ pub fn is_block_gas_limit_disabled ( & self ) -> bool {
166
+ self . disable_block_gas_limit
167
+ }
168
+
169
+ #[ cfg( not( feature = "optional_block_gas_limit" ) ) ]
170
+ pub fn is_block_gas_limit_disabled ( & self ) -> bool {
171
+ false
172
+ }
173
+ }
174
+
124
175
#[ derive( Clone , Default , Debug , Eq , PartialEq ) ]
125
176
#[ cfg_attr( feature = "serde" , derive( serde:: Serialize , serde:: Deserialize ) ) ]
126
177
pub enum AnalysisKind {
@@ -135,7 +186,6 @@ impl Default for CfgEnv {
135
186
CfgEnv {
136
187
chain_id : U256 :: from ( 1 ) ,
137
188
spec_id : SpecId :: LATEST ,
138
- perf_all_precompiles_have_balance : false ,
139
189
perf_analyse_created_bytecodes : Default :: default ( ) ,
140
190
limit_contract_code_size : None ,
141
191
#[ cfg( feature = "memory_limit" ) ]
@@ -196,4 +246,107 @@ impl Env {
196
246
)
197
247
}
198
248
}
249
+
250
+ /// Validate ENV data of the block.
251
+ ///
252
+ /// It can be skip if you are sure that PREVRANDAO is set.
253
+ #[ inline]
254
+ pub fn validate_block_env < SPEC : Spec , T > ( & self ) -> Result < ( ) , EVMError < T > > {
255
+ // Prevrandao is required for merge
256
+ if SPEC :: enabled ( SpecId :: MERGE ) && self . block . prevrandao . is_none ( ) {
257
+ return Err ( EVMError :: PrevrandaoNotSet ) ;
258
+ }
259
+ Ok ( ( ) )
260
+ }
261
+
262
+ /// Validate transaction data that is set inside ENV and return error if something is wrong.
263
+ ///
264
+ /// Return inital spend gas (Gas needed to execute transaction).
265
+ #[ inline]
266
+ pub fn validate_tx < SPEC : Spec > ( & self ) -> Result < ( ) , InvalidTransaction > {
267
+ let gas_limit = self . tx . gas_limit ;
268
+ let effective_gas_price = self . effective_gas_price ( ) ;
269
+ let is_create = self . tx . transact_to . is_create ( ) ;
270
+
271
+ // BASEFEE tx check
272
+ if SPEC :: enabled ( SpecId :: LONDON ) {
273
+ if let Some ( priority_fee) = self . tx . gas_priority_fee {
274
+ if priority_fee > self . tx . gas_price {
275
+ // or gas_max_fee for eip1559
276
+ return Err ( InvalidTransaction :: GasMaxFeeGreaterThanPriorityFee ) ;
277
+ }
278
+ }
279
+ let basefee = self . block . basefee ;
280
+
281
+ // check minimal cost against basefee
282
+ if !self . cfg . is_base_fee_check_disabled ( ) && effective_gas_price < basefee {
283
+ return Err ( InvalidTransaction :: GasPriceLessThanBasefee ) ;
284
+ }
285
+ }
286
+
287
+ // Check if gas_limit is more than block_gas_limit
288
+ if !self . cfg . is_block_gas_limit_disabled ( ) && U256 :: from ( gas_limit) > self . block . gas_limit {
289
+ return Err ( InvalidTransaction :: CallerGasLimitMoreThanBlock ) ;
290
+ }
291
+
292
+ // EIP-3860: Limit and meter initcode
293
+ if SPEC :: enabled ( SpecId :: SHANGHAI ) && is_create && self . tx . data . len ( ) > MAX_INITCODE_SIZE {
294
+ return Err ( InvalidTransaction :: CreateInitcodeSizeLimit ) ;
295
+ }
296
+
297
+ // Check if the transaction's chain id is correct
298
+ if let Some ( tx_chain_id) = self . tx . chain_id {
299
+ if U256 :: from ( tx_chain_id) != self . cfg . chain_id {
300
+ return Err ( InvalidTransaction :: InvalidChainId ) ;
301
+ }
302
+ }
303
+
304
+ // Check if the transaction's chain id is correct
305
+ if !SPEC :: enabled ( SpecId :: BERLIN ) && !self . tx . access_list . is_empty ( ) {
306
+ return Err ( InvalidTransaction :: AccessListNotSupported ) ;
307
+ }
308
+
309
+ Ok ( ( ) )
310
+ }
311
+
312
+ /// Validate transaction agains state.
313
+ #[ inline]
314
+ pub fn validate_tx_agains_state ( & self , account : & Account ) -> Result < ( ) , InvalidTransaction > {
315
+ // EIP-3607: Reject transactions from senders with deployed code
316
+ // This EIP is introduced after london but there was no collision in past
317
+ // so we can leave it enabled always
318
+ if !self . cfg . is_eip3607_disabled ( ) && account. info . code_hash != KECCAK_EMPTY {
319
+ return Err ( InvalidTransaction :: RejectCallerWithCode ) ;
320
+ }
321
+
322
+ // Check that the transaction's nonce is correct
323
+ if let Some ( tx) = self . tx . nonce {
324
+ let state = account. info . nonce ;
325
+ match tx. cmp ( & state) {
326
+ Ordering :: Greater => {
327
+ return Err ( InvalidTransaction :: NonceTooHigh { tx, state } ) ;
328
+ }
329
+ Ordering :: Less => {
330
+ return Err ( InvalidTransaction :: NonceTooLow { tx, state } ) ;
331
+ }
332
+ _ => { }
333
+ }
334
+ }
335
+
336
+ let balance_check = U256 :: from ( self . tx . gas_limit )
337
+ . checked_mul ( self . tx . gas_price )
338
+ . and_then ( |gas_cost| gas_cost. checked_add ( self . tx . value ) )
339
+ . ok_or ( InvalidTransaction :: OverflowPaymentInTransaction ) ?;
340
+
341
+ // Check if account has enough balance for gas_limit*gas_price and value transfer.
342
+ // Transfer will be done inside `*_inner` functions.
343
+ if !self . cfg . is_balance_check_disabled ( ) && balance_check > account. info . balance {
344
+ return Err ( InvalidTransaction :: LackOfFundForMaxFee {
345
+ fee : self . tx . gas_limit ,
346
+ balance : account. info . balance ,
347
+ } ) ;
348
+ }
349
+
350
+ Ok ( ( ) )
351
+ }
199
352
}
0 commit comments