mirror of
https://github.com/paradigmxyz/reth.git
synced 2026-04-30 03:01:58 -04:00
wip
This commit is contained in:
@@ -4,9 +4,11 @@ use crate::ConfigureEvm;
|
||||
use alloy_evm::{block::BlockExecutorFactory, Database, EvmEnv, EvmFactory};
|
||||
use revm::{inspector::NoOpInspector, Inspector};
|
||||
|
||||
/// Helper to access [`BlockExecutorFactory`] for a given [`ConfigureEvm`].
|
||||
pub type ExecFactoryFor<Evm> = <Evm as ConfigureEvm>::BlockExecutorFactory;
|
||||
|
||||
/// Helper to access [`EvmFactory`] for a given [`ConfigureEvm`].
|
||||
pub type EvmFactoryFor<Evm> =
|
||||
<<Evm as ConfigureEvm>::BlockExecutorFactory as BlockExecutorFactory>::EvmFactory;
|
||||
pub type EvmFactoryFor<Evm> = <ExecFactoryFor<Evm> as BlockExecutorFactory>::EvmFactory;
|
||||
|
||||
/// Helper to access [`EvmFactory::Spec`] for a given [`ConfigureEvm`].
|
||||
pub type SpecFor<Evm> = <EvmFactoryFor<Evm> as EvmFactory>::Spec;
|
||||
@@ -30,8 +32,7 @@ pub type HaltReasonFor<Evm> = <EvmFactoryFor<Evm> as EvmFactory>::HaltReason;
|
||||
pub type TxEnvFor<Evm> = <EvmFactoryFor<Evm> as EvmFactory>::Tx;
|
||||
|
||||
/// Helper to access [`BlockExecutorFactory::ExecutionCtx`] for a given [`ConfigureEvm`].
|
||||
pub type ExecutionCtxFor<'a, Evm> =
|
||||
<<Evm as ConfigureEvm>::BlockExecutorFactory as BlockExecutorFactory>::ExecutionCtx<'a>;
|
||||
pub type ExecutionCtxFor<'a, Evm> = <ExecFactoryFor<Evm> as BlockExecutorFactory>::ExecutionCtx<'a>;
|
||||
|
||||
/// Type alias for [`EvmEnv`] for a given [`ConfigureEvm`].
|
||||
pub type EvmEnvFor<Evm> = EvmEnv<SpecFor<Evm>, BlockEnvFor<Evm>>;
|
||||
|
||||
@@ -333,6 +333,23 @@ pub trait ConfigureEvm: Clone + Debug + Send + Sync + Unpin {
|
||||
Ok(self.create_executor(evm, ctx))
|
||||
}
|
||||
|
||||
/// Creates a new [`BlockExecutor`] for executing a given block with the given inspector.
|
||||
fn executor_for_block_with_inspector<'a, DB, I>(
|
||||
&'a self,
|
||||
db: &'a mut State<DB>,
|
||||
block: &'a SealedBlock<<Self::Primitives as NodePrimitives>::Block>,
|
||||
inspector: I,
|
||||
) -> Result<impl BlockExecutorFor<'a, Self::BlockExecutorFactory, DB, I>, Self::Error>
|
||||
where
|
||||
DB: Database,
|
||||
I: InspectorFor<Self, &'a mut State<DB>> + 'a,
|
||||
{
|
||||
let evm_env = self.evm_env(block.header())?;
|
||||
let evm = self.evm_with_env_and_inspector(db, evm_env, inspector);
|
||||
let ctx = self.context_for_block(block)?;
|
||||
Ok(self.create_executor(evm, ctx))
|
||||
}
|
||||
|
||||
/// Creates a [`BlockBuilder`]. Should be used when building a new block.
|
||||
///
|
||||
/// Block builder wraps an inner [`alloy_evm::block::BlockExecutor`] and has a similar
|
||||
|
||||
@@ -20,23 +20,24 @@ use alloy_rpc_types_eth::{
|
||||
use futures::Future;
|
||||
use reth_errors::{ProviderError, RethError};
|
||||
use reth_evm::{
|
||||
env::BlockEnvironment, ConfigureEvm, Evm, EvmEnvFor, HaltReasonFor, InspectorFor,
|
||||
TransactionEnv, TxEnvFor,
|
||||
env::BlockEnvironment, execute::BlockExecutor, ConfigureEvm, Evm, EvmEnvFor, HaltReasonFor,
|
||||
InspectorFor, TransactionEnv, TxEnvFor,
|
||||
};
|
||||
use reth_node_api::BlockBody;
|
||||
use reth_primitives_traits::Recovered;
|
||||
use reth_primitives_traits::{BlockTy, RecoveredBlock};
|
||||
use reth_revm::{database::StateProviderDatabase, db::State};
|
||||
use reth_rpc_convert::{RpcConvert, RpcTxReq};
|
||||
use reth_rpc_eth_types::{
|
||||
cache::db::StateProviderTraitObjWrapper,
|
||||
cache::db::{RpcBlockExecutor, StateProviderTraitObjWrapper},
|
||||
error::FromEthApiError,
|
||||
simulate::{self, EthSimulateError},
|
||||
EthApiError, StateCacheDb,
|
||||
};
|
||||
use reth_storage_api::{BlockIdReader, ProviderTx, StateProvider};
|
||||
use reth_storage_api::{BlockIdReader, StateProvider};
|
||||
use revm::{
|
||||
context::Block,
|
||||
context_interface::{result::ResultAndState, Transaction},
|
||||
inspector::NoOpInspector,
|
||||
Database, DatabaseCommit,
|
||||
};
|
||||
use revm_inspectors::{access_list::AccessListInspector, transfer::TransferInspector};
|
||||
@@ -638,21 +639,15 @@ pub trait Call:
|
||||
};
|
||||
let (tx, tx_info) = transaction.split();
|
||||
|
||||
let (evm_env, _) = self.evm_env_at(block.hash().into()).await?;
|
||||
|
||||
// we need to get the state of the parent block because we're essentially replaying the
|
||||
// block the transaction is included in
|
||||
let parent_block = block.parent_hash();
|
||||
|
||||
self.spawn_with_state_at_block(parent_block, move |this, mut db| {
|
||||
let block_txs = block.transactions_recovered();
|
||||
|
||||
self.spawn_with_state_at_block(block.parent_hash(), move |this, mut db| {
|
||||
// replay all transactions prior to the targeted transaction
|
||||
this.replay_transactions_until(&mut db, evm_env.clone(), block_txs, *tx.tx_hash())?;
|
||||
let res = this
|
||||
.executor_at_tx(&mut db, &block, *tx.tx_hash())?
|
||||
.execute_transaction_without_commit(tx)
|
||||
.map_err(Self::Error::from_eth_err)?;
|
||||
|
||||
let tx_env = RpcNodeCore::evm_config(&this).tx_env(tx);
|
||||
|
||||
let res = this.transact(&mut db, evm_env, tx_env)?;
|
||||
f(tx_info, res, db)
|
||||
})
|
||||
.await
|
||||
@@ -660,37 +655,54 @@ pub trait Call:
|
||||
}
|
||||
}
|
||||
|
||||
/// Replays all the transactions until the target transaction is found.
|
||||
///
|
||||
/// All transactions before the target transaction are executed and their changes are written to
|
||||
/// the _runtime_ db ([`State`]).
|
||||
///
|
||||
/// Note: This assumes the target transaction is in the given iterator.
|
||||
/// Returns the index of the target transaction in the given iterator.
|
||||
fn replay_transactions_until<'a, DB, I>(
|
||||
&self,
|
||||
db: &mut DB,
|
||||
evm_env: EvmEnvFor<Self::Evm>,
|
||||
transactions: I,
|
||||
/// Same as [`executor_at_tx_with_inspector`](Self::executor_at_tx_with_inspector) but the
|
||||
/// returned executor does not have the inspector enabled.
|
||||
fn executor_at_tx<'a>(
|
||||
&'a self,
|
||||
db: &'a mut StateCacheDb,
|
||||
block: &'a RecoveredBlock<BlockTy<Self::Primitives>>,
|
||||
target_tx_hash: B256,
|
||||
) -> Result<usize, Self::Error>
|
||||
) -> Result<impl RpcBlockExecutor<'a, Self::Evm>, Self::Error> {
|
||||
let mut executor =
|
||||
self.executor_at_tx_with_inspector(db, block, target_tx_hash, NoOpInspector)?;
|
||||
// disable inspector before returning to avoid perf overhead
|
||||
executor.evm_mut().disable_inspector();
|
||||
Ok(executor)
|
||||
}
|
||||
|
||||
/// Initializes a [`BlockExecutor`] at the given block, applies pre-execution changes and
|
||||
/// executes all transactions prior the target transaction.
|
||||
///
|
||||
/// After that, returns the [`BlockExecutor`] with the configured inspector.
|
||||
fn executor_at_tx_with_inspector<'a, I>(
|
||||
&'a self,
|
||||
db: &'a mut StateCacheDb,
|
||||
block: &'a RecoveredBlock<BlockTy<Self::Primitives>>,
|
||||
target_tx_hash: B256,
|
||||
inspector: I,
|
||||
) -> Result<impl RpcBlockExecutor<'a, Self::Evm, I>, Self::Error>
|
||||
where
|
||||
DB: Database<Error = ProviderError> + DatabaseCommit + core::fmt::Debug,
|
||||
I: IntoIterator<Item = Recovered<&'a ProviderTx<Self::Provider>>>,
|
||||
I: InspectorFor<Self::Evm, &'a mut StateCacheDb> + 'a,
|
||||
{
|
||||
let mut evm = self.evm_config().evm_with_env(db, evm_env);
|
||||
let mut index = 0;
|
||||
for tx in transactions {
|
||||
let mut executor =
|
||||
self.evm_config().executor_for_block_with_inspector(db, block, inspector)?;
|
||||
|
||||
// Disable inspector while handling pre-execution changes
|
||||
executor.evm_mut().disable_inspector();
|
||||
executor.apply_pre_execution_changes().map_err(Self::Error::from_eth_err)?;
|
||||
|
||||
for tx in block.transactions_recovered() {
|
||||
if *tx.tx_hash() == target_tx_hash {
|
||||
// reached the target transaction
|
||||
break
|
||||
}
|
||||
|
||||
let tx_env = self.evm_config().tx_env(tx);
|
||||
evm.transact_commit(tx_env).map_err(Self::Error::from_evm_err)?;
|
||||
index += 1;
|
||||
executor.execute_transaction(tx).map_err(Self::Error::from_eth_err)?;
|
||||
}
|
||||
Ok(index)
|
||||
|
||||
// Enable inspector before returning
|
||||
executor.evm_mut().enable_inspector();
|
||||
Ok(executor)
|
||||
}
|
||||
|
||||
///
|
||||
|
||||
@@ -9,12 +9,12 @@ use futures::Future;
|
||||
use reth_chainspec::ChainSpecProvider;
|
||||
use reth_errors::ProviderError;
|
||||
use reth_evm::{
|
||||
evm::EvmFactoryExt, system_calls::SystemCaller, tracing::TracingCtx, ConfigureEvm, Database,
|
||||
Evm, EvmEnvFor, EvmFor, HaltReasonFor, InspectorFor, TxEnvFor,
|
||||
evm::EvmFactoryExt, execute::BlockExecutor, system_calls::SystemCaller, tracing::TracingCtx,
|
||||
ConfigureEvm, Database, Evm, EvmEnvFor, EvmFor, HaltReasonFor, InspectorFor, TxEnvFor,
|
||||
};
|
||||
use reth_primitives_traits::{BlockBody, Recovered, RecoveredBlock};
|
||||
use reth_revm::{database::StateProviderDatabase, db::State};
|
||||
use reth_rpc_eth_types::{cache::db::StateCacheDb, EthApiError};
|
||||
use reth_rpc_eth_types::{cache::db::StateCacheDb, error::FromEthApiError, EthApiError};
|
||||
use reth_storage_api::{ProviderBlock, ProviderTx};
|
||||
use revm::{context::Block, context_interface::result::ResultAndState, DatabaseCommit};
|
||||
use revm_inspectors::tracing::{TracingInspector, TracingInspectorConfig};
|
||||
@@ -168,22 +168,16 @@ pub trait Trace: LoadState<Error: FromEvmError<Self::Evm>> + Call {
|
||||
};
|
||||
let (tx, tx_info) = transaction.split();
|
||||
|
||||
let (evm_env, _) = self.evm_env_at(block.hash().into()).await?;
|
||||
|
||||
// we need to get the state of the parent block because we're essentially replaying the
|
||||
// block the transaction is included in
|
||||
let parent_block = block.parent_hash();
|
||||
|
||||
self.spawn_with_state_at_block(parent_block, move |this, mut db| {
|
||||
let block_txs = block.transactions_recovered();
|
||||
let res = this
|
||||
.executor_at_tx_with_inspector(&mut db, &block, *tx.tx_hash(), &mut inspector)?
|
||||
.execute_transaction_without_commit(tx)
|
||||
.map_err(Self::Error::from_eth_err)?;
|
||||
|
||||
this.apply_pre_execution_changes(&block, &mut db, &evm_env)?;
|
||||
|
||||
// replay all transactions prior to the targeted transaction
|
||||
this.replay_transactions_until(&mut db, evm_env.clone(), block_txs, *tx.tx_hash())?;
|
||||
|
||||
let tx_env = this.evm_config().tx_env(tx);
|
||||
let res = this.inspect(&mut db, evm_env, tx_env, &mut inspector)?;
|
||||
f(tx_info, inspector, res, db)
|
||||
})
|
||||
.await
|
||||
|
||||
28
crates/rpc/rpc-eth-types/src/cache/db.rs
vendored
28
crates/rpc/rpc-eth-types/src/cache/db.rs
vendored
@@ -4,10 +4,14 @@
|
||||
|
||||
use alloy_primitives::{Address, B256, U256};
|
||||
use reth_errors::ProviderResult;
|
||||
use reth_evm::{block::BlockExecutorFor, ConfigureEvm, ExecFactoryFor, InspectorFor};
|
||||
use reth_revm::database::StateProviderDatabase;
|
||||
use reth_storage_api::{BytecodeReader, HashedPostStateProvider, StateProvider, StateProviderBox};
|
||||
use reth_trie::{HashedStorage, MultiProofTargets};
|
||||
use revm::database::{BundleState, State};
|
||||
use revm::{
|
||||
database::{BundleState, State},
|
||||
inspector::NoOpInspector,
|
||||
};
|
||||
|
||||
/// Helper alias type for the state's [`State`]
|
||||
pub type StateCacheDb = State<StateProviderDatabase<StateProviderTraitObjWrapper>>;
|
||||
@@ -178,3 +182,25 @@ impl BytecodeReader for StateProviderTraitObjWrapper {
|
||||
self.0.bytecode_by_hash(code_hash)
|
||||
}
|
||||
}
|
||||
|
||||
/// A trait alias for [`reth_evm::block::BlockExecutor`] implementation used in RPC code.
|
||||
pub trait RpcBlockExecutor<'a, Evm, I = NoOpInspector>:
|
||||
BlockExecutorFor<'a, ExecFactoryFor<Evm>, StateProviderDatabase<StateProviderTraitObjWrapper>, I>
|
||||
where
|
||||
Evm: ConfigureEvm,
|
||||
I: InspectorFor<Evm, &'a mut StateCacheDb> + 'a,
|
||||
{
|
||||
}
|
||||
|
||||
impl<'a, Evm, I, T> RpcBlockExecutor<'a, Evm, I> for T
|
||||
where
|
||||
Evm: ConfigureEvm,
|
||||
I: InspectorFor<Evm, &'a mut StateCacheDb> + 'a,
|
||||
T: BlockExecutorFor<
|
||||
'a,
|
||||
ExecFactoryFor<Evm>,
|
||||
StateProviderDatabase<StateProviderTraitObjWrapper>,
|
||||
I,
|
||||
>,
|
||||
{
|
||||
}
|
||||
|
||||
@@ -84,7 +84,10 @@ impl AsEthApiError for EthApiError {
|
||||
|
||||
/// Helper trait to convert from revm errors.
|
||||
pub trait FromEvmError<Evm: ConfigureEvm>:
|
||||
From<EvmErrorFor<Evm, ProviderError>> + FromEvmHalt<HaltReasonFor<Evm>> + FromRevert
|
||||
From<EvmErrorFor<Evm, ProviderError>>
|
||||
+ FromEvmHalt<HaltReasonFor<Evm>>
|
||||
+ From<Evm::Error>
|
||||
+ FromRevert
|
||||
{
|
||||
/// Converts from EVM error to this type.
|
||||
fn from_evm_err(err: EvmErrorFor<Evm, ProviderError>) -> Self {
|
||||
@@ -105,7 +108,10 @@ pub trait FromEvmError<Evm: ConfigureEvm>:
|
||||
|
||||
impl<T, Evm> FromEvmError<Evm> for T
|
||||
where
|
||||
T: From<EvmErrorFor<Evm, ProviderError>> + FromEvmHalt<HaltReasonFor<Evm>> + FromRevert,
|
||||
T: From<EvmErrorFor<Evm, ProviderError>>
|
||||
+ FromEvmHalt<HaltReasonFor<Evm>>
|
||||
+ From<Evm::Error>
|
||||
+ FromRevert,
|
||||
Evm: ConfigureEvm,
|
||||
{
|
||||
}
|
||||
|
||||
@@ -220,22 +220,10 @@ where
|
||||
let this = self.clone();
|
||||
self.eth_api()
|
||||
.spawn_with_state_at_block(state_at, move |eth_api, mut db| {
|
||||
let block_txs = block.transactions_recovered();
|
||||
|
||||
// configure env for the target transaction
|
||||
let tx = transaction.into_recovered();
|
||||
|
||||
eth_api.apply_pre_execution_changes(&block, &mut db, &evm_env)?;
|
||||
|
||||
// replay all transactions prior to the targeted transaction
|
||||
let index = eth_api.replay_transactions_until(
|
||||
&mut db,
|
||||
evm_env.clone(),
|
||||
block_txs,
|
||||
*tx.tx_hash(),
|
||||
)?;
|
||||
let executor = eth_api.executor_at_tx(&mut db, &block, *tx.tx_hash())?;
|
||||
|
||||
let tx_env = eth_api.evm_config().tx_env(&tx);
|
||||
let (tx, info) = transaction.split();
|
||||
|
||||
this.trace_transaction(
|
||||
&opts,
|
||||
@@ -244,7 +232,7 @@ where
|
||||
&mut db,
|
||||
Some(TransactionContext {
|
||||
block_hash: Some(block_hash),
|
||||
tx_index: Some(index),
|
||||
tx_index: info.index.map(|index| index as usize),
|
||||
tx_hash: Some(*tx.tx_hash()),
|
||||
}),
|
||||
&mut None,
|
||||
|
||||
Reference in New Issue
Block a user