feat: generic TxEnv (#13957)

This commit is contained in:
Arsenii Kulikov
2025-01-24 14:48:44 +04:00
committed by GitHub
parent 1296bacb87
commit 006eea0c34
18 changed files with 271 additions and 244 deletions

View File

@ -6,7 +6,6 @@ use crate::{
execute::{BatchExecutor, BlockExecutorProvider, Executor},
system_calls::OnStateHook,
};
use alloc::boxed::Box;
use alloy_primitives::BlockNumber;
use reth_prune_types::PruneModes;
use reth_storage_errors::provider::ProviderError;
@ -60,13 +59,6 @@ where
type Output = A::Output;
type Error = A::Error;
fn init(&mut self, tx_env_overrides: Box<dyn crate::TxEnvOverrides>) {
match self {
Self::Left(a) => a.init(tx_env_overrides),
Self::Right(b) => b.init(tx_env_overrides),
}
}
fn execute(self, input: Self::Input<'_>) -> Result<Self::Output, Self::Error> {
match self {
Self::Left(a) => a.execute(input),

View File

@ -8,7 +8,7 @@ pub use reth_execution_errors::{
pub use reth_execution_types::{BlockExecutionOutput, ExecutionOutcome};
pub use reth_storage_errors::provider::ProviderError;
use crate::{system_calls::OnStateHook, TxEnvOverrides};
use crate::system_calls::OnStateHook;
use alloc::{boxed::Box, vec::Vec};
use alloy_eips::eip7685::Requests;
use alloy_primitives::{
@ -38,9 +38,6 @@ pub trait Executor<DB> {
/// The error type returned by the executor.
type Error;
/// Initialize the executor with the given transaction environment overrides.
fn init(&mut self, _tx_env_overrides: Box<dyn TxEnvOverrides>) {}
/// Consumes the type and executes the block.
///
/// # Note
@ -199,9 +196,6 @@ pub trait BlockExecutionStrategy {
/// The error type returned by this strategy's methods.
type Error: From<ProviderError> + core::error::Error;
/// Initialize the strategy with the given transaction environment overrides.
fn init(&mut self, _tx_env_overrides: Box<dyn TxEnvOverrides>) {}
/// Applies any necessary changes before executing the block's transactions.
fn apply_pre_execution_changes(
&mut self,
@ -341,10 +335,6 @@ where
type Output = BlockExecutionOutput<<S::Primitives as NodePrimitives>::Receipt>;
type Error = S::Error;
fn init(&mut self, env_overrides: Box<dyn TxEnvOverrides>) {
self.strategy.init(env_overrides);
}
fn execute(mut self, block: Self::Input<'_>) -> Result<Self::Output, Self::Error> {
self.strategy.apply_pre_execution_changes(block)?;
let ExecuteOutput { receipts, gas_used } = self.strategy.execute_transactions(block)?;
@ -518,7 +508,7 @@ mod tests {
use reth_chainspec::{ChainSpec, MAINNET};
use reth_primitives::EthPrimitives;
use revm::db::{CacheDB, EmptyDBTyped};
use revm_primitives::{address, bytes, AccountInfo, TxEnv, KECCAK_EMPTY};
use revm_primitives::{address, bytes, AccountInfo, KECCAK_EMPTY};
use std::sync::Arc;
#[derive(Clone, Default)]
@ -734,29 +724,6 @@ mod tests {
assert_eq!(block_execution_output.state, expected_finish_result);
}
#[test]
fn test_tx_env_overrider() {
let strategy_factory = TestExecutorStrategyFactory {
execute_transactions_result: ExecuteOutput {
receipts: vec![Receipt::default()],
gas_used: 10,
},
apply_post_execution_changes_result: Requests::new(vec![bytes!("deadbeef")]),
finish_result: BundleState::default(),
};
let provider = BasicBlockExecutorProvider::new(strategy_factory);
let db = CacheDB::<EmptyDBTyped<ProviderError>>::default();
// if we want to apply tx env overrides the executor must be mut.
let mut executor = provider.executor(db);
// execute consumes the executor, so we can only call it once.
executor.init(Box::new(|tx_env: &mut TxEnv| {
tx_env.nonce.take();
}));
let result = executor.execute(&Default::default());
assert!(result.is_ok());
}
fn setup_state_with_account(
addr: Address,
balance: u128,

View File

@ -17,11 +17,16 @@
extern crate alloc;
use core::fmt::Debug;
use alloy_consensus::BlockHeader as _;
use alloy_eips::eip2930::AccessList;
use alloy_primitives::{Address, Bytes, B256, U256};
use reth_primitives_traits::{BlockHeader, SignedTransaction};
use revm::{Database, DatabaseCommit, GetInspector};
use revm_primitives::{BlockEnv, CfgEnvWithHandlerCfg, EVMError, ResultAndState, SpecId, TxEnv};
use revm_primitives::{
BlockEnv, CfgEnvWithHandlerCfg, EVMError, ResultAndState, SpecId, TxEnv, TxKind,
};
pub mod either;
/// EVM environment configuration.
@ -87,7 +92,11 @@ pub trait Evm {
/// Trait for configuring the EVM for executing full blocks.
pub trait ConfigureEvm: ConfigureEvmEnv {
/// The EVM implementation.
type Evm<'a, DB: Database + 'a, I: 'a>: Evm<Tx = TxEnv, DB = DB, Error = EVMError<DB::Error>>;
type Evm<'a, DB: Database + 'a, I: 'a>: Evm<
Tx = Self::TxEnv,
DB = DB,
Error = EVMError<DB::Error>,
>;
/// Returns a new EVM with the given database configured with the given environment settings,
/// including the spec id and transaction environment.
@ -127,7 +136,7 @@ pub trait ConfigureEvm: ConfigureEvmEnv {
impl<'b, T> ConfigureEvm for &'b T
where
T: ConfigureEvm,
&'b T: ConfigureEvmEnv<Header = T::Header>,
&'b T: ConfigureEvmEnv<Header = T::Header, TxEnv = T::TxEnv>,
{
type Evm<'a, DB: Database + 'a, I: 'a> = T::Evm<'a, DB, I>;
@ -165,18 +174,26 @@ pub trait ConfigureEvmEnv: Send + Sync + Unpin + Clone + 'static {
/// The transaction type.
type Transaction: SignedTransaction;
/// Transaction environment used by EVM.
type TxEnv: TransactionEnv;
/// The error type that is returned by [`Self::next_cfg_and_block_env`].
type Error: core::error::Error + Send + Sync;
/// Returns a [`TxEnv`] from a transaction and [`Address`].
fn tx_env(&self, transaction: &Self::Transaction, signer: Address) -> TxEnv {
let mut tx_env = TxEnv::default();
fn tx_env(&self, transaction: &Self::Transaction, signer: Address) -> Self::TxEnv {
let mut tx_env = Default::default();
self.fill_tx_env(&mut tx_env, transaction, signer);
tx_env
}
/// Fill transaction environment from a transaction and the given sender address.
fn fill_tx_env(&self, tx_env: &mut TxEnv, transaction: &Self::Transaction, sender: Address);
fn fill_tx_env(
&self,
tx_env: &mut Self::TxEnv,
transaction: &Self::Transaction,
sender: Address,
);
/// Returns a [`CfgEnvWithHandlerCfg`] for the given header.
fn cfg_env(&self, header: &Self::Header) -> CfgEnvWithHandlerCfg {
@ -262,17 +279,77 @@ pub struct NextBlockEnvAttributes {
pub gas_limit: u64,
}
/// Function hook that allows to modify a transaction environment.
pub trait TxEnvOverrides {
/// Apply the overrides by modifying the given `TxEnv`.
fn apply(&mut self, env: &mut TxEnv);
/// Abstraction over transaction environment.
pub trait TransactionEnv:
Into<revm_primitives::TxEnv> + Debug + Default + Clone + Send + Sync + 'static
{
/// Returns configured gas limit.
fn gas_limit(&self) -> u64;
/// Set the gas limit.
fn set_gas_limit(&mut self, gas_limit: u64);
/// Set the gas limit.
fn with_gas_limit(mut self, gas_limit: u64) -> Self {
self.set_gas_limit(gas_limit);
self
}
/// Returns configured gas price.
fn gas_price(&self) -> U256;
/// Returns configured value.
fn value(&self) -> U256;
/// Caller of the transaction.
fn caller(&self) -> Address;
/// Set access list.
fn set_access_list(&mut self, access_list: AccessList);
/// Set access list.
fn with_access_list(mut self, access_list: AccessList) -> Self {
self.set_access_list(access_list);
self
}
/// Returns calldata for the transaction.
fn input(&self) -> &Bytes;
/// Returns [`TxKind`] of the transaction.
fn kind(&self) -> TxKind;
}
impl<F> TxEnvOverrides for F
where
F: FnMut(&mut TxEnv),
{
fn apply(&mut self, env: &mut TxEnv) {
self(env)
impl TransactionEnv for TxEnv {
fn gas_limit(&self) -> u64 {
self.gas_limit
}
fn set_gas_limit(&mut self, gas_limit: u64) {
self.gas_limit = gas_limit;
}
fn gas_price(&self) -> U256 {
self.gas_price.to()
}
fn value(&self) -> U256 {
self.value
}
fn caller(&self) -> Address {
self.caller
}
fn set_access_list(&mut self, access_list: AccessList) {
self.access_list = access_list.to_vec();
}
fn input(&self) -> &Bytes {
&self.data
}
fn kind(&self) -> TxKind {
self.transact_to
}
}