@@ -14,10 +14,10 @@ use alloy::{
14
14
use core:: convert:: Infallible ;
15
15
use revm:: {
16
16
db:: { states:: bundle_state:: BundleRetention , BundleState , State } ,
17
- interpreter:: gas:: CALL_STIPEND ,
17
+ interpreter:: gas:: { calculate_initial_tx_gas , CALL_STIPEND } ,
18
18
primitives:: {
19
- AccountInfo , BlockEnv , Bytecode , EVMError , EvmState , ExecutionResult , InvalidTransaction ,
20
- ResultAndState , SpecId , TxEnv , TxKind , KECCAK_EMPTY ,
19
+ AccountInfo , AuthorizationList , BlockEnv , Bytecode , EVMError , Env , EvmState ,
20
+ ExecutionResult , InvalidTransaction , ResultAndState , SpecId , TxEnv , TxKind , KECCAK_EMPTY ,
21
21
} ,
22
22
Database , DatabaseCommit , DatabaseRef , Evm ,
23
23
} ;
@@ -71,6 +71,30 @@ impl<'a, Ext, Db: Database + DatabaseCommit, TrevmState> Trevm<'a, Ext, Db, Trev
71
71
self . inner
72
72
}
73
73
74
+ /// Get a reference to the inner env. This contains the current
75
+ /// [`BlockEnv`], [`TxEnv`], and [`CfgEnv`].
76
+ ///
77
+ /// These values may be meaningless, stale, or otherwise incorrect. Reading
78
+ /// them should be done with caution, as it may lead to logic bugs.
79
+ ///
80
+ /// [`CfgEnv`]: revm::primitives::CfgEnv
81
+ pub fn env_unchecked ( & self ) -> & Env {
82
+ & self . inner ( ) . context . evm . inner . env
83
+ }
84
+
85
+ /// Get a mutable reference to the inner env. This contains the current
86
+ /// [`BlockEnv`], [`TxEnv`], and [`CfgEnv`].
87
+ ///
88
+ /// These values may be meaningless, stale, or otherwise incorrect. Reading
89
+ /// them should be done with caution, as it may lead to logic bugs.
90
+ /// Modifying these values may lead to inconsistent state or invalid
91
+ /// execution.
92
+ ///
93
+ /// [`CfgEnv`]: revm::primitives::CfgEnv
94
+ pub fn env_mut_unchecked ( & mut self ) -> & mut Env {
95
+ & mut self . inner_mut_unchecked ( ) . context . evm . inner . env
96
+ }
97
+
74
98
/// Get the id of the currently running hardfork spec. Convenience function
75
99
/// calling [`Evm::spec_id`].
76
100
pub fn spec_id ( & self ) -> SpecId {
@@ -1176,7 +1200,7 @@ impl<'a, Ext, Db: Database + DatabaseCommit, TrevmState: HasTx> Trevm<'a, Ext, D
1176
1200
}
1177
1201
}
1178
1202
1179
- // -- HAS TX with State<Db>
1203
+ // -- NEEDS TX with State<Db>
1180
1204
1181
1205
impl < Ext , Db : Database > EvmNeedsTx < ' _ , Ext , State < Db > > {
1182
1206
/// Apply block overrides to the current block.
@@ -1236,12 +1260,36 @@ impl<'a, Ext, Db: Database + DatabaseCommit> EvmReady<'a, Ext, Db> {
1236
1260
}
1237
1261
}
1238
1262
1263
+ /// Calculate the minimum gas required to start EVM execution.
1264
+ ///
1265
+ /// This uses [`calculate_initial_tx_gas`] to calculate the initial gas.
1266
+ /// Its output is dependent on
1267
+ /// - the EVM spec
1268
+ /// - the input data
1269
+ /// - whether the transaction is a contract creation or a call
1270
+ /// - the EIP-2930 access list
1271
+ /// - the number of [EIP-7702] authorizations
1272
+ ///
1273
+ /// [EIP-2930]: https://eips.ethereum.org/EIPS/eip-2930
1274
+ /// [EIP-7702]: https://eips.ethereum.org/EIPS/eip-7702
1275
+ fn calculate_initial_gas ( & self ) -> u64 {
1276
+ calculate_initial_tx_gas (
1277
+ self . spec_id ( ) ,
1278
+ & [ ] ,
1279
+ false ,
1280
+ & self . tx ( ) . access_list ,
1281
+ self . tx ( ) . authorization_list . as_ref ( ) . map ( AuthorizationList :: len) . unwrap_or_default ( )
1282
+ as u64 ,
1283
+ )
1284
+ . initial_gas
1285
+ }
1286
+
1239
1287
/// Estimate gas for a simple transfer. This will
1240
1288
/// - Check that the transaction has no input data.
1241
1289
/// - Check that the target is not a `create`.
1242
1290
/// - Check that the target is not a contract.
1243
1291
/// - Return the minimum gas required for the transfer.
1244
- fn estimate_gas_simple_transfer ( & mut self ) -> Result < Option < ( ) > , EVMError < Db :: Error > > {
1292
+ fn estimate_gas_simple_transfer ( & mut self ) -> Result < Option < u64 > , EVMError < Db :: Error > > {
1245
1293
if !self . is_transfer ( ) {
1246
1294
return Ok ( None ) ;
1247
1295
}
@@ -1254,8 +1302,9 @@ impl<'a, Ext, Db: Database + DatabaseCommit> EvmReady<'a, Ext, Db> {
1254
1302
return Ok ( None ) ;
1255
1303
}
1256
1304
1257
- // If the target is not a contract, then the gas is the minimum gas.
1258
- Ok ( Some ( ( ) ) )
1305
+ // delegate calculation to revm. This ensures that things like bogus
1306
+ // 2930 access lists don't mess up our estimates
1307
+ Ok ( Some ( self . calculate_initial_gas ( ) ) )
1259
1308
}
1260
1309
1261
1310
/// Convenience function to simplify nesting of [`Self::estimate_gas`].
@@ -1330,22 +1379,28 @@ impl<'a, Ext, Db: Database + DatabaseCommit> EvmReady<'a, Ext, Db> {
1330
1379
///
1331
1380
/// [here]: https://github.com/paradigmxyz/reth/blob/ad503a08fa242b28ad3c1fea9caa83df2dfcf72d/crates/rpc/rpc-eth-api/src/helpers/estimate.rs#L35-L42
1332
1381
pub fn estimate_gas ( mut self ) -> Result < ( EstimationResult , Self ) , EvmErrored < ' a , Ext , Db > > {
1333
- if unwrap_or_trevm_err ! ( self . estimate_gas_simple_transfer( ) , self ) . is_some ( ) {
1334
- return Ok ( ( EstimationResult :: basic_transfer_success ( ) , self ) ) ;
1382
+ if let Some ( est ) = unwrap_or_trevm_err ! ( self . estimate_gas_simple_transfer( ) , self ) {
1383
+ return Ok ( ( EstimationResult :: basic_transfer_success ( est ) , self ) ) ;
1335
1384
}
1336
1385
1337
1386
// We shrink the gas limit to 64 bits, as using more than 18 quintillion
1338
- // gas in a block is not likely .
1387
+ // gas in a block is unlikely .
1339
1388
let initial_limit = self . gas_limit ( ) ;
1340
1389
1390
+ // Start the search range at 21_000 gas.
1341
1391
let mut search_range = SearchRange :: new ( MIN_TRANSACTION_GAS , initial_limit) ;
1392
+
1393
+ // Block it to the gas cap.
1342
1394
search_range. maybe_lower_max ( self . block_gas_limit ( ) . saturating_to :: < u64 > ( ) ) ;
1343
1395
1344
1396
// Check that the account has enough ETH to cover the gas, and lower if
1345
1397
// necessary.
1346
1398
let allowance = unwrap_or_trevm_err ! ( self . gas_allowance( ) , self ) ;
1347
1399
search_range. maybe_lower_max ( allowance) ;
1348
1400
1401
+ // Raise the floor to the amount of gas required to initialize the EVM.
1402
+ search_range. maybe_raise_min ( self . calculate_initial_gas ( ) ) ;
1403
+
1349
1404
// Run an estimate with the max gas limit.
1350
1405
// NB: we declare these mut as we re-use the binding throughout the
1351
1406
// function.
0 commit comments