refactor: use EvmEnv when setting up Evm (#13800)

This commit is contained in:
Arsenii Kulikov
2025-01-15 20:09:03 +04:00
committed by GitHub
parent f2bf02413f
commit d5978a78b4
16 changed files with 551 additions and 585 deletions

2
Cargo.lock generated
View File

@ -2985,7 +2985,9 @@ dependencies = [
"clap",
"futures-util",
"reth",
"reth-evm",
"reth-node-ethereum",
"revm-primitives",
]
[[package]]

View File

@ -198,7 +198,7 @@ mod tests {
primitives::{BlockEnv, CfgEnv, SpecId},
JournaledState,
};
use revm_primitives::{EnvWithHandlerCfg, HandlerCfg};
use revm_primitives::HandlerCfg;
use std::collections::HashSet;
#[test]
@ -272,12 +272,13 @@ mod tests {
let db = CacheDB::<EmptyDBTyped<ProviderError>>::default();
let env_with_handler = EnvWithHandlerCfg::default();
let evm_env = EvmEnv::default();
let evm = evm_config.evm_with_env(db, env_with_handler.clone());
let evm = evm_config.evm_with_env(db, evm_env.clone(), Default::default());
// Check that the EVM environment
assert_eq!(evm.context.evm.env, env_with_handler.env);
assert_eq!(evm.context.evm.env.block, evm_env.block_env);
assert_eq!(evm.context.evm.env.cfg, evm_env.cfg_env_with_handler_cfg.cfg_env);
// Default spec ID
assert_eq!(evm.handler.spec_id(), SpecId::LATEST);
@ -296,16 +297,15 @@ mod tests {
// Create a custom configuration environment with a chain ID of 111
let cfg = CfgEnv::default().with_chain_id(111);
let env_with_handler = EnvWithHandlerCfg {
env: Box::new(Env {
cfg: cfg.clone(),
block: BlockEnv::default(),
tx: TxEnv::default(),
}),
let evm_env = EvmEnv {
cfg_env_with_handler_cfg: CfgEnvWithHandlerCfg {
cfg_env: cfg.clone(),
handler_cfg: Default::default(),
},
..Default::default()
};
let evm = evm_config.evm_with_env(db, env_with_handler);
let evm = evm_config.evm_with_env(db, evm_env, Default::default());
// Check that the EVM environment is initialized with the custom environment
assert_eq!(evm.context.evm.inner.env.cfg, cfg);
@ -333,16 +333,19 @@ mod tests {
};
let tx = TxEnv { gas_limit: 5_000_000, gas_price: U256::from(50), ..Default::default() };
let env_with_handler = EnvWithHandlerCfg {
env: Box::new(Env { cfg: CfgEnv::default(), block, tx }),
let evm_env = EvmEnv {
cfg_env_with_handler_cfg: CfgEnvWithHandlerCfg {
cfg_env: CfgEnv::default(),
handler_cfg: Default::default(),
},
block_env: block,
};
let evm = evm_config.evm_with_env(db, env_with_handler.clone());
let evm = evm_config.evm_with_env(db, evm_env.clone(), tx.clone());
// Verify that the block and transaction environments are set correctly
assert_eq!(evm.context.evm.env.block, env_with_handler.env.block);
assert_eq!(evm.context.evm.env.tx, env_with_handler.env.tx);
assert_eq!(evm.context.evm.env.block, evm_env.block_env);
assert_eq!(evm.context.evm.env.tx, tx);
// Default spec ID
assert_eq!(evm.handler.spec_id(), SpecId::LATEST);
@ -360,9 +363,15 @@ mod tests {
let handler_cfg = HandlerCfg { spec_id: SpecId::CONSTANTINOPLE, ..Default::default() };
let env_with_handler = EnvWithHandlerCfg { env: Box::new(Env::default()), handler_cfg };
let evm_env = EvmEnv {
cfg_env_with_handler_cfg: CfgEnvWithHandlerCfg {
cfg_env: Default::default(),
handler_cfg,
},
..Default::default()
};
let evm = evm_config.evm_with_env(db, env_with_handler);
let evm = evm_config.evm_with_env(db, evm_env, Default::default());
// Check that the spec ID is setup properly
assert_eq!(evm.handler.spec_id(), SpecId::CONSTANTINOPLE);
@ -422,13 +431,18 @@ mod tests {
let evm_config = EthEvmConfig::new(MAINNET.clone());
let db = CacheDB::<EmptyDBTyped<ProviderError>>::default();
let env_with_handler = EnvWithHandlerCfg::default();
let evm_env = EvmEnv::default();
let evm =
evm_config.evm_with_env_and_inspector(db, env_with_handler.clone(), NoOpInspector);
let evm = evm_config.evm_with_env_and_inspector(
db,
evm_env.clone(),
Default::default(),
NoOpInspector,
);
// Check that the EVM environment is set to default values
assert_eq!(evm.context.evm.env, env_with_handler.env);
assert_eq!(evm.context.evm.env.block, evm_env.block_env);
assert_eq!(evm.context.evm.env.cfg, evm_env.cfg_env_with_handler_cfg.cfg_env);
assert_eq!(evm.context.external, NoOpInspector);
assert_eq!(evm.handler.spec_id(), SpecId::LATEST);
@ -442,18 +456,21 @@ mod tests {
let evm_config = EthEvmConfig::new(MAINNET.clone());
let db = CacheDB::<EmptyDBTyped<ProviderError>>::default();
let cfg = CfgEnv::default().with_chain_id(111);
let cfg_env = CfgEnv::default().with_chain_id(111);
let block = BlockEnv::default();
let tx = TxEnv::default();
let env_with_handler = EnvWithHandlerCfg {
env: Box::new(Env { cfg: cfg.clone(), block, tx }),
let evm_env = EvmEnv {
cfg_env_with_handler_cfg: CfgEnvWithHandlerCfg {
cfg_env: cfg_env.clone(),
handler_cfg: Default::default(),
},
block_env: block,
};
let evm = evm_config.evm_with_env_and_inspector(db, env_with_handler, NoOpInspector);
let evm = evm_config.evm_with_env_and_inspector(db, evm_env, tx, NoOpInspector);
// Check that the EVM environment is set with custom configuration
assert_eq!(evm.context.evm.env.cfg, cfg);
assert_eq!(evm.context.evm.env.cfg, cfg_env);
assert_eq!(evm.context.external, NoOpInspector);
assert_eq!(evm.handler.spec_id(), SpecId::LATEST);
@ -475,17 +492,14 @@ mod tests {
..Default::default()
};
let tx = TxEnv { gas_limit: 5_000_000, gas_price: U256::from(50), ..Default::default() };
let env_with_handler = EnvWithHandlerCfg {
env: Box::new(Env { cfg: CfgEnv::default(), block, tx }),
handler_cfg: Default::default(),
};
let evm_env = EvmEnv { block_env: block, ..Default::default() };
let evm =
evm_config.evm_with_env_and_inspector(db, env_with_handler.clone(), NoOpInspector);
evm_config.evm_with_env_and_inspector(db, evm_env.clone(), tx.clone(), NoOpInspector);
// Verify that the block and transaction environments are set correctly
assert_eq!(evm.context.evm.env.block, env_with_handler.env.block);
assert_eq!(evm.context.evm.env.tx, env_with_handler.env.tx);
assert_eq!(evm.context.evm.env.block, evm_env.block_env);
assert_eq!(evm.context.evm.env.tx, tx);
assert_eq!(evm.context.external, NoOpInspector);
assert_eq!(evm.handler.spec_id(), SpecId::LATEST);
@ -500,14 +514,26 @@ mod tests {
let db = CacheDB::<EmptyDBTyped<ProviderError>>::default();
let handler_cfg = HandlerCfg { spec_id: SpecId::CONSTANTINOPLE, ..Default::default() };
let env_with_handler = EnvWithHandlerCfg { env: Box::new(Env::default()), handler_cfg };
let evm_env = EvmEnv {
cfg_env_with_handler_cfg: CfgEnvWithHandlerCfg {
handler_cfg,
cfg_env: Default::default(),
},
..Default::default()
};
let evm =
evm_config.evm_with_env_and_inspector(db, env_with_handler.clone(), NoOpInspector);
let evm = evm_config.evm_with_env_and_inspector(
db,
evm_env.clone(),
Default::default(),
NoOpInspector,
);
// Check that the spec ID is set properly
assert_eq!(evm.handler.spec_id(), SpecId::CONSTANTINOPLE);
assert_eq!(evm.context.evm.env, env_with_handler.env);
assert_eq!(evm.context.evm.env.block, evm_env.block_env);
assert_eq!(evm.context.evm.env.cfg, evm_env.cfg_env_with_handler_cfg.cfg_env);
assert_eq!(evm.context.evm.env.tx, Default::default());
assert_eq!(evm.context.external, NoOpInspector);
// No Optimism

View File

@ -41,10 +41,7 @@ use reth_transaction_pool::{
};
use revm::{
db::{states::bundle_state::BundleRetention, State},
primitives::{
BlockEnv, CfgEnvWithHandlerCfg, EVMError, EnvWithHandlerCfg, InvalidTransaction,
ResultAndState, TxEnv,
},
primitives::{EVMError, InvalidTransaction, ResultAndState},
DatabaseCommit,
};
use std::sync::Arc;
@ -77,7 +74,7 @@ impl<EvmConfig> EthereumPayloadBuilder<EvmConfig>
where
EvmConfig: ConfigureEvm<Header = Header>,
{
/// Returns the configured [`CfgEnvWithHandlerCfg`] and [`BlockEnv`] for the targeted payload
/// Returns the configured [`EvmEnv`] for the targeted payload
/// (that has the `parent` as its parent).
fn cfg_and_block_env(
&self,
@ -108,7 +105,7 @@ where
&self,
args: BuildArguments<Pool, Client, EthPayloadBuilderAttributes, EthBuiltPayload>,
) -> Result<BuildOutcome<EthBuiltPayload>, PayloadBuilderError> {
let EvmEnv { cfg_env_with_handler_cfg, block_env } = self
let evm_env = self
.cfg_and_block_env(&args.config, &args.config.parent_header)
.map_err(PayloadBuilderError::other)?;
@ -117,8 +114,7 @@ where
self.evm_config.clone(),
self.builder_config.clone(),
args,
cfg_env_with_handler_cfg,
block_env,
evm_env,
|attributes| pool.best_transactions_with_attributes(attributes),
)
}
@ -138,7 +134,7 @@ where
None,
);
let EvmEnv { cfg_env_with_handler_cfg, block_env } = self
let evm_env = self
.cfg_and_block_env(&args.config, &args.config.parent_header)
.map_err(PayloadBuilderError::other)?;
@ -148,8 +144,7 @@ where
self.evm_config.clone(),
self.builder_config.clone(),
args,
cfg_env_with_handler_cfg,
block_env,
evm_env,
|attributes| pool.best_transactions_with_attributes(attributes),
)?
.into_payload()
@ -167,8 +162,7 @@ pub fn default_ethereum_payload<EvmConfig, Pool, Client, F>(
evm_config: EvmConfig,
builder_config: EthereumBuilderConfig,
args: BuildArguments<Pool, Client, EthPayloadBuilderAttributes, EthBuiltPayload>,
initialized_cfg: CfgEnvWithHandlerCfg,
initialized_block_env: BlockEnv,
evm_env: EvmEnv,
best_txs: F,
) -> Result<BuildOutcome<EthBuiltPayload>, PayloadBuilderError>
where
@ -189,19 +183,20 @@ where
debug!(target: "payload_builder", id=%attributes.id, parent_header = ?parent_header.hash(), parent_number = parent_header.number, "building new payload");
let mut cumulative_gas_used = 0;
let mut sum_blob_gas_used = 0;
let block_gas_limit: u64 = initialized_block_env.gas_limit.to::<u64>();
let base_fee = initialized_block_env.basefee.to::<u64>();
let block_gas_limit: u64 = evm_env.block_env.gas_limit.to::<u64>();
let base_fee = evm_env.block_env.basefee.to::<u64>();
let mut executed_txs = Vec::new();
let mut executed_senders = Vec::new();
let mut best_txs = best_txs(BestTransactionsAttributes::new(
base_fee,
initialized_block_env.get_blob_gasprice().map(|gasprice| gasprice as u64),
evm_env.block_env.get_blob_gasprice().map(|gasprice| gasprice as u64),
));
let mut total_fees = U256::ZERO;
let block_number = initialized_block_env.number.to::<u64>();
let block_number = evm_env.block_env.number.to::<u64>();
let beneficiary = evm_env.block_env.coinbase;
let mut system_caller = SystemCaller::new(evm_config.clone(), chain_spec.clone());
@ -209,8 +204,8 @@ where
system_caller
.pre_block_beacon_root_contract_call(
&mut db,
&initialized_cfg,
&initialized_block_env,
evm_env.cfg_env_with_handler_cfg(),
evm_env.block_env(),
attributes.parent_beacon_block_root,
)
.map_err(|err| {
@ -225,8 +220,8 @@ where
// apply eip-2935 blockhashes update
system_caller.pre_block_blockhashes_contract_call(
&mut db,
&initialized_cfg,
&initialized_block_env,
evm_env.cfg_env_with_handler_cfg(),
evm_env.block_env(),
parent_header.hash(),
)
.map_err(|err| {
@ -234,12 +229,7 @@ where
PayloadBuilderError::Internal(err.into())
})?;
let env = EnvWithHandlerCfg::new_with_cfg_env(
initialized_cfg.clone(),
initialized_block_env.clone(),
TxEnv::default(),
);
let mut evm = evm_config.evm_with_env(&mut db, env);
let mut evm = evm_config.evm_with_env(&mut db, evm_env, Default::default());
let mut receipts = Vec::new();
while let Some(pool_tx) = best_txs.next() {
@ -458,7 +448,7 @@ where
let header = Header {
parent_hash: parent_header.hash(),
ommers_hash: EMPTY_OMMER_ROOT_HASH,
beneficiary: initialized_block_env.coinbase,
beneficiary,
state_root,
transactions_root,
receipts_root,

View File

@ -9,6 +9,19 @@ pub struct EvmEnv {
pub block_env: BlockEnv,
}
impl Default for EvmEnv {
fn default() -> Self {
Self {
cfg_env_with_handler_cfg: CfgEnvWithHandlerCfg {
cfg_env: Default::default(),
// Will set `is_optimism` if `revm/optimism-default-handler` is enabled.
handler_cfg: Default::default(),
},
block_env: BlockEnv::default(),
}
}
}
impl EvmEnv {
/// Create a new `EvmEnv` from its components.
///

View File

@ -18,19 +18,18 @@
extern crate alloc;
use crate::builder::RethEvmBuilder;
use alloc::boxed::Box;
use alloy_consensus::BlockHeader as _;
use alloy_primitives::{Address, Bytes, B256, U256};
use reth_primitives_traits::{BlockHeader, SignedTransaction};
use revm::{Database, Evm, GetInspector};
use revm_primitives::{BlockEnv, CfgEnvWithHandlerCfg, Env, EnvWithHandlerCfg, SpecId, TxEnv};
use revm_primitives::{BlockEnv, CfgEnvWithHandlerCfg, Env, SpecId, TxEnv};
pub mod builder;
pub mod either;
/// EVM environment configuration.
pub mod env;
pub mod execute;
use env::EvmEnv;
pub use env::EvmEnv;
#[cfg(feature = "std")]
pub mod metrics;
@ -53,13 +52,14 @@ pub trait ConfigureEvm: ConfigureEvmEnv {
}
/// Returns a new EVM with the given database configured with the given environment settings,
/// including the spec id.
/// including the spec id and transaction environment.
///
/// This will preserve any handler modifications
fn evm_with_env<DB: Database>(&self, db: DB, env: EnvWithHandlerCfg) -> Evm<'_, (), DB> {
fn evm_with_env<DB: Database>(&self, db: DB, evm_env: EvmEnv, tx: TxEnv) -> Evm<'_, (), DB> {
let mut evm = self.evm(db);
evm.modify_spec_id(env.spec_id());
evm.context.evm.env = env.env;
evm.modify_spec_id(evm_env.cfg_env_with_handler_cfg.handler_cfg.spec_id);
evm.context.evm.env =
Env::boxed(evm_env.cfg_env_with_handler_cfg.cfg_env, evm_env.block_env, tx);
evm
}
@ -71,17 +71,8 @@ pub trait ConfigureEvm: ConfigureEvmEnv {
///
/// This does not initialize the tx environment.
fn evm_for_block<DB: Database>(&self, db: DB, header: &Self::Header) -> Evm<'_, (), DB> {
let EvmEnv {
cfg_env_with_handler_cfg: CfgEnvWithHandlerCfg { cfg_env, handler_cfg },
block_env,
} = self.cfg_and_block_env(header);
self.evm_with_env(
db,
EnvWithHandlerCfg {
env: Box::new(Env { cfg: cfg_env, block: block_env, tx: Default::default() }),
handler_cfg,
},
)
let evm_env = self.cfg_and_block_env(header);
self.evm_with_env(db, evm_env, Default::default())
}
/// Returns a new EVM with the given database configured with the given environment settings,
@ -93,7 +84,8 @@ pub trait ConfigureEvm: ConfigureEvmEnv {
fn evm_with_env_and_inspector<DB, I>(
&self,
db: DB,
env: EnvWithHandlerCfg,
evm_env: EvmEnv,
tx: TxEnv,
inspector: I,
) -> Evm<'_, I, DB>
where
@ -101,8 +93,9 @@ pub trait ConfigureEvm: ConfigureEvmEnv {
I: GetInspector<DB>,
{
let mut evm = self.evm_with_inspector(db, inspector);
evm.modify_spec_id(env.spec_id());
evm.context.evm.env = env.env;
evm.modify_spec_id(evm_env.cfg_env_with_handler_cfg.handler_cfg.spec_id);
evm.context.evm.env =
Env::boxed(evm_env.cfg_env_with_handler_cfg.cfg_env, evm_env.block_env, tx);
evm
}
@ -133,21 +126,22 @@ where
(*self).evm_for_block(db, header)
}
fn evm_with_env<DB: Database>(&self, db: DB, env: EnvWithHandlerCfg) -> Evm<'_, (), DB> {
(*self).evm_with_env(db, env)
fn evm_with_env<DB: Database>(&self, db: DB, evm_env: EvmEnv, tx: TxEnv) -> Evm<'_, (), DB> {
(*self).evm_with_env(db, evm_env, tx)
}
fn evm_with_env_and_inspector<DB, I>(
&self,
db: DB,
env: EnvWithHandlerCfg,
evm_env: EvmEnv,
tx_env: TxEnv,
inspector: I,
) -> Evm<'_, I, DB>
where
DB: Database,
I: GetInspector<DB>,
{
(*self).evm_with_env_and_inspector(db, env, inspector)
(*self).evm_with_env_and_inspector(db, evm_env, tx_env, inspector)
}
fn evm_with_inspector<DB, I>(&self, db: DB, inspector: I) -> Evm<'_, I, DB>

View File

@ -211,7 +211,7 @@ mod tests {
primitives::{AccountInfo, BlockEnv, CfgEnv, SpecId},
JournaledState,
};
use revm_primitives::{EnvWithHandlerCfg, HandlerCfg};
use revm_primitives::HandlerCfg;
use std::sync::Arc;
fn test_evm_config() -> OpEvmConfig {
@ -291,12 +291,12 @@ mod tests {
let db = CacheDB::<EmptyDBTyped<ProviderError>>::default();
let env_with_handler = EnvWithHandlerCfg::default();
let evm_env = EvmEnv::default();
let evm = evm_config.evm_with_env(db, env_with_handler.clone());
let evm = evm_config.evm_with_env(db, evm_env.clone(), Default::default());
// Check that the EVM environment
assert_eq!(evm.context.evm.env, env_with_handler.env);
assert_eq!(evm.context.evm.env.cfg, evm_env.cfg_env_with_handler_cfg.cfg_env);
// Default spec ID
assert_eq!(evm.handler.spec_id(), SpecId::LATEST);
@ -314,16 +314,15 @@ mod tests {
// Create a custom configuration environment with a chain ID of 111
let cfg = CfgEnv::default().with_chain_id(111);
let env_with_handler = EnvWithHandlerCfg {
env: Box::new(Env {
cfg: cfg.clone(),
block: BlockEnv::default(),
tx: TxEnv::default(),
}),
let evm_env = EvmEnv {
cfg_env_with_handler_cfg: CfgEnvWithHandlerCfg {
cfg_env: cfg.clone(),
handler_cfg: Default::default(),
},
..Default::default()
};
let evm = evm_config.evm_with_env(db, env_with_handler);
let evm = evm_config.evm_with_env(db, evm_env, Default::default());
// Check that the EVM environment is initialized with the custom environment
assert_eq!(evm.context.evm.inner.env.cfg, cfg);
@ -350,16 +349,13 @@ mod tests {
};
let tx = TxEnv { gas_limit: 5_000_000, gas_price: U256::from(50), ..Default::default() };
let env_with_handler = EnvWithHandlerCfg {
env: Box::new(Env { cfg: CfgEnv::default(), block, tx }),
handler_cfg: Default::default(),
};
let evm_env = EvmEnv { block_env: block, ..Default::default() };
let evm = evm_config.evm_with_env(db, env_with_handler.clone());
let evm = evm_config.evm_with_env(db, evm_env.clone(), tx.clone());
// Verify that the block and transaction environments are set correctly
assert_eq!(evm.context.evm.env.block, env_with_handler.env.block);
assert_eq!(evm.context.evm.env.tx, env_with_handler.env.tx);
assert_eq!(evm.context.evm.env.block, evm_env.block_env);
assert_eq!(evm.context.evm.env.tx, tx);
// Default spec ID
assert_eq!(evm.handler.spec_id(), SpecId::LATEST);
@ -376,9 +372,15 @@ mod tests {
let handler_cfg = HandlerCfg { spec_id: SpecId::ECOTONE, ..Default::default() };
let env_with_handler = EnvWithHandlerCfg { env: Box::new(Env::default()), handler_cfg };
let evm_env = EvmEnv {
cfg_env_with_handler_cfg: CfgEnvWithHandlerCfg {
handler_cfg,
cfg_env: Default::default(),
},
..Default::default()
};
let evm = evm_config.evm_with_env(db, env_with_handler);
let evm = evm_config.evm_with_env(db, evm_env, Default::default());
// Check that the spec ID is setup properly
assert_eq!(evm.handler.spec_id(), SpecId::ECOTONE);
@ -436,13 +438,25 @@ mod tests {
let evm_config = test_evm_config();
let db = CacheDB::<EmptyDBTyped<ProviderError>>::default();
let env_with_handler = EnvWithHandlerCfg::default();
let evm_env = EvmEnv {
cfg_env_with_handler_cfg: CfgEnvWithHandlerCfg {
cfg_env: Default::default(),
handler_cfg: HandlerCfg { is_optimism: true, ..Default::default() },
},
..Default::default()
};
let evm =
evm_config.evm_with_env_and_inspector(db, env_with_handler.clone(), NoOpInspector);
let evm = evm_config.evm_with_env_and_inspector(
db,
evm_env.clone(),
Default::default(),
NoOpInspector,
);
// Check that the EVM environment is set to default values
assert_eq!(evm.context.evm.env, env_with_handler.env);
assert_eq!(evm.context.evm.env.block, evm_env.block_env);
assert_eq!(evm.context.evm.env.cfg, evm_env.cfg_env_with_handler_cfg.cfg_env);
assert_eq!(evm.context.evm.env.tx, Default::default());
assert_eq!(evm.context.external, NoOpInspector);
assert_eq!(evm.handler.spec_id(), SpecId::LATEST);
@ -458,15 +472,21 @@ mod tests {
let cfg = CfgEnv::default().with_chain_id(111);
let block = BlockEnv::default();
let tx = TxEnv::default();
let env_with_handler = EnvWithHandlerCfg {
env: Box::new(Env { cfg: cfg.clone(), block, tx }),
let evm_env = EvmEnv {
block_env: block,
cfg_env_with_handler_cfg: CfgEnvWithHandlerCfg {
cfg_env: cfg.clone(),
handler_cfg: Default::default(),
},
};
let evm = evm_config.evm_with_env_and_inspector(db, env_with_handler, NoOpInspector);
let evm =
evm_config.evm_with_env_and_inspector(db, evm_env.clone(), tx.clone(), NoOpInspector);
// Check that the EVM environment is set with custom configuration
assert_eq!(evm.context.evm.env.cfg, cfg);
assert_eq!(evm.context.evm.env.block, evm_env.block_env);
assert_eq!(evm.context.evm.env.tx, tx);
assert_eq!(evm.context.external, NoOpInspector);
assert_eq!(evm.handler.spec_id(), SpecId::LATEST);
@ -487,17 +507,14 @@ mod tests {
..Default::default()
};
let tx = TxEnv { gas_limit: 5_000_000, gas_price: U256::from(50), ..Default::default() };
let env_with_handler = EnvWithHandlerCfg {
env: Box::new(Env { cfg: CfgEnv::default(), block, tx }),
handler_cfg: Default::default(),
};
let evm_env = EvmEnv { block_env: block, ..Default::default() };
let evm =
evm_config.evm_with_env_and_inspector(db, env_with_handler.clone(), NoOpInspector);
evm_config.evm_with_env_and_inspector(db, evm_env.clone(), tx.clone(), NoOpInspector);
// Verify that the block and transaction environments are set correctly
assert_eq!(evm.context.evm.env.block, env_with_handler.env.block);
assert_eq!(evm.context.evm.env.tx, env_with_handler.env.tx);
assert_eq!(evm.context.evm.env.block, evm_env.block_env);
assert_eq!(evm.context.evm.env.tx, tx);
assert_eq!(evm.context.external, NoOpInspector);
assert_eq!(evm.handler.spec_id(), SpecId::LATEST);
@ -511,14 +528,25 @@ mod tests {
let db = CacheDB::<EmptyDBTyped<ProviderError>>::default();
let handler_cfg = HandlerCfg { spec_id: SpecId::ECOTONE, ..Default::default() };
let env_with_handler = EnvWithHandlerCfg { env: Box::new(Env::default()), handler_cfg };
let evm_env = EvmEnv {
cfg_env_with_handler_cfg: CfgEnvWithHandlerCfg {
cfg_env: Default::default(),
handler_cfg,
},
..Default::default()
};
let evm =
evm_config.evm_with_env_and_inspector(db, env_with_handler.clone(), NoOpInspector);
let evm = evm_config.evm_with_env_and_inspector(
db,
evm_env.clone(),
Default::default(),
NoOpInspector,
);
// Check that the spec ID is set properly
assert_eq!(evm.handler.spec_id(), SpecId::ECOTONE);
assert_eq!(evm.context.evm.env, env_with_handler.env);
assert_eq!(evm.context.evm.env.cfg, evm_env.cfg_env_with_handler_cfg.cfg_env);
assert_eq!(evm.context.evm.env.block, evm_env.block_env);
assert_eq!(evm.context.external, NoOpInspector);
// Check that the spec ID is setup properly

View File

@ -38,10 +38,7 @@ use reth_transaction_pool::{
};
use revm::{
db::{states::bundle_state::BundleRetention, State},
primitives::{
BlockEnv, CfgEnvWithHandlerCfg, EVMError, EnvWithHandlerCfg, InvalidTransaction,
ResultAndState, TxEnv,
},
primitives::{EVMError, InvalidTransaction, ResultAndState},
Database, DatabaseCommit,
};
use std::{fmt::Display, sync::Arc};
@ -127,7 +124,6 @@ where
let evm_env = self
.cfg_and_block_env(&args.config.attributes, &args.config.parent_header)
.map_err(PayloadBuilderError::other)?;
let EvmEnv { cfg_env_with_handler_cfg, block_env } = evm_env;
let BuildArguments { client, pool: _, mut cached_reads, config, cancel, best_payload } =
args;
@ -136,8 +132,7 @@ where
evm_config: self.evm_config.clone(),
chain_spec: client.chain_spec(),
config,
initialized_cfg: cfg_env_with_handler_cfg,
initialized_block_env: block_env,
evm_env,
cancel,
best_payload,
};
@ -192,15 +187,13 @@ where
let evm_env =
self.cfg_and_block_env(&attributes, &parent).map_err(PayloadBuilderError::other)?;
let EvmEnv { cfg_env_with_handler_cfg, block_env } = evm_env;
let config = PayloadConfig { parent_header: Arc::new(parent), attributes };
let ctx = OpPayloadBuilderCtx {
evm_config: self.evm_config.clone(),
chain_spec: client.chain_spec(),
config,
initialized_cfg: cfg_env_with_handler_cfg,
initialized_block_env: block_env,
evm_env,
cancel: Default::default(),
best_payload: Default::default(),
};
@ -402,7 +395,7 @@ where
let header = Header {
parent_hash: ctx.parent().hash(),
ommers_hash: EMPTY_OMMER_ROOT_HASH,
beneficiary: ctx.initialized_block_env.coinbase,
beneficiary: ctx.evm_env.block_env.coinbase,
state_root,
transactions_root,
receipts_root,
@ -557,9 +550,7 @@ pub struct OpPayloadBuilderCtx<EvmConfig> {
/// How to build the payload.
pub config: PayloadConfig<OpPayloadBuilderAttributes>,
/// Evm Settings
pub initialized_cfg: CfgEnvWithHandlerCfg,
/// Block config
pub initialized_block_env: BlockEnv,
pub evm_env: EvmEnv,
/// Marker to check whether the job has been cancelled.
pub cancel: Cancelled,
/// The currently best payload.
@ -588,22 +579,22 @@ impl<EvmConfig> OpPayloadBuilderCtx<EvmConfig> {
pub fn block_gas_limit(&self) -> u64 {
self.attributes()
.gas_limit
.unwrap_or_else(|| self.initialized_block_env.gas_limit.saturating_to())
.unwrap_or_else(|| self.evm_env.block_env.gas_limit.saturating_to())
}
/// Returns the block number for the block.
pub fn block_number(&self) -> u64 {
self.initialized_block_env.number.to()
self.evm_env.block_env.number.to()
}
/// Returns the current base fee
pub fn base_fee(&self) -> u64 {
self.initialized_block_env.basefee.to()
self.evm_env.block_env.basefee.to()
}
/// Returns the current blob gas price.
pub fn get_blob_gasprice(&self) -> Option<u64> {
self.initialized_block_env.get_blob_gasprice().map(|gasprice| gasprice as u64)
self.evm_env.block_env.get_blob_gasprice().map(|gasprice| gasprice as u64)
}
/// Returns the blob fields for the header.
@ -722,8 +713,8 @@ where
SystemCaller::new(self.evm_config.clone(), self.chain_spec.clone())
.pre_block_beacon_root_contract_call(
db,
&self.initialized_cfg,
&self.initialized_block_env,
&self.evm_env.cfg_env_with_handler_cfg,
&self.evm_env.block_env,
self.attributes().payload_attributes.parent_beacon_block_root,
)
.map_err(|err| {
@ -747,13 +738,8 @@ where
DB: Database<Error = ProviderError>,
{
let mut info = ExecutionInfo::with_capacity(self.attributes().transactions.len());
let env = EnvWithHandlerCfg::new_with_cfg_env(
self.initialized_cfg.clone(),
self.initialized_block_env.clone(),
TxEnv::default(),
);
let mut evm = self.evm_config.evm_with_env(&mut *db, env);
let mut evm =
self.evm_config.evm_with_env(&mut *db, self.evm_env.clone(), Default::default());
for sequencer_tx in &self.attributes().transactions {
// A sequencer's block should never contain blob transactions.
@ -862,12 +848,8 @@ where
let block_gas_limit = self.block_gas_limit();
let base_fee = self.base_fee();
let env = EnvWithHandlerCfg::new_with_cfg_env(
self.initialized_cfg.clone(),
self.initialized_block_env.clone(),
TxEnv::default(),
);
let mut evm = self.evm_config.evm_with_env(&mut *db, env);
let mut evm =
self.evm_config.evm_with_env(&mut *db, self.evm_env.clone(), Default::default());
while let Some(tx) = best_txs.next(()) {
// ensure we still have capacity for this transaction

View File

@ -41,6 +41,7 @@ use reth_rpc_eth_types::{
};
use revm::{Database, DatabaseCommit, GetInspector};
use revm_inspectors::{access_list::AccessListInspector, transfer::TransferInspector};
use revm_primitives::Env;
use tracing::trace;
/// Result type for `eth_simulateV1` RPC method.
@ -86,8 +87,7 @@ pub trait EthCall: EstimateCall + Call + LoadPendingBlock + LoadBlock + FullEthA
}
// Build cfg and block env, we'll reuse those.
let (evm_env, block) = self.evm_env_at(block.unwrap_or_default()).await?;
let EvmEnv { mut cfg_env_with_handler_cfg, mut block_env } = evm_env;
let (mut evm_env, block) = self.evm_env_at(block.unwrap_or_default()).await?;
// Gas cap for entire operation
let total_gas_limit = self.call_gas_limit();
@ -97,9 +97,9 @@ pub trait EthCall: EstimateCall + Call + LoadPendingBlock + LoadBlock + FullEthA
let mut parent_hash = base_block.hash();
// Only enforce base fee if validation is enabled
cfg_env_with_handler_cfg.disable_base_fee = !validation;
evm_env.cfg_env_with_handler_cfg.disable_base_fee = !validation;
// Always disable EIP-3607
cfg_env_with_handler_cfg.disable_eip3607 = true;
evm_env.cfg_env_with_handler_cfg.disable_eip3607 = true;
let this = self.clone();
self.spawn_with_state_at_block(block, move |state| {
@ -110,13 +110,13 @@ pub trait EthCall: EstimateCall + Call + LoadPendingBlock + LoadBlock + FullEthA
let mut block_state_calls = block_state_calls.into_iter().peekable();
while let Some(block) = block_state_calls.next() {
// Increase number and timestamp for every new block
block_env.number += U256::from(1);
block_env.timestamp += U256::from(1);
evm_env.block_env.number += U256::from(1);
evm_env.block_env.timestamp += U256::from(1);
if validation {
let chain_spec = RpcNodeCore::provider(&this).chain_spec();
let base_fee_params =
chain_spec.base_fee_params_at_timestamp(block_env.timestamp.to());
let base_fee_params = chain_spec
.base_fee_params_at_timestamp(evm_env.block_env.timestamp.to());
let base_fee = if let Some(latest) = blocks.last() {
let header = &latest.inner.header;
calc_next_block_base_fee(
@ -128,21 +128,21 @@ pub trait EthCall: EstimateCall + Call + LoadPendingBlock + LoadBlock + FullEthA
} else {
base_block.next_block_base_fee(base_fee_params).unwrap_or_default()
};
block_env.basefee = U256::from(base_fee);
evm_env.block_env.basefee = U256::from(base_fee);
} else {
block_env.basefee = U256::ZERO;
evm_env.block_env.basefee = U256::ZERO;
}
let SimBlock { block_overrides, state_overrides, calls } = block;
if let Some(block_overrides) = block_overrides {
apply_block_overrides(block_overrides, &mut db, &mut block_env);
apply_block_overrides(block_overrides, &mut db, &mut evm_env.block_env);
}
if let Some(state_overrides) = state_overrides {
apply_state_overrides(state_overrides, &mut db)?;
}
if (total_gas_limit - gas_used) < block_env.gas_limit.to() {
if (total_gas_limit - gas_used) < evm_env.block_env.gas_limit.to() {
return Err(
EthApiError::Other(Box::new(EthSimulateError::GasLimitReached)).into()
)
@ -153,7 +153,7 @@ pub trait EthCall: EstimateCall + Call + LoadPendingBlock + LoadBlock + FullEthA
let txs_without_gas_limit =
calls.iter().filter(|tx| tx.gas.is_none()).count();
if total_specified_gas > block_env.gas_limit.to() {
if total_specified_gas > evm_env.block_env.gas_limit.to() {
return Err(EthApiError::Other(Box::new(
EthSimulateError::BlockGasLimitExceeded,
))
@ -161,7 +161,7 @@ pub trait EthCall: EstimateCall + Call + LoadPendingBlock + LoadBlock + FullEthA
}
if txs_without_gas_limit > 0 {
(block_env.gas_limit.to::<u64>() - total_specified_gas) /
(evm_env.block_env.gas_limit.to::<u64>() - total_specified_gas) /
txs_without_gas_limit as u64
} else {
0
@ -182,27 +182,23 @@ pub trait EthCall: EstimateCall + Call + LoadPendingBlock + LoadBlock + FullEthA
call,
validation,
default_gas_limit,
cfg_env_with_handler_cfg.chain_id,
evm_env.cfg_env_with_handler_cfg.chain_id,
&mut db,
this.tx_resp_builder(),
)?;
let tx_env = this.evm_config().tx_env(&tx, sender);
let env = EnvWithHandlerCfg::new_with_cfg_env(
cfg_env_with_handler_cfg.clone(),
block_env.clone(),
tx_env,
);
let (res, env) = {
let (res, (_, tx_env)) = {
if trace_transfers {
this.transact_with_inspector(
&mut db,
env,
evm_env.clone(),
tx_env,
TransferInspector::new(false).with_logs(true),
)?
} else {
this.transact(&mut db, env)?
this.transact(&mut db, evm_env.clone(), tx_env.clone())?
}
};
@ -213,12 +209,12 @@ pub trait EthCall: EstimateCall + Call + LoadPendingBlock + LoadBlock + FullEthA
}
transactions.push(tx);
senders.push(env.tx.caller);
senders.push(tx_env.caller);
results.push(res.result);
}
let (block, _) = this.assemble_block_and_receipts(
&block_env,
&evm_env.block_env,
parent_hash,
// state root calculation is skipped for performance reasons
B256::ZERO,
@ -300,7 +296,6 @@ pub trait EthCall: EstimateCall + Call + LoadPendingBlock + LoadBlock + FullEthA
self.evm_env_at(target_block),
self.block_with_senders(target_block)
)?;
let EvmEnv { cfg_env_with_handler_cfg, block_env } = evm_env;
let block = block.ok_or(EthApiError::HeaderNotFound(target_block))?;
@ -330,12 +325,8 @@ pub trait EthCall: EstimateCall + Call + LoadPendingBlock + LoadBlock + FullEthA
// to be replayed
let transactions = block.transactions_with_sender().take(num_txs);
for (signer, tx) in transactions {
let env = EnvWithHandlerCfg::new_with_cfg_env(
cfg_env_with_handler_cfg.clone(),
block_env.clone(),
RpcNodeCore::evm_config(&this).tx_env(tx, *signer),
);
let (res, _) = this.transact(&mut db, env)?;
let tx_env = RpcNodeCore::evm_config(&this).tx_env(tx, *signer);
let (res, _) = this.transact(&mut db, evm_env.clone(), tx_env)?;
db.commit(res.state);
}
}
@ -348,14 +339,9 @@ pub trait EthCall: EstimateCall + Call + LoadPendingBlock + LoadBlock + FullEthA
let state_overrides = state_override.take();
let overrides = EvmOverrides::new(state_overrides, block_overrides.clone());
let env = this.prepare_call_env(
cfg_env_with_handler_cfg.clone(),
block_env.clone(),
tx,
&mut db,
overrides,
)?;
let (res, _) = this.transact(&mut db, env)?;
let (evm_env, tx) =
this.prepare_call_env(evm_env.clone(), tx, &mut db, overrides)?;
let (res, _) = this.transact(&mut db, evm_env, tx)?;
match ensure_success(res.result) {
Ok(output) => {
@ -395,11 +381,8 @@ pub trait EthCall: EstimateCall + Call + LoadPendingBlock + LoadBlock + FullEthA
async move {
let block_id = block_number.unwrap_or_default();
let (evm_env, at) = self.evm_env_at(block_id).await?;
let EvmEnv { cfg_env_with_handler_cfg, block_env } = evm_env;
self.spawn_blocking_io(move |this| {
this.create_access_list_with(cfg_env_with_handler_cfg, block_env, at, request)
})
self.spawn_blocking_io(move |this| this.create_access_list_with(evm_env, at, request))
.await
}
}
@ -408,8 +391,7 @@ pub trait EthCall: EstimateCall + Call + LoadPendingBlock + LoadBlock + FullEthA
/// [`BlockId`].
fn create_access_list_with(
&self,
cfg: CfgEnvWithHandlerCfg,
block: BlockEnv,
mut evm_env: EvmEnv,
at: BlockId,
mut request: TransactionRequest,
) -> Result<AccessListResult, Self::Error>
@ -418,23 +400,23 @@ pub trait EthCall: EstimateCall + Call + LoadPendingBlock + LoadBlock + FullEthA
{
let state = self.state_at_block_id(at)?;
let mut env = self.build_call_evm_env(cfg, block, request.clone())?;
let mut tx_env = self.create_txn_env(&evm_env.block_env, request.clone())?;
// we want to disable this in eth_createAccessList, since this is common practice used by
// other node impls and providers <https://github.com/foundry-rs/foundry/issues/4388>
env.cfg.disable_block_gas_limit = true;
evm_env.cfg_env_with_handler_cfg.disable_block_gas_limit = true;
// The basefee should be ignored for eth_createAccessList
// See:
// <https://github.com/ethereum/go-ethereum/blob/8990c92aea01ca07801597b00c0d83d4e2d9b811/internal/ethapi/api.go#L1476-L1476>
env.cfg.disable_base_fee = true;
evm_env.cfg_env_with_handler_cfg.disable_base_fee = true;
let mut db = CacheDB::new(StateProviderDatabase::new(state));
if request.gas.is_none() && env.tx.gas_price > U256::ZERO {
let cap = caller_gas_allowance(&mut db, &env.tx)?;
if request.gas.is_none() && tx_env.gas_price > U256::ZERO {
let cap = caller_gas_allowance(&mut db, &tx_env)?;
// no gas limit was provided in the request, so we need to cap the request's gas limit
env.tx.gas_limit = cap.min(env.block.gas_limit).saturating_to();
tx_env.gas_limit = cap.min(evm_env.block_env.gas_limit).saturating_to();
}
let from = request.from.unwrap_or_default();
@ -449,16 +431,17 @@ pub trait EthCall: EstimateCall + Call + LoadPendingBlock + LoadBlock + FullEthA
// can consume the list since we're not using the request anymore
let initial = request.access_list.take().unwrap_or_default();
let precompiles = get_precompiles(env.handler_cfg.spec_id);
let precompiles = get_precompiles(evm_env.cfg_env_with_handler_cfg.handler_cfg.spec_id);
let mut inspector = AccessListInspector::new(initial, from, to, precompiles);
let (result, mut env) = self.inspect(&mut db, env, &mut inspector)?;
let (result, (evm_env, mut tx_env)) =
self.inspect(&mut db, evm_env, tx_env, &mut inspector)?;
let access_list = inspector.into_access_list();
env.tx.access_list = access_list.to_vec();
tx_env.access_list = access_list.to_vec();
match result.result {
ExecutionResult::Halt { reason, gas_used } => {
let error =
Some(RpcInvalidTransactionError::halt(reason, env.tx.gas_limit).to_string());
Some(RpcInvalidTransactionError::halt(reason, tx_env.gas_limit).to_string());
return Ok(AccessListResult { access_list, gas_used: U256::from(gas_used), error })
}
ExecutionResult::Revert { output, gas_used } => {
@ -469,11 +452,11 @@ pub trait EthCall: EstimateCall + Call + LoadPendingBlock + LoadBlock + FullEthA
};
// transact again to get the exact gas used
let (result, env) = self.transact(&mut db, env)?;
let (result, (_, tx_env)) = self.transact(&mut db, evm_env, tx_env)?;
let res = match result.result {
ExecutionResult::Halt { reason, gas_used } => {
let error =
Some(RpcInvalidTransactionError::halt(reason, env.tx.gas_limit).to_string());
Some(RpcInvalidTransactionError::halt(reason, tx_env.gas_limit).to_string());
AccessListResult { access_list, gas_used: U256::from(gas_used), error }
}
ExecutionResult::Revert { output, gas_used } => {
@ -515,16 +498,25 @@ pub trait Call:
fn transact<DB>(
&self,
db: DB,
env: EnvWithHandlerCfg,
) -> Result<(ResultAndState, EnvWithHandlerCfg), Self::Error>
evm_env: EvmEnv,
tx_env: TxEnv,
) -> Result<(ResultAndState, (EvmEnv, TxEnv)), Self::Error>
where
DB: Database,
EthApiError: From<DB::Error>,
{
let mut evm = self.evm_config().evm_with_env(db, env);
let mut evm = self.evm_config().evm_with_env(db, evm_env, tx_env);
let res = evm.transact().map_err(Self::Error::from_evm_err)?;
let (_, env) = evm.into_db_and_env_with_handler_cfg();
Ok((res, env))
let EnvWithHandlerCfg { env, handler_cfg } = env;
let Env { cfg, block, tx } = *env;
let evm_env = EvmEnv {
cfg_env_with_handler_cfg: CfgEnvWithHandlerCfg { cfg_env: cfg, handler_cfg },
block_env: block,
};
Ok((res, (evm_env, tx)))
}
/// Executes the [`EnvWithHandlerCfg`] against the given [Database] without committing state
@ -532,17 +524,26 @@ pub trait Call:
fn transact_with_inspector<DB>(
&self,
db: DB,
env: EnvWithHandlerCfg,
evm_env: EvmEnv,
tx_env: TxEnv,
inspector: impl GetInspector<DB>,
) -> Result<(ResultAndState, EnvWithHandlerCfg), Self::Error>
) -> Result<(ResultAndState, (EvmEnv, TxEnv)), Self::Error>
where
DB: Database,
EthApiError: From<DB::Error>,
{
let mut evm = self.evm_config().evm_with_env_and_inspector(db, env, inspector);
let mut evm = self.evm_config().evm_with_env_and_inspector(db, evm_env, tx_env, inspector);
let res = evm.transact().map_err(Self::Error::from_evm_err)?;
let (_, env) = evm.into_db_and_env_with_handler_cfg();
Ok((res, env))
let EnvWithHandlerCfg { env, handler_cfg } = env;
let Env { cfg, block, tx } = *env;
let evm_env = EvmEnv {
cfg_env_with_handler_cfg: CfgEnvWithHandlerCfg { cfg_env: cfg, handler_cfg },
block_env: block,
};
Ok((res, (evm_env, tx)))
}
/// Executes the call request at the given [`BlockId`].
@ -551,12 +552,14 @@ pub trait Call:
request: TransactionRequest,
at: BlockId,
overrides: EvmOverrides,
) -> impl Future<Output = Result<(ResultAndState, EnvWithHandlerCfg), Self::Error>> + Send
) -> impl Future<Output = Result<(ResultAndState, (EvmEnv, TxEnv)), Self::Error>> + Send
where
Self: LoadPendingBlock,
{
let this = self.clone();
self.spawn_with_call_at(request, at, overrides, move |db, env| this.transact(db, env))
self.spawn_with_call_at(request, at, overrides, move |db, evm_env, tx_env| {
this.transact(db, evm_env, tx_env)
})
}
/// Executes the closure with the state that corresponds to the given [`BlockId`] on a new task
@ -599,29 +602,23 @@ pub trait Call:
) -> impl Future<Output = Result<R, Self::Error>> + Send
where
Self: LoadPendingBlock,
F: FnOnce(StateCacheDbRefMutWrapper<'_, '_>, EnvWithHandlerCfg) -> Result<R, Self::Error>
F: FnOnce(StateCacheDbRefMutWrapper<'_, '_>, EvmEnv, TxEnv) -> Result<R, Self::Error>
+ Send
+ 'static,
R: Send + 'static,
{
async move {
let (evm_env, at) = self.evm_env_at(at).await?;
let EvmEnv { cfg_env_with_handler_cfg, block_env } = evm_env;
let this = self.clone();
self.spawn_blocking_io(move |_| {
let state = this.state_at_block_id(at)?;
let mut db =
CacheDB::new(StateProviderDatabase::new(StateProviderTraitObjWrapper(&state)));
let env = this.prepare_call_env(
cfg_env_with_handler_cfg,
block_env,
request,
&mut db,
overrides,
)?;
let (evm_env, tx_env) =
this.prepare_call_env(evm_env, request, &mut db, overrides)?;
f(StateCacheDbRefMutWrapper(&mut db), env)
f(StateCacheDbRefMutWrapper(&mut db), evm_env, tx_env)
})
.await
}
@ -656,7 +653,6 @@ pub trait Call:
let (tx, tx_info) = transaction.split();
let (evm_env, _) = self.evm_env_at(block.hash().into()).await?;
let EvmEnv { cfg_env_with_handler_cfg, block_env } = evm_env;
// we need to get the state of the parent block because we're essentially replaying the
// block the transaction is included in
@ -668,21 +664,11 @@ pub trait Call:
let block_txs = block.transactions_with_sender();
// replay all transactions prior to the targeted transaction
this.replay_transactions_until(
&mut db,
cfg_env_with_handler_cfg.clone(),
block_env.clone(),
block_txs,
*tx.tx_hash(),
)?;
this.replay_transactions_until(&mut db, evm_env.clone(), block_txs, *tx.tx_hash())?;
let env = EnvWithHandlerCfg::new_with_cfg_env(
cfg_env_with_handler_cfg,
block_env,
RpcNodeCore::evm_config(&this).tx_env(tx.tx(), tx.signer()),
);
let tx_env = RpcNodeCore::evm_config(&this).tx_env(tx.tx(), tx.signer());
let (res, _) = this.transact(&mut db, env)?;
let (res, _) = this.transact(&mut db, evm_env, tx_env)?;
f(tx_info, res, db)
})
.await
@ -700,8 +686,7 @@ pub trait Call:
fn replay_transactions_until<'a, DB, I>(
&self,
db: &mut DB,
cfg: CfgEnvWithHandlerCfg,
block_env: BlockEnv,
evm_env: EvmEnv,
transactions: I,
target_tx_hash: B256,
) -> Result<usize, Self::Error>
@ -711,9 +696,7 @@ pub trait Call:
I: IntoIterator<Item = (&'a Address, &'a <Self::Evm as ConfigureEvmEnv>::Transaction)>,
<Self::Evm as ConfigureEvmEnv>::Transaction: SignedTransaction,
{
let env = EnvWithHandlerCfg::new_with_cfg_env(cfg, block_env, Default::default());
let mut evm = self.evm_config().evm_with_env(db, env);
let mut evm = self.evm_config().evm_with_env(db, evm_env, Default::default());
let mut index = 0;
for (sender, tx) in transactions {
if *tx.tx_hash() == target_tx_hash {
@ -807,20 +790,6 @@ pub trait Call:
Ok(env)
}
/// Creates a new [`EnvWithHandlerCfg`] to be used for executing the [`TransactionRequest`] in
/// `eth_call`.
///
/// Note: this does _not_ access the Database to check the sender.
fn build_call_evm_env(
&self,
cfg: CfgEnvWithHandlerCfg,
block: BlockEnv,
request: TransactionRequest,
) -> Result<EnvWithHandlerCfg, Self::Error> {
let tx = self.create_txn_env(&block, request)?;
Ok(EnvWithHandlerCfg::new_with_cfg_env(cfg, block, tx))
}
/// Prepares the [`EnvWithHandlerCfg`] for execution of calls.
///
/// Does not commit any changes to the underlying database.
@ -836,12 +805,11 @@ pub trait Call:
/// In addition, this changes the block's gas limit to the configured [`Self::call_gas_limit`].
fn prepare_call_env<DB>(
&self,
mut cfg: CfgEnvWithHandlerCfg,
mut block: BlockEnv,
mut evm_env: EvmEnv,
mut request: TransactionRequest,
db: &mut CacheDB<DB>,
overrides: EvmOverrides,
) -> Result<EnvWithHandlerCfg, Self::Error>
) -> Result<(EvmEnv, TxEnv), Self::Error>
where
DB: DatabaseRef,
EthApiError: From<<DB as DatabaseRef>::Error>,
@ -854,41 +822,41 @@ pub trait Call:
}
// apply configured gas cap
block.gas_limit = U256::from(self.call_gas_limit());
evm_env.block_env.gas_limit = U256::from(self.call_gas_limit());
// Disabled because eth_call is sometimes used with eoa senders
// See <https://github.com/paradigmxyz/reth/issues/1959>
cfg.disable_eip3607 = true;
evm_env.cfg_env_with_handler_cfg.disable_eip3607 = true;
// The basefee should be ignored for eth_call
// See:
// <https://github.com/ethereum/go-ethereum/blob/ee8e83fa5f6cb261dad2ed0a7bbcde4930c41e6c/internal/ethapi/api.go#L985>
cfg.disable_base_fee = true;
evm_env.cfg_env_with_handler_cfg.disable_base_fee = true;
// set nonce to None so that the correct nonce is chosen by the EVM
request.nonce = None;
if let Some(block_overrides) = overrides.block {
apply_block_overrides(*block_overrides, db, &mut block);
apply_block_overrides(*block_overrides, db, &mut evm_env.block_env);
}
if let Some(state_overrides) = overrides.state {
apply_state_overrides(state_overrides, db)?;
}
let request_gas = request.gas;
let mut env = self.build_call_evm_env(cfg, block, request)?;
let mut tx_env = self.create_txn_env(&evm_env.block_env, request)?;
if request_gas.is_none() {
// No gas limit was provided in the request, so we need to cap the transaction gas limit
if env.tx.gas_price > U256::ZERO {
if tx_env.gas_price > U256::ZERO {
// If gas price is specified, cap transaction gas limit with caller allowance
trace!(target: "rpc::eth::call", ?env, "Applying gas limit cap with caller allowance");
let cap = caller_gas_allowance(db, &env.tx)?;
trace!(target: "rpc::eth::call", ?tx_env, "Applying gas limit cap with caller allowance");
let cap = caller_gas_allowance(db, &tx_env)?;
// ensure we cap gas_limit to the block's
env.tx.gas_limit = cap.min(env.block.gas_limit).saturating_to();
tx_env.gas_limit = cap.min(evm_env.block_env.gas_limit).saturating_to();
}
}
Ok(env)
Ok((evm_env, tx_env))
}
}

View File

@ -11,14 +11,14 @@ use reth_provider::StateProvider;
use reth_revm::{
database::StateProviderDatabase,
db::CacheDB,
primitives::{BlockEnv, CfgEnvWithHandlerCfg, ExecutionResult, HaltReason, TransactTo},
primitives::{ExecutionResult, HaltReason, TransactTo},
};
use reth_rpc_eth_types::{
revm_utils::{apply_state_overrides, caller_gas_allowance},
EthApiError, RevertError, RpcInvalidTransactionError,
};
use reth_rpc_server_types::constants::gas_oracle::{CALL_STIPEND_GAS, ESTIMATE_GAS_ERROR_RATIO};
use revm_primitives::{db::Database, EnvWithHandlerCfg};
use revm_primitives::{db::Database, TxEnv};
use tracing::trace;
/// Gas execution estimates
@ -36,8 +36,7 @@ pub trait EstimateCall: Call {
/// - `nonce` is set to `None`
fn estimate_gas_with<S>(
&self,
mut cfg: CfgEnvWithHandlerCfg,
block: BlockEnv,
mut evm_env: EvmEnv,
mut request: TransactionRequest,
state: S,
state_override: Option<StateOverride>,
@ -47,12 +46,12 @@ pub trait EstimateCall: Call {
{
// Disabled because eth_estimateGas is sometimes used with eoa senders
// See <https://github.com/paradigmxyz/reth/issues/1959>
cfg.disable_eip3607 = true;
evm_env.cfg_env_with_handler_cfg.disable_eip3607 = true;
// The basefee should be ignored for eth_estimateGas and similar
// See:
// <https://github.com/ethereum/go-ethereum/blob/ee8e83fa5f6cb261dad2ed0a7bbcde4930c41e6c/internal/ethapi/api.go#L985>
cfg.disable_base_fee = true;
evm_env.cfg_env_with_handler_cfg.disable_base_fee = true;
// set nonce to None so that the correct nonce is chosen by the EVM
request.nonce = None;
@ -61,7 +60,7 @@ pub trait EstimateCall: Call {
let tx_request_gas_limit = request.gas.map(U256::from);
let tx_request_gas_price = request.gas_price;
// the gas limit of the corresponding block
let block_env_gas_limit = block.gas_limit;
let block_env_gas_limit = evm_env.block_env.gas_limit;
// Determine the highest possible gas limit, considering both the request's specified limit
// and the block's limit.
@ -76,7 +75,7 @@ pub trait EstimateCall: Call {
.unwrap_or(block_env_gas_limit);
// Configure the evm env
let mut env = self.build_call_evm_env(cfg, block, request)?;
let mut tx_env = self.create_txn_env(&evm_env.block_env, request)?;
let mut db = CacheDB::new(StateProviderDatabase::new(state));
// Apply any state overrides if specified.
@ -85,8 +84,8 @@ pub trait EstimateCall: Call {
}
// Optimize for simple transfer transactions, potentially reducing the gas estimate.
if env.tx.data.is_empty() {
if let TransactTo::Call(to) = env.tx.transact_to {
if tx_env.data.is_empty() {
if let TransactTo::Call(to) = tx_env.transact_to {
if let Ok(code) = db.db.account_code(&to) {
let no_code_callee = code.map(|code| code.is_empty()).unwrap_or(true);
if no_code_callee {
@ -95,9 +94,9 @@ pub trait EstimateCall: Call {
// `MIN_TRANSACTION_GAS` is dangerous because there might be additional
// field combos that bump the price up, so we try executing the function
// with the minimum gas limit to make sure.
let mut env = env.clone();
env.tx.gas_limit = MIN_TRANSACTION_GAS;
if let Ok((res, _)) = self.transact(&mut db, env) {
let mut tx_env = tx_env.clone();
tx_env.gas_limit = MIN_TRANSACTION_GAS;
if let Ok((res, _)) = self.transact(&mut db, evm_env.clone(), tx_env) {
if res.result.is_success() {
return Ok(U256::from(MIN_TRANSACTION_GAS))
}
@ -110,31 +109,37 @@ pub trait EstimateCall: Call {
// Check funds of the sender (only useful to check if transaction gas price is more than 0).
//
// The caller allowance is check by doing `(account.balance - tx.value) / tx.gas_price`
if env.tx.gas_price > U256::ZERO {
if tx_env.gas_price > U256::ZERO {
// cap the highest gas limit by max gas caller can afford with given gas price
highest_gas_limit = highest_gas_limit
.min(caller_gas_allowance(&mut db, &env.tx).map_err(Self::Error::from_eth_err)?);
.min(caller_gas_allowance(&mut db, &tx_env).map_err(Self::Error::from_eth_err)?);
}
// We can now normalize the highest gas limit to a u64
let mut highest_gas_limit = highest_gas_limit.saturating_to::<u64>();
// If the provided gas limit is less than computed cap, use that
env.tx.gas_limit = env.tx.gas_limit.min(highest_gas_limit);
tx_env.gas_limit = tx_env.gas_limit.min(highest_gas_limit);
trace!(target: "rpc::eth::estimate", ?env, "Starting gas estimation");
trace!(target: "rpc::eth::estimate", ?evm_env, ?tx_env, "Starting gas estimation");
// Execute the transaction with the highest possible gas limit.
let (mut res, mut env) = match self.transact(&mut db, env.clone()) {
// Handle the exceptional case where the transaction initialization uses too much gas.
// If the gas price or gas limit was specified in the request, retry the transaction
// with the block's gas limit to determine if the failure was due to
// insufficient gas.
let (mut res, (mut evm_env, mut tx_env)) =
match self.transact(&mut db, evm_env.clone(), tx_env.clone()) {
// Handle the exceptional case where the transaction initialization uses too much
// gas. If the gas price or gas limit was specified in the request,
// retry the transaction with the block's gas limit to determine if
// the failure was due to insufficient gas.
Err(err)
if err.is_gas_too_high() &&
(tx_request_gas_limit.is_some() || tx_request_gas_price.is_some()) =>
{
return Err(self.map_out_of_gas_err(block_env_gas_limit, env, &mut db))
return Err(self.map_out_of_gas_err(
block_env_gas_limit,
evm_env,
tx_env,
&mut db,
))
}
// Propagate other results (successful or other errors).
ethres => ethres?,
@ -151,7 +156,7 @@ pub trait EstimateCall: Call {
// if price or limit was included in the request then we can execute the request
// again with the block's gas limit to check if revert is gas related or not
return if tx_request_gas_limit.is_some() || tx_request_gas_price.is_some() {
Err(self.map_out_of_gas_err(block_env_gas_limit, env, &mut db))
Err(self.map_out_of_gas_err(block_env_gas_limit, evm_env, tx_env, &mut db))
} else {
// the transaction did revert
Err(RpcInvalidTransactionError::Revert(RevertError::new(output)).into_eth_err())
@ -164,7 +169,7 @@ pub trait EstimateCall: Call {
// we know the tx succeeded with the configured gas limit, so we can use that as the
// highest, in case we applied a gas cap due to caller allowance above
highest_gas_limit = env.tx.gas_limit;
highest_gas_limit = tx_env.gas_limit;
// NOTE: this is the gas the transaction used, which is less than the
// transaction requires to succeed.
@ -181,10 +186,10 @@ pub trait EstimateCall: Call {
let optimistic_gas_limit = (gas_used + gas_refund + CALL_STIPEND_GAS) * 64 / 63;
if optimistic_gas_limit < highest_gas_limit {
// Set the transaction's gas limit to the calculated optimistic gas limit.
env.tx.gas_limit = optimistic_gas_limit;
tx_env.gas_limit = optimistic_gas_limit;
// Re-execute the transaction with the new gas limit and update the result and
// environment.
(res, env) = self.transact(&mut db, env)?;
(res, (evm_env, tx_env)) = self.transact(&mut db, evm_env, tx_env)?;
// Update the gas used based on the new result.
gas_used = res.result.gas_used();
// Update the gas limit estimates (highest and lowest) based on the execution result.
@ -202,7 +207,7 @@ pub trait EstimateCall: Call {
((highest_gas_limit as u128 + lowest_gas_limit as u128) / 2) as u64,
);
trace!(target: "rpc::eth::estimate", ?env, ?highest_gas_limit, ?lowest_gas_limit, ?mid_gas_limit, "Starting binary search for gas");
trace!(target: "rpc::eth::estimate", ?evm_env, ?tx_env, ?highest_gas_limit, ?lowest_gas_limit, ?mid_gas_limit, "Starting binary search for gas");
// Binary search narrows the range to find the minimum gas limit needed for the transaction
// to succeed.
@ -216,10 +221,10 @@ pub trait EstimateCall: Call {
break
};
env.tx.gas_limit = mid_gas_limit;
tx_env.gas_limit = mid_gas_limit;
// Execute transaction and handle potential gas errors, adjusting limits accordingly.
match self.transact(&mut db, env.clone()) {
match self.transact(&mut db, evm_env.clone(), tx_env.clone()) {
Err(err) if err.is_gas_too_high() => {
// Decrease the highest gas limit if gas is too high
highest_gas_limit = mid_gas_limit;
@ -231,7 +236,7 @@ pub trait EstimateCall: Call {
// Handle other cases, including successful transactions.
ethres => {
// Unpack the result and environment if the transaction was successful.
(res, env) = ethres?;
(res, (evm_env, tx_env)) = ethres?;
// Update the estimated gas range based on the transaction result.
update_estimated_gas_range(
res.result,
@ -261,18 +266,10 @@ pub trait EstimateCall: Call {
{
async move {
let (evm_env, at) = self.evm_env_at(at).await?;
let EvmEnv { cfg_env_with_handler_cfg, block_env } = evm_env;
self.spawn_blocking_io(move |this| {
let state = this.state_at_block_id(at)?;
EstimateCall::estimate_gas_with(
&this,
cfg_env_with_handler_cfg,
block_env,
request,
state,
state_override,
)
EstimateCall::estimate_gas_with(&this, evm_env, request, state, state_override)
})
.await
}
@ -284,16 +281,17 @@ pub trait EstimateCall: Call {
fn map_out_of_gas_err<DB>(
&self,
env_gas_limit: U256,
mut env: EnvWithHandlerCfg,
evm_env: EvmEnv,
mut tx_env: TxEnv,
db: &mut DB,
) -> Self::Error
where
DB: Database,
EthApiError: From<DB::Error>,
{
let req_gas_limit = env.tx.gas_limit;
env.tx.gas_limit = env_gas_limit.try_into().unwrap_or(u64::MAX);
let (res, _) = match self.transact(db, env) {
let req_gas_limit = tx_env.gas_limit;
tx_env.gas_limit = env_gas_limit.try_into().unwrap_or(u64::MAX);
let (res, _) = match self.transact(db, evm_env, tx_env) {
Ok(res) => res,
Err(err) => return err,
};

View File

@ -1,7 +1,7 @@
//! Loads a pending block from database. Helper trait for `eth_` call and trace RPC methods.
use super::{Call, LoadBlock, LoadPendingBlock, LoadState, LoadTransaction};
use crate::{FromEvmError, RpcNodeCore};
use crate::FromEvmError;
use alloy_consensus::BlockHeader;
use alloy_primitives::B256;
use alloy_rpc_types_eth::{BlockId, TransactionInfo};
@ -19,7 +19,7 @@ use reth_rpc_eth_types::{
use revm::{db::CacheDB, Database, DatabaseCommit, GetInspector, Inspector};
use revm_inspectors::tracing::{TracingInspector, TracingInspectorConfig};
use revm_primitives::{
BlockEnv, CfgEnvWithHandlerCfg, EnvWithHandlerCfg, EvmState, ExecutionResult, ResultAndState,
CfgEnvWithHandlerCfg, Env, EnvWithHandlerCfg, EvmState, ExecutionResult, ResultAndState, TxEnv,
};
use std::{fmt::Display, sync::Arc};
@ -38,38 +38,25 @@ pub trait Trace:
fn inspect<DB, I>(
&self,
db: DB,
env: EnvWithHandlerCfg,
evm_env: EvmEnv,
tx_env: TxEnv,
inspector: I,
) -> Result<(ResultAndState, EnvWithHandlerCfg), Self::Error>
) -> Result<(ResultAndState, (EvmEnv, TxEnv)), Self::Error>
where
DB: Database,
EthApiError: From<DB::Error>,
I: GetInspector<DB>,
{
self.inspect_and_return_db(db, env, inspector).map(|(res, env, _)| (res, env))
}
/// Same as [`inspect`](Self::inspect) but also returns the database again.
///
/// Even though [Database] is also implemented on `&mut`
/// this is still useful if there are certain trait bounds on the Inspector's database generic
/// type
fn inspect_and_return_db<DB, I>(
&self,
db: DB,
env: EnvWithHandlerCfg,
inspector: I,
) -> Result<(ResultAndState, EnvWithHandlerCfg, DB), Self::Error>
where
DB: Database,
EthApiError: From<DB::Error>,
I: GetInspector<DB>,
{
let mut evm = self.evm_config().evm_with_env_and_inspector(db, env, inspector);
let mut evm = self.evm_config().evm_with_env_and_inspector(db, evm_env, tx_env, inspector);
let res = evm.transact().map_err(Self::Error::from_evm_err)?;
let (db, env) = evm.into_db_and_env_with_handler_cfg();
Ok((res, env, db))
let (_, env) = evm.into_db_and_env_with_handler_cfg();
let EnvWithHandlerCfg { env, handler_cfg } = env;
let Env { cfg, block, tx } = *env;
let evm_env = EvmEnv {
cfg_env_with_handler_cfg: CfgEnvWithHandlerCfg { cfg_env: cfg, handler_cfg },
block_env: block,
};
Ok((res, (evm_env, tx)))
}
/// Executes the transaction on top of the given [`BlockId`] with a tracer configured by the
@ -81,7 +68,8 @@ pub trait Trace:
/// Caution: this is blocking
fn trace_at<F, R>(
&self,
env: EnvWithHandlerCfg,
evm_env: EvmEnv,
tx_env: TxEnv,
config: TracingInspectorConfig,
at: BlockId,
f: F,
@ -93,7 +81,7 @@ pub trait Trace:
self.with_state_at_block(at, |state| {
let mut db = CacheDB::new(StateProviderDatabase::new(state));
let mut inspector = TracingInspector::new(config);
let (res, _) = self.inspect(&mut db, env, &mut inspector)?;
let (res, _) = self.inspect(&mut db, evm_env, tx_env, &mut inspector)?;
f(inspector, res)
})
}
@ -107,7 +95,8 @@ pub trait Trace:
/// the configured [`EnvWithHandlerCfg`] was inspected.
fn spawn_trace_at_with_state<F, R>(
&self,
env: EnvWithHandlerCfg,
evm_env: EvmEnv,
tx_env: TxEnv,
config: TracingInspectorConfig,
at: BlockId,
f: F,
@ -123,7 +112,7 @@ pub trait Trace:
self.spawn_with_state_at_block(at, move |state| {
let mut db = CacheDB::new(StateProviderDatabase::new(state));
let mut inspector = TracingInspector::new(config);
let (res, _) = this.inspect(&mut db, env, &mut inspector)?;
let (res, _) = this.inspect(&mut db, evm_env, tx_env, &mut inspector)?;
f(inspector, res, db)
})
}
@ -194,7 +183,6 @@ pub trait Trace:
let (tx, tx_info) = transaction.split();
let (evm_env, _) = self.evm_env_at(block.hash().into()).await?;
let EvmEnv { cfg_env_with_handler_cfg, block_env } = evm_env;
// we need to get the state of the parent block because we're essentially replaying the
// block the transaction is included in
@ -205,29 +193,18 @@ pub trait Trace:
let mut db = CacheDB::new(StateProviderDatabase::new(state));
let block_txs = block.transactions_with_sender();
this.apply_pre_execution_changes(
&block,
&mut db,
&cfg_env_with_handler_cfg,
&block_env,
)?;
this.apply_pre_execution_changes(&block, &mut db, &evm_env)?;
// replay all transactions prior to the targeted transaction
this.replay_transactions_until(
&mut db,
cfg_env_with_handler_cfg.clone(),
block_env.clone(),
block_txs,
*tx.tx_hash(),
)?;
this.replay_transactions_until(&mut db, evm_env.clone(), block_txs, *tx.tx_hash())?;
let env = EnvWithHandlerCfg::new_with_cfg_env(
cfg_env_with_handler_cfg,
block_env,
RpcNodeCore::evm_config(&this).tx_env(tx.tx(), tx.signer()),
);
let (res, _) =
this.inspect(StateCacheDbRefMutWrapper(&mut db), env, &mut inspector)?;
let tx_env = this.evm_config().tx_env(tx.tx(), tx.signer());
let (res, _) = this.inspect(
StateCacheDbRefMutWrapper(&mut db),
evm_env,
tx_env,
&mut inspector,
)?;
f(tx_info, inspector, res, db)
})
.await
@ -314,8 +291,6 @@ pub trait Trace:
let ((evm_env, _), block) = futures::try_join!(self.evm_env_at(block_id), block)?;
let EvmEnv { cfg_env_with_handler_cfg, block_env } = evm_env;
let Some(block) = block else { return Ok(None) };
if block.body().transactions().is_empty() {
@ -330,20 +305,15 @@ pub trait Trace:
let state_at = block.parent_hash();
let block_hash = block.hash();
let block_number = block_env.number.saturating_to::<u64>();
let base_fee = block_env.basefee.saturating_to::<u128>();
let block_number = evm_env.block_env.number.saturating_to::<u64>();
let base_fee = evm_env.block_env.basefee.saturating_to::<u128>();
// now get the state
let state = this.state_at_block_id(state_at.into())?;
let mut db =
CacheDB::new(StateProviderDatabase::new(StateProviderTraitObjWrapper(&state)));
this.apply_pre_execution_changes(
&block,
&mut db,
&cfg_env_with_handler_cfg,
&block_env,
)?;
this.apply_pre_execution_changes(&block, &mut db, &evm_env)?;
// prepare transactions, we do everything upfront to reduce time spent with open
// state
@ -372,15 +342,13 @@ pub trait Trace:
.peekable();
while let Some((tx_info, tx)) = transactions.next() {
let env = EnvWithHandlerCfg::new_with_cfg_env(
cfg_env_with_handler_cfg.clone(),
block_env.clone(),
tx,
);
let mut inspector = inspector_setup();
let (res, _) =
this.inspect(StateCacheDbRefMutWrapper(&mut db), env, &mut inspector)?;
let (res, _) = this.inspect(
StateCacheDbRefMutWrapper(&mut db),
evm_env.clone(),
tx,
&mut inspector,
)?;
let ResultAndState { result, state } = res;
results.push(f(tx_info, inspector, result, &state, &db)?);
@ -483,8 +451,7 @@ pub trait Trace:
&self,
block: &RecoveredBlock<ProviderBlock<Self::Provider>>,
db: &mut DB,
cfg: &CfgEnvWithHandlerCfg,
block_env: &BlockEnv,
evm_env: &EvmEnv,
) -> Result<(), Self::Error> {
let mut system_caller =
SystemCaller::new(self.evm_config().clone(), self.provider().chain_spec());
@ -492,14 +459,19 @@ pub trait Trace:
system_caller
.pre_block_beacon_root_contract_call(
db,
cfg,
block_env,
evm_env.cfg_env_with_handler_cfg(),
evm_env.block_env(),
block.parent_beacon_block_root(),
)
.map_err(|_| EthApiError::EvmCustom("failed to apply 4788 system call".to_string()))?;
system_caller
.pre_block_blockhashes_contract_call(db, cfg, block_env, block.parent_hash())
.pre_block_blockhashes_contract_call(
db,
evm_env.cfg_env_with_handler_cfg(),
evm_env.block_env(),
block.parent_hash(),
)
.map_err(|_| {
EthApiError::EvmCustom("failed to apply blockhashes system call".to_string())
})?;

View File

@ -37,11 +37,12 @@ use reth_rpc_server_types::{result::internal_rpc_err, ToRpcResult};
use reth_tasks::pool::BlockingTaskGuard;
use revm::{
db::{CacheDB, State},
primitives::{db::DatabaseCommit, BlockEnv, CfgEnvWithHandlerCfg, Env, EnvWithHandlerCfg},
primitives::{db::DatabaseCommit, Env},
};
use revm_inspectors::tracing::{
FourByteInspector, MuxInspector, TracingInspector, TracingInspectorConfig, TransactionContext,
};
use revm_primitives::TxEnv;
use std::sync::Arc;
use tokio::sync::{AcquireError, OwnedSemaphorePermit};
@ -95,8 +96,7 @@ where
async fn trace_block(
&self,
block: Arc<RecoveredBlock<ProviderBlock<Eth::Provider>>>,
cfg: CfgEnvWithHandlerCfg,
block_env: BlockEnv,
evm_env: EvmEnv,
opts: GethDebugTracingOptions,
) -> Result<Vec<TraceResult>, Eth::Error> {
// replay all transactions of the block
@ -106,24 +106,19 @@ where
let mut results = Vec::with_capacity(block.body().transactions().len());
let mut db = CacheDB::new(StateProviderDatabase::new(state));
this.eth_api().apply_pre_execution_changes(&block, &mut db, &cfg, &block_env)?;
this.eth_api().apply_pre_execution_changes(&block, &mut db, &evm_env)?;
let mut transactions = block.transactions_with_sender().enumerate().peekable();
let mut inspector = None;
while let Some((index, (signer, tx))) = transactions.next() {
let tx_hash = *tx.tx_hash();
let env = EnvWithHandlerCfg {
env: Env::boxed(
cfg.cfg_env.clone(),
block_env.clone(),
this.eth_api().evm_config().tx_env(tx, *signer),
),
handler_cfg: cfg.handler_cfg,
};
let tx_env = this.eth_api().evm_config().tx_env(tx, *signer);
let (result, state_changes) = this.trace_transaction(
&opts,
env,
evm_env.clone(),
tx_env,
&mut db,
Some(TransactionContext {
block_hash: Some(block.hash()),
@ -162,8 +157,7 @@ where
.map_err(BlockError::RlpDecodeRawBlock)
.map_err(Eth::Error::from_eth_err)?;
let EvmEnv { cfg_env_with_handler_cfg, block_env } =
self.eth_api().evm_config().cfg_and_block_env(block.header());
let evm_env = self.eth_api().evm_config().cfg_and_block_env(block.header());
// Depending on EIP-2 we need to recover the transactions differently
let senders =
@ -191,13 +185,7 @@ where
.collect::<Result<Vec<_>, Eth::Error>>()?
};
self.trace_block(
Arc::new(block.with_senders_unchecked(senders)),
cfg_env_with_handler_cfg,
block_env,
opts,
)
.await
self.trace_block(Arc::new(block.with_senders_unchecked(senders)), evm_env, opts).await
}
/// Replays a block and returns the trace of each transaction.
@ -216,11 +204,10 @@ where
self.eth_api().evm_env_at(block_hash.into()),
self.eth_api().block_with_senders(block_hash.into()),
)?;
let EvmEnv { cfg_env_with_handler_cfg, block_env } = evm_env;
let block = block.ok_or(EthApiError::HeaderNotFound(block_id))?;
self.trace_block(block, cfg_env_with_handler_cfg, block_env, opts).await
self.trace_block(block, evm_env, opts).await
}
/// Trace the transaction according to the provided options.
@ -236,7 +223,6 @@ where
Some(res) => res,
};
let (evm_env, _) = self.eth_api().evm_env_at(block.hash().into()).await?;
let EvmEnv { cfg_env_with_handler_cfg, block_env } = evm_env;
// we need to get the state of the parent block because we're essentially replaying the
// block the transaction is included in
@ -253,34 +239,22 @@ where
let mut db = CacheDB::new(StateProviderDatabase::new(state));
this.eth_api().apply_pre_execution_changes(
&block,
&mut db,
&cfg_env_with_handler_cfg,
&block_env,
)?;
this.eth_api().apply_pre_execution_changes(&block, &mut db, &evm_env)?;
// replay all transactions prior to the targeted transaction
let index = this.eth_api().replay_transactions_until(
&mut db,
cfg_env_with_handler_cfg.clone(),
block_env.clone(),
evm_env.clone(),
block_txs,
*tx.tx_hash(),
)?;
let env = EnvWithHandlerCfg {
env: Env::boxed(
cfg_env_with_handler_cfg.cfg_env.clone(),
block_env,
this.eth_api().evm_config().tx_env(tx.tx(), tx.signer()),
),
handler_cfg: cfg_env_with_handler_cfg.handler_cfg,
};
let tx_env = this.eth_api().evm_config().tx_env(tx.tx(), tx.signer());
this.trace_transaction(
&opts,
env,
evm_env,
tx_env,
&mut db,
Some(TransactionContext {
block_hash: Some(block_hash),
@ -319,8 +293,8 @@ where
let mut inspector = FourByteInspector::default();
let inspector = self
.eth_api()
.spawn_with_call_at(call, at, overrides, move |db, env| {
this.eth_api().inspect(db, env, &mut inspector)?;
.spawn_with_call_at(call, at, overrides, move |db, evm_env, tx_env| {
this.eth_api().inspect(db, evm_env, tx_env, &mut inspector)?;
Ok(inspector)
})
.await?;
@ -337,10 +311,11 @@ where
let frame = self
.eth_api()
.spawn_with_call_at(call, at, overrides, move |db, env| {
let (res, env) = this.eth_api().inspect(db, env, &mut inspector)?;
.spawn_with_call_at(call, at, overrides, move |db, evm_env, tx_env| {
let (res, (_, tx_env)) =
this.eth_api().inspect(db, evm_env, tx_env, &mut inspector)?;
let frame = inspector
.with_transaction_gas_limit(env.tx.gas_limit)
.with_transaction_gas_limit(tx_env.gas_limit)
.into_geth_builder()
.geth_call_traces(call_config, res.result.gas_used());
Ok(frame.into())
@ -358,15 +333,19 @@ where
let frame = self
.eth_api()
.spawn_with_call_at(call, at, overrides, move |db, env| {
.spawn_with_call_at(call, at, overrides, move |db, evm_env, tx_env| {
// wrapper is hack to get around 'higher-ranked lifetime error',
// see <https://github.com/rust-lang/rust/issues/100013>
let db = db.0;
let (res, env) =
this.eth_api().inspect(&mut *db, env, &mut inspector)?;
let (res, (_, tx_env)) = this.eth_api().inspect(
&mut *db,
evm_env,
tx_env,
&mut inspector,
)?;
let frame = inspector
.with_transaction_gas_limit(env.tx.gas_limit)
.with_transaction_gas_limit(tx_env.gas_limit)
.into_geth_builder()
.geth_prestate_traces(&res, &prestate_config, db)
.map_err(Eth::Error::from_eth_err)?;
@ -387,25 +366,29 @@ where
let frame = self
.inner
.eth_api
.spawn_with_call_at(call, at, overrides, move |db, env| {
.spawn_with_call_at(call, at, overrides, move |db, evm_env, tx_env| {
// wrapper is hack to get around 'higher-ranked lifetime error', see
// <https://github.com/rust-lang/rust/issues/100013>
let db = db.0;
let tx_info = TransactionInfo {
block_number: Some(
env.block.number.try_into().unwrap_or_default(),
evm_env.block_env.number.try_into().unwrap_or_default(),
),
base_fee: Some(
env.block.basefee.try_into().unwrap_or_default(),
evm_env.block_env.basefee.try_into().unwrap_or_default(),
),
hash: None,
block_hash: None,
index: None,
};
let (res, _) =
this.eth_api().inspect(&mut *db, env, &mut inspector)?;
let (res, _) = this.eth_api().inspect(
&mut *db,
evm_env,
tx_env,
&mut inspector,
)?;
let frame = inspector
.try_into_mux_frame(&res, db, tx_info)
.map_err(Eth::Error::from_eth_err)?;
@ -426,12 +409,12 @@ where
let frame: FlatCallFrame = self
.inner
.eth_api
.spawn_with_call_at(call, at, overrides, move |db, env| {
let (_res, env) =
this.eth_api().inspect(db, env, &mut inspector)?;
.spawn_with_call_at(call, at, overrides, move |db, evm_env, tx_env| {
let (_res, (_, tx_env)) =
this.eth_api().inspect(db, evm_env, tx_env, &mut inspector)?;
let tx_info = TransactionInfo::default();
let frame: FlatCallFrame = inspector
.with_transaction_gas_limit(env.tx.gas_limit)
.with_transaction_gas_limit(tx_env.gas_limit)
.into_parity_builder()
.into_localized_transaction_traces(tx_info);
Ok(frame)
@ -453,7 +436,7 @@ where
let res = self
.eth_api()
.spawn_with_call_at(call, at, overrides, move |db, env| {
.spawn_with_call_at(call, at, overrides, move |db, evm_env, tx_env| {
// wrapper is hack to get around 'higher-ranked lifetime error', see
// <https://github.com/rust-lang/rust/issues/100013>
let db = db.0;
@ -461,8 +444,17 @@ where
let mut inspector =
revm_inspectors::tracing::js::JsInspector::new(code, config)
.map_err(Eth::Error::from_eth_err)?;
let (res, _) =
this.eth_api().inspect(&mut *db, env.clone(), &mut inspector)?;
let (res, _) = this.eth_api().inspect(
&mut *db,
evm_env.clone(),
tx_env.clone(),
&mut inspector,
)?;
let env = Env::boxed(
evm_env.cfg_env_with_handler_cfg.cfg_env,
evm_env.block_env,
tx_env,
);
inspector.json_result(res, &env, db).map_err(Eth::Error::from_eth_err)
})
.await?;
@ -479,9 +471,10 @@ where
let (res, tx_gas_limit, inspector) = self
.eth_api()
.spawn_with_call_at(call, at, overrides, move |db, env| {
let (res, env) = this.eth_api().inspect(db, env, &mut inspector)?;
Ok((res, env.tx.gas_limit, inspector))
.spawn_with_call_at(call, at, overrides, move |db, evm_env, tx_env| {
let (res, (_, tx_env)) =
this.eth_api().inspect(db, evm_env, tx_env, &mut inspector)?;
Ok((res, tx_env.gas_limit, inspector))
})
.await?;
let gas_used = res.result.gas_used();
@ -511,11 +504,10 @@ where
let transaction_index = transaction_index.unwrap_or_default();
let target_block = block_number.unwrap_or_default();
let ((evm_env, _), block) = futures::try_join!(
let ((mut evm_env, _), block) = futures::try_join!(
self.eth_api().evm_env_at(target_block),
self.eth_api().block_with_senders(target_block),
)?;
let EvmEnv { cfg_env_with_handler_cfg, mut block_env } = evm_env;
let opts = opts.unwrap_or_default();
let block = block.ok_or(EthApiError::HeaderNotFound(target_block))?;
@ -552,15 +544,8 @@ where
// Execute all transactions until index
for (signer, tx) in transactions {
let env = EnvWithHandlerCfg {
env: Env::boxed(
cfg_env_with_handler_cfg.cfg_env.clone(),
block_env.clone(),
this.eth_api().evm_config().tx_env(tx, *signer),
),
handler_cfg: cfg_env_with_handler_cfg.handler_cfg,
};
let (res, _) = this.eth_api().transact(&mut db, env)?;
let tx_env = this.eth_api().evm_config().tx_env(tx, *signer);
let (res, _) = this.eth_api().transact(&mut db, evm_env.clone(), tx_env)?;
db.commit(res.state);
}
}
@ -580,9 +565,8 @@ where
let state_overrides = state_overrides.take();
let overrides = EvmOverrides::new(state_overrides, block_overrides.clone());
let env = this.eth_api().prepare_call_env(
cfg_env_with_handler_cfg.clone(),
block_env.clone(),
let (evm_env, tx_env) = this.eth_api().prepare_call_env(
evm_env.clone(),
tx,
&mut db,
overrides,
@ -590,7 +574,8 @@ where
let (trace, state) = this.trace_transaction(
&tracing_options,
env,
evm_env,
tx_env,
&mut db,
None,
&mut inspector,
@ -606,8 +591,8 @@ where
results.push(trace);
}
// Increment block_env number and timestamp for the next bundle
block_env.number += U256::from(1);
block_env.timestamp += U256::from(12);
evm_env.block_env.number += U256::from(1);
evm_env.block_env.timestamp += U256::from(12);
all_bundles.push(results);
}
@ -670,7 +655,8 @@ where
fn trace_transaction(
&self,
opts: &GethDebugTracingOptions,
env: EnvWithHandlerCfg,
evm_env: EvmEnv,
tx_env: TxEnv,
db: &mut StateCacheDb<'_>,
transaction_context: Option<TransactionContext>,
fused_inspector: &mut Option<TracingInspector>,
@ -684,8 +670,8 @@ where
.map(|c| c.tx_index.map(|i| i as u64))
.unwrap_or_default(),
block_hash: transaction_context.as_ref().map(|c| c.block_hash).unwrap_or_default(),
block_number: Some(env.block.number.try_into().unwrap_or_default()),
base_fee: Some(env.block.basefee.try_into().unwrap_or_default()),
block_number: Some(evm_env.block_env.number.try_into().unwrap_or_default()),
base_fee: Some(evm_env.block_env.basefee.try_into().unwrap_or_default()),
};
if let Some(tracer) = tracer {
@ -693,7 +679,8 @@ where
GethDebugTracerType::BuiltInTracer(tracer) => match tracer {
GethDebugBuiltInTracerType::FourByteTracer => {
let mut inspector = FourByteInspector::default();
let (res, _) = self.eth_api().inspect(db, env, &mut inspector)?;
let (res, _) =
self.eth_api().inspect(db, evm_env, tx_env, &mut inspector)?;
return Ok((FourByteFrame::from(&inspector).into(), res.state))
}
GethDebugBuiltInTracerType::CallTracer => {
@ -708,9 +695,10 @@ where
))
});
let (res, env) = self.eth_api().inspect(db, env, &mut inspector)?;
let (res, (_, tx_env)) =
self.eth_api().inspect(db, evm_env, tx_env, &mut inspector)?;
inspector.set_transaction_gas_limit(env.tx.gas_limit);
inspector.set_transaction_gas_limit(tx_env.gas_limit);
let frame = inspector
.geth_builder()
@ -729,9 +717,10 @@ where
TracingInspectorConfig::from_geth_prestate_config(&prestate_config),
)
});
let (res, env) = self.eth_api().inspect(&mut *db, env, &mut inspector)?;
let (res, (_, tx_env)) =
self.eth_api().inspect(&mut *db, evm_env, tx_env, &mut inspector)?;
inspector.set_transaction_gas_limit(env.tx.gas_limit);
inspector.set_transaction_gas_limit(tx_env.gas_limit);
let frame = inspector
.geth_builder()
.geth_prestate_traces(&res, &prestate_config, db)
@ -751,7 +740,8 @@ where
let mut inspector = MuxInspector::try_from_config(mux_config)
.map_err(Eth::Error::from_eth_err)?;
let (res, _) = self.eth_api().inspect(&mut *db, env, &mut inspector)?;
let (res, _) =
self.eth_api().inspect(&mut *db, evm_env, tx_env, &mut inspector)?;
let frame = inspector
.try_into_mux_frame(&res, db, tx_info)
.map_err(Eth::Error::from_eth_err)?;
@ -767,9 +757,10 @@ where
TracingInspectorConfig::from_flat_call_config(&flat_call_config),
);
let (res, env) = self.eth_api().inspect(db, env, &mut inspector)?;
let (res, (_, tx_env)) =
self.eth_api().inspect(db, evm_env, tx_env, &mut inspector)?;
let frame: FlatCallFrame = inspector
.with_transaction_gas_limit(env.tx.gas_limit)
.with_transaction_gas_limit(tx_env.gas_limit)
.into_parity_builder()
.into_localized_transaction_traces(tx_info);
@ -790,9 +781,15 @@ where
transaction_context.unwrap_or_default(),
)
.map_err(Eth::Error::from_eth_err)?;
let (res, env) = self.eth_api().inspect(&mut *db, env, &mut inspector)?;
let (res, (evm_env, tx_env)) =
self.eth_api().inspect(&mut *db, evm_env, tx_env, &mut inspector)?;
let state = res.state.clone();
let env = Env::boxed(
evm_env.cfg_env_with_handler_cfg.cfg_env,
evm_env.block_env,
tx_env,
);
let result =
inspector.json_result(res, &env, db).map_err(Eth::Error::from_eth_err)?;
Ok((GethTrace::JS(result), state))
@ -805,10 +802,10 @@ where
let inspector_config = TracingInspectorConfig::from_geth_config(config);
TracingInspector::new(inspector_config)
});
let (res, env) = self.eth_api().inspect(db, env, &mut inspector)?;
let (res, (_, tx_env)) = self.eth_api().inspect(db, evm_env, tx_env, &mut inspector)?;
let gas_used = res.result.gas_used();
let return_value = res.result.into_output().unwrap_or_default();
inspector.set_transaction_gas_limit(env.tx.gas_limit);
inspector.set_transaction_gas_limit(tx_env.gas_limit);
let frame = inspector.geth_builder().geth_traces(gas_used, return_value, *config);
Ok((frame.into(), res.state))

View File

@ -6,7 +6,7 @@ use alloy_primitives::{Keccak256, U256};
use alloy_rpc_types_mev::{EthCallBundle, EthCallBundleResponse, EthCallBundleTransactionResult};
use jsonrpsee::core::RpcResult;
use reth_chainspec::EthChainSpec;
use reth_evm::{env::EvmEnv, ConfigureEvm, ConfigureEvmEnv};
use reth_evm::{ConfigureEvm, ConfigureEvmEnv};
use reth_primitives_traits::SignedTransaction;
use reth_provider::{ChainSpecProvider, HeaderProvider};
use reth_revm::database::StateProviderDatabase;
@ -21,9 +21,9 @@ use reth_transaction_pool::{
};
use revm::{
db::{CacheDB, DatabaseCommit, DatabaseRef},
primitives::{ResultAndState, TxEnv},
primitives::ResultAndState,
};
use revm_primitives::{EnvKzgSettings, EnvWithHandlerCfg, SpecId};
use revm_primitives::{EnvKzgSettings, SpecId};
use std::sync::Arc;
/// `Eth` bundle implementation.
@ -101,40 +101,40 @@ where
let block_id: alloy_rpc_types_eth::BlockId = state_block_number.into();
// Note: the block number is considered the `parent` block: <https://github.com/flashbots/mev-geth/blob/fddf97beec5877483f879a77b7dea2e58a58d653/internal/ethapi/api.go#L2104>
let (evm_env, at) = self.eth_api().evm_env_at(block_id).await?;
let EvmEnv { cfg_env_with_handler_cfg, mut block_env } = evm_env;
let (mut evm_env, at) = self.eth_api().evm_env_at(block_id).await?;
if let Some(coinbase) = coinbase {
block_env.coinbase = coinbase;
evm_env.block_env.coinbase = coinbase;
}
// need to adjust the timestamp for the next block
if let Some(timestamp) = timestamp {
block_env.timestamp = U256::from(timestamp);
evm_env.block_env.timestamp = U256::from(timestamp);
} else {
block_env.timestamp += U256::from(12);
evm_env.block_env.timestamp += U256::from(12);
}
if let Some(difficulty) = difficulty {
block_env.difficulty = U256::from(difficulty);
evm_env.block_env.difficulty = U256::from(difficulty);
}
// default to call gas limit unless user requests a smaller limit
block_env.gas_limit = U256::from(self.inner.eth_api.call_gas_limit());
evm_env.block_env.gas_limit = U256::from(self.inner.eth_api.call_gas_limit());
if let Some(gas_limit) = gas_limit {
let gas_limit = U256::from(gas_limit);
if gas_limit > block_env.gas_limit {
if gas_limit > evm_env.block_env.gas_limit {
return Err(
EthApiError::InvalidTransaction(RpcInvalidTransactionError::GasTooHigh).into()
)
}
block_env.gas_limit = gas_limit;
evm_env.block_env.gas_limit = gas_limit;
}
if let Some(base_fee) = base_fee {
block_env.basefee = U256::from(base_fee);
} else if cfg_env_with_handler_cfg.handler_cfg.spec_id.is_enabled_in(SpecId::LONDON) {
let parent_block = block_env.number.saturating_to::<u64>();
evm_env.block_env.basefee = U256::from(base_fee);
} else if evm_env.cfg_env_with_handler_cfg.handler_cfg.spec_id.is_enabled_in(SpecId::LONDON)
{
let parent_block = evm_env.block_env.number.saturating_to::<u64>();
// here we need to fetch the _next_ block's basefee based on the parent block <https://github.com/flashbots/mev-geth/blob/fddf97beec5877483f879a77b7dea2e58a58d653/internal/ethapi/api.go#L2130>
let parent = RpcNodeCore::provider(self.eth_api())
.header_by_number(parent_block)
@ -145,25 +145,20 @@ where
.chain_spec()
.base_fee_params_at_block(parent_block),
) {
block_env.basefee = U256::from(base_fee);
evm_env.block_env.basefee = U256::from(base_fee);
}
}
let state_block_number = block_env.number;
let state_block_number = evm_env.block_env.number;
// use the block number of the request
block_env.number = U256::from(block_number);
evm_env.block_env.number = U256::from(block_number);
let eth_api = self.eth_api().clone();
self.eth_api()
.spawn_with_state_at_block(at, move |state| {
let coinbase = block_env.coinbase;
let basefee = Some(block_env.basefee.to::<u64>());
let env = EnvWithHandlerCfg::new_with_cfg_env(
cfg_env_with_handler_cfg,
block_env,
TxEnv::default(),
);
let coinbase = evm_env.block_env.coinbase;
let basefee = Some(evm_env.block_env.basefee.to::<u64>());
let db = CacheDB::new(StateProviderDatabase::new(state));
let initial_coinbase = db
@ -177,7 +172,7 @@ where
let mut total_gas_fess = U256::ZERO;
let mut hasher = Keccak256::new();
let mut evm = eth_api.evm_config().evm_with_env(db, env);
let mut evm = eth_api.evm_config().evm_with_env(db, evm_env, Default::default());
let mut results = Vec::with_capacity(transactions.len());
let mut transactions = transactions.into_iter().peekable();

View File

@ -10,7 +10,7 @@ use alloy_rpc_types_mev::{
};
use jsonrpsee::core::RpcResult;
use reth_chainspec::EthChainSpec;
use reth_evm::{env::EvmEnv, ConfigureEvm, ConfigureEvmEnv};
use reth_evm::{ConfigureEvm, ConfigureEvmEnv};
use reth_provider::{ChainSpecProvider, HeaderProvider, ProviderTx};
use reth_revm::database::StateProviderDatabase;
use reth_rpc_api::MevSimApiServer;
@ -23,7 +23,7 @@ use reth_tasks::pool::BlockingTaskGuard;
use reth_transaction_pool::{PoolConsensusTx, PoolPooledTx, PoolTransaction, TransactionPool};
use revm::{
db::CacheDB,
primitives::{Address, EnvWithHandlerCfg, ResultAndState, SpecId, TxEnv},
primitives::{Address, ResultAndState, SpecId},
DatabaseCommit, DatabaseRef,
};
use std::{sync::Arc, time::Duration};
@ -244,42 +244,44 @@ where
let flattened_bundle = self.parse_and_flatten_bundle(&request)?;
let block_id = parent_block.unwrap_or(BlockId::Number(BlockNumberOrTag::Pending));
let (evm_env, current_block) = self.eth_api().evm_env_at(block_id).await?;
let EvmEnv { cfg_env_with_handler_cfg, mut block_env } = evm_env;
let (mut evm_env, current_block) = self.eth_api().evm_env_at(block_id).await?;
let parent_header = RpcNodeCore::provider(&self.inner.eth_api)
.header_by_number(block_env.number.saturating_to::<u64>())
.header_by_number(evm_env.block_env.number.saturating_to::<u64>())
.map_err(EthApiError::from_eth_err)? // Explicitly map the error
.ok_or_else(|| {
EthApiError::HeaderNotFound((block_env.number.saturating_to::<u64>()).into())
EthApiError::HeaderNotFound(
(evm_env.block_env.number.saturating_to::<u64>()).into(),
)
})?;
// apply overrides
if let Some(block_number) = block_number {
block_env.number = U256::from(block_number);
evm_env.block_env.number = U256::from(block_number);
}
if let Some(coinbase) = coinbase {
block_env.coinbase = coinbase;
evm_env.block_env.coinbase = coinbase;
}
if let Some(timestamp) = timestamp {
block_env.timestamp = U256::from(timestamp);
evm_env.block_env.timestamp = U256::from(timestamp);
}
if let Some(gas_limit) = gas_limit {
block_env.gas_limit = U256::from(gas_limit);
evm_env.block_env.gas_limit = U256::from(gas_limit);
}
if let Some(base_fee) = base_fee {
block_env.basefee = U256::from(base_fee);
} else if cfg_env_with_handler_cfg.handler_cfg.spec_id.is_enabled_in(SpecId::LONDON) {
evm_env.block_env.basefee = U256::from(base_fee);
} else if evm_env.cfg_env_with_handler_cfg.handler_cfg.spec_id.is_enabled_in(SpecId::LONDON)
{
if let Some(base_fee) = parent_header.next_block_base_fee(
RpcNodeCore::provider(&self.inner.eth_api)
.chain_spec()
.base_fee_params_at_block(block_env.number.saturating_to::<u64>()),
.base_fee_params_at_block(evm_env.block_env.number.saturating_to::<u64>()),
) {
block_env.basefee = U256::from(base_fee);
evm_env.block_env.basefee = U256::from(base_fee);
}
}
@ -291,13 +293,8 @@ where
.spawn_with_state_at_block(current_block, move |state| {
// Setup environment
let current_block_number = current_block.as_u64().unwrap();
let coinbase = block_env.coinbase;
let basefee = block_env.basefee;
let env = EnvWithHandlerCfg::new_with_cfg_env(
cfg_env_with_handler_cfg,
block_env,
TxEnv::default(),
);
let coinbase = evm_env.block_env.coinbase;
let basefee = evm_env.block_env.basefee;
let db = CacheDB::new(StateProviderDatabase::new(state));
let initial_coinbase_balance = DatabaseRef::basic_ref(&db, coinbase)
@ -311,7 +308,7 @@ where
let mut refundable_value = U256::ZERO;
let mut body_logs: Vec<SimBundleLogs> = Vec::new();
let mut evm = eth_api.evm_config().evm_with_env(db, env);
let mut evm = eth_api.evm_config().evm_with_env(db, evm_env, Default::default());
for item in &flattened_bundle {
// Check inclusion constraints

View File

@ -16,7 +16,7 @@ use async_trait::async_trait;
use jsonrpsee::core::RpcResult;
use reth_chainspec::{EthChainSpec, EthereumHardfork, MAINNET, SEPOLIA};
use reth_consensus_common::calc::{base_block_reward_pre_merge, block_reward, ommer_reward};
use reth_evm::{env::EvmEnv, ConfigureEvmEnv};
use reth_evm::ConfigureEvmEnv;
use reth_primitives_traits::{BlockBody, BlockHeader};
use reth_provider::{BlockNumReader, BlockReader, ChainSpecProvider};
use reth_revm::database::StateProviderDatabase;
@ -25,10 +25,7 @@ use reth_rpc_eth_api::{helpers::TraceExt, FromEthApiError, RpcNodeCore};
use reth_rpc_eth_types::{error::EthApiError, utils::recover_raw_transaction};
use reth_tasks::pool::BlockingTaskGuard;
use reth_transaction_pool::{PoolPooledTx, PoolTransaction, TransactionPool};
use revm::{
db::{CacheDB, DatabaseCommit},
primitives::EnvWithHandlerCfg,
};
use revm::db::{CacheDB, DatabaseCommit};
use revm_inspectors::{
opcode::OpcodeGasInspector,
tracing::{parity::populate_state_diff, TracingInspector, TracingInspectorConfig},
@ -90,12 +87,12 @@ where
let mut inspector = TracingInspector::new(config);
let this = self.clone();
self.eth_api()
.spawn_with_call_at(trace_request.call, at, overrides, move |db, env| {
.spawn_with_call_at(trace_request.call, at, overrides, move |db, evm_env, tx_env| {
// wrapper is hack to get around 'higher-ranked lifetime error', see
// <https://github.com/rust-lang/rust/issues/100013>
let db = db.0;
let (res, _) = this.eth_api().inspect(&mut *db, env, &mut inspector)?;
let (res, _) = this.eth_api().inspect(&mut *db, evm_env, tx_env, &mut inspector)?;
let trace_res = inspector
.into_parity_builder()
.into_trace_results_with_state(&res, &trace_request.trace_types, &db)
@ -116,18 +113,12 @@ where
.map_transaction(<Eth::Pool as TransactionPool>::Transaction::pooled_into_consensus);
let (evm_env, at) = self.eth_api().evm_env_at(block_id.unwrap_or_default()).await?;
let EvmEnv { cfg_env_with_handler_cfg, block_env } = evm_env;
let env = EnvWithHandlerCfg::new_with_cfg_env(
cfg_env_with_handler_cfg,
block_env,
self.eth_api().evm_config().tx_env(tx.tx(), tx.signer()),
);
let tx_env = self.eth_api().evm_config().tx_env(tx.tx(), tx.signer());
let config = TracingInspectorConfig::from_parity_config(&trace_types);
self.eth_api()
.spawn_trace_at_with_state(env, config, at, move |inspector, res, db| {
.spawn_trace_at_with_state(evm_env, tx_env, config, at, move |inspector, res, db| {
inspector
.into_parity_builder()
.into_trace_results_with_state(&res, &trace_types, &db)
@ -147,7 +138,6 @@ where
) -> Result<Vec<TraceResults>, Eth::Error> {
let at = block_id.unwrap_or(BlockId::pending());
let (evm_env, at) = self.eth_api().evm_env_at(at).await?;
let EvmEnv { cfg_env_with_handler_cfg, block_env } = evm_env;
let this = self.clone();
// execute all transactions on top of each other and record the traces
@ -159,16 +149,16 @@ where
let mut calls = calls.into_iter().peekable();
while let Some((call, trace_types)) = calls.next() {
let env = this.eth_api().prepare_call_env(
cfg_env_with_handler_cfg.clone(),
block_env.clone(),
let (evm_env, tx_env) = this.eth_api().prepare_call_env(
evm_env.clone(),
call,
&mut db,
Default::default(),
)?;
let config = TracingInspectorConfig::from_parity_config(&trace_types);
let mut inspector = TracingInspector::new(config);
let (res, _) = this.eth_api().inspect(&mut db, env, &mut inspector)?;
let (res, _) =
this.eth_api().inspect(&mut db, evm_env, tx_env, &mut inspector)?;
let trace_res = inspector
.into_parity_builder()

View File

@ -7,7 +7,9 @@ license.workspace = true
[dependencies]
reth.workspace = true
reth-evm.workspace = true
reth-node-ethereum.workspace = true
revm-primitives.workspace = true
alloy-rpc-types-eth.workspace = true
clap = { workspace = true, features = ["derive"] }
futures-util.workspace = true

View File

@ -22,12 +22,15 @@ use reth::{
revm::{
inspector_handle_register,
interpreter::{Interpreter, OpCode},
primitives::{Env, EnvWithHandlerCfg},
Database, Evm, EvmContext, Inspector,
},
rpc::{api::eth::helpers::Call, compat::transaction::transaction_to_call_request},
transaction_pool::TransactionPool,
};
use reth_evm::EvmEnv;
use reth_node_ethereum::node::EthereumNode;
use revm_primitives::CfgEnvWithHandlerCfg;
fn main() {
Cli::<EthereumChainSpecParser, RethCliTxpoolExt>::parse()
@ -61,7 +64,16 @@ fn main() {
call_request,
BlockNumberOrTag::Latest.into(),
EvmOverrides::default(),
move |db, env| {
move |db, evm_env, tx_env| {
let EvmEnv {
cfg_env_with_handler_cfg:
CfgEnvWithHandlerCfg { handler_cfg, cfg_env },
block_env,
} = evm_env;
let env = EnvWithHandlerCfg {
handler_cfg,
env: Env::boxed(cfg_env, block_env, tx_env),
};
let mut dummy_inspector = DummyInspector::default();
{
// configure the evm with the custom inspector