feat: alloy-evm and new revm integration (#14021)

Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
Co-authored-by: rakita <rakita@users.noreply.github.com>
This commit is contained in:
Arsenii Kulikov
2025-02-17 23:59:23 +04:00
committed by GitHub
parent bb6dec7ceb
commit 336c3d1fac
142 changed files with 1841 additions and 1929 deletions

View File

@ -13,9 +13,9 @@ workspace = true
[dependencies]
# reth
revm.workspace = true
revm = { workspace = true, features = ["optional_block_gas_limit", "optional_eip3607", "optional_no_base_fee"] }
revm-inspectors.workspace = true
revm-primitives = { workspace = true, features = ["dev"] }
revm-primitives = { workspace = true }
reth-primitives-traits.workspace = true
reth-errors.workspace = true
reth-evm.workspace = true

View File

@ -3,8 +3,7 @@
use super::{LoadBlock, LoadPendingBlock, LoadState, LoadTransaction, SpawnBlocking, Trace};
use crate::{
helpers::estimate::EstimateCall, FromEthApiError, FromEvmError, FullEthApiTypes, RpcBlock,
RpcNodeCore,
helpers::estimate::EstimateCall, FromEvmError, FullEthApiTypes, RpcBlock, RpcNodeCore,
};
use alloy_consensus::BlockHeader;
use alloy_eips::{eip1559::calc_next_block_base_fee, eip2930::AccessListResult};
@ -18,16 +17,14 @@ use alloy_rpc_types_eth::{
use futures::Future;
use reth_chainspec::EthChainSpec;
use reth_errors::ProviderError;
use reth_evm::{env::EvmEnv, ConfigureEvm, ConfigureEvmEnv, Database, Evm, TransactionEnv};
use reth_evm::{
ConfigureEvm, ConfigureEvmEnv, Evm, EvmEnv, HaltReasonFor, InspectorFor, SpecFor,
TransactionEnv,
};
use reth_node_api::BlockBody;
use reth_primitives_traits::SignedTransaction;
use reth_provider::{BlockIdReader, ChainSpecProvider, ProviderHeader};
use reth_revm::{
database::StateProviderDatabase,
db::CacheDB,
primitives::{BlockEnv, ExecutionResult, ResultAndState},
DatabaseRef,
};
use reth_revm::{database::StateProviderDatabase, db::CacheDB, DatabaseRef};
use reth_rpc_eth_types::{
cache::db::{StateCacheDbRefMutWrapper, StateProviderTraitObjWrapper},
error::{api::FromEvmHalt, ensure_success},
@ -35,7 +32,13 @@ use reth_rpc_eth_types::{
simulate::{self, EthSimulateError},
EthApiError, RevertError, RpcInvalidTransactionError, StateCacheDb,
};
use revm::{DatabaseCommit, GetInspector};
use revm::{
context_interface::{
result::{ExecutionResult, ResultAndState},
Transaction,
},
Database, DatabaseCommit,
};
use revm_inspectors::{access_list::AccessListInspector, transfer::TransferInspector};
use tracing::trace;
@ -106,12 +109,12 @@ pub trait EthCall: EstimateCall + Call + LoadPendingBlock + LoadBlock + FullEthA
let chain_spec = RpcNodeCore::provider(&this).chain_spec();
while let Some(block) = block_state_calls.next() {
// Increase number and timestamp for every new block
evm_env.block_env.number += U256::from(1);
evm_env.block_env.timestamp += U256::from(1);
evm_env.block_env.number += 1;
evm_env.block_env.timestamp += 1;
if validation {
let base_fee_params = chain_spec
.base_fee_params_at_timestamp(evm_env.block_env.timestamp.to());
let base_fee_params =
chain_spec.base_fee_params_at_timestamp(evm_env.block_env.timestamp);
let base_fee = if let Some(latest) = blocks.last() {
let header = &latest.inner.header;
calc_next_block_base_fee(
@ -123,9 +126,9 @@ pub trait EthCall: EstimateCall + Call + LoadPendingBlock + LoadBlock + FullEthA
} else {
base_block.next_block_base_fee(base_fee_params).unwrap_or_default()
};
evm_env.block_env.basefee = U256::from(base_fee);
evm_env.block_env.basefee = base_fee;
} else {
evm_env.block_env.basefee = U256::ZERO;
evm_env.block_env.basefee = 0;
}
let SimBlock { block_overrides, state_overrides, calls } = block;
@ -137,7 +140,7 @@ pub trait EthCall: EstimateCall + Call + LoadPendingBlock + LoadBlock + FullEthA
apply_state_overrides(state_overrides, &mut db)?;
}
if (total_gas_limit - gas_used) < evm_env.block_env.gas_limit.to() {
if (total_gas_limit - gas_used) < evm_env.block_env.gas_limit {
return Err(
EthApiError::Other(Box::new(EthSimulateError::GasLimitReached)).into()
)
@ -148,7 +151,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 > evm_env.block_env.gas_limit.to() {
if total_specified_gas > evm_env.block_env.gas_limit {
return Err(EthApiError::Other(Box::new(
EthSimulateError::BlockGasLimitExceeded,
))
@ -156,7 +159,7 @@ pub trait EthCall: EstimateCall + Call + LoadPendingBlock + LoadBlock + FullEthA
}
if txs_without_gas_limit > 0 {
(evm_env.block_env.gas_limit.to::<u64>() - total_specified_gas) /
(evm_env.block_env.gas_limit - total_specified_gas) /
txs_without_gas_limit as u64
} else {
0
@ -252,7 +255,7 @@ pub trait EthCall: EstimateCall + Call + LoadPendingBlock + LoadBlock + FullEthA
let (res, _env) =
self.transact_call_at(request, block_number.unwrap_or_default(), overrides).await?;
ensure_success(res.result).map_err(Self::Error::from_eth_err)
ensure_success(res.result)
}
}
@ -341,7 +344,7 @@ pub trait EthCall: EstimateCall + Call + LoadPendingBlock + LoadBlock + FullEthA
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) {
match ensure_success::<_, Self::Error>(res.result) {
Ok(output) => {
results.push(EthCallResponse { value: Some(output), error: None });
}
@ -397,8 +400,9 @@ pub trait EthCall: EstimateCall + Call + LoadPendingBlock + LoadBlock + FullEthA
Self: Trace,
{
let state = self.state_at_block_id(at)?;
let mut db = CacheDB::new(StateProviderDatabase::new(state));
let mut tx_env = self.create_txn_env(&evm_env.block_env, request.clone())?;
let mut tx_env = self.create_txn_env(&evm_env, request.clone(), &mut db)?;
// 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>
@ -409,12 +413,10 @@ pub trait EthCall: EstimateCall + Call + LoadPendingBlock + LoadBlock + FullEthA
// <https://github.com/ethereum/go-ethereum/blob/8990c92aea01ca07801597b00c0d83d4e2d9b811/internal/ethapi/api.go#L1476-L1476>
evm_env.cfg_env.disable_base_fee = true;
let mut db = CacheDB::new(StateProviderDatabase::new(state));
if request.gas.is_none() && tx_env.gas_price() > U256::ZERO {
if request.gas.is_none() && tx_env.gas_price() > 0 {
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
tx_env.set_gas_limit(cap.min(evm_env.block_env.gas_limit).saturating_to());
tx_env.set_gas_limit(cap.min(evm_env.block_env.gas_limit));
}
// can consume the list since we're not using the request anymore
@ -494,7 +496,7 @@ pub trait Call:
tx_env: <Self::Evm as ConfigureEvmEnv>::TxEnv,
) -> Result<
(
ResultAndState,
ResultAndState<HaltReasonFor<Self::Evm>>,
(EvmEnv<<Self::Evm as ConfigureEvmEnv>::Spec>, <Self::Evm as ConfigureEvmEnv>::TxEnv),
),
Self::Error,
@ -511,21 +513,22 @@ pub trait Call:
/// Executes the [`EvmEnv`] against the given [Database] without committing state
/// changes.
#[expect(clippy::type_complexity)]
fn transact_with_inspector<DB>(
fn transact_with_inspector<DB, I>(
&self,
db: DB,
evm_env: EvmEnv<<Self::Evm as ConfigureEvmEnv>::Spec>,
tx_env: <Self::Evm as ConfigureEvmEnv>::TxEnv,
inspector: impl GetInspector<DB>,
inspector: I,
) -> Result<
(
ResultAndState,
ResultAndState<HaltReasonFor<Self::Evm>>,
(EvmEnv<<Self::Evm as ConfigureEvmEnv>::Spec>, <Self::Evm as ConfigureEvmEnv>::TxEnv),
),
Self::Error,
>
where
DB: Database<Error = ProviderError>,
I: InspectorFor<DB, Self::Evm>,
{
let mut evm = self.evm_config().evm_with_env_and_inspector(db, evm_env.clone(), inspector);
let res = evm.transact(tx_env.clone()).map_err(Self::Error::from_evm_err)?;
@ -543,7 +546,7 @@ pub trait Call:
) -> impl Future<
Output = Result<
(
ResultAndState,
ResultAndState<HaltReasonFor<Self::Evm>>,
(
EvmEnv<<Self::Evm as ConfigureEvmEnv>::Spec>,
<Self::Evm as ConfigureEvmEnv>::TxEnv,
@ -643,7 +646,11 @@ pub trait Call:
) -> impl Future<Output = Result<Option<R>, Self::Error>> + Send
where
Self: LoadBlock + LoadTransaction,
F: FnOnce(TransactionInfo, ResultAndState, StateCacheDb<'_>) -> Result<R, Self::Error>
F: FnOnce(
TransactionInfo,
ResultAndState<HaltReasonFor<Self::Evm>>,
StateCacheDb<'_>,
) -> Result<R, Self::Error>
+ Send
+ 'static,
R: Send + 'static,
@ -716,11 +723,12 @@ pub trait Call:
/// Configures a new `TxEnv` for the [`TransactionRequest`]
///
/// All `TxEnv` fields are derived from the given [`TransactionRequest`], if fields are
/// `None`, they fall back to the [`BlockEnv`]'s settings.
/// `None`, they fall back to the [`EvmEnv`]'s settings.
fn create_txn_env(
&self,
block_env: &BlockEnv,
evm_env: &EvmEnv<SpecFor<Self::Evm>>,
request: TransactionRequest,
db: impl Database<Error: Into<EthApiError>>,
) -> Result<<Self::Evm as ConfigureEvmEnv>::TxEnv, Self::Error>;
/// Prepares the [`EvmEnv`] for execution of calls.
@ -759,7 +767,7 @@ pub trait Call:
}
// apply configured gas cap
evm_env.block_env.gas_limit = U256::from(self.call_gas_limit());
evm_env.block_env.gas_limit = self.call_gas_limit();
// Disabled because eth_call is sometimes used with eoa senders
// See <https://github.com/paradigmxyz/reth/issues/1959>
@ -781,16 +789,16 @@ pub trait Call:
}
let request_gas = request.gas;
let mut tx_env = self.create_txn_env(&evm_env.block_env, request)?;
let mut tx_env = self.create_txn_env(&evm_env, request, &mut *db)?;
if request_gas.is_none() {
// No gas limit was provided in the request, so we need to cap the transaction gas limit
if tx_env.gas_price() > U256::ZERO {
if tx_env.gas_price() > 0 {
// If gas price is specified, cap transaction gas limit with caller allowance
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
tx_env.set_gas_limit(cap.min(evm_env.block_env.gas_limit).saturating_to());
tx_env.set_gas_limit(cap.min(evm_env.block_env.gas_limit));
}
}

View File

@ -7,15 +7,16 @@ use alloy_rpc_types_eth::{state::StateOverride, transaction::TransactionRequest,
use futures::Future;
use reth_chainspec::MIN_TRANSACTION_GAS;
use reth_errors::ProviderError;
use reth_evm::{env::EvmEnv, ConfigureEvmEnv, Database, TransactionEnv};
use reth_evm::{ConfigureEvmEnv, Database, EvmEnv, TransactionEnv};
use reth_provider::StateProvider;
use reth_revm::{database::StateProviderDatabase, db::CacheDB, primitives::ExecutionResult};
use reth_revm::{database::StateProviderDatabase, db::CacheDB};
use reth_rpc_eth_types::{
error::api::FromEvmHalt,
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::context_interface::{result::ExecutionResult, Transaction};
use revm_primitives::TxKind;
use tracing::trace;
@ -55,7 +56,7 @@ pub trait EstimateCall: Call {
request.nonce = None;
// Keep a copy of gas related request values
let tx_request_gas_limit = request.gas.map(U256::from);
let tx_request_gas_limit = request.gas;
let tx_request_gas_price = request.gas_price;
// the gas limit of the corresponding block
let block_env_gas_limit = evm_env.block_env.gas_limit;
@ -73,8 +74,8 @@ pub trait EstimateCall: Call {
.unwrap_or(block_env_gas_limit);
// Configure the evm env
let mut tx_env = self.create_txn_env(&evm_env.block_env, request)?;
let mut db = CacheDB::new(StateProviderDatabase::new(state));
let mut tx_env = self.create_txn_env(&evm_env, request, &mut db)?;
// Apply any state overrides if specified.
if let Some(state_override) = state_override {
@ -107,15 +108,12 @@ 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 tx_env.gas_price() > U256::ZERO {
if tx_env.gas_price() > 0 {
// 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, &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
tx_env.set_gas_limit(tx_env.gas_limit().min(highest_gas_limit));
@ -288,7 +286,7 @@ pub trait EstimateCall: Call {
#[inline]
fn map_out_of_gas_err<DB>(
&self,
env_gas_limit: U256,
env_gas_limit: u64,
evm_env: EvmEnv<<Self::Evm as ConfigureEvmEnv>::Spec>,
mut tx_env: <Self::Evm as ConfigureEvmEnv>::TxEnv,
db: &mut DB,
@ -298,7 +296,7 @@ pub trait EstimateCall: Call {
EthApiError: From<DB::Error>,
{
let req_gas_limit = tx_env.gas_limit();
tx_env.set_gas_limit(env_gas_limit.try_into().unwrap_or(u64::MAX));
tx_env.set_gas_limit(env_gas_limit);
let (res, _) = match self.transact(db, evm_env, tx_env) {
Ok(res) => res,
Err(err) => return err,
@ -314,7 +312,7 @@ pub trait EstimateCall: Call {
RpcInvalidTransactionError::Revert(RevertError::new(output)).into_eth_err()
}
ExecutionResult::Halt { reason, .. } => {
RpcInvalidTransactionError::EvmHalt(reason).into_eth_err()
Self::Error::from_evm_halt(reason, req_gas_limit)
}
}
}
@ -326,8 +324,8 @@ pub trait EstimateCall: Call {
/// gas limit for a transaction. It adjusts the highest or lowest gas limits depending on
/// whether the execution succeeded, reverted, or halted due to specific reasons.
#[inline]
pub fn update_estimated_gas_range(
result: ExecutionResult,
pub fn update_estimated_gas_range<Halt>(
result: ExecutionResult<Halt>,
tx_gas_limit: u64,
highest_gas_limit: &mut u64,
lowest_gas_limit: &mut u64,

View File

@ -11,8 +11,8 @@ use futures::Future;
use reth_chainspec::{EthChainSpec, EthereumHardforks};
use reth_errors::RethError;
use reth_evm::{
env::EvmEnv, state_change::post_block_withdrawals_balance_increments,
system_calls::SystemCaller, ConfigureEvm, ConfigureEvmEnv, Evm, EvmError, InvalidTxError,
state_change::post_block_withdrawals_balance_increments, system_calls::SystemCaller,
ConfigureEvm, ConfigureEvmEnv, Evm, EvmEnv, EvmError, HaltReasonFor, InvalidTxError,
NextBlockEnvAttributes,
};
use reth_primitives::{InvalidTransactionError, RecoveredBlock};
@ -23,14 +23,21 @@ use reth_provider::{
};
use reth_revm::{
database::StateProviderDatabase,
primitives::{BlockEnv, ExecutionResult, ResultAndState},
db::{states::bundle_state::BundleRetention, State},
};
use reth_rpc_eth_types::{EthApiError, PendingBlock, PendingBlockEnv, PendingBlockEnvOrigin};
use reth_transaction_pool::{
error::InvalidPoolTransactionError, BestTransactionsAttributes, PoolTransaction,
TransactionPool,
};
use revm::{db::states::bundle_state::BundleRetention, DatabaseCommit, State};
use revm::{
context::BlockEnv,
context_interface::{
result::{ExecutionResult, ResultAndState},
Block,
},
DatabaseCommit,
};
use std::time::{Duration, Instant};
use tokio::sync::Mutex;
use tracing::debug;
@ -155,7 +162,7 @@ pub trait LoadPendingBlock:
// check if the block is still good
if let Some(pending_block) = lock.as_ref() {
// this is guaranteed to be the `latest` header
if pending.evm_env.block_env.number.to::<u64>() == pending_block.block.number() &&
if pending.evm_env.block_env.number == pending_block.block.number() &&
parent_hash == pending_block.block.parent_hash() &&
now <= pending_block.expires_at
{
@ -193,7 +200,7 @@ pub trait LoadPendingBlock:
fn assemble_receipt(
&self,
tx: &ProviderTx<Self::Provider>,
result: ExecutionResult,
result: ExecutionResult<HaltReasonFor<Self::Evm>>,
cumulative_gas_used: u64,
) -> ProviderReceipt<Self::Provider>;
@ -214,7 +221,7 @@ pub trait LoadPendingBlock:
parent_hash: B256,
state_root: B256,
transactions: Vec<ProviderTx<Self::Provider>>,
results: Vec<ExecutionResult>,
results: Vec<ExecutionResult<HaltReasonFor<Self::Evm>>>,
) -> (ProviderBlock<Self::Provider>, Vec<ProviderReceipt<Self::Provider>>) {
let mut cumulative_gas_used = 0;
let mut receipts = Vec::with_capacity(results.len());
@ -257,15 +264,15 @@ pub trait LoadPendingBlock:
let mut cumulative_gas_used = 0;
let mut sum_blob_gas_used = 0;
let block_gas_limit: u64 = evm_env.block_env.gas_limit.to::<u64>();
let base_fee = evm_env.block_env.basefee.to::<u64>();
let block_gas_limit: u64 = evm_env.block_env.gas_limit;
let base_fee = evm_env.block_env.basefee;
let mut executed_txs = Vec::new();
let mut senders = Vec::new();
let mut best_txs =
self.pool().best_transactions_with_attributes(BestTransactionsAttributes::new(
base_fee,
evm_env.block_env.get_blob_gasprice().map(|gasprice| gasprice as u64),
evm_env.block_env.blob_gasprice().map(|gasprice| gasprice as u64),
));
let chain_spec = self.provider().chain_spec();
@ -384,7 +391,7 @@ pub trait LoadPendingBlock:
// executes the withdrawals and commits them to the Database and BundleState.
let balance_increments = post_block_withdrawals_balance_increments(
chain_spec.as_ref(),
evm_env.block_env.timestamp.try_into().unwrap_or(u64::MAX),
evm_env.block_env.timestamp,
&[],
);

View File

@ -10,7 +10,7 @@ use alloy_serde::JsonStorageKey;
use futures::Future;
use reth_chainspec::{EthChainSpec, EthereumHardforks};
use reth_errors::RethError;
use reth_evm::{env::EvmEnv, ConfigureEvmEnv};
use reth_evm::{ConfigureEvmEnv, EvmEnv};
use reth_provider::{
BlockIdReader, BlockNumReader, ChainSpecProvider, StateProvider, StateProviderBox,
StateProviderFactory,

View File

@ -9,20 +9,24 @@ use futures::Future;
use reth_chainspec::ChainSpecProvider;
use reth_errors::ProviderError;
use reth_evm::{
env::EvmEnv, system_calls::SystemCaller, ConfigureEvm, ConfigureEvmEnv, Database, Evm,
system_calls::SystemCaller, ConfigureEvm, ConfigureEvmEnv, Database, Evm, EvmEnv,
HaltReasonFor, InspectorFor,
};
use reth_primitives::RecoveredBlock;
use reth_primitives_traits::{BlockBody, SignedTransaction};
use reth_provider::{BlockReader, ProviderBlock, ProviderHeader, ProviderTx};
use reth_revm::database::StateProviderDatabase;
use reth_revm::{database::StateProviderDatabase, db::CacheDB};
use reth_rpc_eth_types::{
cache::db::{StateCacheDb, StateCacheDbRefMutWrapper, StateProviderTraitObjWrapper},
EthApiError,
};
use revm::{db::CacheDB, DatabaseCommit, GetInspector, Inspector};
use revm::{
context_interface::result::{ExecutionResult, ResultAndState},
state::EvmState,
DatabaseCommit,
};
use revm_inspectors::tracing::{TracingInspector, TracingInspectorConfig};
use revm_primitives::{EvmState, ExecutionResult, ResultAndState};
use std::{fmt::Display, sync::Arc};
use std::sync::Arc;
/// Executes CPU heavy tasks.
pub trait Trace:
@ -46,14 +50,14 @@ pub trait Trace:
inspector: I,
) -> Result<
(
ResultAndState,
ResultAndState<HaltReasonFor<Self::Evm>>,
(EvmEnv<<Self::Evm as ConfigureEvmEnv>::Spec>, <Self::Evm as ConfigureEvmEnv>::TxEnv),
),
Self::Error,
>
where
DB: Database<Error = ProviderError>,
I: GetInspector<DB>,
I: InspectorFor<DB, Self::Evm>,
{
let mut evm = self.evm_config().evm_with_env_and_inspector(db, evm_env.clone(), inspector);
let res = evm.transact(tx_env.clone()).map_err(Self::Error::from_evm_err)?;
@ -77,7 +81,10 @@ pub trait Trace:
) -> Result<R, Self::Error>
where
Self: Call,
F: FnOnce(TracingInspector, ResultAndState) -> Result<R, Self::Error>,
F: FnOnce(
TracingInspector,
ResultAndState<HaltReasonFor<Self::Evm>>,
) -> Result<R, Self::Error>,
{
self.with_state_at_block(at, |state| {
let mut db = CacheDB::new(StateProviderDatabase::new(state));
@ -104,7 +111,11 @@ pub trait Trace:
) -> impl Future<Output = Result<R, Self::Error>> + Send
where
Self: LoadPendingBlock + Call,
F: FnOnce(TracingInspector, ResultAndState, StateCacheDb<'_>) -> Result<R, Self::Error>
F: FnOnce(
TracingInspector,
ResultAndState<HaltReasonFor<Self::Evm>>,
StateCacheDb<'_>,
) -> Result<R, Self::Error>
+ Send
+ 'static,
R: Send + 'static,
@ -138,7 +149,7 @@ pub trait Trace:
F: FnOnce(
TransactionInfo,
TracingInspector,
ResultAndState,
ResultAndState<HaltReasonFor<Self::Evm>>,
StateCacheDb<'_>,
) -> Result<R, Self::Error>
+ Send
@ -168,12 +179,13 @@ pub trait Trace:
F: FnOnce(
TransactionInfo,
Insp,
ResultAndState,
ResultAndState<HaltReasonFor<Self::Evm>>,
StateCacheDb<'_>,
) -> Result<R, Self::Error>
+ Send
+ 'static,
Insp: for<'a, 'b> Inspector<StateCacheDbRefMutWrapper<'a, 'b>> + Send + 'static,
Insp:
for<'a, 'b> InspectorFor<StateCacheDbRefMutWrapper<'a, 'b>, Self::Evm> + Send + 'static,
R: Send + 'static,
{
async move {
@ -232,7 +244,7 @@ pub trait Trace:
F: Fn(
TransactionInfo,
TracingInspector,
ExecutionResult,
ExecutionResult<HaltReasonFor<Self::Evm>>,
&EvmState,
&StateCacheDb<'_>,
) -> Result<R, Self::Error>
@ -272,14 +284,15 @@ pub trait Trace:
F: Fn(
TransactionInfo,
Insp,
ExecutionResult,
ExecutionResult<HaltReasonFor<Self::Evm>>,
&EvmState,
&StateCacheDb<'_>,
) -> Result<R, Self::Error>
+ Send
+ 'static,
Setup: FnMut() -> Insp + Send + 'static,
Insp: for<'a, 'b> Inspector<StateCacheDbRefMutWrapper<'a, 'b>> + Send + 'static,
Insp:
for<'a, 'b> InspectorFor<StateCacheDbRefMutWrapper<'a, 'b>, Self::Evm> + Send + 'static,
R: Send + 'static,
{
async move {
@ -306,8 +319,8 @@ pub trait Trace:
let state_at = block.parent_hash();
let block_hash = block.hash();
let block_number = evm_env.block_env.number.saturating_to::<u64>();
let base_fee = evm_env.block_env.basefee.saturating_to::<u64>();
let block_number = evm_env.block_env.number;
let base_fee = evm_env.block_env.basefee;
// now get the state
let state = this.state_at_block_id(state_at.into())?;
@ -391,7 +404,7 @@ pub trait Trace:
F: Fn(
TransactionInfo,
TracingInspector,
ExecutionResult,
ExecutionResult<HaltReasonFor<Self::Evm>>,
&EvmState,
&StateCacheDb<'_>,
) -> Result<R, Self::Error>
@ -430,14 +443,15 @@ pub trait Trace:
F: Fn(
TransactionInfo,
Insp,
ExecutionResult,
ExecutionResult<HaltReasonFor<Self::Evm>>,
&EvmState,
&StateCacheDb<'_>,
) -> Result<R, Self::Error>
+ Send
+ 'static,
Setup: FnMut() -> Insp + Send + 'static,
Insp: for<'a, 'b> Inspector<StateCacheDbRefMutWrapper<'a, 'b>> + Send + 'static,
Insp:
for<'a, 'b> InspectorFor<StateCacheDbRefMutWrapper<'a, 'b>, Self::Evm> + Send + 'static,
R: Send + 'static,
{
self.trace_block_until_with_inspector(block_id, block, None, insp_setup, f)
@ -448,7 +462,7 @@ pub trait Trace:
/// Note: This should only be called when tracing an entire block vs individual transactions.
/// When tracing transaction on top of an already committed block state, those transitions are
/// already applied.
fn apply_pre_execution_changes<DB: Send + Database<Error: Display> + DatabaseCommit>(
fn apply_pre_execution_changes<DB: Send + Database + DatabaseCommit>(
&self,
block: &RecoveredBlock<ProviderBlock<Self::Provider>>,
db: &mut DB,

View File

@ -38,8 +38,7 @@ use std::sync::Arc;
/// There are subtle differences between when transacting [`TransactionRequest`]:
///
/// The endpoints `eth_call` and `eth_estimateGas` and `eth_createAccessList` should always
/// __disable__ the base fee check in the
/// [`EnvWithHandlerCfg`](revm_primitives::CfgEnvWithHandlerCfg).
/// __disable__ the base fee check in the [`CfgEnv`](revm::context::CfgEnv).
///
/// The behaviour for tracing endpoints is not consistent across clients.
/// Geth also disables the basefee check for tracing: <https://github.com/ethereum/go-ethereum/blob/bc0b87ca196f92e5af49bd33cc190ef0ec32b197/eth/tracers/api.go#L955-L955>

View File

@ -35,8 +35,9 @@ alloy-consensus.workspace = true
alloy-sol-types.workspace = true
alloy-rpc-types-eth.workspace = true
revm.workspace = true
revm-database.workspace = true
revm-inspectors.workspace = true
revm-primitives = { workspace = true, features = ["dev"] }
revm-primitives.workspace = true
# rpc
jsonrpsee-core.workspace = true

View File

@ -4,10 +4,14 @@
use alloy_primitives::{Address, B256, U256};
use reth_errors::ProviderResult;
use reth_revm::{database::StateProviderDatabase, db::CacheDB, DatabaseRef};
use reth_revm::{database::StateProviderDatabase, DatabaseRef};
use reth_storage_api::{HashedPostStateProvider, StateProvider};
use reth_trie::{HashedStorage, MultiProofTargets};
use revm::Database;
use revm::{
state::{AccountInfo, Bytecode},
Database,
};
use revm_database::CacheDB;
/// Helper alias type for the state's [`CacheDB`]
pub type StateCacheDb<'a> = CacheDB<StateProviderDatabase<StateProviderTraitObjWrapper<'a>>>;
@ -138,7 +142,7 @@ impl reth_storage_api::BlockHashReader for StateProviderTraitObjWrapper<'_> {
impl HashedPostStateProvider for StateProviderTraitObjWrapper<'_> {
fn hashed_post_state(
&self,
bundle_state: &revm::db::BundleState,
bundle_state: &revm_database::BundleState,
) -> reth_trie::HashedPostState {
self.0.hashed_post_state(bundle_state)
}
@ -192,11 +196,11 @@ impl<'a> Database for StateCacheDbRefMutWrapper<'a, '_> {
fn basic(
&mut self,
address: revm_primitives::Address,
) -> Result<Option<revm_primitives::AccountInfo>, Self::Error> {
) -> Result<Option<AccountInfo>, Self::Error> {
self.0.basic(address)
}
fn code_by_hash(&mut self, code_hash: B256) -> Result<revm_primitives::Bytecode, Self::Error> {
fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error> {
self.0.code_by_hash(code_hash)
}
@ -219,11 +223,11 @@ impl<'a> DatabaseRef for StateCacheDbRefMutWrapper<'a, '_> {
fn basic_ref(
&self,
address: revm_primitives::Address,
) -> Result<Option<revm_primitives::AccountInfo>, Self::Error> {
) -> Result<Option<AccountInfo>, Self::Error> {
self.0.basic_ref(address)
}
fn code_by_hash_ref(&self, code_hash: B256) -> Result<revm_primitives::Bytecode, Self::Error> {
fn code_by_hash_ref(&self, code_hash: B256) -> Result<Bytecode, Self::Error> {
self.0.code_by_hash_ref(code_hash)
}

View File

@ -1,10 +1,12 @@
//! Helper traits to wrap generic l1 errors, in network specific error type configured in
//! `reth_rpc_eth_api::EthApiTypes`.
use crate::{EthApiError, RpcInvalidTransactionError};
use crate::EthApiError;
use reth_errors::ProviderError;
use reth_evm::ConfigureEvm;
use revm_primitives::HaltReason;
use reth_evm::{ConfigureEvm, EvmErrorFor, HaltReasonFor};
use revm::context_interface::result::HaltReason;
use super::RpcInvalidTransactionError;
/// Helper trait to wrap core [`EthApiError`].
pub trait FromEthApiError: From<EthApiError> {
@ -81,28 +83,28 @@ impl AsEthApiError for EthApiError {
/// Helper trait to convert from revm errors.
pub trait FromEvmError<Evm: ConfigureEvm>:
From<Evm::EvmError<ProviderError>> + FromEvmHalt
From<EvmErrorFor<Evm, ProviderError>> + FromEvmHalt<HaltReasonFor<Evm>>
{
/// Converts from EVM error to this type.
fn from_evm_err(err: Evm::EvmError<ProviderError>) -> Self {
fn from_evm_err(err: EvmErrorFor<Evm, ProviderError>) -> Self {
err.into()
}
}
impl<T, Evm> FromEvmError<Evm> for T
where
T: From<Evm::EvmError<ProviderError>> + FromEvmHalt,
T: From<EvmErrorFor<Evm, ProviderError>> + FromEvmHalt<HaltReasonFor<Evm>>,
Evm: ConfigureEvm,
{
}
/// Helper trait to convert from revm errors.
pub trait FromEvmHalt<Halt = HaltReason> {
pub trait FromEvmHalt<Halt> {
/// Converts from EVM halt to this type.
fn from_evm_halt(halt: Halt, gas_limit: u64) -> Self;
}
impl FromEvmHalt for EthApiError {
impl FromEvmHalt<HaltReason> for EthApiError {
fn from_evm_halt(halt: HaltReason, gas_limit: u64) -> Self {
RpcInvalidTransactionError::halt(halt, gas_limit).into()
}

View File

@ -1,14 +1,13 @@
//! Implementation specific Errors for the `eth_` namespace.
pub mod api;
pub use api::{AsEthApiError, FromEthApiError, FromEvmError, IntoEthApiError};
use core::time::Duration;
use crate::error::api::FromEvmHalt;
use alloy_eips::BlockId;
use alloy_primitives::{Address, Bytes, U256};
use alloy_rpc_types_eth::{error::EthRpcErrorCode, request::TransactionInputError, BlockError};
use alloy_sol_types::{ContractError, RevertReason};
pub use api::{AsEthApiError, FromEthApiError, FromEvmError, IntoEthApiError};
use core::time::Duration;
use reth_errors::RethError;
use reth_primitives_traits::transaction::signed::RecoveryError;
use reth_rpc_server_types::result::{
@ -18,9 +17,10 @@ use reth_transaction_pool::error::{
Eip4844PoolTransactionError, Eip7702PoolTransactionError, InvalidPoolTransactionError,
PoolError, PoolErrorKind, PoolTransactionError,
};
use revm::primitives::{EVMError, ExecutionResult, HaltReason, InvalidTransaction, OutOfGasError};
use revm::context_interface::result::{
EVMError, ExecutionResult, HaltReason, InvalidHeader, InvalidTransaction, OutOfGasError,
};
use revm_inspectors::tracing::MuxError;
use revm_primitives::InvalidHeader;
use tracing::error;
/// A trait to convert an error to an RPC error.
@ -273,11 +273,20 @@ impl From<reth_errors::ProviderError> for EthApiError {
}
}
impl<T> From<EVMError<T>> for EthApiError
impl From<InvalidHeader> for EthApiError {
fn from(value: InvalidHeader) -> Self {
match value {
InvalidHeader::ExcessBlobGasNotSet => Self::ExcessBlobGasNotSet,
InvalidHeader::PrevrandaoNotSet => Self::PrevrandaoNotSet,
}
}
}
impl<T> From<EVMError<T, InvalidTransaction>> for EthApiError
where
T: Into<Self>,
{
fn from(err: EVMError<T>) -> Self {
fn from(err: EVMError<T, InvalidTransaction>) -> Self {
match err {
EVMError::Transaction(invalid_tx) => match invalid_tx {
InvalidTransaction::NonceTooLow { tx, state } => {
@ -285,8 +294,7 @@ where
}
_ => RpcInvalidTransactionError::from(invalid_tx).into(),
},
EVMError::Header(InvalidHeader::PrevrandaoNotSet) => Self::PrevrandaoNotSet,
EVMError::Header(InvalidHeader::ExcessBlobGasNotSet) => Self::ExcessBlobGasNotSet,
EVMError::Header(err) => err.into(),
EVMError::Database(err) => err.into(),
EVMError::Custom(err) => Self::EvmCustom(err),
EVMError::Precompile(err) => Self::EvmPrecompile(err),
@ -489,7 +497,9 @@ impl RpcInvalidTransactionError {
/// Converts the out of gas error
pub const fn out_of_gas(reason: OutOfGasError, gas_limit: u64) -> Self {
match reason {
OutOfGasError::Basic => Self::BasicOutOfGas(gas_limit),
OutOfGasError::Basic | OutOfGasError::ReentrancySentry => {
Self::BasicOutOfGas(gas_limit)
}
OutOfGasError::Memory | OutOfGasError::MemoryLimit => Self::MemoryOutOfGas(gas_limit),
OutOfGasError::Precompile => Self::PrecompileOutOfGas(gas_limit),
OutOfGasError::InvalidOperand => Self::InvalidOperandOutOfGas(gas_limit),
@ -514,9 +524,8 @@ impl From<RpcInvalidTransactionError> for jsonrpsee_types::error::ErrorObject<'s
}
}
impl From<revm::primitives::InvalidTransaction> for RpcInvalidTransactionError {
fn from(err: revm::primitives::InvalidTransaction) -> Self {
use revm::primitives::InvalidTransaction;
impl From<InvalidTransaction> for RpcInvalidTransactionError {
fn from(err: InvalidTransaction) -> Self {
match err {
InvalidTransaction::InvalidChainId => Self::InvalidChainId,
InvalidTransaction::PriorityFeeGreaterThanMaxFee => Self::TipAboveFeeCap,
@ -546,7 +555,7 @@ impl From<revm::primitives::InvalidTransaction> for RpcInvalidTransactionError {
InvalidTransaction::BlobGasPriceGreaterThanMax => Self::BlobFeeCapTooLow,
InvalidTransaction::EmptyBlobs => Self::BlobTransactionMissingBlobHashes,
InvalidTransaction::BlobVersionNotSupported => Self::BlobHashVersionMismatch,
InvalidTransaction::TooManyBlobs { have } => Self::TooManyBlobs { have },
InvalidTransaction::TooManyBlobs { have, .. } => Self::TooManyBlobs { have },
InvalidTransaction::BlobCreateTransaction => Self::BlobTransactionIsCreate,
InvalidTransaction::EofCrateShouldHaveToAddress => Self::EofCrateShouldHaveToAddress,
InvalidTransaction::AuthorizationListNotSupported => {
@ -779,15 +788,15 @@ pub enum SignError {
/// Converts the evm [`ExecutionResult`] into a result where `Ok` variant is the output bytes if it
/// is [`ExecutionResult::Success`].
pub fn ensure_success(result: ExecutionResult) -> EthResult<Bytes> {
pub fn ensure_success<Halt, Error: FromEvmHalt<Halt> + FromEthApiError>(
result: ExecutionResult<Halt>,
) -> Result<Bytes, Error> {
match result {
ExecutionResult::Success { output, .. } => Ok(output.into_data()),
ExecutionResult::Revert { output, .. } => {
Err(RpcInvalidTransactionError::Revert(RevertError::new(output)).into())
}
ExecutionResult::Halt { reason, gas_used } => {
Err(RpcInvalidTransactionError::halt(reason, gas_used).into())
Err(Error::from_eth_err(RpcInvalidTransactionError::Revert(RevertError::new(output))))
}
ExecutionResult::Halt { reason, gas_used } => Err(Error::from_evm_halt(reason, gas_used)),
}
}

View File

@ -6,24 +6,12 @@ use alloy_rpc_types_eth::{
BlockOverrides,
};
use reth_evm::TransactionEnv;
use revm::{
db::CacheDB,
precompile::{PrecompileSpecId, Precompiles},
primitives::{db::DatabaseRef, Bytecode, SpecId},
Database,
};
use revm_primitives::BlockEnv;
use revm::{context::BlockEnv, state::Bytecode, Database, DatabaseRef};
use revm_database::CacheDB;
use std::cmp::min;
use super::{EthApiError, EthResult, RpcInvalidTransactionError};
/// Returns the addresses of the precompiles corresponding to the `SpecId`.
#[inline]
pub fn get_precompiles(spec_id: SpecId) -> impl IntoIterator<Item = Address> {
let spec = PrecompileSpecId::from_spec_id(spec_id);
Precompiles::new(spec).addresses().copied()
}
/// Calculates the caller gas allowance.
///
/// `allowance = (account.balance - tx.value) / tx.gas_price`
@ -33,7 +21,7 @@ pub fn get_precompiles(spec_id: SpecId) -> impl IntoIterator<Item = Address> {
///
/// Note: this takes the mut [Database] trait because the loaded sender can be reused for the
/// following operation like `eth_call`.
pub fn caller_gas_allowance<DB>(db: &mut DB, env: &impl TransactionEnv) -> EthResult<U256>
pub fn caller_gas_allowance<DB>(db: &mut DB, env: &impl TransactionEnv) -> EthResult<u64>
where
DB: Database,
EthApiError: From<<DB as Database>::Error>,
@ -52,9 +40,10 @@ where
Ok(balance
// Calculate the amount of gas the caller can afford with the specified gas price.
.checked_div(env.gas_price())
.checked_div(U256::from(env.gas_price()))
// This will be 0 if gas price is 0. It is fine, because we check it before.
.unwrap_or_default())
.unwrap_or_default()
.saturating_to())
}
/// Helper type for representing the fees of a `TransactionRequest`
@ -220,25 +209,25 @@ pub fn apply_block_overrides<DB>(
}
if let Some(number) = number {
env.number = number;
env.number = number.saturating_to();
}
if let Some(difficulty) = difficulty {
env.difficulty = difficulty;
}
if let Some(time) = time {
env.timestamp = U256::from(time);
env.timestamp = time;
}
if let Some(gas_limit) = gas_limit {
env.gas_limit = U256::from(gas_limit);
env.gas_limit = gas_limit;
}
if let Some(coinbase) = coinbase {
env.coinbase = coinbase;
env.beneficiary = coinbase;
}
if let Some(random) = random {
env.prevrandao = Some(random);
}
if let Some(base_fee) = base_fee {
env.basefee = base_fee;
env.basefee = base_fee.saturating_to();
}
}

View File

@ -11,8 +11,8 @@ use reth_primitives::RecoveredBlock;
use reth_primitives_traits::{block::BlockTx, BlockBody as _, SignedTransaction};
use reth_rpc_server_types::result::rpc_err;
use reth_rpc_types_compat::{block::from_block, TransactionCompat};
use revm::Database;
use revm_primitives::{Address, Bytes, ExecutionResult, TxKind};
use revm::{context_interface::result::ExecutionResult, Database};
use revm_primitives::{Address, Bytes, TxKind};
use crate::{
error::{
@ -113,15 +113,15 @@ where
/// Handles outputs of the calls execution and builds a [`SimulatedBlock`].
#[expect(clippy::type_complexity)]
pub fn build_simulated_block<T, B>(
pub fn build_simulated_block<T, B, Halt: Clone>(
senders: Vec<Address>,
results: Vec<ExecutionResult>,
results: Vec<ExecutionResult<Halt>>,
full_transactions: bool,
tx_resp_builder: &T,
block: B,
) -> Result<SimulatedBlock<Block<T::Transaction, Header<B::Header>>>, T::Error>
where
T: TransactionCompat<BlockTx<B>, Error: FromEthApiError + FromEvmHalt>,
T: TransactionCompat<BlockTx<B>, Error: FromEthApiError + FromEvmHalt<Halt>>,
B: reth_primitives_traits::Block,
{
let mut calls: Vec<SimCallResult> = Vec::with_capacity(results.len());
@ -130,7 +130,7 @@ where
for (index, (result, tx)) in results.iter().zip(block.body().transactions()).enumerate() {
let call = match result {
ExecutionResult::Halt { reason, gas_used } => {
let error = T::Error::from_evm_halt(*reason, tx.gas_limit());
let error = T::Error::from_evm_halt(reason.clone(), tx.gas_limit());
SimCallResult {
return_data: Bytes::new(),
error: Some(SimulateError {

View File

@ -1,7 +1,7 @@
use alloy_consensus::BlockHeader;
use alloy_eips::{eip2718::Encodable2718, BlockId, BlockNumberOrTag};
use alloy_genesis::ChainConfig;
use alloy_primitives::{Address, Bytes, B256, U256};
use alloy_primitives::{Address, Bytes, B256};
use alloy_rlp::{Decodable, Encodable};
use alloy_rpc_types_debug::ExecutionWitness;
use alloy_rpc_types_eth::{
@ -17,9 +17,8 @@ use async_trait::async_trait;
use jsonrpsee::core::RpcResult;
use reth_chainspec::{EthChainSpec, EthereumHardforks};
use reth_evm::{
env::EvmEnv,
execute::{BlockExecutorProvider, Executor},
ConfigureEvmEnv, TransactionEnv,
ConfigureEvmEnv, EvmEnv,
};
use reth_primitives::{NodePrimitives, ReceiptWithBloom, RecoveredBlock};
use reth_primitives_traits::{Block as _, BlockBody, SignedTransaction};
@ -28,7 +27,11 @@ use reth_provider::{
ReceiptProviderIdExt, StateProofProvider, StateProvider, StateProviderFactory,
TransactionVariant,
};
use reth_revm::{database::StateProviderDatabase, witness::ExecutionWitnessRecord};
use reth_revm::{
database::StateProviderDatabase,
db::{CacheDB, State},
witness::ExecutionWitnessRecord,
};
use reth_rpc_api::DebugApiServer;
use reth_rpc_eth_api::{
helpers::{EthTransactions, TraceExt},
@ -37,10 +40,7 @@ use reth_rpc_eth_api::{
use reth_rpc_eth_types::{EthApiError, StateCacheDb};
use reth_rpc_server_types::{result::internal_rpc_err, ToRpcResult};
use reth_tasks::pool::BlockingTaskGuard;
use revm::{
db::{CacheDB, State},
primitives::db::DatabaseCommit,
};
use revm::{context_interface::Transaction, state::EvmState, DatabaseCommit};
use revm_inspectors::tracing::{
FourByteInspector, MuxInspector, TracingInspector, TracingInspectorConfig, TransactionContext,
};
@ -369,12 +369,8 @@ where
let db = db.0;
let tx_info = TransactionInfo {
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(),
),
block_number: Some(evm_env.block_env.number),
base_fee: Some(evm_env.block_env.basefee),
hash: None,
block_hash: None,
index: None,
@ -447,12 +443,9 @@ where
tx_env.clone(),
&mut inspector,
)?;
let env = revm_primitives::Env::boxed(
evm_env.cfg_env,
evm_env.block_env,
tx_env.into(),
);
inspector.json_result(res, &env, db).map_err(Eth::Error::from_eth_err)
inspector
.json_result(res, &tx_env, &evm_env.block_env, db)
.map_err(Eth::Error::from_eth_err)
})
.await?;
@ -588,8 +581,8 @@ where
results.push(trace);
}
// Increment block_env number and timestamp for the next bundle
evm_env.block_env.number += U256::from(1);
evm_env.block_env.timestamp += U256::from(12);
evm_env.block_env.number += 1;
evm_env.block_env.timestamp += 12;
all_bundles.push(results);
}
@ -700,7 +693,7 @@ where
db: &mut StateCacheDb<'_>,
transaction_context: Option<TransactionContext>,
fused_inspector: &mut Option<TracingInspector>,
) -> Result<(GethTrace, revm_primitives::EvmState), Eth::Error> {
) -> Result<(GethTrace, EvmState), Eth::Error> {
let GethDebugTracingOptions { config, tracer, tracer_config, .. } = opts;
let tx_info = TransactionInfo {
@ -710,8 +703,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(evm_env.block_env.number.try_into().unwrap_or_default()),
base_fee: Some(evm_env.block_env.basefee.try_into().unwrap_or_default()),
block_number: Some(evm_env.block_env.number),
base_fee: Some(evm_env.block_env.basefee),
};
if let Some(tracer) = tracer {
@ -825,13 +818,9 @@ where
self.eth_api().inspect(&mut *db, evm_env, tx_env, &mut inspector)?;
let state = res.state.clone();
let env = revm_primitives::Env::boxed(
evm_env.cfg_env,
evm_env.block_env,
tx_env.into(),
);
let result =
inspector.json_result(res, &env, db).map_err(Eth::Error::from_eth_err)?;
let result = inspector
.json_result(res, &tx_env, &evm_env.block_env, db)
.map_err(Eth::Error::from_eth_err)?;
Ok((GethTrace::JS(result), state))
}
}

View File

@ -7,7 +7,7 @@ use alloy_rpc_types_mev::{EthCallBundle, EthCallBundleResponse, EthCallBundleTra
use jsonrpsee::core::RpcResult;
use reth_evm::{ConfigureEvm, ConfigureEvmEnv, Evm};
use reth_primitives_traits::SignedTransaction;
use reth_revm::database::StateProviderDatabase;
use reth_revm::{database::StateProviderDatabase, db::CacheDB};
use reth_rpc_eth_api::{
helpers::{Call, EthTransactions, LoadPendingBlock},
EthCallBundleApiServer, FromEthApiError, FromEvmError,
@ -17,10 +17,7 @@ use reth_tasks::pool::BlockingTaskGuard;
use reth_transaction_pool::{
EthBlobTransactionSidecar, EthPoolTransaction, PoolPooledTx, PoolTransaction, TransactionPool,
};
use revm::{
db::{CacheDB, DatabaseCommit, DatabaseRef},
primitives::ResultAndState,
};
use revm::{context_interface::result::ResultAndState, DatabaseCommit, DatabaseRef};
use std::sync::Arc;
/// `Eth` bundle implementation.
@ -101,14 +98,14 @@ where
let (mut evm_env, at) = self.eth_api().evm_env_at(block_id).await?;
if let Some(coinbase) = coinbase {
evm_env.block_env.coinbase = coinbase;
evm_env.block_env.beneficiary = coinbase;
}
// need to adjust the timestamp for the next block
if let Some(timestamp) = timestamp {
evm_env.block_env.timestamp = U256::from(timestamp);
evm_env.block_env.timestamp = timestamp;
} else {
evm_env.block_env.timestamp += U256::from(12);
evm_env.block_env.timestamp += 12;
}
if let Some(difficulty) = difficulty {
@ -116,9 +113,8 @@ where
}
// default to call gas limit unless user requests a smaller limit
evm_env.block_env.gas_limit = U256::from(self.inner.eth_api.call_gas_limit());
evm_env.block_env.gas_limit = self.inner.eth_api.call_gas_limit();
if let Some(gas_limit) = gas_limit {
let gas_limit = U256::from(gas_limit);
if gas_limit > evm_env.block_env.gas_limit {
return Err(
EthApiError::InvalidTransaction(RpcInvalidTransactionError::GasTooHigh).into()
@ -128,19 +124,19 @@ where
}
if let Some(base_fee) = base_fee {
evm_env.block_env.basefee = U256::from(base_fee);
evm_env.block_env.basefee = base_fee.try_into().unwrap_or(u64::MAX);
}
let state_block_number = evm_env.block_env.number;
// use the block number of the request
evm_env.block_env.number = U256::from(block_number);
evm_env.block_env.number = block_number;
let eth_api = self.eth_api().clone();
self.eth_api()
.spawn_with_state_at_block(at, move |state| {
let coinbase = evm_env.block_env.coinbase;
let basefee = Some(evm_env.block_env.basefee.to::<u64>());
let coinbase = evm_env.block_env.beneficiary;
let basefee = Some(evm_env.block_env.basefee);
let db = CacheDB::new(StateProviderDatabase::new(state));
let initial_coinbase = db
@ -244,7 +240,7 @@ where
eth_sent_to_coinbase,
gas_fees: total_gas_fess,
results,
state_block_number: state_block_number.to(),
state_block_number,
total_gas_used,
};

View File

@ -2,15 +2,16 @@
use crate::EthApi;
use alloy_consensus::Header;
use alloy_primitives::{TxKind, U256};
use alloy_rpc_types::TransactionRequest;
use reth_evm::ConfigureEvm;
use reth_evm::{ConfigureEvm, EvmEnv, SpecFor};
use reth_provider::{BlockReader, ProviderHeader};
use reth_rpc_eth_api::{
helpers::{estimate::EstimateCall, Call, EthCall, LoadPendingBlock, LoadState, SpawnBlocking},
FromEthApiError, FromEvmError, FullEthApiTypes, IntoEthApiError,
};
use reth_rpc_eth_types::{revm_utils::CallFees, RpcInvalidTransactionError};
use revm_primitives::{BlockEnv, TxEnv, TxKind, U256};
use reth_rpc_eth_types::{revm_utils::CallFees, EthApiError, RpcInvalidTransactionError};
use revm::{context::TxEnv, context_interface::Block, Database};
impl<Provider, Pool, Network, EvmConfig> EthCall for EthApi<Provider, Pool, Network, EvmConfig>
where
@ -40,14 +41,17 @@ where
fn create_txn_env(
&self,
block_env: &BlockEnv,
evm_env: &EvmEnv<SpecFor<Self::Evm>>,
request: TransactionRequest,
mut db: impl Database<Error: Into<EthApiError>>,
) -> Result<TxEnv, Self::Error> {
// Ensure that if versioned hashes are set, they're not empty
if request.blob_versioned_hashes.as_ref().is_some_and(|hashes| hashes.is_empty()) {
return Err(RpcInvalidTransactionError::BlobTransactionMissingBlobHashes.into_eth_err())
}
let tx_type = request.preferred_type() as u8;
let TransactionRequest {
from,
to,
@ -72,42 +76,54 @@ where
gas_price.map(U256::from),
max_fee_per_gas.map(U256::from),
max_priority_fee_per_gas.map(U256::from),
block_env.basefee,
U256::from(evm_env.block_env.basefee),
blob_versioned_hashes.as_deref(),
max_fee_per_blob_gas.map(U256::from),
block_env.get_blob_gasprice().map(U256::from),
evm_env.block_env.blob_gasprice().map(U256::from),
)?;
let gas_limit = gas.unwrap_or_else(|| {
let gas_limit = gas.unwrap_or(
// Use maximum allowed gas limit. The reason for this
// is that both Erigon and Geth use pre-configured gas cap even if
// it's possible to derive the gas limit from the block:
// <https://github.com/ledgerwatch/erigon/blob/eae2d9a79cb70dbe30b3a6b79c436872e4605458/cmd/rpcdaemon/commands/trace_adhoc.go#L956
// https://github.com/ledgerwatch/erigon/blob/eae2d9a79cb70dbe30b3a6b79c436872e4605458/eth/ethconfig/config.go#L94>
block_env.gas_limit.saturating_to()
});
evm_env.block_env.gas_limit,
);
let chain_id = chain_id.unwrap_or(evm_env.cfg_env.chain_id);
let caller = from.unwrap_or_default();
let nonce = if let Some(nonce) = nonce {
nonce
} else {
db.basic(caller).map_err(Into::into)?.map(|acc| acc.nonce).unwrap_or_default()
};
#[allow(clippy::needless_update)]
let env = TxEnv {
tx_type,
gas_limit,
nonce,
caller: from.unwrap_or_default(),
gas_price,
gas_priority_fee: max_priority_fee_per_gas,
transact_to: to.unwrap_or(TxKind::Create),
caller,
gas_price: gas_price.saturating_to(),
gas_priority_fee: max_priority_fee_per_gas.map(|v| v.saturating_to()),
kind: to.unwrap_or(TxKind::Create),
value: value.unwrap_or_default(),
data: input
.try_into_unique_input()
.map_err(Self::Error::from_eth_err)?
.unwrap_or_default(),
chain_id,
access_list: access_list.unwrap_or_default().into(),
chain_id: Some(chain_id),
access_list: access_list.unwrap_or_default(),
// EIP-4844 fields
blob_hashes: blob_versioned_hashes.unwrap_or_default(),
max_fee_per_blob_gas,
max_fee_per_blob_gas: max_fee_per_blob_gas
.map(|v| v.saturating_to())
.unwrap_or_default(),
// EIP-7702 fields
authorization_list: authorization_list.map(Into::into),
..Default::default()
authorization_list: authorization_list.unwrap_or_default(),
};
Ok(env)

View File

@ -4,7 +4,7 @@ use alloy_consensus::{constants::EMPTY_WITHDRAWALS, Header, Transaction, EMPTY_O
use alloy_eips::{eip7685::EMPTY_REQUESTS_HASH, merge::BEACON_NONCE};
use alloy_primitives::U256;
use reth_chainspec::{EthChainSpec, EthereumHardforks};
use reth_evm::ConfigureEvm;
use reth_evm::{ConfigureEvm, HaltReasonFor};
use reth_primitives::{logs_bloom, BlockBody, Receipt};
use reth_primitives_traits::proofs::calculate_transaction_root;
use reth_provider::{
@ -18,7 +18,11 @@ use reth_rpc_eth_api::{
};
use reth_rpc_eth_types::PendingBlock;
use reth_transaction_pool::{PoolTransaction, TransactionPool};
use revm_primitives::{BlockEnv, B256};
use revm::{
context::BlockEnv,
context_interface::{result::ExecutionResult, Block},
};
use revm_primitives::B256;
use crate::EthApi;
@ -67,7 +71,7 @@ where
let logs_bloom = logs_bloom(receipts.iter().flat_map(|r| &r.logs));
let timestamp = block_env.timestamp.to::<u64>();
let timestamp = block_env.timestamp;
let is_shanghai = chain_spec.is_shanghai_active_at_timestamp(timestamp);
let is_cancun = chain_spec.is_cancun_active_at_timestamp(timestamp);
let is_prague = chain_spec.is_prague_active_at_timestamp(timestamp);
@ -75,24 +79,24 @@ where
let header = Header {
parent_hash,
ommers_hash: EMPTY_OMMER_ROOT_HASH,
beneficiary: block_env.coinbase,
beneficiary: block_env.beneficiary,
state_root,
transactions_root,
receipts_root,
withdrawals_root: is_shanghai.then_some(EMPTY_WITHDRAWALS),
logs_bloom,
timestamp: block_env.timestamp.to::<u64>(),
timestamp: block_env.timestamp,
mix_hash: block_env.prevrandao.unwrap_or_default(),
nonce: BEACON_NONCE.into(),
base_fee_per_gas: Some(block_env.basefee.to::<u64>()),
number: block_env.number.to::<u64>(),
gas_limit: block_env.gas_limit.to::<u64>(),
base_fee_per_gas: Some(block_env.basefee),
number: block_env.number,
gas_limit: block_env.gas_limit,
difficulty: U256::ZERO,
gas_used: receipts.last().map(|r| r.cumulative_gas_used).unwrap_or_default(),
blob_gas_used: is_cancun.then(|| {
transactions.iter().map(|tx| tx.blob_gas_used().unwrap_or_default()).sum::<u64>()
}),
excess_blob_gas: block_env.get_blob_excess_gas(),
excess_blob_gas: block_env.blob_excess_gas(),
extra_data: Default::default(),
parent_beacon_block_root: is_cancun.then_some(B256::ZERO),
requests_hash: is_prague.then_some(EMPTY_REQUESTS_HASH),
@ -108,7 +112,7 @@ where
fn assemble_receipt(
&self,
tx: &ProviderTx<Self::Provider>,
result: revm_primitives::ExecutionResult,
result: ExecutionResult<HaltReasonFor<Self::Evm>>,
cumulative_gas_used: u64,
) -> reth_provider::ProviderReceipt<Self::Provider> {
#[allow(clippy::needless_update)]

View File

@ -3,7 +3,7 @@
use alloy_consensus::BlockHeader;
use alloy_eips::BlockNumberOrTag;
use alloy_primitives::U256;
use alloy_rpc_types_eth::{BlockId, BlockOverrides};
use alloy_rpc_types_eth::BlockId;
use alloy_rpc_types_mev::{
BundleItem, Inclusion, Privacy, RefundConfig, SendBundleRequest, SimBundleLogs,
SimBundleOverrides, SimBundleResponse, Validity,
@ -11,20 +11,19 @@ use alloy_rpc_types_mev::{
use jsonrpsee::core::RpcResult;
use reth_evm::{ConfigureEvm, ConfigureEvmEnv, Evm};
use reth_provider::ProviderTx;
use reth_revm::database::StateProviderDatabase;
use reth_revm::{database::StateProviderDatabase, db::CacheDB};
use reth_rpc_api::MevSimApiServer;
use reth_rpc_eth_api::{
helpers::{block::LoadBlock, Call, EthTransactions},
FromEthApiError, FromEvmError,
};
use reth_rpc_eth_types::{utils::recover_raw_transaction, EthApiError};
use reth_rpc_eth_types::{
revm_utils::apply_block_overrides, utils::recover_raw_transaction, EthApiError,
};
use reth_tasks::pool::BlockingTaskGuard;
use reth_transaction_pool::{PoolConsensusTx, PoolPooledTx, PoolTransaction, TransactionPool};
use revm::{
db::CacheDB,
primitives::{Address, ResultAndState},
DatabaseCommit, DatabaseRef,
};
use revm::{context_interface::result::ResultAndState, DatabaseCommit, DatabaseRef};
use revm_primitives::Address;
use std::{sync::Arc, time::Duration};
use tracing::info;
@ -229,7 +228,6 @@ where
logs: bool,
) -> Result<SimBundleResponse, Eth::Error> {
let SimBundleOverrides { parent_block, block_overrides, .. } = overrides;
let BlockOverrides { number, coinbase, time, gas_limit, base_fee, .. } = block_overrides;
// Parse and validate bundle
// Also, flatten the bundle here so that its easier to process
@ -240,27 +238,6 @@ where
let current_block = self.eth_api().block_with_senders(current_block_id).await?;
let current_block = current_block.ok_or(EthApiError::HeaderNotFound(block_id))?;
// apply overrides
if let Some(block_number) = number {
evm_env.block_env.number = U256::from(block_number);
}
if let Some(coinbase) = coinbase {
evm_env.block_env.coinbase = coinbase;
}
if let Some(timestamp) = time {
evm_env.block_env.timestamp = U256::from(timestamp);
}
if let Some(gas_limit) = gas_limit {
evm_env.block_env.gas_limit = U256::from(gas_limit);
}
if let Some(base_fee) = base_fee {
evm_env.block_env.basefee = U256::from(base_fee);
}
let eth_api = self.inner.eth_api.clone();
let sim_response = self
@ -269,9 +246,12 @@ where
.spawn_with_state_at_block(current_block_id, move |state| {
// Setup environment
let current_block_number = current_block.number();
let coinbase = evm_env.block_env.coinbase;
let coinbase = evm_env.block_env.beneficiary;
let basefee = evm_env.block_env.basefee;
let db = CacheDB::new(StateProviderDatabase::new(state));
let mut db = CacheDB::new(StateProviderDatabase::new(state));
// apply overrides
apply_block_overrides(block_overrides, &mut db, &mut evm_env.block_env);
let initial_coinbase_balance = DatabaseRef::basic_ref(&db, coinbase)
.map_err(EthApiError::from_eth_err)?
@ -354,7 +334,7 @@ where
});
// Calculate payout transaction fee
let payout_tx_fee = basefee *
let payout_tx_fee = U256::from(basefee) *
U256::from(SBUNDLE_PAYOUT_MAX_COST) *
U256::from(refund_configs.len() as u64);

View File

@ -19,11 +19,11 @@ use reth_rpc_eth_api::{
};
use reth_rpc_eth_types::{utils::binary_search, EthApiError};
use reth_rpc_server_types::result::internal_rpc_err;
use revm::context_interface::result::ExecutionResult;
use revm_inspectors::{
tracing::{types::CallTraceNode, TracingInspectorConfig},
transfer::{TransferInspector, TransferKind},
};
use revm_primitives::ExecutionResult;
const API_LEVEL: u64 = 8;

View File

@ -19,13 +19,13 @@ use reth_consensus_common::calc::{base_block_reward_pre_merge, block_reward, omm
use reth_evm::ConfigureEvmEnv;
use reth_primitives_traits::{BlockBody, BlockHeader};
use reth_provider::{BlockNumReader, BlockReader, ChainSpecProvider};
use reth_revm::database::StateProviderDatabase;
use reth_revm::{database::StateProviderDatabase, db::CacheDB};
use reth_rpc_api::TraceApiServer;
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};
use revm::DatabaseCommit;
use revm_inspectors::{
opcode::OpcodeGasInspector,
tracing::{parity::populate_state_diff, TracingInspector, TracingInspectorConfig},