mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
refactor: BlockExecutionStrategy API (#14480)
This commit is contained in:
5
Cargo.lock
generated
5
Cargo.lock
generated
@ -7744,12 +7744,12 @@ dependencies = [
|
|||||||
"alloy-evm",
|
"alloy-evm",
|
||||||
"alloy-primitives",
|
"alloy-primitives",
|
||||||
"auto_impl",
|
"auto_impl",
|
||||||
|
"derive_more 2.0.1",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"metrics",
|
"metrics",
|
||||||
"metrics-util",
|
"metrics-util",
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
"reth-chainspec",
|
"reth-chainspec",
|
||||||
"reth-consensus",
|
|
||||||
"reth-consensus-common",
|
"reth-consensus-common",
|
||||||
"reth-ethereum-forks",
|
"reth-ethereum-forks",
|
||||||
"reth-ethereum-primitives",
|
"reth-ethereum-primitives",
|
||||||
@ -7774,9 +7774,8 @@ dependencies = [
|
|||||||
"alloy-genesis",
|
"alloy-genesis",
|
||||||
"alloy-primitives",
|
"alloy-primitives",
|
||||||
"alloy-sol-types",
|
"alloy-sol-types",
|
||||||
|
"derive_more 2.0.1",
|
||||||
"reth-chainspec",
|
"reth-chainspec",
|
||||||
"reth-consensus",
|
|
||||||
"reth-ethereum-consensus",
|
|
||||||
"reth-ethereum-forks",
|
"reth-ethereum-forks",
|
||||||
"reth-evm",
|
"reth-evm",
|
||||||
"reth-execution-types",
|
"reth-execution-types",
|
||||||
|
|||||||
@ -8,7 +8,6 @@ use reth_evm::{
|
|||||||
state_change::post_block_balance_increments, system_calls::SystemCaller, ConfigureEvmFor, Evm,
|
state_change::post_block_balance_increments, system_calls::SystemCaller, ConfigureEvmFor, Evm,
|
||||||
};
|
};
|
||||||
use reth_primitives::{NodePrimitives, RecoveredBlock, SealedHeader};
|
use reth_primitives::{NodePrimitives, RecoveredBlock, SealedHeader};
|
||||||
use reth_primitives_traits::{BlockBody, SignedTransaction};
|
|
||||||
use reth_provider::{BlockExecutionOutput, ChainSpecProvider, StateProviderFactory};
|
use reth_provider::{BlockExecutionOutput, ChainSpecProvider, StateProviderFactory};
|
||||||
use reth_revm::{
|
use reth_revm::{
|
||||||
database::StateProviderDatabase,
|
database::StateProviderDatabase,
|
||||||
@ -85,10 +84,8 @@ where
|
|||||||
|
|
||||||
// Re-execute all of the transactions in the block to load all touched accounts into
|
// Re-execute all of the transactions in the block to load all touched accounts into
|
||||||
// the cache DB.
|
// the cache DB.
|
||||||
for tx in block.body().transactions() {
|
for tx in block.transactions_recovered() {
|
||||||
let signer =
|
evm.transact_commit(self.evm_config.tx_env(tx))?;
|
||||||
tx.recover_signer().map_err(|_| eyre::eyre!("failed to recover sender"))?;
|
|
||||||
evm.transact_commit(self.evm_config.tx_env(tx, signer))?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
drop(evm);
|
drop(evm);
|
||||||
|
|||||||
@ -2775,7 +2775,7 @@ where
|
|||||||
let mut evm = evm_config.evm_with_env(state_provider, evm_env);
|
let mut evm = evm_config.evm_with_env(state_provider, evm_env);
|
||||||
|
|
||||||
// create the tx env and reset nonce
|
// create the tx env and reset nonce
|
||||||
let tx_env = evm_config.tx_env(&tx, tx.signer());
|
let tx_env = evm_config.tx_env(&tx);
|
||||||
|
|
||||||
// exit early if execution is done
|
// exit early if execution is done
|
||||||
if cancel_execution.is_cancelled() {
|
if cancel_execution.is_cancelled() {
|
||||||
|
|||||||
@ -312,7 +312,7 @@ where
|
|||||||
// Configure the environment for the block.
|
// Configure the environment for the block.
|
||||||
let tx_recovered =
|
let tx_recovered =
|
||||||
tx.try_clone_into_recovered().map_err(|_| ProviderError::SenderRecoveryError)?;
|
tx.try_clone_into_recovered().map_err(|_| ProviderError::SenderRecoveryError)?;
|
||||||
let tx_env = evm_config.tx_env(&tx_recovered, tx_recovered.signer());
|
let tx_env = evm_config.tx_env(tx_recovered);
|
||||||
let exec_result = match evm.transact(tx_env) {
|
let exec_result = match evm.transact(tx_env) {
|
||||||
Ok(result) => result,
|
Ok(result) => result,
|
||||||
Err(err) if err.is_invalid_tx_err() => {
|
Err(err) if err.is_invalid_tx_err() => {
|
||||||
|
|||||||
@ -12,13 +12,12 @@ workspace = true
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
# Reth
|
# Reth
|
||||||
|
reth-execution-types.workspace = true
|
||||||
reth-chainspec.workspace = true
|
reth-chainspec.workspace = true
|
||||||
reth-ethereum-forks.workspace = true
|
reth-ethereum-forks.workspace = true
|
||||||
reth-revm.workspace = true
|
reth-revm.workspace = true
|
||||||
reth-evm.workspace = true
|
reth-evm.workspace = true
|
||||||
reth-primitives.workspace = true
|
reth-primitives.workspace = true
|
||||||
reth-ethereum-consensus.workspace = true
|
|
||||||
reth-consensus.workspace = true
|
|
||||||
|
|
||||||
# Ethereum
|
# Ethereum
|
||||||
reth-primitives-traits.workspace = true
|
reth-primitives-traits.workspace = true
|
||||||
@ -30,6 +29,8 @@ alloy-evm.workspace = true
|
|||||||
alloy-sol-types.workspace = true
|
alloy-sol-types.workspace = true
|
||||||
alloy-consensus.workspace = true
|
alloy-consensus.workspace = true
|
||||||
|
|
||||||
|
derive_more.workspace = true
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
reth-testing-utils.workspace = true
|
reth-testing-utils.workspace = true
|
||||||
reth-evm = { workspace = true, features = ["test-utils"] }
|
reth-evm = { workspace = true, features = ["test-utils"] }
|
||||||
@ -43,7 +44,6 @@ alloy-genesis.workspace = true
|
|||||||
[features]
|
[features]
|
||||||
default = ["std"]
|
default = ["std"]
|
||||||
std = [
|
std = [
|
||||||
"reth-consensus/std",
|
|
||||||
"reth-primitives/std",
|
"reth-primitives/std",
|
||||||
"reth-revm/std",
|
"reth-revm/std",
|
||||||
"alloy-consensus/std",
|
"alloy-consensus/std",
|
||||||
@ -58,4 +58,5 @@ std = [
|
|||||||
"alloy-evm/std",
|
"alloy-evm/std",
|
||||||
"reth-execution-types/std",
|
"reth-execution-types/std",
|
||||||
"reth-evm/std",
|
"reth-evm/std",
|
||||||
|
"derive_more/std",
|
||||||
]
|
]
|
||||||
|
|||||||
@ -8,19 +8,20 @@ use alloc::{boxed::Box, sync::Arc, vec::Vec};
|
|||||||
use alloy_consensus::{BlockHeader, Transaction};
|
use alloy_consensus::{BlockHeader, Transaction};
|
||||||
use alloy_eips::{eip6110, eip7685::Requests};
|
use alloy_eips::{eip6110, eip7685::Requests};
|
||||||
use reth_chainspec::{ChainSpec, EthereumHardfork, EthereumHardforks, MAINNET};
|
use reth_chainspec::{ChainSpec, EthereumHardfork, EthereumHardforks, MAINNET};
|
||||||
use reth_consensus::ConsensusError;
|
|
||||||
use reth_ethereum_consensus::validate_block_post_execution;
|
|
||||||
use reth_evm::{
|
use reth_evm::{
|
||||||
execute::{
|
execute::{
|
||||||
balance_increment_state, BasicBlockExecutorProvider, BlockExecutionError,
|
balance_increment_state, BasicBlockExecutorProvider, BlockExecutionError,
|
||||||
BlockExecutionStrategy, BlockExecutionStrategyFactory, BlockValidationError, ExecuteOutput,
|
BlockExecutionStrategy, BlockExecutionStrategyFactory, BlockValidationError,
|
||||||
},
|
},
|
||||||
state_change::post_block_balance_increments,
|
state_change::post_block_balance_increments,
|
||||||
system_calls::{OnStateHook, StateChangePostBlockSource, StateChangeSource, SystemCaller},
|
system_calls::{OnStateHook, StateChangePostBlockSource, StateChangeSource, SystemCaller},
|
||||||
ConfigureEvm, Database, Evm,
|
ConfigureEvm, ConfigureEvmEnv, Database, Evm,
|
||||||
};
|
};
|
||||||
use reth_primitives::{EthPrimitives, Receipt, RecoveredBlock};
|
use reth_execution_types::BlockExecutionResult;
|
||||||
use reth_primitives_traits::{BlockBody, SignedTransaction};
|
use reth_primitives::{
|
||||||
|
EthPrimitives, Receipt, Recovered, RecoveredBlock, SealedBlock, TransactionSigned,
|
||||||
|
};
|
||||||
|
use reth_primitives_traits::NodePrimitives;
|
||||||
use reth_revm::{context_interface::result::ResultAndState, db::State, DatabaseCommit};
|
use reth_revm::{context_interface::result::ResultAndState, db::State, DatabaseCommit};
|
||||||
|
|
||||||
/// Factory for [`EthExecutionStrategy`].
|
/// Factory for [`EthExecutionStrategy`].
|
||||||
@ -46,7 +47,7 @@ impl EthExecutionStrategyFactory {
|
|||||||
|
|
||||||
impl<EvmConfig> EthExecutionStrategyFactory<EvmConfig> {
|
impl<EvmConfig> EthExecutionStrategyFactory<EvmConfig> {
|
||||||
/// Creates a new executor strategy factory.
|
/// Creates a new executor strategy factory.
|
||||||
pub const fn new(chain_spec: Arc<ChainSpec>, evm_config: EvmConfig) -> Self {
|
pub fn new(chain_spec: Arc<ChainSpec>, evm_config: EvmConfig) -> Self {
|
||||||
Self { chain_spec, evm_config }
|
Self { chain_spec, evm_config }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -65,113 +66,108 @@ where
|
|||||||
{
|
{
|
||||||
type Primitives = EthPrimitives;
|
type Primitives = EthPrimitives;
|
||||||
|
|
||||||
type Strategy<DB: Database> = EthExecutionStrategy<DB, EvmConfig>;
|
fn create_strategy<'a, DB>(
|
||||||
|
&'a mut self,
|
||||||
fn create_strategy<DB>(&self, db: DB) -> Self::Strategy<DB>
|
db: &'a mut State<DB>,
|
||||||
|
block: &'a RecoveredBlock<<Self::Primitives as NodePrimitives>::Block>,
|
||||||
|
) -> impl BlockExecutionStrategy<Primitives = Self::Primitives, Error = BlockExecutionError> + 'a
|
||||||
where
|
where
|
||||||
DB: Database,
|
DB: Database,
|
||||||
{
|
{
|
||||||
let state =
|
let evm = self.evm_config.evm_for_block(db, block.header());
|
||||||
State::builder().with_database(db).with_bundle_update().without_state_clear().build();
|
EthExecutionStrategy::new(evm, block.sealed_block(), self)
|
||||||
EthExecutionStrategy::new(state, self.chain_spec.clone(), self.evm_config.clone())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Block execution strategy for Ethereum.
|
/// Block execution strategy for Ethereum.
|
||||||
#[allow(missing_debug_implementations)]
|
#[derive(Debug, derive_more::Deref)]
|
||||||
pub struct EthExecutionStrategy<DB, EvmConfig>
|
pub struct EthExecutionStrategy<'a, Evm, EvmConfig> {
|
||||||
where
|
/// Reference to the parent factory providing access to [`ChainSpec`].
|
||||||
EvmConfig: Clone,
|
#[deref]
|
||||||
{
|
factory: &'a EthExecutionStrategyFactory<EvmConfig>,
|
||||||
/// The chainspec
|
|
||||||
chain_spec: Arc<ChainSpec>,
|
/// Block being executed.
|
||||||
/// How to create an EVM.
|
block: &'a SealedBlock,
|
||||||
evm_config: EvmConfig,
|
/// The EVM used by strategy.
|
||||||
/// Current state for block execution.
|
evm: Evm,
|
||||||
state: State<DB>,
|
/// Receipts of executed transactions.
|
||||||
|
receipts: Vec<Receipt>,
|
||||||
/// Utility to call system smart contracts.
|
/// Utility to call system smart contracts.
|
||||||
system_caller: SystemCaller<Arc<ChainSpec>>,
|
system_caller: SystemCaller<&'a ChainSpec>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<DB, EvmConfig> EthExecutionStrategy<DB, EvmConfig>
|
impl<'a, Evm, EvmConfig> EthExecutionStrategy<'a, Evm, EvmConfig> {
|
||||||
where
|
|
||||||
EvmConfig: Clone,
|
|
||||||
{
|
|
||||||
/// Creates a new [`EthExecutionStrategy`]
|
/// Creates a new [`EthExecutionStrategy`]
|
||||||
pub fn new(state: State<DB>, chain_spec: Arc<ChainSpec>, evm_config: EvmConfig) -> Self {
|
pub fn new(
|
||||||
let system_caller = SystemCaller::new(chain_spec.clone());
|
evm: Evm,
|
||||||
Self { state, chain_spec, evm_config, system_caller }
|
block: &'a SealedBlock,
|
||||||
|
factory: &'a EthExecutionStrategyFactory<EvmConfig>,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
evm,
|
||||||
|
factory,
|
||||||
|
block,
|
||||||
|
receipts: Vec::new(),
|
||||||
|
system_caller: SystemCaller::new(&factory.chain_spec),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<DB, EvmConfig> BlockExecutionStrategy for EthExecutionStrategy<DB, EvmConfig>
|
impl<'db, DB, E, EvmConfig> BlockExecutionStrategy for EthExecutionStrategy<'_, E, EvmConfig>
|
||||||
where
|
where
|
||||||
DB: Database,
|
DB: Database + 'db,
|
||||||
EvmConfig: ConfigureEvm<
|
E: Evm<DB = &'db mut State<DB>, Tx = EvmConfig::TxEnv>,
|
||||||
Header = alloy_consensus::Header,
|
EvmConfig: ConfigureEvmEnv<Transaction = TransactionSigned>,
|
||||||
Transaction = reth_primitives::TransactionSigned,
|
|
||||||
>,
|
|
||||||
{
|
{
|
||||||
type DB = DB;
|
|
||||||
type Error = BlockExecutionError;
|
type Error = BlockExecutionError;
|
||||||
type Primitives = EthPrimitives;
|
type Primitives = EthPrimitives;
|
||||||
|
|
||||||
fn apply_pre_execution_changes(
|
fn apply_pre_execution_changes(&mut self) -> Result<(), Self::Error> {
|
||||||
&mut self,
|
|
||||||
block: &RecoveredBlock<reth_primitives::Block>,
|
|
||||||
) -> Result<(), Self::Error> {
|
|
||||||
// Set state clear flag if the block is after the Spurious Dragon hardfork.
|
// Set state clear flag if the block is after the Spurious Dragon hardfork.
|
||||||
let state_clear_flag = self.chain_spec.is_spurious_dragon_active_at_block(block.number());
|
let state_clear_flag =
|
||||||
self.state.set_state_clear_flag(state_clear_flag);
|
self.chain_spec.is_spurious_dragon_active_at_block(self.block.number());
|
||||||
|
self.evm.db_mut().set_state_clear_flag(state_clear_flag);
|
||||||
let mut evm = self.evm_config.evm_for_block(&mut self.state, block.header());
|
self.system_caller.apply_pre_execution_changes(self.block.header(), &mut self.evm)?;
|
||||||
|
|
||||||
self.system_caller.apply_pre_execution_changes(block.header(), &mut evm)?;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn execute_transactions(
|
fn execute_transactions<'a>(
|
||||||
&mut self,
|
&mut self,
|
||||||
block: &RecoveredBlock<reth_primitives::Block>,
|
transactions: impl IntoIterator<Item = Recovered<&'a TransactionSigned>>,
|
||||||
) -> Result<ExecuteOutput<Receipt>, Self::Error> {
|
) -> Result<(), Self::Error> {
|
||||||
let mut evm = self.evm_config.evm_for_block(&mut self.state, block.header());
|
|
||||||
|
|
||||||
let mut cumulative_gas_used = 0;
|
let mut cumulative_gas_used = 0;
|
||||||
let mut receipts = Vec::with_capacity(block.body().transaction_count());
|
for (tx_index, tx) in transactions.into_iter().enumerate() {
|
||||||
for (tx_index, (sender, transaction)) in block.transactions_with_sender().enumerate() {
|
|
||||||
// The sum of the transaction's gas limit, Tg, and the gas utilized in this block prior,
|
// The sum of the transaction's gas limit, Tg, and the gas utilized in this block prior,
|
||||||
// must be no greater than the block's gasLimit.
|
// must be no greater than the block's gasLimit.
|
||||||
let block_available_gas = block.gas_limit() - cumulative_gas_used;
|
let block_available_gas = self.block.gas_limit() - cumulative_gas_used;
|
||||||
if transaction.gas_limit() > block_available_gas {
|
if tx.gas_limit() > block_available_gas {
|
||||||
return Err(BlockValidationError::TransactionGasLimitMoreThanAvailableBlockGas {
|
return Err(BlockValidationError::TransactionGasLimitMoreThanAvailableBlockGas {
|
||||||
transaction_gas_limit: transaction.gas_limit(),
|
transaction_gas_limit: tx.gas_limit(),
|
||||||
block_available_gas,
|
block_available_gas,
|
||||||
}
|
}
|
||||||
.into())
|
.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
let tx_env = self.evm_config.tx_env(transaction, *sender);
|
let tx_env = self.evm_config.tx_env(tx.clone());
|
||||||
|
let hash = tx.hash();
|
||||||
|
|
||||||
// Execute transaction.
|
// Execute transaction.
|
||||||
let result_and_state = evm.transact(tx_env).map_err(move |err| {
|
let result_and_state = self.evm.transact(tx_env).map_err(move |err| {
|
||||||
// Ensure hash is calculated for error log, if not already done
|
// Ensure hash is calculated for error log, if not already done
|
||||||
BlockValidationError::EVM {
|
BlockValidationError::EVM { hash: *hash, error: Box::new(err) }
|
||||||
hash: transaction.recalculate_hash(),
|
|
||||||
error: Box::new(err),
|
|
||||||
}
|
|
||||||
})?;
|
})?;
|
||||||
self.system_caller
|
self.system_caller
|
||||||
.on_state(StateChangeSource::Transaction(tx_index), &result_and_state.state);
|
.on_state(StateChangeSource::Transaction(tx_index), &result_and_state.state);
|
||||||
let ResultAndState { result, state } = result_and_state;
|
let ResultAndState { result, state } = result_and_state;
|
||||||
evm.db_mut().commit(state);
|
self.evm.db_mut().commit(state);
|
||||||
|
|
||||||
// append gas used
|
// append gas used
|
||||||
cumulative_gas_used += result.gas_used();
|
cumulative_gas_used += result.gas_used();
|
||||||
|
|
||||||
// Push transaction changeset and calculate header bloom filter for receipt.
|
// Push transaction changeset and calculate header bloom filter for receipt.
|
||||||
receipts.push(Receipt {
|
self.receipts.push(Receipt {
|
||||||
tx_type: transaction.tx_type(),
|
tx_type: tx.tx_type(),
|
||||||
// Success flag was added in `EIP-658: Embedding transaction status code in
|
// Success flag was added in `EIP-658: Embedding transaction status code in
|
||||||
// receipts`.
|
// receipts`.
|
||||||
success: result.is_success(),
|
success: result.is_success(),
|
||||||
@ -179,20 +175,16 @@ where
|
|||||||
logs: result.into_logs(),
|
logs: result.into_logs(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Ok(ExecuteOutput { receipts, gas_used: cumulative_gas_used })
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_post_execution_changes(
|
fn apply_post_execution_changes(
|
||||||
&mut self,
|
mut self,
|
||||||
block: &RecoveredBlock<reth_primitives::Block>,
|
) -> Result<BlockExecutionResult<Receipt>, Self::Error> {
|
||||||
receipts: &[Receipt],
|
let requests = if self.chain_spec.is_prague_active_at_timestamp(self.block.timestamp) {
|
||||||
) -> Result<Requests, Self::Error> {
|
|
||||||
let mut evm = self.evm_config.evm_for_block(&mut self.state, block.header());
|
|
||||||
|
|
||||||
let requests = if self.chain_spec.is_prague_active_at_timestamp(block.timestamp) {
|
|
||||||
// Collect all EIP-6110 deposits
|
// Collect all EIP-6110 deposits
|
||||||
let deposit_requests =
|
let deposit_requests =
|
||||||
crate::eip6110::parse_deposits_from_receipts(&self.chain_spec, receipts)?;
|
crate::eip6110::parse_deposits_from_receipts(&self.chain_spec, &self.receipts)?;
|
||||||
|
|
||||||
let mut requests = Requests::default();
|
let mut requests = Requests::default();
|
||||||
|
|
||||||
@ -200,20 +192,20 @@ where
|
|||||||
requests.push_request_with_type(eip6110::DEPOSIT_REQUEST_TYPE, deposit_requests);
|
requests.push_request_with_type(eip6110::DEPOSIT_REQUEST_TYPE, deposit_requests);
|
||||||
}
|
}
|
||||||
|
|
||||||
requests.extend(self.system_caller.apply_post_execution_changes(&mut evm)?);
|
requests.extend(self.system_caller.apply_post_execution_changes(&mut self.evm)?);
|
||||||
requests
|
requests
|
||||||
} else {
|
} else {
|
||||||
Requests::default()
|
Requests::default()
|
||||||
};
|
};
|
||||||
drop(evm);
|
|
||||||
|
|
||||||
let mut balance_increments = post_block_balance_increments(&self.chain_spec, block);
|
let mut balance_increments = post_block_balance_increments(&self.chain_spec, self.block);
|
||||||
|
|
||||||
// Irregular state change at Ethereum DAO hardfork
|
// Irregular state change at Ethereum DAO hardfork
|
||||||
if self.chain_spec.fork(EthereumHardfork::Dao).transitions_at_block(block.number()) {
|
if self.chain_spec.fork(EthereumHardfork::Dao).transitions_at_block(self.block.number()) {
|
||||||
// drain balances from hardcoded addresses.
|
// drain balances from hardcoded addresses.
|
||||||
let drained_balance: u128 = self
|
let drained_balance: u128 = self
|
||||||
.state
|
.evm
|
||||||
|
.db_mut()
|
||||||
.drain_balances(DAO_HARDFORK_ACCOUNTS)
|
.drain_balances(DAO_HARDFORK_ACCOUNTS)
|
||||||
.map_err(|_| BlockValidationError::IncrementBalanceFailed)?
|
.map_err(|_| BlockValidationError::IncrementBalanceFailed)?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@ -223,43 +215,24 @@ where
|
|||||||
*balance_increments.entry(DAO_HARDFORK_BENEFICIARY).or_default() += drained_balance;
|
*balance_increments.entry(DAO_HARDFORK_BENEFICIARY).or_default() += drained_balance;
|
||||||
}
|
}
|
||||||
// increment balances
|
// increment balances
|
||||||
self.state
|
self.evm
|
||||||
|
.db_mut()
|
||||||
.increment_balances(balance_increments.clone())
|
.increment_balances(balance_increments.clone())
|
||||||
.map_err(|_| BlockValidationError::IncrementBalanceFailed)?;
|
.map_err(|_| BlockValidationError::IncrementBalanceFailed)?;
|
||||||
// call state hook with changes due to balance increments.
|
// call state hook with changes due to balance increments.
|
||||||
let balance_state = balance_increment_state(&balance_increments, &mut self.state)?;
|
let balance_state = balance_increment_state(&balance_increments, self.evm.db_mut())?;
|
||||||
self.system_caller.on_state(
|
self.system_caller.on_state(
|
||||||
StateChangeSource::PostBlock(StateChangePostBlockSource::BalanceIncrements),
|
StateChangeSource::PostBlock(StateChangePostBlockSource::BalanceIncrements),
|
||||||
&balance_state,
|
&balance_state,
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(requests)
|
let gas_used = self.receipts.last().map(|r| r.cumulative_gas_used).unwrap_or_default();
|
||||||
}
|
Ok(BlockExecutionResult { receipts: self.receipts, requests, gas_used })
|
||||||
|
|
||||||
fn state_ref(&self) -> &State<DB> {
|
|
||||||
&self.state
|
|
||||||
}
|
|
||||||
|
|
||||||
fn state_mut(&mut self) -> &mut State<DB> {
|
|
||||||
&mut self.state
|
|
||||||
}
|
|
||||||
|
|
||||||
fn into_state(self) -> State<Self::DB> {
|
|
||||||
self.state
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_state_hook(&mut self, hook: Option<Box<dyn OnStateHook>>) {
|
fn with_state_hook(&mut self, hook: Option<Box<dyn OnStateHook>>) {
|
||||||
self.system_caller.with_state_hook(hook);
|
self.system_caller.with_state_hook(hook);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_block_post_execution(
|
|
||||||
&self,
|
|
||||||
block: &RecoveredBlock<reth_primitives::Block>,
|
|
||||||
receipts: &[Receipt],
|
|
||||||
requests: &Requests,
|
|
||||||
) -> Result<(), ConsensusError> {
|
|
||||||
validate_block_post_execution(block, &self.chain_spec.clone(), receipts, requests)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper type with backwards compatible methods to obtain Ethereum executor
|
/// Helper type with backwards compatible methods to obtain Ethereum executor
|
||||||
|
|||||||
@ -17,11 +17,11 @@
|
|||||||
|
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
use alloc::sync::Arc;
|
use alloc::{borrow::Borrow, sync::Arc};
|
||||||
use alloy_consensus::{BlockHeader, Header};
|
use alloy_consensus::{transaction::Recovered, BlockHeader, Header};
|
||||||
pub use alloy_evm::EthEvm;
|
pub use alloy_evm::EthEvm;
|
||||||
use alloy_evm::EthEvmFactory;
|
use alloy_evm::EthEvmFactory;
|
||||||
use alloy_primitives::{Address, U256};
|
use alloy_primitives::U256;
|
||||||
use core::{convert::Infallible, fmt::Debug};
|
use core::{convert::Infallible, fmt::Debug};
|
||||||
use reth_chainspec::{ChainSpec, EthChainSpec, MAINNET};
|
use reth_chainspec::{ChainSpec, EthChainSpec, MAINNET};
|
||||||
use reth_evm::{ConfigureEvm, ConfigureEvmEnv, EvmEnv, NextBlockEnvAttributes};
|
use reth_evm::{ConfigureEvm, ConfigureEvmEnv, EvmEnv, NextBlockEnvAttributes};
|
||||||
@ -77,9 +77,14 @@ impl ConfigureEvmEnv for EthEvmConfig {
|
|||||||
type TxEnv = TxEnv;
|
type TxEnv = TxEnv;
|
||||||
type Spec = SpecId;
|
type Spec = SpecId;
|
||||||
|
|
||||||
fn tx_env(&self, transaction: &TransactionSigned, sender: Address) -> Self::TxEnv {
|
fn tx_env<T: Borrow<Self::Transaction>>(
|
||||||
|
&self,
|
||||||
|
transaction: impl Borrow<Recovered<T>>,
|
||||||
|
) -> Self::TxEnv {
|
||||||
|
let transaction = transaction.borrow();
|
||||||
|
|
||||||
let mut tx_env = TxEnv::default();
|
let mut tx_env = TxEnv::default();
|
||||||
transaction.fill_tx_env(&mut tx_env, sender);
|
transaction.tx().borrow().fill_tx_env(&mut tx_env, transaction.signer());
|
||||||
tx_env
|
tx_env
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -279,7 +279,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Configure the environment for the tx.
|
// Configure the environment for the tx.
|
||||||
let tx_env = evm_config.tx_env(tx.tx(), tx.signer());
|
let tx_env = evm_config.tx_env(&tx);
|
||||||
|
|
||||||
let ResultAndState { result, state } = match evm.transact(tx_env) {
|
let ResultAndState { result, state } = match evm.transact(tx_env) {
|
||||||
Ok(res) => res,
|
Ok(res) => res,
|
||||||
|
|||||||
@ -13,7 +13,6 @@ workspace = true
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
# reth
|
# reth
|
||||||
reth-chainspec.workspace = true
|
reth-chainspec.workspace = true
|
||||||
reth-consensus.workspace = true
|
|
||||||
reth-consensus-common.workspace = true
|
reth-consensus-common.workspace = true
|
||||||
reth-execution-errors.workspace = true
|
reth-execution-errors.workspace = true
|
||||||
reth-execution-types.workspace = true
|
reth-execution-types.workspace = true
|
||||||
@ -34,6 +33,7 @@ alloy-evm.workspace = true
|
|||||||
alloy-consensus.workspace = true
|
alloy-consensus.workspace = true
|
||||||
|
|
||||||
auto_impl.workspace = true
|
auto_impl.workspace = true
|
||||||
|
derive_more.workspace = true
|
||||||
futures-util.workspace = true
|
futures-util.workspace = true
|
||||||
metrics = { workspace = true, optional = true }
|
metrics = { workspace = true, optional = true }
|
||||||
parking_lot = { workspace = true, optional = true }
|
parking_lot = { workspace = true, optional = true }
|
||||||
@ -47,7 +47,6 @@ metrics-util = { workspace = true, features = ["debugging"] }
|
|||||||
[features]
|
[features]
|
||||||
default = ["std"]
|
default = ["std"]
|
||||||
std = [
|
std = [
|
||||||
"reth-consensus/std",
|
|
||||||
"reth-primitives/std",
|
"reth-primitives/std",
|
||||||
"reth-primitives-traits/std",
|
"reth-primitives-traits/std",
|
||||||
"alloy-eips/std",
|
"alloy-eips/std",
|
||||||
@ -65,6 +64,7 @@ std = [
|
|||||||
"reth-execution-types/std",
|
"reth-execution-types/std",
|
||||||
"reth-storage-errors/std",
|
"reth-storage-errors/std",
|
||||||
"futures-util/std",
|
"futures-util/std",
|
||||||
|
"derive_more/std",
|
||||||
]
|
]
|
||||||
metrics = [
|
metrics = [
|
||||||
"std",
|
"std",
|
||||||
@ -74,7 +74,6 @@ metrics = [
|
|||||||
test-utils = [
|
test-utils = [
|
||||||
"dep:parking_lot",
|
"dep:parking_lot",
|
||||||
"reth-chainspec/test-utils",
|
"reth-chainspec/test-utils",
|
||||||
"reth-consensus/test-utils",
|
|
||||||
"reth-ethereum-primitives/test-utils",
|
"reth-ethereum-primitives/test-utils",
|
||||||
"reth-primitives/test-utils",
|
"reth-primitives/test-utils",
|
||||||
"reth-primitives-traits/test-utils",
|
"reth-primitives-traits/test-utils",
|
||||||
|
|||||||
@ -3,7 +3,7 @@ use alloy_eips::eip7685::Requests;
|
|||||||
use revm_database::BundleState;
|
use revm_database::BundleState;
|
||||||
|
|
||||||
/// The result of executing a block.
|
/// The result of executing a block.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, Default, PartialEq, Eq)]
|
||||||
pub struct BlockExecutionResult<T> {
|
pub struct BlockExecutionResult<T> {
|
||||||
/// All the receipts of the transactions in the block.
|
/// All the receipts of the transactions in the block.
|
||||||
pub receipts: Vec<T>,
|
pub receipts: Vec<T>,
|
||||||
|
|||||||
@ -2,22 +2,19 @@
|
|||||||
|
|
||||||
use alloy_consensus::BlockHeader;
|
use alloy_consensus::BlockHeader;
|
||||||
// Re-export execution types
|
// Re-export execution types
|
||||||
|
use crate::{system_calls::OnStateHook, Database};
|
||||||
|
use alloc::{boxed::Box, vec::Vec};
|
||||||
|
use alloy_primitives::{
|
||||||
|
map::{DefaultHashBuilder, HashMap},
|
||||||
|
Address,
|
||||||
|
};
|
||||||
pub use reth_execution_errors::{
|
pub use reth_execution_errors::{
|
||||||
BlockExecutionError, BlockValidationError, InternalBlockExecutionError,
|
BlockExecutionError, BlockValidationError, InternalBlockExecutionError,
|
||||||
};
|
};
|
||||||
use reth_execution_types::BlockExecutionResult;
|
use reth_execution_types::BlockExecutionResult;
|
||||||
pub use reth_execution_types::{BlockExecutionOutput, ExecutionOutcome};
|
pub use reth_execution_types::{BlockExecutionOutput, ExecutionOutcome};
|
||||||
|
use reth_primitives::{NodePrimitives, Receipt, Recovered, RecoveredBlock};
|
||||||
pub use reth_storage_errors::provider::ProviderError;
|
pub use reth_storage_errors::provider::ProviderError;
|
||||||
|
|
||||||
use crate::{system_calls::OnStateHook, Database};
|
|
||||||
use alloc::{boxed::Box, vec::Vec};
|
|
||||||
use alloy_eips::eip7685::Requests;
|
|
||||||
use alloy_primitives::{
|
|
||||||
map::{DefaultHashBuilder, HashMap},
|
|
||||||
Address,
|
|
||||||
};
|
|
||||||
use reth_consensus::ConsensusError;
|
|
||||||
use reth_primitives::{NodePrimitives, Receipt, RecoveredBlock};
|
|
||||||
use revm::state::{Account, AccountStatus, EvmState};
|
use revm::state::{Account, AccountStatus, EvmState};
|
||||||
use revm_database::{states::bundle_state::BundleRetention, State};
|
use revm_database::{states::bundle_state::BundleRetention, State};
|
||||||
|
|
||||||
@ -167,9 +164,6 @@ pub struct ExecuteOutput<R = Receipt> {
|
|||||||
|
|
||||||
/// Defines the strategy for executing a single block.
|
/// Defines the strategy for executing a single block.
|
||||||
pub trait BlockExecutionStrategy {
|
pub trait BlockExecutionStrategy {
|
||||||
/// Database this strategy operates on.
|
|
||||||
type DB: revm::Database;
|
|
||||||
|
|
||||||
/// Primitive types used by the strategy.
|
/// Primitive types used by the strategy.
|
||||||
type Primitives: NodePrimitives;
|
type Primitives: NodePrimitives;
|
||||||
|
|
||||||
@ -177,45 +171,23 @@ pub trait BlockExecutionStrategy {
|
|||||||
type Error: core::error::Error;
|
type Error: core::error::Error;
|
||||||
|
|
||||||
/// Applies any necessary changes before executing the block's transactions.
|
/// Applies any necessary changes before executing the block's transactions.
|
||||||
fn apply_pre_execution_changes(
|
fn apply_pre_execution_changes(&mut self) -> Result<(), Self::Error>;
|
||||||
&mut self,
|
|
||||||
block: &RecoveredBlock<<Self::Primitives as NodePrimitives>::Block>,
|
|
||||||
) -> Result<(), Self::Error>;
|
|
||||||
|
|
||||||
/// Executes all transactions in the block.
|
/// Executes all transactions in the block.
|
||||||
fn execute_transactions(
|
fn execute_transactions<'a>(
|
||||||
&mut self,
|
&mut self,
|
||||||
block: &RecoveredBlock<<Self::Primitives as NodePrimitives>::Block>,
|
transactions: impl IntoIterator<
|
||||||
) -> Result<ExecuteOutput<<Self::Primitives as NodePrimitives>::Receipt>, Self::Error>;
|
Item = Recovered<&'a <Self::Primitives as NodePrimitives>::SignedTx>,
|
||||||
|
>,
|
||||||
|
) -> Result<(), Self::Error>;
|
||||||
|
|
||||||
/// Applies any necessary changes after executing the block's transactions.
|
/// Applies any necessary changes after executing the block's transactions.
|
||||||
fn apply_post_execution_changes(
|
fn apply_post_execution_changes(
|
||||||
&mut self,
|
self,
|
||||||
block: &RecoveredBlock<<Self::Primitives as NodePrimitives>::Block>,
|
) -> Result<BlockExecutionResult<<Self::Primitives as NodePrimitives>::Receipt>, Self::Error>;
|
||||||
receipts: &[<Self::Primitives as NodePrimitives>::Receipt],
|
|
||||||
) -> Result<Requests, Self::Error>;
|
|
||||||
|
|
||||||
/// Returns a reference to the current state.
|
|
||||||
fn state_ref(&self) -> &State<Self::DB>;
|
|
||||||
|
|
||||||
/// Returns a mutable reference to the current state.
|
|
||||||
fn state_mut(&mut self) -> &mut State<Self::DB>;
|
|
||||||
|
|
||||||
/// Consumes the strategy and returns inner [`State`].
|
|
||||||
fn into_state(self) -> State<Self::DB>;
|
|
||||||
|
|
||||||
/// Sets a hook to be called after each state change during execution.
|
/// Sets a hook to be called after each state change during execution.
|
||||||
fn with_state_hook(&mut self, _hook: Option<Box<dyn OnStateHook>>) {}
|
fn with_state_hook(&mut self, hook: Option<Box<dyn OnStateHook>>);
|
||||||
|
|
||||||
/// Validate a block with regard to execution results.
|
|
||||||
fn validate_block_post_execution(
|
|
||||||
&self,
|
|
||||||
_block: &RecoveredBlock<<Self::Primitives as NodePrimitives>::Block>,
|
|
||||||
_receipts: &[<Self::Primitives as NodePrimitives>::Receipt],
|
|
||||||
_requests: &Requests,
|
|
||||||
) -> Result<(), ConsensusError> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A strategy factory that can create block execution strategies.
|
/// A strategy factory that can create block execution strategies.
|
||||||
@ -223,15 +195,12 @@ pub trait BlockExecutionStrategyFactory: Send + Sync + Clone + Unpin + 'static {
|
|||||||
/// Primitive types used by the strategy.
|
/// Primitive types used by the strategy.
|
||||||
type Primitives: NodePrimitives;
|
type Primitives: NodePrimitives;
|
||||||
|
|
||||||
/// Associated strategy type.
|
/// Creates a strategy using the given database.
|
||||||
type Strategy<DB: Database>: BlockExecutionStrategy<
|
fn create_strategy<'a, DB>(
|
||||||
DB = DB,
|
&'a mut self,
|
||||||
Primitives = Self::Primitives,
|
db: &'a mut State<DB>,
|
||||||
Error = BlockExecutionError,
|
block: &'a RecoveredBlock<<Self::Primitives as NodePrimitives>::Block>,
|
||||||
>;
|
) -> impl BlockExecutionStrategy<Primitives = Self::Primitives, Error = BlockExecutionError> + 'a
|
||||||
|
|
||||||
/// Creates a strategy using the give database.
|
|
||||||
fn create_strategy<DB>(&self, db: DB) -> Self::Strategy<DB>
|
|
||||||
where
|
where
|
||||||
DB: Database;
|
DB: Database;
|
||||||
}
|
}
|
||||||
@ -264,74 +233,85 @@ where
|
|||||||
{
|
{
|
||||||
type Primitives = F::Primitives;
|
type Primitives = F::Primitives;
|
||||||
|
|
||||||
type Executor<DB: Database> = BasicBlockExecutor<F::Strategy<DB>>;
|
type Executor<DB: Database> = BasicBlockExecutor<F, DB>;
|
||||||
|
|
||||||
fn executor<DB>(&self, db: DB) -> Self::Executor<DB>
|
fn executor<DB>(&self, db: DB) -> Self::Executor<DB>
|
||||||
where
|
where
|
||||||
DB: Database,
|
DB: Database,
|
||||||
{
|
{
|
||||||
let strategy = self.strategy_factory.create_strategy(db);
|
BasicBlockExecutor::new(self.strategy_factory.clone(), db)
|
||||||
BasicBlockExecutor::new(strategy)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A generic block executor that uses a [`BlockExecutionStrategy`] to
|
/// A generic block executor that uses a [`BlockExecutionStrategy`] to
|
||||||
/// execute blocks.
|
/// execute blocks.
|
||||||
#[allow(missing_debug_implementations, dead_code)]
|
#[allow(missing_debug_implementations, dead_code)]
|
||||||
pub struct BasicBlockExecutor<S> {
|
pub struct BasicBlockExecutor<F, DB> {
|
||||||
/// Block execution strategy.
|
/// Block execution strategy.
|
||||||
pub(crate) strategy: S,
|
pub(crate) strategy_factory: F,
|
||||||
|
/// Database.
|
||||||
|
pub(crate) db: State<DB>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S> BasicBlockExecutor<S> {
|
impl<F, DB: Database> BasicBlockExecutor<F, DB> {
|
||||||
/// Creates a new `BasicBlockExecutor` with the given strategy.
|
/// Creates a new `BasicBlockExecutor` with the given strategy.
|
||||||
pub const fn new(strategy: S) -> Self {
|
pub fn new(strategy_factory: F, db: DB) -> Self {
|
||||||
Self { strategy }
|
let db =
|
||||||
|
State::builder().with_database(db).with_bundle_update().without_state_clear().build();
|
||||||
|
Self { strategy_factory, db }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S, DB> Executor<DB> for BasicBlockExecutor<S>
|
impl<F, DB> Executor<DB> for BasicBlockExecutor<F, DB>
|
||||||
where
|
where
|
||||||
S: BlockExecutionStrategy<DB = DB>,
|
F: BlockExecutionStrategyFactory,
|
||||||
DB: Database,
|
DB: Database,
|
||||||
{
|
{
|
||||||
type Primitives = S::Primitives;
|
type Primitives = F::Primitives;
|
||||||
type Error = S::Error;
|
type Error = BlockExecutionError;
|
||||||
|
|
||||||
fn execute_one(
|
fn execute_one(
|
||||||
&mut self,
|
&mut self,
|
||||||
block: &RecoveredBlock<<Self::Primitives as NodePrimitives>::Block>,
|
block: &RecoveredBlock<<Self::Primitives as NodePrimitives>::Block>,
|
||||||
) -> Result<BlockExecutionResult<<Self::Primitives as NodePrimitives>::Receipt>, Self::Error>
|
) -> Result<BlockExecutionResult<<Self::Primitives as NodePrimitives>::Receipt>, Self::Error>
|
||||||
{
|
{
|
||||||
self.strategy.apply_pre_execution_changes(block)?;
|
let mut strategy = self.strategy_factory.create_strategy(&mut self.db, block);
|
||||||
let ExecuteOutput { receipts, gas_used } = self.strategy.execute_transactions(block)?;
|
|
||||||
let requests = self.strategy.apply_post_execution_changes(block, &receipts)?;
|
|
||||||
self.strategy.state_mut().merge_transitions(BundleRetention::Reverts);
|
|
||||||
|
|
||||||
Ok(BlockExecutionResult { receipts, requests, gas_used })
|
strategy.apply_pre_execution_changes()?;
|
||||||
|
strategy.execute_transactions(block.transactions_recovered())?;
|
||||||
|
let result = strategy.apply_post_execution_changes()?;
|
||||||
|
|
||||||
|
self.db.merge_transitions(BundleRetention::Reverts);
|
||||||
|
|
||||||
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn execute_one_with_state_hook<F>(
|
fn execute_one_with_state_hook<H>(
|
||||||
&mut self,
|
&mut self,
|
||||||
block: &RecoveredBlock<<Self::Primitives as NodePrimitives>::Block>,
|
block: &RecoveredBlock<<Self::Primitives as NodePrimitives>::Block>,
|
||||||
state_hook: F,
|
state_hook: H,
|
||||||
) -> Result<BlockExecutionResult<<Self::Primitives as NodePrimitives>::Receipt>, Self::Error>
|
) -> Result<BlockExecutionResult<<Self::Primitives as NodePrimitives>::Receipt>, Self::Error>
|
||||||
where
|
where
|
||||||
F: OnStateHook + 'static,
|
H: OnStateHook + 'static,
|
||||||
{
|
{
|
||||||
self.strategy.with_state_hook(Some(Box::new(state_hook)));
|
let mut strategy = self.strategy_factory.create_strategy(&mut self.db, block);
|
||||||
let result = self.execute_one(block);
|
strategy.with_state_hook(Some(Box::new(state_hook)));
|
||||||
self.strategy.with_state_hook(None);
|
|
||||||
|
|
||||||
result
|
strategy.apply_pre_execution_changes()?;
|
||||||
|
strategy.execute_transactions(block.transactions_recovered())?;
|
||||||
|
let result = strategy.apply_post_execution_changes()?;
|
||||||
|
|
||||||
|
self.db.merge_transitions(BundleRetention::Reverts);
|
||||||
|
|
||||||
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn into_state(self) -> State<DB> {
|
fn into_state(self) -> State<DB> {
|
||||||
self.strategy.into_state()
|
self.db
|
||||||
}
|
}
|
||||||
|
|
||||||
fn size_hint(&self) -> usize {
|
fn size_hint(&self) -> usize {
|
||||||
self.strategy.state_ref().bundle_state.size_hint()
|
self.db.bundle_state.size_hint()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -374,17 +354,14 @@ where
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use alloy_primitives::U256;
|
use alloy_consensus::constants::KECCAK_EMPTY;
|
||||||
|
use alloy_eips::eip7685::Requests;
|
||||||
|
use alloy_primitives::{address, bytes, U256};
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
use reth_chainspec::{ChainSpec, MAINNET};
|
use reth_ethereum_primitives::TransactionSigned;
|
||||||
use reth_primitives::EthPrimitives;
|
use reth_primitives::EthPrimitives;
|
||||||
use revm::{
|
use revm::state::AccountInfo;
|
||||||
database_interface::EmptyDBTyped,
|
use revm_database::{CacheDB, EmptyDBTyped};
|
||||||
primitives::{address, bytes, KECCAK_EMPTY},
|
|
||||||
state::AccountInfo,
|
|
||||||
};
|
|
||||||
use revm_database::CacheDB;
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
#[derive(Clone, Default)]
|
#[derive(Clone, Default)]
|
||||||
struct TestExecutorProvider;
|
struct TestExecutorProvider;
|
||||||
@ -435,94 +412,55 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TestExecutorStrategy<DB, EvmConfig> {
|
struct TestExecutorStrategy {
|
||||||
// chain spec and evm config here only to illustrate how the strategy
|
result: BlockExecutionResult<Receipt>,
|
||||||
// factory can use them in a real use case.
|
|
||||||
_chain_spec: Arc<ChainSpec>,
|
|
||||||
_evm_config: EvmConfig,
|
|
||||||
state: State<DB>,
|
|
||||||
execute_transactions_result: ExecuteOutput<Receipt>,
|
|
||||||
apply_post_execution_changes_result: Requests,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct TestExecutorStrategyFactory {
|
struct TestExecutorStrategyFactory {
|
||||||
execute_transactions_result: ExecuteOutput<Receipt>,
|
result: BlockExecutionResult<Receipt>,
|
||||||
apply_post_execution_changes_result: Requests,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BlockExecutionStrategyFactory for TestExecutorStrategyFactory {
|
impl BlockExecutionStrategyFactory for TestExecutorStrategyFactory {
|
||||||
type Primitives = EthPrimitives;
|
type Primitives = EthPrimitives;
|
||||||
type Strategy<DB: Database> = TestExecutorStrategy<DB, TestEvmConfig>;
|
|
||||||
|
|
||||||
fn create_strategy<DB>(&self, db: DB) -> Self::Strategy<DB>
|
fn create_strategy<'a, DB>(
|
||||||
|
&'a mut self,
|
||||||
|
_db: &'a mut State<DB>,
|
||||||
|
_block: &'a RecoveredBlock<<Self::Primitives as NodePrimitives>::Block>,
|
||||||
|
) -> impl BlockExecutionStrategy<Primitives = Self::Primitives, Error = BlockExecutionError> + 'a
|
||||||
where
|
where
|
||||||
DB: Database,
|
DB: Database,
|
||||||
{
|
{
|
||||||
let state = State::builder()
|
TestExecutorStrategy { result: self.result.clone() }
|
||||||
.with_database(db)
|
|
||||||
.with_bundle_update()
|
|
||||||
.without_state_clear()
|
|
||||||
.build();
|
|
||||||
|
|
||||||
TestExecutorStrategy {
|
|
||||||
_chain_spec: MAINNET.clone(),
|
|
||||||
_evm_config: TestEvmConfig {},
|
|
||||||
execute_transactions_result: self.execute_transactions_result.clone(),
|
|
||||||
apply_post_execution_changes_result: self
|
|
||||||
.apply_post_execution_changes_result
|
|
||||||
.clone(),
|
|
||||||
state,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<DB> BlockExecutionStrategy for TestExecutorStrategy<DB, TestEvmConfig>
|
impl BlockExecutionStrategy for TestExecutorStrategy {
|
||||||
where
|
|
||||||
DB: Database,
|
|
||||||
{
|
|
||||||
type DB = DB;
|
|
||||||
type Primitives = EthPrimitives;
|
type Primitives = EthPrimitives;
|
||||||
type Error = BlockExecutionError;
|
type Error = BlockExecutionError;
|
||||||
|
|
||||||
fn apply_pre_execution_changes(
|
fn apply_pre_execution_changes(&mut self) -> Result<(), Self::Error> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn execute_transactions<'a>(
|
||||||
&mut self,
|
&mut self,
|
||||||
_block: &RecoveredBlock<reth_primitives::Block>,
|
_transactions: impl IntoIterator<Item = Recovered<&'a TransactionSigned>>,
|
||||||
) -> Result<(), Self::Error> {
|
) -> Result<(), Self::Error> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn execute_transactions(
|
|
||||||
&mut self,
|
|
||||||
_block: &RecoveredBlock<reth_primitives::Block>,
|
|
||||||
) -> Result<ExecuteOutput<Receipt>, Self::Error> {
|
|
||||||
Ok(self.execute_transactions_result.clone())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn apply_post_execution_changes(
|
fn apply_post_execution_changes(
|
||||||
&mut self,
|
self,
|
||||||
_block: &RecoveredBlock<reth_primitives::Block>,
|
) -> Result<BlockExecutionResult<<Self::Primitives as NodePrimitives>::Receipt>, Self::Error>
|
||||||
_receipts: &[Receipt],
|
{
|
||||||
) -> Result<Requests, Self::Error> {
|
Ok(self.result)
|
||||||
Ok(self.apply_post_execution_changes_result.clone())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn state_ref(&self) -> &State<DB> {
|
fn with_state_hook(&mut self, _hook: Option<Box<dyn OnStateHook>>) {}
|
||||||
&self.state
|
|
||||||
}
|
|
||||||
|
|
||||||
fn state_mut(&mut self) -> &mut State<DB> {
|
|
||||||
&mut self.state
|
|
||||||
}
|
|
||||||
|
|
||||||
fn into_state(self) -> State<Self::DB> {
|
|
||||||
self.state
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
struct TestEvmConfig {}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_provider() {
|
fn test_provider() {
|
||||||
let provider = TestExecutorProvider;
|
let provider = TestExecutorProvider;
|
||||||
@ -533,19 +471,13 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_strategy() {
|
fn test_strategy() {
|
||||||
let expected_gas_used = 10;
|
let expected_result = BlockExecutionResult {
|
||||||
let expected_receipts = vec![Receipt::default()];
|
receipts: vec![Receipt::default()],
|
||||||
let expected_execute_transactions_result = ExecuteOutput::<Receipt> {
|
gas_used: 10,
|
||||||
receipts: expected_receipts.clone(),
|
requests: Requests::new(vec![bytes!("deadbeef")]),
|
||||||
gas_used: expected_gas_used,
|
|
||||||
};
|
};
|
||||||
let expected_apply_post_execution_changes_result = Requests::new(vec![bytes!("deadbeef")]);
|
|
||||||
|
|
||||||
let strategy_factory = TestExecutorStrategyFactory {
|
let strategy_factory = TestExecutorStrategyFactory { result: expected_result.clone() };
|
||||||
execute_transactions_result: expected_execute_transactions_result,
|
|
||||||
apply_post_execution_changes_result: expected_apply_post_execution_changes_result
|
|
||||||
.clone(),
|
|
||||||
};
|
|
||||||
let provider = BasicBlockExecutorProvider::new(strategy_factory);
|
let provider = BasicBlockExecutorProvider::new(strategy_factory);
|
||||||
let db = CacheDB::<EmptyDBTyped<ProviderError>>::default();
|
let db = CacheDB::<EmptyDBTyped<ProviderError>>::default();
|
||||||
let executor = provider.executor(db);
|
let executor = provider.executor(db);
|
||||||
@ -553,9 +485,7 @@ mod tests {
|
|||||||
|
|
||||||
assert!(result.is_ok());
|
assert!(result.is_ok());
|
||||||
let block_execution_output = result.unwrap();
|
let block_execution_output = result.unwrap();
|
||||||
assert_eq!(block_execution_output.gas_used, expected_gas_used);
|
assert_eq!(block_execution_output.result, expected_result);
|
||||||
assert_eq!(block_execution_output.receipts, expected_receipts);
|
|
||||||
assert_eq!(block_execution_output.requests, expected_apply_post_execution_changes_result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup_state_with_account(
|
fn setup_state_with_account(
|
||||||
|
|||||||
@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
|
use alloc::borrow::Borrow;
|
||||||
use alloy_consensus::transaction::Recovered;
|
use alloy_consensus::transaction::Recovered;
|
||||||
use alloy_eips::eip2930::AccessList;
|
use alloy_eips::eip2930::AccessList;
|
||||||
pub use alloy_evm::evm::EvmFactory;
|
pub use alloy_evm::evm::EvmFactory;
|
||||||
@ -182,13 +183,10 @@ pub trait ConfigureEvmEnv: Send + Sync + Unpin + Clone + 'static {
|
|||||||
type Spec: Debug + Copy + Send + Sync + 'static;
|
type Spec: Debug + Copy + Send + Sync + 'static;
|
||||||
|
|
||||||
/// Returns a [`TxEnv`] from a transaction and [`Address`].
|
/// Returns a [`TxEnv`] from a transaction and [`Address`].
|
||||||
fn tx_env(&self, transaction: &Self::Transaction, signer: Address) -> Self::TxEnv;
|
fn tx_env<T: Borrow<Self::Transaction>>(
|
||||||
|
&self,
|
||||||
/// Returns a [`TxEnv`] from a [`Recovered`] transaction.
|
transaction: impl Borrow<Recovered<T>>,
|
||||||
fn tx_env_from_recovered(&self, tx: Recovered<&Self::Transaction>) -> Self::TxEnv {
|
) -> Self::TxEnv;
|
||||||
let (tx, address) = tx.into_parts();
|
|
||||||
self.tx_env(tx, address)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a new [`EvmEnv`] for the given header.
|
/// Creates a new [`EvmEnv`] for the given header.
|
||||||
fn evm_env(&self, header: &Self::Header) -> EvmEnv<Self::Spec>;
|
fn evm_env(&self, header: &Self::Header) -> EvmEnv<Self::Spec>;
|
||||||
|
|||||||
@ -77,10 +77,11 @@ impl OnStateHook for NoopHook {
|
|||||||
/// An ephemeral helper type for executing system calls.
|
/// An ephemeral helper type for executing system calls.
|
||||||
///
|
///
|
||||||
/// This can be used to chain system transaction calls.
|
/// This can be used to chain system transaction calls.
|
||||||
#[allow(missing_debug_implementations)]
|
#[derive(derive_more::Debug)]
|
||||||
pub struct SystemCaller<ChainSpec> {
|
pub struct SystemCaller<ChainSpec> {
|
||||||
chain_spec: ChainSpec,
|
chain_spec: ChainSpec,
|
||||||
/// Optional hook to be called after each state change.
|
/// Optional hook to be called after each state change.
|
||||||
|
#[debug(skip)]
|
||||||
hook: Option<Box<dyn OnStateHook>>,
|
hook: Option<Box<dyn OnStateHook>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,7 +150,7 @@ where
|
|||||||
eip2935::transact_blockhashes_contract_call(&self.chain_spec, parent_block_hash, evm)?;
|
eip2935::transact_blockhashes_contract_call(&self.chain_spec, parent_block_hash, evm)?;
|
||||||
|
|
||||||
if let Some(res) = result_and_state {
|
if let Some(res) = result_and_state {
|
||||||
if let Some(ref mut hook) = self.hook {
|
if let Some(hook) = &mut self.hook {
|
||||||
hook.on_state(
|
hook.on_state(
|
||||||
StateChangeSource::PreBlock(StateChangePreBlockSource::BlockHashesContract),
|
StateChangeSource::PreBlock(StateChangePreBlockSource::BlockHashesContract),
|
||||||
&res.state,
|
&res.state,
|
||||||
@ -174,7 +175,7 @@ where
|
|||||||
)?;
|
)?;
|
||||||
|
|
||||||
if let Some(res) = result_and_state {
|
if let Some(res) = result_and_state {
|
||||||
if let Some(ref mut hook) = self.hook {
|
if let Some(hook) = &mut self.hook {
|
||||||
hook.on_state(
|
hook.on_state(
|
||||||
StateChangeSource::PreBlock(StateChangePreBlockSource::BeaconRootContract),
|
StateChangeSource::PreBlock(StateChangePreBlockSource::BeaconRootContract),
|
||||||
&res.state,
|
&res.state,
|
||||||
@ -193,7 +194,7 @@ where
|
|||||||
) -> Result<Bytes, BlockExecutionError> {
|
) -> Result<Bytes, BlockExecutionError> {
|
||||||
let result_and_state = eip7002::transact_withdrawal_requests_contract_call(evm)?;
|
let result_and_state = eip7002::transact_withdrawal_requests_contract_call(evm)?;
|
||||||
|
|
||||||
if let Some(ref mut hook) = self.hook {
|
if let Some(ref mut hook) = &mut self.hook {
|
||||||
hook.on_state(
|
hook.on_state(
|
||||||
StateChangeSource::PostBlock(
|
StateChangeSource::PostBlock(
|
||||||
StateChangePostBlockSource::WithdrawalRequestsContract,
|
StateChangePostBlockSource::WithdrawalRequestsContract,
|
||||||
@ -213,7 +214,7 @@ where
|
|||||||
) -> Result<Bytes, BlockExecutionError> {
|
) -> Result<Bytes, BlockExecutionError> {
|
||||||
let result_and_state = eip7251::transact_consolidation_requests_contract_call(evm)?;
|
let result_and_state = eip7251::transact_consolidation_requests_contract_call(evm)?;
|
||||||
|
|
||||||
if let Some(ref mut hook) = self.hook {
|
if let Some(ref mut hook) = &mut self.hook {
|
||||||
hook.on_state(
|
hook.on_state(
|
||||||
StateChangeSource::PostBlock(
|
StateChangeSource::PostBlock(
|
||||||
StateChangePostBlockSource::ConsolidationRequestsContract,
|
StateChangePostBlockSource::ConsolidationRequestsContract,
|
||||||
@ -228,7 +229,7 @@ where
|
|||||||
|
|
||||||
/// Delegate to stored `OnStateHook`, noop if hook is `None`.
|
/// Delegate to stored `OnStateHook`, noop if hook is `None`.
|
||||||
pub fn on_state(&mut self, source: StateChangeSource, state: &EvmState) {
|
pub fn on_state(&mut self, source: StateChangeSource, state: &EvmState) {
|
||||||
if let Some(ref mut hook) = &mut self.hook {
|
if let Some(hook) = &mut self.hook {
|
||||||
hook.on_state(source, state);
|
hook.on_state(source, state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,10 +1,7 @@
|
|||||||
//! Helpers for testing.
|
//! Helpers for testing.
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
execute::{
|
execute::{BasicBlockExecutor, BlockExecutionOutput, BlockExecutorProvider, Executor},
|
||||||
BasicBlockExecutor, BlockExecutionOutput, BlockExecutionStrategy, BlockExecutorProvider,
|
|
||||||
Executor,
|
|
||||||
},
|
|
||||||
system_calls::OnStateHook,
|
system_calls::OnStateHook,
|
||||||
Database,
|
Database,
|
||||||
};
|
};
|
||||||
@ -125,23 +122,20 @@ impl<DB: Database> Executor<DB> for MockExecutorProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S> BasicBlockExecutor<S>
|
impl<Factory, DB> BasicBlockExecutor<Factory, DB> {
|
||||||
where
|
|
||||||
S: BlockExecutionStrategy,
|
|
||||||
{
|
|
||||||
/// Provides safe read access to the state
|
/// Provides safe read access to the state
|
||||||
pub fn with_state<F, R>(&self, f: F) -> R
|
pub fn with_state<F, R>(&self, f: F) -> R
|
||||||
where
|
where
|
||||||
F: FnOnce(&State<S::DB>) -> R,
|
F: FnOnce(&State<DB>) -> R,
|
||||||
{
|
{
|
||||||
f(self.strategy.state_ref())
|
f(&self.db)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Provides safe write access to the state
|
/// Provides safe write access to the state
|
||||||
pub fn with_state_mut<F, R>(&mut self, f: F) -> R
|
pub fn with_state_mut<F, R>(&mut self, f: F) -> R
|
||||||
where
|
where
|
||||||
F: FnOnce(&mut State<S::DB>) -> R,
|
F: FnOnce(&mut State<DB>) -> R,
|
||||||
{
|
{
|
||||||
f(self.strategy.state_mut())
|
f(&mut self.db)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,24 +5,24 @@ use crate::{
|
|||||||
OpReceiptBuilder, ReceiptBuilderCtx,
|
OpReceiptBuilder, ReceiptBuilderCtx,
|
||||||
};
|
};
|
||||||
use alloc::{boxed::Box, sync::Arc, vec::Vec};
|
use alloc::{boxed::Box, sync::Arc, vec::Vec};
|
||||||
use alloy_consensus::{BlockHeader, Eip658Value, Receipt, Transaction as _};
|
use alloy_consensus::{
|
||||||
use alloy_eips::eip7685::Requests;
|
transaction::Recovered, BlockHeader, Eip658Value, Receipt, Transaction as _, TxReceipt,
|
||||||
|
};
|
||||||
use op_alloy_consensus::OpDepositReceipt;
|
use op_alloy_consensus::OpDepositReceipt;
|
||||||
use reth_consensus::ConsensusError;
|
|
||||||
use reth_evm::{
|
use reth_evm::{
|
||||||
execute::{
|
execute::{
|
||||||
balance_increment_state, BasicBlockExecutorProvider, BlockExecutionError,
|
balance_increment_state, BasicBlockExecutorProvider, BlockExecutionError,
|
||||||
BlockExecutionStrategy, BlockExecutionStrategyFactory, BlockValidationError, ExecuteOutput,
|
BlockExecutionStrategy, BlockExecutionStrategyFactory, BlockValidationError,
|
||||||
},
|
},
|
||||||
state_change::post_block_balance_increments,
|
state_change::post_block_balance_increments,
|
||||||
system_calls::{OnStateHook, StateChangePostBlockSource, StateChangeSource, SystemCaller},
|
system_calls::{OnStateHook, StateChangePostBlockSource, StateChangeSource, SystemCaller},
|
||||||
ConfigureEvm, ConfigureEvmFor, Database, Evm, HaltReasonFor,
|
ConfigureEvm, ConfigureEvmFor, Database, Evm, HaltReasonFor,
|
||||||
};
|
};
|
||||||
|
use reth_execution_types::BlockExecutionResult;
|
||||||
use reth_optimism_chainspec::OpChainSpec;
|
use reth_optimism_chainspec::OpChainSpec;
|
||||||
use reth_optimism_consensus::validate_block_post_execution;
|
|
||||||
use reth_optimism_forks::OpHardforks;
|
use reth_optimism_forks::OpHardforks;
|
||||||
use reth_optimism_primitives::{transaction::signed::OpTransaction, DepositReceipt, OpPrimitives};
|
use reth_optimism_primitives::{transaction::signed::OpTransaction, DepositReceipt, OpPrimitives};
|
||||||
use reth_primitives_traits::{BlockBody, NodePrimitives, RecoveredBlock, SignedTransaction};
|
use reth_primitives_traits::{NodePrimitives, RecoveredBlock, SealedBlock, SignedTransaction};
|
||||||
use revm::{context_interface::result::ResultAndState, DatabaseCommit};
|
use revm::{context_interface::result::ResultAndState, DatabaseCommit};
|
||||||
use revm_database::State;
|
use revm_database::State;
|
||||||
use tracing::trace;
|
use tracing::trace;
|
||||||
@ -79,43 +79,38 @@ where
|
|||||||
EvmConfig: ConfigureEvmFor<N> + Clone + Unpin + Sync + Send + 'static,
|
EvmConfig: ConfigureEvmFor<N> + Clone + Unpin + Sync + Send + 'static,
|
||||||
{
|
{
|
||||||
type Primitives = N;
|
type Primitives = N;
|
||||||
type Strategy<DB: Database> = OpExecutionStrategy<DB, N, ChainSpec, EvmConfig>;
|
|
||||||
|
|
||||||
fn create_strategy<DB>(&self, db: DB) -> Self::Strategy<DB>
|
fn create_strategy<'a, DB>(
|
||||||
|
&'a mut self,
|
||||||
|
db: &'a mut State<DB>,
|
||||||
|
block: &'a RecoveredBlock<<Self::Primitives as NodePrimitives>::Block>,
|
||||||
|
) -> impl BlockExecutionStrategy<Primitives = Self::Primitives, Error = BlockExecutionError> + 'a
|
||||||
where
|
where
|
||||||
DB: Database,
|
DB: Database,
|
||||||
{
|
{
|
||||||
let state =
|
let evm = self.evm_config.evm_for_block(db, block.header());
|
||||||
State::builder().with_database(db).with_bundle_update().without_state_clear().build();
|
OpExecutionStrategy::new(evm, block.sealed_block(), self)
|
||||||
OpExecutionStrategy::new(
|
|
||||||
state,
|
|
||||||
self.chain_spec.clone(),
|
|
||||||
self.evm_config.clone(),
|
|
||||||
self.receipt_builder.clone(),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Block execution strategy for Optimism.
|
/// Block execution strategy for Optimism.
|
||||||
#[allow(missing_debug_implementations)]
|
#[derive(Debug, derive_more::Deref)]
|
||||||
pub struct OpExecutionStrategy<DB, N: NodePrimitives, ChainSpec, EvmConfig>
|
pub struct OpExecutionStrategy<'a, Evm, N: NodePrimitives, ChainSpec, EvmConfig: ConfigureEvm> {
|
||||||
where
|
/// Reference to the parent factory.
|
||||||
EvmConfig: ConfigureEvm,
|
#[deref]
|
||||||
{
|
factory: &'a OpExecutionStrategyFactory<N, ChainSpec, EvmConfig>,
|
||||||
/// The chainspec
|
|
||||||
chain_spec: Arc<ChainSpec>,
|
/// Block being executed.
|
||||||
/// How to create an EVM.
|
block: &'a SealedBlock<N::Block>,
|
||||||
evm_config: EvmConfig,
|
/// The EVM used by strategy.
|
||||||
/// Current state for block execution.
|
evm: Evm,
|
||||||
state: State<DB>,
|
/// Receipts of executed transactions.
|
||||||
|
receipts: Vec<N::Receipt>,
|
||||||
/// Utility to call system smart contracts.
|
/// Utility to call system smart contracts.
|
||||||
system_caller: SystemCaller<Arc<ChainSpec>>,
|
system_caller: SystemCaller<&'a ChainSpec>,
|
||||||
/// Receipt builder.
|
|
||||||
receipt_builder:
|
|
||||||
Arc<dyn OpReceiptBuilder<N::SignedTx, HaltReasonFor<EvmConfig>, Receipt = N::Receipt>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<DB, N, ChainSpec, EvmConfig> OpExecutionStrategy<DB, N, ChainSpec, EvmConfig>
|
impl<'a, Evm, N, ChainSpec, EvmConfig> OpExecutionStrategy<'a, Evm, N, ChainSpec, EvmConfig>
|
||||||
where
|
where
|
||||||
N: NodePrimitives,
|
N: NodePrimitives,
|
||||||
ChainSpec: OpHardforks,
|
ChainSpec: OpHardforks,
|
||||||
@ -123,73 +118,67 @@ where
|
|||||||
{
|
{
|
||||||
/// Creates a new [`OpExecutionStrategy`]
|
/// Creates a new [`OpExecutionStrategy`]
|
||||||
pub fn new(
|
pub fn new(
|
||||||
state: State<DB>,
|
evm: Evm,
|
||||||
chain_spec: Arc<ChainSpec>,
|
block: &'a SealedBlock<N::Block>,
|
||||||
evm_config: EvmConfig,
|
factory: &'a OpExecutionStrategyFactory<N, ChainSpec, EvmConfig>,
|
||||||
receipt_builder: Arc<
|
|
||||||
dyn OpReceiptBuilder<N::SignedTx, HaltReasonFor<EvmConfig>, Receipt = N::Receipt>,
|
|
||||||
>,
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let system_caller = SystemCaller::new(chain_spec.clone());
|
Self {
|
||||||
Self { state, chain_spec, evm_config, system_caller, receipt_builder }
|
evm,
|
||||||
|
factory,
|
||||||
|
block,
|
||||||
|
receipts: Vec::new(),
|
||||||
|
system_caller: SystemCaller::new(&factory.chain_spec),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<DB, N, ChainSpec, EvmConfig> BlockExecutionStrategy
|
impl<'db, DB, E, N, ChainSpec, EvmConfig> BlockExecutionStrategy
|
||||||
for OpExecutionStrategy<DB, N, ChainSpec, EvmConfig>
|
for OpExecutionStrategy<'_, E, N, ChainSpec, EvmConfig>
|
||||||
where
|
where
|
||||||
DB: Database,
|
DB: Database + 'db,
|
||||||
|
E: Evm<DB = &'db mut State<DB>, Tx = EvmConfig::TxEnv, HaltReason = HaltReasonFor<EvmConfig>>,
|
||||||
N: NodePrimitives<SignedTx: OpTransaction, Receipt: DepositReceipt>,
|
N: NodePrimitives<SignedTx: OpTransaction, Receipt: DepositReceipt>,
|
||||||
ChainSpec: OpHardforks,
|
ChainSpec: OpHardforks,
|
||||||
EvmConfig: ConfigureEvmFor<N>,
|
EvmConfig: ConfigureEvmFor<N>,
|
||||||
{
|
{
|
||||||
type DB = DB;
|
|
||||||
type Primitives = N;
|
type Primitives = N;
|
||||||
type Error = BlockExecutionError;
|
type Error = BlockExecutionError;
|
||||||
|
|
||||||
fn apply_pre_execution_changes(
|
fn apply_pre_execution_changes(&mut self) -> Result<(), Self::Error> {
|
||||||
&mut self,
|
|
||||||
block: &RecoveredBlock<N::Block>,
|
|
||||||
) -> Result<(), Self::Error> {
|
|
||||||
// Set state clear flag if the block is after the Spurious Dragon hardfork.
|
// Set state clear flag if the block is after the Spurious Dragon hardfork.
|
||||||
let state_clear_flag =
|
let state_clear_flag =
|
||||||
(*self.chain_spec).is_spurious_dragon_active_at_block(block.number());
|
(*self.chain_spec).is_spurious_dragon_active_at_block(self.block.number());
|
||||||
self.state.set_state_clear_flag(state_clear_flag);
|
self.evm.db_mut().set_state_clear_flag(state_clear_flag);
|
||||||
|
|
||||||
let mut evm = self.evm_config.evm_for_block(&mut self.state, block.header());
|
self.system_caller.apply_beacon_root_contract_call(
|
||||||
|
self.block.parent_beacon_block_root(),
|
||||||
self.system_caller
|
&mut self.evm,
|
||||||
.apply_beacon_root_contract_call(block.header().parent_beacon_block_root(), &mut evm)?;
|
)?;
|
||||||
|
|
||||||
// Ensure that the create2deployer is force-deployed at the canyon transition. Optimism
|
// Ensure that the create2deployer is force-deployed at the canyon transition. Optimism
|
||||||
// blocks will always have at least a single transaction in them (the L1 info transaction),
|
// blocks will always have at least a single transaction in them (the L1 info transaction),
|
||||||
// so we can safely assume that this will always be triggered upon the transition and that
|
// so we can safely assume that this will always be triggered upon the transition and that
|
||||||
// the above check for empty blocks will never be hit on OP chains.
|
// the above check for empty blocks will never be hit on OP chains.
|
||||||
ensure_create2_deployer(self.chain_spec.clone(), block.header().timestamp(), evm.db_mut())
|
ensure_create2_deployer(self.chain_spec.clone(), self.block.timestamp(), self.evm.db_mut())
|
||||||
.map_err(|_| OpBlockExecutionError::ForceCreate2DeployerFail)?;
|
.map_err(|_| OpBlockExecutionError::ForceCreate2DeployerFail)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn execute_transactions(
|
fn execute_transactions<'a>(
|
||||||
&mut self,
|
&mut self,
|
||||||
block: &RecoveredBlock<N::Block>,
|
transactions: impl IntoIterator<Item = Recovered<&'a N::SignedTx>>,
|
||||||
) -> Result<ExecuteOutput<N::Receipt>, Self::Error> {
|
) -> Result<(), Self::Error> {
|
||||||
let mut evm = self.evm_config.evm_for_block(&mut self.state, block.header());
|
let is_regolith = self.chain_spec.is_regolith_active_at_timestamp(self.block.timestamp());
|
||||||
|
|
||||||
let is_regolith = self.chain_spec.is_regolith_active_at_timestamp(block.timestamp());
|
|
||||||
|
|
||||||
let mut cumulative_gas_used = 0;
|
let mut cumulative_gas_used = 0;
|
||||||
let mut receipts = Vec::with_capacity(block.body().transaction_count());
|
for (tx_index, tx) in transactions.into_iter().enumerate() {
|
||||||
for (tx_index, (sender, transaction)) in block.transactions_with_sender().enumerate() {
|
|
||||||
// The sum of the transaction’s gas limit, Tg, and the gas utilized in this block prior,
|
// The sum of the transaction’s gas limit, Tg, and the gas utilized in this block prior,
|
||||||
// must be no greater than the block’s gasLimit.
|
// must be no greater than the block’s gasLimit.
|
||||||
let block_available_gas = block.gas_limit() - cumulative_gas_used;
|
let block_available_gas = self.block.gas_limit() - cumulative_gas_used;
|
||||||
if transaction.gas_limit() > block_available_gas &&
|
if tx.gas_limit() > block_available_gas && (is_regolith || !tx.is_deposit()) {
|
||||||
(is_regolith || !transaction.is_deposit())
|
|
||||||
{
|
|
||||||
return Err(BlockValidationError::TransactionGasLimitMoreThanAvailableBlockGas {
|
return Err(BlockValidationError::TransactionGasLimitMoreThanAvailableBlockGas {
|
||||||
transaction_gas_limit: transaction.gas_limit(),
|
transaction_gas_limit: tx.gas_limit(),
|
||||||
block_available_gas,
|
block_available_gas,
|
||||||
}
|
}
|
||||||
.into())
|
.into())
|
||||||
@ -200,42 +189,41 @@ where
|
|||||||
// Note that this *only* needs to be done post-regolith hardfork, as deposit nonces
|
// Note that this *only* needs to be done post-regolith hardfork, as deposit nonces
|
||||||
// were not introduced in Bedrock. In addition, regular transactions don't have deposit
|
// were not introduced in Bedrock. In addition, regular transactions don't have deposit
|
||||||
// nonces, so we don't need to touch the DB for those.
|
// nonces, so we don't need to touch the DB for those.
|
||||||
let depositor = (is_regolith && transaction.is_deposit())
|
let depositor = (is_regolith && tx.is_deposit())
|
||||||
.then(|| {
|
.then(|| {
|
||||||
evm.db_mut()
|
self.evm
|
||||||
.load_cache_account(*sender)
|
.db_mut()
|
||||||
|
.load_cache_account(tx.signer())
|
||||||
.map(|acc| acc.account_info().unwrap_or_default())
|
.map(|acc| acc.account_info().unwrap_or_default())
|
||||||
})
|
})
|
||||||
.transpose()
|
.transpose()
|
||||||
.map_err(|_| OpBlockExecutionError::AccountLoadFailed(*sender))?;
|
.map_err(|_| OpBlockExecutionError::AccountLoadFailed(tx.signer()))?;
|
||||||
|
|
||||||
let tx_env = self.evm_config.tx_env(transaction, *sender);
|
let tx_env = self.evm_config.tx_env(&tx);
|
||||||
|
let hash = tx.tx_hash();
|
||||||
|
|
||||||
// Execute transaction.
|
// Execute transaction.
|
||||||
let result_and_state = evm.transact(tx_env).map_err(move |err| {
|
let result_and_state = self.evm.transact(tx_env).map_err(move |err| {
|
||||||
// Ensure hash is calculated for error log, if not already done
|
// Ensure hash is calculated for error log, if not already done
|
||||||
BlockValidationError::EVM {
|
BlockValidationError::EVM { hash: *hash, error: Box::new(err) }
|
||||||
hash: transaction.recalculate_hash(),
|
|
||||||
error: Box::new(err),
|
|
||||||
}
|
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
trace!(
|
trace!(
|
||||||
target: "evm",
|
target: "evm",
|
||||||
?transaction,
|
?tx,
|
||||||
"Executed transaction"
|
"Executed transaction"
|
||||||
);
|
);
|
||||||
self.system_caller
|
self.system_caller
|
||||||
.on_state(StateChangeSource::Transaction(tx_index), &result_and_state.state);
|
.on_state(StateChangeSource::Transaction(tx_index), &result_and_state.state);
|
||||||
let ResultAndState { result, state } = result_and_state;
|
let ResultAndState { result, state } = result_and_state;
|
||||||
evm.db_mut().commit(state);
|
self.evm.db_mut().commit(state);
|
||||||
|
|
||||||
// append gas used
|
// append gas used
|
||||||
cumulative_gas_used += result.gas_used();
|
cumulative_gas_used += result.gas_used();
|
||||||
|
|
||||||
receipts.push(
|
self.receipts.push(
|
||||||
match self.receipt_builder.build_receipt(ReceiptBuilderCtx {
|
match self.receipt_builder.build_receipt(ReceiptBuilderCtx {
|
||||||
tx: transaction,
|
tx: tx.tx(),
|
||||||
result,
|
result,
|
||||||
cumulative_gas_used,
|
cumulative_gas_used,
|
||||||
}) {
|
}) {
|
||||||
@ -257,9 +245,9 @@ where
|
|||||||
// when set. The state transition process ensures
|
// when set. The state transition process ensures
|
||||||
// this is only set for post-Canyon deposit
|
// this is only set for post-Canyon deposit
|
||||||
// transactions.
|
// transactions.
|
||||||
deposit_receipt_version: (transaction.is_deposit() &&
|
deposit_receipt_version: (tx.is_deposit() &&
|
||||||
self.chain_spec
|
self.chain_spec
|
||||||
.is_canyon_active_at_timestamp(block.timestamp()))
|
.is_canyon_active_at_timestamp(self.block.timestamp()))
|
||||||
.then_some(1),
|
.then_some(1),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -267,53 +255,33 @@ where
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(ExecuteOutput { receipts, gas_used: cumulative_gas_used })
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_post_execution_changes(
|
fn apply_post_execution_changes(
|
||||||
&mut self,
|
mut self,
|
||||||
block: &RecoveredBlock<N::Block>,
|
) -> Result<BlockExecutionResult<N::Receipt>, Self::Error> {
|
||||||
_receipts: &[N::Receipt],
|
let balance_increments =
|
||||||
) -> Result<Requests, Self::Error> {
|
post_block_balance_increments(&self.chain_spec.clone(), self.block);
|
||||||
let balance_increments = post_block_balance_increments(&self.chain_spec.clone(), block);
|
|
||||||
// increment balances
|
// increment balances
|
||||||
self.state
|
self.evm
|
||||||
|
.db_mut()
|
||||||
.increment_balances(balance_increments.clone())
|
.increment_balances(balance_increments.clone())
|
||||||
.map_err(|_| BlockValidationError::IncrementBalanceFailed)?;
|
.map_err(|_| BlockValidationError::IncrementBalanceFailed)?;
|
||||||
// call state hook with changes due to balance increments.
|
// call state hook with changes due to balance increments.
|
||||||
let balance_state = balance_increment_state(&balance_increments, &mut self.state)?;
|
let balance_state = balance_increment_state(&balance_increments, self.evm.db_mut())?;
|
||||||
self.system_caller.on_state(
|
self.system_caller.on_state(
|
||||||
StateChangeSource::PostBlock(StateChangePostBlockSource::BalanceIncrements),
|
StateChangeSource::PostBlock(StateChangePostBlockSource::BalanceIncrements),
|
||||||
&balance_state,
|
&balance_state,
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(Requests::default())
|
let gas_used = self.receipts.last().map(|r| r.cumulative_gas_used()).unwrap_or_default();
|
||||||
}
|
Ok(BlockExecutionResult { receipts: self.receipts, requests: Default::default(), gas_used })
|
||||||
|
|
||||||
fn state_ref(&self) -> &State<DB> {
|
|
||||||
&self.state
|
|
||||||
}
|
|
||||||
|
|
||||||
fn state_mut(&mut self) -> &mut State<DB> {
|
|
||||||
&mut self.state
|
|
||||||
}
|
|
||||||
|
|
||||||
fn into_state(self) -> revm_database::State<Self::DB> {
|
|
||||||
self.state
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_state_hook(&mut self, hook: Option<Box<dyn OnStateHook>>) {
|
fn with_state_hook(&mut self, hook: Option<Box<dyn OnStateHook>>) {
|
||||||
self.system_caller.with_state_hook(hook);
|
self.system_caller.with_state_hook(hook);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_block_post_execution(
|
|
||||||
&self,
|
|
||||||
block: &RecoveredBlock<N::Block>,
|
|
||||||
receipts: &[N::Receipt],
|
|
||||||
_requests: &Requests,
|
|
||||||
) -> Result<(), ConsensusError> {
|
|
||||||
validate_block_post_execution(block.header(), self.chain_spec.clone(), receipts)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper type with backwards compatible methods to obtain executor providers.
|
/// Helper type with backwards compatible methods to obtain executor providers.
|
||||||
|
|||||||
@ -11,10 +11,10 @@
|
|||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
use alloc::sync::Arc;
|
use alloc::sync::Arc;
|
||||||
use alloy_consensus::{BlockHeader, Header};
|
use alloy_consensus::{transaction::Recovered, BlockHeader, Header};
|
||||||
use alloy_op_evm::OpEvmFactory;
|
use alloy_op_evm::OpEvmFactory;
|
||||||
use alloy_primitives::{Address, U256};
|
use alloy_primitives::U256;
|
||||||
use core::fmt::Debug;
|
use core::{borrow::Borrow, fmt::Debug};
|
||||||
use op_alloy_consensus::EIP1559ParamError;
|
use op_alloy_consensus::EIP1559ParamError;
|
||||||
use reth_chainspec::EthChainSpec;
|
use reth_chainspec::EthChainSpec;
|
||||||
use reth_evm::{ConfigureEvm, ConfigureEvmEnv, EvmEnv, NextBlockEnvAttributes};
|
use reth_evm::{ConfigureEvm, ConfigureEvmEnv, EvmEnv, NextBlockEnvAttributes};
|
||||||
@ -74,9 +74,14 @@ impl<ChainSpec: EthChainSpec + OpHardforks + 'static> ConfigureEvmEnv for OpEvmC
|
|||||||
type TxEnv = OpTransaction<TxEnv>;
|
type TxEnv = OpTransaction<TxEnv>;
|
||||||
type Spec = OpSpecId;
|
type Spec = OpSpecId;
|
||||||
|
|
||||||
fn tx_env(&self, transaction: &Self::Transaction, signer: Address) -> Self::TxEnv {
|
fn tx_env<T: Borrow<Self::Transaction>>(
|
||||||
|
&self,
|
||||||
|
transaction: impl Borrow<Recovered<T>>,
|
||||||
|
) -> Self::TxEnv {
|
||||||
|
let transaction = transaction.borrow();
|
||||||
|
|
||||||
let mut tx_env = Default::default();
|
let mut tx_env = Default::default();
|
||||||
transaction.fill_tx_env(&mut tx_env, signer);
|
transaction.tx().borrow().fill_tx_env(&mut tx_env, transaction.signer());
|
||||||
tx_env
|
tx_env
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -934,7 +934,7 @@ where
|
|||||||
))
|
))
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let tx_env = self.evm_config.tx_env(sequencer_tx.tx(), sequencer_tx.signer());
|
let tx_env = self.evm_config.tx_env(&sequencer_tx);
|
||||||
|
|
||||||
let ResultAndState { result, state: _ } = match evm.transact_commit(tx_env) {
|
let ResultAndState { result, state: _ } = match evm.transact_commit(tx_env) {
|
||||||
Ok(res) => res,
|
Ok(res) => res,
|
||||||
@ -1011,7 +1011,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Configure the environment for the tx.
|
// Configure the environment for the tx.
|
||||||
let tx_env = self.evm_config.tx_env(tx.tx(), tx.signer());
|
let tx_env = self.evm_config.tx_env(&tx);
|
||||||
|
|
||||||
let ResultAndState { result, state: _ } = match evm.transact_commit(tx_env) {
|
let ResultAndState { result, state: _ } = match evm.transact_commit(tx_env) {
|
||||||
Ok(res) => res,
|
Ok(res) => res,
|
||||||
|
|||||||
@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
use crate::OpEthApi;
|
use crate::OpEthApi;
|
||||||
use alloy_consensus::{
|
use alloy_consensus::{
|
||||||
constants::EMPTY_WITHDRAWALS, proofs::calculate_transaction_root, Eip658Value, Header,
|
constants::EMPTY_WITHDRAWALS, proofs::calculate_transaction_root, transaction::Recovered,
|
||||||
Transaction as _, TxReceipt, EMPTY_OMMER_ROOT_HASH,
|
Eip658Value, Header, Transaction as _, TxReceipt, EMPTY_OMMER_ROOT_HASH,
|
||||||
};
|
};
|
||||||
use alloy_eips::{eip7685::EMPTY_REQUESTS_HASH, merge::BEACON_NONCE, BlockNumberOrTag};
|
use alloy_eips::{eip7685::EMPTY_REQUESTS_HASH, merge::BEACON_NONCE, BlockNumberOrTag};
|
||||||
use alloy_primitives::{B256, U256};
|
use alloy_primitives::{B256, U256};
|
||||||
@ -100,7 +100,7 @@ where
|
|||||||
block_env: &BlockEnv,
|
block_env: &BlockEnv,
|
||||||
parent_hash: B256,
|
parent_hash: B256,
|
||||||
state_root: B256,
|
state_root: B256,
|
||||||
transactions: Vec<ProviderTx<Self::Provider>>,
|
transactions: Vec<Recovered<ProviderTx<Self::Provider>>>,
|
||||||
receipts: &[ProviderReceipt<Self::Provider>],
|
receipts: &[ProviderReceipt<Self::Provider>],
|
||||||
) -> reth_provider::ProviderBlock<Self::Provider> {
|
) -> reth_provider::ProviderBlock<Self::Provider> {
|
||||||
let chain_spec = self.provider().chain_spec();
|
let chain_spec = self.provider().chain_spec();
|
||||||
@ -144,7 +144,11 @@ where
|
|||||||
// seal the block
|
// seal the block
|
||||||
reth_primitives::Block {
|
reth_primitives::Block {
|
||||||
header,
|
header,
|
||||||
body: BlockBody { transactions, ommers: vec![], withdrawals: None },
|
body: BlockBody {
|
||||||
|
transactions: transactions.into_iter().map(|tx| tx.into_tx()).collect(),
|
||||||
|
ommers: vec![],
|
||||||
|
withdrawals: None,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -7,7 +7,7 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use alloy_consensus::BlockHeader;
|
use alloy_consensus::BlockHeader;
|
||||||
use alloy_eips::{eip1559::calc_next_block_base_fee, eip2930::AccessListResult};
|
use alloy_eips::{eip1559::calc_next_block_base_fee, eip2930::AccessListResult};
|
||||||
use alloy_primitives::{Address, Bytes, B256, U256};
|
use alloy_primitives::{Bytes, B256, U256};
|
||||||
use alloy_rpc_types_eth::{
|
use alloy_rpc_types_eth::{
|
||||||
simulate::{SimBlock, SimulatePayload, SimulatedBlock},
|
simulate::{SimBlock, SimulatePayload, SimulatedBlock},
|
||||||
state::{EvmOverrides, StateOverride},
|
state::{EvmOverrides, StateOverride},
|
||||||
@ -22,6 +22,7 @@ use reth_evm::{
|
|||||||
TransactionEnv,
|
TransactionEnv,
|
||||||
};
|
};
|
||||||
use reth_node_api::BlockBody;
|
use reth_node_api::BlockBody;
|
||||||
|
use reth_primitives::Recovered;
|
||||||
use reth_primitives_traits::SignedTransaction;
|
use reth_primitives_traits::SignedTransaction;
|
||||||
use reth_provider::{BlockIdReader, ChainSpecProvider, ProviderHeader};
|
use reth_provider::{BlockIdReader, ChainSpecProvider, ProviderHeader};
|
||||||
use reth_revm::{database::StateProviderDatabase, db::CacheDB, DatabaseRef};
|
use reth_revm::{database::StateProviderDatabase, db::CacheDB, DatabaseRef};
|
||||||
@ -172,8 +173,6 @@ pub trait EthCall: EstimateCall + Call + LoadPendingBlock + LoadBlock + FullEthA
|
|||||||
let mut results = Vec::with_capacity(calls.len());
|
let mut results = Vec::with_capacity(calls.len());
|
||||||
|
|
||||||
while let Some(call) = calls.next() {
|
while let Some(call) = calls.next() {
|
||||||
let sender = call.from.unwrap_or_default();
|
|
||||||
|
|
||||||
// Resolve transaction, populate missing fields and enforce calls
|
// Resolve transaction, populate missing fields and enforce calls
|
||||||
// correctness.
|
// correctness.
|
||||||
let tx = simulate::resolve_transaction(
|
let tx = simulate::resolve_transaction(
|
||||||
@ -185,7 +184,7 @@ pub trait EthCall: EstimateCall + Call + LoadPendingBlock + LoadBlock + FullEthA
|
|||||||
this.tx_resp_builder(),
|
this.tx_resp_builder(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let tx_env = this.evm_config().tx_env(&tx, sender);
|
let tx_env = this.evm_config().tx_env(&tx);
|
||||||
|
|
||||||
let (res, (_, tx_env)) = {
|
let (res, (_, tx_env)) = {
|
||||||
if trace_transfers {
|
if trace_transfers {
|
||||||
@ -324,9 +323,9 @@ pub trait EthCall: EstimateCall + Call + LoadPendingBlock + LoadBlock + FullEthA
|
|||||||
if replay_block_txs {
|
if replay_block_txs {
|
||||||
// only need to replay the transactions in the block if not all transactions are
|
// only need to replay the transactions in the block if not all transactions are
|
||||||
// to be replayed
|
// to be replayed
|
||||||
let transactions = block.transactions_with_sender().take(num_txs);
|
let transactions = block.transactions_recovered().take(num_txs);
|
||||||
for (signer, tx) in transactions {
|
for tx in transactions {
|
||||||
let tx_env = RpcNodeCore::evm_config(&this).tx_env(tx, *signer);
|
let tx_env = RpcNodeCore::evm_config(&this).tx_env(tx);
|
||||||
let (res, _) = this.transact(&mut db, evm_env.clone(), tx_env)?;
|
let (res, _) = this.transact(&mut db, evm_env.clone(), tx_env)?;
|
||||||
db.commit(res.state);
|
db.commit(res.state);
|
||||||
}
|
}
|
||||||
@ -671,12 +670,12 @@ pub trait Call:
|
|||||||
let this = self.clone();
|
let this = self.clone();
|
||||||
self.spawn_with_state_at_block(parent_block.into(), move |state| {
|
self.spawn_with_state_at_block(parent_block.into(), move |state| {
|
||||||
let mut db = CacheDB::new(StateProviderDatabase::new(state));
|
let mut db = CacheDB::new(StateProviderDatabase::new(state));
|
||||||
let block_txs = block.transactions_with_sender();
|
let block_txs = block.transactions_recovered();
|
||||||
|
|
||||||
// replay all transactions prior to the targeted transaction
|
// replay all transactions prior to the targeted transaction
|
||||||
this.replay_transactions_until(&mut db, evm_env.clone(), block_txs, *tx.tx_hash())?;
|
this.replay_transactions_until(&mut db, evm_env.clone(), block_txs, *tx.tx_hash())?;
|
||||||
|
|
||||||
let tx_env = RpcNodeCore::evm_config(&this).tx_env(tx.tx(), tx.signer());
|
let tx_env = RpcNodeCore::evm_config(&this).tx_env(tx);
|
||||||
|
|
||||||
let (res, _) = this.transact(&mut db, evm_env, tx_env)?;
|
let (res, _) = this.transact(&mut db, evm_env, tx_env)?;
|
||||||
f(tx_info, res, db)
|
f(tx_info, res, db)
|
||||||
@ -702,18 +701,18 @@ pub trait Call:
|
|||||||
) -> Result<usize, Self::Error>
|
) -> Result<usize, Self::Error>
|
||||||
where
|
where
|
||||||
DB: Database<Error = ProviderError> + DatabaseCommit,
|
DB: Database<Error = ProviderError> + DatabaseCommit,
|
||||||
I: IntoIterator<Item = (&'a Address, &'a <Self::Evm as ConfigureEvmEnv>::Transaction)>,
|
I: IntoIterator<Item = Recovered<&'a <Self::Evm as ConfigureEvmEnv>::Transaction>>,
|
||||||
<Self::Evm as ConfigureEvmEnv>::Transaction: SignedTransaction,
|
<Self::Evm as ConfigureEvmEnv>::Transaction: SignedTransaction,
|
||||||
{
|
{
|
||||||
let mut evm = self.evm_config().evm_with_env(db, evm_env);
|
let mut evm = self.evm_config().evm_with_env(db, evm_env);
|
||||||
let mut index = 0;
|
let mut index = 0;
|
||||||
for (sender, tx) in transactions {
|
for tx in transactions {
|
||||||
if *tx.tx_hash() == target_tx_hash {
|
if *tx.tx_hash() == target_tx_hash {
|
||||||
// reached the target transaction
|
// reached the target transaction
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
let tx_env = self.evm_config().tx_env(tx, *sender);
|
let tx_env = self.evm_config().tx_env(tx);
|
||||||
evm.transact_commit(tx_env).map_err(Self::Error::from_evm_err)?;
|
evm.transact_commit(tx_env).map_err(Self::Error::from_evm_err)?;
|
||||||
index += 1;
|
index += 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
use super::SpawnBlocking;
|
use super::SpawnBlocking;
|
||||||
use crate::{types::RpcTypes, EthApiTypes, FromEthApiError, FromEvmError, RpcNodeCore};
|
use crate::{types::RpcTypes, EthApiTypes, FromEthApiError, FromEvmError, RpcNodeCore};
|
||||||
use alloy_consensus::{BlockHeader, Transaction};
|
use alloy_consensus::{transaction::Recovered, BlockHeader, Transaction};
|
||||||
use alloy_eips::eip4844::MAX_DATA_GAS_PER_BLOCK;
|
use alloy_eips::eip4844::MAX_DATA_GAS_PER_BLOCK;
|
||||||
use alloy_primitives::B256;
|
use alloy_primitives::B256;
|
||||||
use alloy_rpc_types_eth::BlockNumberOrTag;
|
use alloy_rpc_types_eth::BlockNumberOrTag;
|
||||||
@ -209,7 +209,7 @@ pub trait LoadPendingBlock:
|
|||||||
block_env: &BlockEnv,
|
block_env: &BlockEnv,
|
||||||
parent_hash: B256,
|
parent_hash: B256,
|
||||||
state_root: B256,
|
state_root: B256,
|
||||||
transactions: Vec<ProviderTx<Self::Provider>>,
|
transactions: Vec<Recovered<ProviderTx<Self::Provider>>>,
|
||||||
receipts: &[ProviderReceipt<Self::Provider>],
|
receipts: &[ProviderReceipt<Self::Provider>],
|
||||||
) -> ProviderBlock<Self::Provider>;
|
) -> ProviderBlock<Self::Provider>;
|
||||||
|
|
||||||
@ -219,7 +219,7 @@ pub trait LoadPendingBlock:
|
|||||||
block_env: &BlockEnv,
|
block_env: &BlockEnv,
|
||||||
parent_hash: B256,
|
parent_hash: B256,
|
||||||
state_root: B256,
|
state_root: B256,
|
||||||
transactions: Vec<ProviderTx<Self::Provider>>,
|
transactions: Vec<Recovered<ProviderTx<Self::Provider>>>,
|
||||||
results: Vec<ExecutionResult<HaltReasonFor<Self::Evm>>>,
|
results: Vec<ExecutionResult<HaltReasonFor<Self::Evm>>>,
|
||||||
) -> (ProviderBlock<Self::Provider>, Vec<ProviderReceipt<Self::Provider>>) {
|
) -> (ProviderBlock<Self::Provider>, Vec<ProviderReceipt<Self::Provider>>) {
|
||||||
let mut cumulative_gas_used = 0;
|
let mut cumulative_gas_used = 0;
|
||||||
@ -267,7 +267,6 @@ pub trait LoadPendingBlock:
|
|||||||
let base_fee = evm_env.block_env.basefee;
|
let base_fee = evm_env.block_env.basefee;
|
||||||
|
|
||||||
let mut executed_txs = Vec::new();
|
let mut executed_txs = Vec::new();
|
||||||
let mut senders = Vec::new();
|
|
||||||
let mut best_txs =
|
let mut best_txs =
|
||||||
self.pool().best_transactions_with_attributes(BestTransactionsAttributes::new(
|
self.pool().best_transactions_with_attributes(BestTransactionsAttributes::new(
|
||||||
base_fee,
|
base_fee,
|
||||||
@ -336,7 +335,7 @@ pub trait LoadPendingBlock:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let tx_env = self.evm_config().tx_env(tx.tx(), tx.signer());
|
let tx_env = self.evm_config().tx_env(&tx);
|
||||||
|
|
||||||
let ResultAndState { result, state: _ } = match evm.transact_commit(tx_env) {
|
let ResultAndState { result, state: _ } = match evm.transact_commit(tx_env) {
|
||||||
Ok(res) => res,
|
Ok(res) => res,
|
||||||
@ -377,9 +376,7 @@ pub trait LoadPendingBlock:
|
|||||||
cumulative_gas_used += gas_used;
|
cumulative_gas_used += gas_used;
|
||||||
|
|
||||||
// append transaction to the list of executed transactions
|
// append transaction to the list of executed transactions
|
||||||
let (tx, sender) = tx.into_parts();
|
|
||||||
executed_txs.push(tx);
|
executed_txs.push(tx);
|
||||||
senders.push(sender);
|
|
||||||
results.push(result);
|
results.push(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -405,6 +402,8 @@ pub trait LoadPendingBlock:
|
|||||||
// calculate the state root
|
// calculate the state root
|
||||||
let state_root = db.database.state_root(hashed_state).map_err(Self::Error::from_eth_err)?;
|
let state_root = db.database.state_root(hashed_state).map_err(Self::Error::from_eth_err)?;
|
||||||
|
|
||||||
|
let senders = executed_txs.iter().map(|tx| tx.signer()).collect();
|
||||||
|
|
||||||
let (block, receipts) = self.assemble_block_and_receipts(
|
let (block, receipts) = self.assemble_block_and_receipts(
|
||||||
&evm_env.block_env,
|
&evm_env.block_env,
|
||||||
parent_hash,
|
parent_hash,
|
||||||
|
|||||||
@ -204,14 +204,14 @@ pub trait Trace:
|
|||||||
let this = self.clone();
|
let this = self.clone();
|
||||||
self.spawn_with_state_at_block(parent_block.into(), move |state| {
|
self.spawn_with_state_at_block(parent_block.into(), move |state| {
|
||||||
let mut db = CacheDB::new(StateProviderDatabase::new(state));
|
let mut db = CacheDB::new(StateProviderDatabase::new(state));
|
||||||
let block_txs = block.transactions_with_sender();
|
let block_txs = block.transactions_recovered();
|
||||||
|
|
||||||
this.apply_pre_execution_changes(&block, &mut db, &evm_env)?;
|
this.apply_pre_execution_changes(&block, &mut db, &evm_env)?;
|
||||||
|
|
||||||
// replay all transactions prior to the targeted transaction
|
// replay all transactions prior to the targeted transaction
|
||||||
this.replay_transactions_until(&mut db, evm_env.clone(), block_txs, *tx.tx_hash())?;
|
this.replay_transactions_until(&mut db, evm_env.clone(), block_txs, *tx.tx_hash())?;
|
||||||
|
|
||||||
let tx_env = this.evm_config().tx_env(tx.tx(), tx.signer());
|
let tx_env = this.evm_config().tx_env(tx);
|
||||||
let (res, _) = this.inspect(
|
let (res, _) = this.inspect(
|
||||||
StateCacheDbRefMutWrapper(&mut db),
|
StateCacheDbRefMutWrapper(&mut db),
|
||||||
evm_env,
|
evm_env,
|
||||||
@ -339,10 +339,10 @@ pub trait Trace:
|
|||||||
let mut results = Vec::with_capacity(max_transactions);
|
let mut results = Vec::with_capacity(max_transactions);
|
||||||
|
|
||||||
let mut transactions = block
|
let mut transactions = block
|
||||||
.transactions_with_sender()
|
.transactions_recovered()
|
||||||
.take(max_transactions)
|
.take(max_transactions)
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(idx, (signer, tx))| {
|
.map(|(idx, tx)| {
|
||||||
let tx_info = TransactionInfo {
|
let tx_info = TransactionInfo {
|
||||||
hash: Some(*tx.tx_hash()),
|
hash: Some(*tx.tx_hash()),
|
||||||
index: Some(idx as u64),
|
index: Some(idx as u64),
|
||||||
@ -350,7 +350,7 @@ pub trait Trace:
|
|||||||
block_number: Some(block_number),
|
block_number: Some(block_number),
|
||||||
base_fee: Some(base_fee),
|
base_fee: Some(base_fee),
|
||||||
};
|
};
|
||||||
let tx_env = this.evm_config().tx_env(tx, *signer);
|
let tx_env = this.evm_config().tx_env(tx);
|
||||||
(tx_info, tx_env)
|
(tx_info, tx_env)
|
||||||
})
|
})
|
||||||
.peekable();
|
.peekable();
|
||||||
|
|||||||
@ -7,7 +7,7 @@ use alloy_rpc_types_eth::{
|
|||||||
Block, BlockTransactionsKind, Header,
|
Block, BlockTransactionsKind, Header,
|
||||||
};
|
};
|
||||||
use jsonrpsee_types::ErrorObject;
|
use jsonrpsee_types::ErrorObject;
|
||||||
use reth_primitives::RecoveredBlock;
|
use reth_primitives::{Recovered, RecoveredBlock};
|
||||||
use reth_primitives_traits::{block::BlockTx, BlockBody as _, SignedTransaction};
|
use reth_primitives_traits::{block::BlockTx, BlockBody as _, SignedTransaction};
|
||||||
use reth_rpc_server_types::result::rpc_err;
|
use reth_rpc_server_types::result::rpc_err;
|
||||||
use reth_rpc_types_compat::{block::from_block, TransactionCompat};
|
use reth_rpc_types_compat::{block::from_block, TransactionCompat};
|
||||||
@ -60,7 +60,7 @@ pub fn resolve_transaction<DB: Database, Tx, T: TransactionCompat<Tx>>(
|
|||||||
chain_id: u64,
|
chain_id: u64,
|
||||||
db: &mut DB,
|
db: &mut DB,
|
||||||
tx_resp_builder: &T,
|
tx_resp_builder: &T,
|
||||||
) -> Result<Tx, EthApiError>
|
) -> Result<Recovered<Tx>, EthApiError>
|
||||||
where
|
where
|
||||||
EthApiError: From<DB::Error>,
|
EthApiError: From<DB::Error>,
|
||||||
{
|
{
|
||||||
@ -108,7 +108,11 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tx_resp_builder.build_simulate_v1_transaction(tx).map_err(|e| EthApiError::other(e.into()))
|
let tx = tx_resp_builder
|
||||||
|
.build_simulate_v1_transaction(tx)
|
||||||
|
.map_err(|e| EthApiError::other(e.into()))?;
|
||||||
|
|
||||||
|
Ok(Recovered::new_unchecked(tx, from))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handles outputs of the calls execution and builds a [`SimulatedBlock`].
|
/// Handles outputs of the calls execution and builds a [`SimulatedBlock`].
|
||||||
|
|||||||
@ -109,12 +109,12 @@ where
|
|||||||
|
|
||||||
this.eth_api().apply_pre_execution_changes(&block, &mut db, &evm_env)?;
|
this.eth_api().apply_pre_execution_changes(&block, &mut db, &evm_env)?;
|
||||||
|
|
||||||
let mut transactions = block.transactions_with_sender().enumerate().peekable();
|
let mut transactions = block.transactions_recovered().enumerate().peekable();
|
||||||
let mut inspector = None;
|
let mut inspector = None;
|
||||||
while let Some((index, (signer, tx))) = transactions.next() {
|
while let Some((index, tx)) = transactions.next() {
|
||||||
let tx_hash = *tx.tx_hash();
|
let tx_hash = *tx.tx_hash();
|
||||||
|
|
||||||
let tx_env = this.eth_api().evm_config().tx_env(tx, *signer);
|
let tx_env = this.eth_api().evm_config().tx_env(tx);
|
||||||
|
|
||||||
let (result, state_changes) = this.trace_transaction(
|
let (result, state_changes) = this.trace_transaction(
|
||||||
&opts,
|
&opts,
|
||||||
@ -229,7 +229,7 @@ where
|
|||||||
let this = self.clone();
|
let this = self.clone();
|
||||||
self.eth_api()
|
self.eth_api()
|
||||||
.spawn_with_state_at_block(state_at, move |state| {
|
.spawn_with_state_at_block(state_at, move |state| {
|
||||||
let block_txs = block.transactions_with_sender();
|
let block_txs = block.transactions_recovered();
|
||||||
|
|
||||||
// configure env for the target transaction
|
// configure env for the target transaction
|
||||||
let tx = transaction.into_recovered();
|
let tx = transaction.into_recovered();
|
||||||
@ -246,7 +246,7 @@ where
|
|||||||
*tx.tx_hash(),
|
*tx.tx_hash(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let tx_env = this.eth_api().evm_config().tx_env(tx.tx(), tx.signer());
|
let tx_env = this.eth_api().evm_config().tx_env(&tx);
|
||||||
|
|
||||||
this.trace_transaction(
|
this.trace_transaction(
|
||||||
&opts,
|
&opts,
|
||||||
@ -530,11 +530,11 @@ where
|
|||||||
if replay_block_txs {
|
if replay_block_txs {
|
||||||
// only need to replay the transactions in the block if not all transactions are
|
// only need to replay the transactions in the block if not all transactions are
|
||||||
// to be replayed
|
// to be replayed
|
||||||
let transactions = block.transactions_with_sender().take(num_txs);
|
let transactions = block.transactions_recovered().take(num_txs);
|
||||||
|
|
||||||
// Execute all transactions until index
|
// Execute all transactions until index
|
||||||
for (signer, tx) in transactions {
|
for tx in transactions {
|
||||||
let tx_env = this.eth_api().evm_config().tx_env(tx, *signer);
|
let tx_env = this.eth_api().evm_config().tx_env(tx);
|
||||||
let (res, _) = this.eth_api().transact(&mut db, evm_env.clone(), tx_env)?;
|
let (res, _) = this.eth_api().transact(&mut db, evm_env.clone(), tx_env)?;
|
||||||
db.commit(res.state);
|
db.commit(res.state);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -176,7 +176,7 @@ where
|
|||||||
hasher.update(*tx.tx_hash());
|
hasher.update(*tx.tx_hash());
|
||||||
let gas_price = tx.effective_gas_price(basefee);
|
let gas_price = tx.effective_gas_price(basefee);
|
||||||
let ResultAndState { result, state } = evm
|
let ResultAndState { result, state } = evm
|
||||||
.transact(eth_api.evm_config().tx_env(&tx, signer))
|
.transact(eth_api.evm_config().tx_env(&tx))
|
||||||
.map_err(Eth::Error::from_evm_err)?;
|
.map_err(Eth::Error::from_evm_err)?;
|
||||||
|
|
||||||
let gas_used = result.gas_used();
|
let gas_used = result.gas_used();
|
||||||
|
|||||||
@ -1,6 +1,9 @@
|
|||||||
//! Support for building a pending block with transactions from local view of mempool.
|
//! Support for building a pending block with transactions from local view of mempool.
|
||||||
|
|
||||||
use alloy_consensus::{constants::EMPTY_WITHDRAWALS, Header, Transaction, EMPTY_OMMER_ROOT_HASH};
|
use alloy_consensus::{
|
||||||
|
constants::EMPTY_WITHDRAWALS, transaction::Recovered, Header, Transaction,
|
||||||
|
EMPTY_OMMER_ROOT_HASH,
|
||||||
|
};
|
||||||
use alloy_eips::{eip7685::EMPTY_REQUESTS_HASH, merge::BEACON_NONCE};
|
use alloy_eips::{eip7685::EMPTY_REQUESTS_HASH, merge::BEACON_NONCE};
|
||||||
use alloy_primitives::U256;
|
use alloy_primitives::U256;
|
||||||
use reth_chainspec::{EthChainSpec, EthereumHardforks};
|
use reth_chainspec::{EthChainSpec, EthereumHardforks};
|
||||||
@ -61,7 +64,7 @@ where
|
|||||||
block_env: &BlockEnv,
|
block_env: &BlockEnv,
|
||||||
parent_hash: revm_primitives::B256,
|
parent_hash: revm_primitives::B256,
|
||||||
state_root: revm_primitives::B256,
|
state_root: revm_primitives::B256,
|
||||||
transactions: Vec<ProviderTx<Self::Provider>>,
|
transactions: Vec<Recovered<ProviderTx<Self::Provider>>>,
|
||||||
receipts: &[ProviderReceipt<Self::Provider>],
|
receipts: &[ProviderReceipt<Self::Provider>],
|
||||||
) -> reth_provider::ProviderBlock<Self::Provider> {
|
) -> reth_provider::ProviderBlock<Self::Provider> {
|
||||||
let chain_spec = self.provider().chain_spec();
|
let chain_spec = self.provider().chain_spec();
|
||||||
@ -105,7 +108,11 @@ where
|
|||||||
// seal the block
|
// seal the block
|
||||||
reth_primitives::Block {
|
reth_primitives::Block {
|
||||||
header,
|
header,
|
||||||
body: BlockBody { transactions, ommers: vec![], withdrawals: None },
|
body: BlockBody {
|
||||||
|
transactions: transactions.into_iter().map(|tx| tx.into_tx()).collect(),
|
||||||
|
ommers: vec![],
|
||||||
|
withdrawals: None,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -10,6 +10,7 @@ use alloy_rpc_types_mev::{
|
|||||||
};
|
};
|
||||||
use jsonrpsee::core::RpcResult;
|
use jsonrpsee::core::RpcResult;
|
||||||
use reth_evm::{ConfigureEvm, ConfigureEvmEnv, Evm};
|
use reth_evm::{ConfigureEvm, ConfigureEvmEnv, Evm};
|
||||||
|
use reth_primitives::Recovered;
|
||||||
use reth_provider::ProviderTx;
|
use reth_provider::ProviderTx;
|
||||||
use reth_revm::{database::StateProviderDatabase, db::CacheDB};
|
use reth_revm::{database::StateProviderDatabase, db::CacheDB};
|
||||||
use reth_rpc_api::MevSimApiServer;
|
use reth_rpc_api::MevSimApiServer;
|
||||||
@ -21,9 +22,8 @@ use reth_rpc_eth_types::{
|
|||||||
revm_utils::apply_block_overrides, utils::recover_raw_transaction, EthApiError,
|
revm_utils::apply_block_overrides, utils::recover_raw_transaction, EthApiError,
|
||||||
};
|
};
|
||||||
use reth_tasks::pool::BlockingTaskGuard;
|
use reth_tasks::pool::BlockingTaskGuard;
|
||||||
use reth_transaction_pool::{PoolConsensusTx, PoolPooledTx, PoolTransaction, TransactionPool};
|
use reth_transaction_pool::{PoolPooledTx, PoolTransaction, TransactionPool};
|
||||||
use revm::{context_interface::result::ResultAndState, DatabaseCommit, DatabaseRef};
|
use revm::{context_interface::result::ResultAndState, DatabaseCommit, DatabaseRef};
|
||||||
use revm_primitives::Address;
|
|
||||||
use std::{sync::Arc, time::Duration};
|
use std::{sync::Arc, time::Duration};
|
||||||
use tracing::info;
|
use tracing::info;
|
||||||
|
|
||||||
@ -46,9 +46,7 @@ const SBUNDLE_PAYOUT_MAX_COST: u64 = 30_000;
|
|||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct FlattenedBundleItem<T> {
|
pub struct FlattenedBundleItem<T> {
|
||||||
/// The signed transaction
|
/// The signed transaction
|
||||||
pub tx: T,
|
pub tx: Recovered<T>,
|
||||||
/// The address that signed the transaction
|
|
||||||
pub signer: Address,
|
|
||||||
/// Whether the transaction is allowed to revert
|
/// Whether the transaction is allowed to revert
|
||||||
pub can_revert: bool,
|
pub can_revert: bool,
|
||||||
/// Item-level inclusion constraints
|
/// Item-level inclusion constraints
|
||||||
@ -169,10 +167,10 @@ where
|
|||||||
while idx < body.len() {
|
while idx < body.len() {
|
||||||
match &body[idx] {
|
match &body[idx] {
|
||||||
BundleItem::Tx { tx, can_revert } => {
|
BundleItem::Tx { tx, can_revert } => {
|
||||||
let recovered_tx = recover_raw_transaction::<PoolPooledTx<Eth::Pool>>(tx)?;
|
let tx = recover_raw_transaction::<PoolPooledTx<Eth::Pool>>(tx)?;
|
||||||
let (tx, signer) = recovered_tx.into_parts();
|
let tx = tx.map_transaction(
|
||||||
let tx: PoolConsensusTx<Eth::Pool> =
|
<Eth::Pool as TransactionPool>::Transaction::pooled_into_consensus,
|
||||||
<Eth::Pool as TransactionPool>::Transaction::pooled_into_consensus(tx);
|
);
|
||||||
|
|
||||||
let refund_percent =
|
let refund_percent =
|
||||||
validity.as_ref().and_then(|v| v.refund.as_ref()).and_then(|refunds| {
|
validity.as_ref().and_then(|v| v.refund.as_ref()).and_then(|refunds| {
|
||||||
@ -186,7 +184,6 @@ where
|
|||||||
// Create FlattenedBundleItem with current inclusion, validity, and privacy
|
// Create FlattenedBundleItem with current inclusion, validity, and privacy
|
||||||
let flattened_item = FlattenedBundleItem {
|
let flattened_item = FlattenedBundleItem {
|
||||||
tx,
|
tx,
|
||||||
signer,
|
|
||||||
can_revert: *can_revert,
|
can_revert: *can_revert,
|
||||||
inclusion: inclusion.clone(),
|
inclusion: inclusion.clone(),
|
||||||
validity: validity.clone(),
|
validity: validity.clone(),
|
||||||
@ -282,7 +279,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
let ResultAndState { result, state } = evm
|
let ResultAndState { result, state } = evm
|
||||||
.transact(eth_api.evm_config().tx_env(&item.tx, item.signer))
|
.transact(eth_api.evm_config().tx_env(&item.tx))
|
||||||
.map_err(Eth::Error::from_evm_err)?;
|
.map_err(Eth::Error::from_evm_err)?;
|
||||||
|
|
||||||
if !result.is_success() && !item.can_revert {
|
if !result.is_success() && !item.can_revert {
|
||||||
@ -330,7 +327,7 @@ where
|
|||||||
if let Some(refund_percent) = item.refund_percent {
|
if let Some(refund_percent) = item.refund_percent {
|
||||||
// Get refund configurations
|
// Get refund configurations
|
||||||
let refund_configs = item.refund_configs.clone().unwrap_or_else(|| {
|
let refund_configs = item.refund_configs.clone().unwrap_or_else(|| {
|
||||||
vec![RefundConfig { address: item.signer, percent: 100 }]
|
vec![RefundConfig { address: item.tx.signer(), percent: 100 }]
|
||||||
});
|
});
|
||||||
|
|
||||||
// Calculate payout transaction fee
|
// Calculate payout transaction fee
|
||||||
|
|||||||
@ -113,7 +113,7 @@ where
|
|||||||
.map_transaction(<Eth::Pool as TransactionPool>::Transaction::pooled_into_consensus);
|
.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 (evm_env, at) = self.eth_api().evm_env_at(block_id.unwrap_or_default()).await?;
|
||||||
let tx_env = self.eth_api().evm_config().tx_env(tx.tx(), tx.signer());
|
let tx_env = self.eth_api().evm_config().tx_env(tx);
|
||||||
|
|
||||||
let config = TracingInspectorConfig::from_parity_config(&trace_types);
|
let config = TracingInspectorConfig::from_parity_config(&trace_types);
|
||||||
|
|
||||||
|
|||||||
@ -4,13 +4,14 @@
|
|||||||
#![cfg_attr(not(test), warn(unused_crate_dependencies))]
|
#![cfg_attr(not(test), warn(unused_crate_dependencies))]
|
||||||
|
|
||||||
use alloy_consensus::BlockHeader;
|
use alloy_consensus::BlockHeader;
|
||||||
use alloy_eips::{eip4895::Withdrawal, eip7685::Requests};
|
use alloy_eips::eip4895::Withdrawal;
|
||||||
use alloy_sol_macro::sol;
|
use alloy_sol_macro::sol;
|
||||||
use alloy_sol_types::SolCall;
|
use alloy_sol_types::SolCall;
|
||||||
use reth::{
|
use reth::{
|
||||||
api::{ConfigureEvm, NodeTypesWithEngine},
|
api::{ConfigureEvm, NodeTypesWithEngine},
|
||||||
builder::{components::ExecutorBuilder, BuilderContext, FullNodeTypes},
|
builder::{components::ExecutorBuilder, BuilderContext, FullNodeTypes},
|
||||||
cli::Cli,
|
cli::Cli,
|
||||||
|
providers::BlockExecutionResult,
|
||||||
revm::{
|
revm::{
|
||||||
db::State,
|
db::State,
|
||||||
primitives::{address, Address},
|
primitives::{address, Address},
|
||||||
@ -20,14 +21,16 @@ use reth::{
|
|||||||
use reth_chainspec::{ChainSpec, EthereumHardforks};
|
use reth_chainspec::{ChainSpec, EthereumHardforks};
|
||||||
use reth_evm::{
|
use reth_evm::{
|
||||||
execute::{
|
execute::{
|
||||||
BlockExecutionError, BlockExecutionStrategy, BlockExecutionStrategyFactory, ExecuteOutput,
|
BlockExecutionError, BlockExecutionStrategy, BlockExecutionStrategyFactory,
|
||||||
InternalBlockExecutionError,
|
InternalBlockExecutionError,
|
||||||
},
|
},
|
||||||
Database, Evm,
|
Database, Evm,
|
||||||
};
|
};
|
||||||
use reth_evm_ethereum::EthEvmConfig;
|
use reth_evm_ethereum::EthEvmConfig;
|
||||||
use reth_node_ethereum::{node::EthereumAddOns, BasicBlockExecutorProvider, EthereumNode};
|
use reth_node_ethereum::{node::EthereumAddOns, BasicBlockExecutorProvider, EthereumNode};
|
||||||
use reth_primitives::{EthPrimitives, Receipt, RecoveredBlock};
|
use reth_primitives::{
|
||||||
|
Block, EthPrimitives, Receipt, Recovered, RecoveredBlock, SealedBlock, TransactionSigned,
|
||||||
|
};
|
||||||
use std::{fmt::Display, sync::Arc};
|
use std::{fmt::Display, sync::Arc};
|
||||||
|
|
||||||
pub const SYSTEM_ADDRESS: Address = address!("fffffffffffffffffffffffffffffffffffffffe");
|
pub const SYSTEM_ADDRESS: Address = address!("fffffffffffffffffffffffffffffffffffffffe");
|
||||||
@ -90,86 +93,64 @@ pub struct CustomExecutorStrategyFactory {
|
|||||||
|
|
||||||
impl BlockExecutionStrategyFactory for CustomExecutorStrategyFactory {
|
impl BlockExecutionStrategyFactory for CustomExecutorStrategyFactory {
|
||||||
type Primitives = EthPrimitives;
|
type Primitives = EthPrimitives;
|
||||||
type Strategy<DB: Database> = CustomExecutorStrategy<DB>;
|
|
||||||
|
|
||||||
fn create_strategy<DB>(&self, db: DB) -> Self::Strategy<DB>
|
fn create_strategy<'a, DB>(
|
||||||
|
&'a mut self,
|
||||||
|
db: &'a mut State<DB>,
|
||||||
|
block: &'a RecoveredBlock<Block>,
|
||||||
|
) -> impl BlockExecutionStrategy<Primitives = Self::Primitives, Error = BlockExecutionError> + 'a
|
||||||
where
|
where
|
||||||
DB: Database,
|
DB: Database,
|
||||||
{
|
{
|
||||||
let state =
|
let evm = self.evm_config.evm_for_block(db, block.header());
|
||||||
State::builder().with_database(db).with_bundle_update().without_state_clear().build();
|
CustomExecutorStrategy { evm, factory: self, block }
|
||||||
CustomExecutorStrategy {
|
|
||||||
state,
|
|
||||||
chain_spec: self.chain_spec.clone(),
|
|
||||||
evm_config: self.evm_config.clone(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct CustomExecutorStrategy<DB>
|
pub struct CustomExecutorStrategy<'a, Evm> {
|
||||||
where
|
/// Reference to the parent factory.
|
||||||
DB: Database,
|
factory: &'a CustomExecutorStrategyFactory,
|
||||||
{
|
/// EVM used for execution.
|
||||||
/// The chainspec
|
evm: Evm,
|
||||||
chain_spec: Arc<ChainSpec>,
|
/// Block being executed.
|
||||||
/// How to create an EVM.
|
block: &'a SealedBlock,
|
||||||
evm_config: EthEvmConfig,
|
|
||||||
/// Current state for block execution.
|
|
||||||
state: State<DB>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<DB> BlockExecutionStrategy for CustomExecutorStrategy<DB>
|
impl<'db, DB, E> BlockExecutionStrategy for CustomExecutorStrategy<'_, E>
|
||||||
where
|
where
|
||||||
DB: Database,
|
DB: Database + 'db,
|
||||||
|
E: Evm<DB = &'db mut State<DB>>,
|
||||||
{
|
{
|
||||||
type DB = DB;
|
|
||||||
type Primitives = EthPrimitives;
|
type Primitives = EthPrimitives;
|
||||||
type Error = BlockExecutionError;
|
type Error = BlockExecutionError;
|
||||||
|
|
||||||
fn apply_pre_execution_changes(
|
fn apply_pre_execution_changes(&mut self) -> Result<(), Self::Error> {
|
||||||
&mut self,
|
|
||||||
block: &RecoveredBlock<reth_primitives::Block>,
|
|
||||||
) -> Result<(), Self::Error> {
|
|
||||||
// Set state clear flag if the block is after the Spurious Dragon hardfork.
|
// Set state clear flag if the block is after the Spurious Dragon hardfork.
|
||||||
let state_clear_flag =
|
let state_clear_flag =
|
||||||
(*self.chain_spec).is_spurious_dragon_active_at_block(block.number());
|
(*self.factory.chain_spec).is_spurious_dragon_active_at_block(self.block.number());
|
||||||
self.state.set_state_clear_flag(state_clear_flag);
|
self.evm.db_mut().set_state_clear_flag(state_clear_flag);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn execute_transactions(
|
fn execute_transactions<'a>(
|
||||||
&mut self,
|
&mut self,
|
||||||
_block: &RecoveredBlock<reth_primitives::Block>,
|
_transactions: impl IntoIterator<Item = Recovered<&'a TransactionSigned>>,
|
||||||
) -> Result<ExecuteOutput<Receipt>, Self::Error> {
|
) -> Result<(), Self::Error> {
|
||||||
Ok(ExecuteOutput { receipts: vec![], gas_used: 0 })
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_post_execution_changes(
|
fn apply_post_execution_changes(
|
||||||
&mut self,
|
mut self,
|
||||||
block: &RecoveredBlock<reth_primitives::Block>,
|
) -> Result<BlockExecutionResult<Receipt>, Self::Error> {
|
||||||
_receipts: &[Receipt],
|
if let Some(withdrawals) = self.block.body().withdrawals.as_ref() {
|
||||||
) -> Result<Requests, Self::Error> {
|
apply_withdrawals_contract_call(withdrawals, &mut self.evm)?;
|
||||||
let mut evm = self.evm_config.evm_for_block(&mut self.state, block.header());
|
|
||||||
|
|
||||||
if let Some(withdrawals) = block.body().withdrawals.as_ref() {
|
|
||||||
apply_withdrawals_contract_call(withdrawals, &mut evm)?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Requests::default())
|
Ok(Default::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn state_ref(&self) -> &State<DB> {
|
fn with_state_hook(&mut self, _hook: Option<Box<dyn reth_evm::system_calls::OnStateHook>>) {}
|
||||||
&self.state
|
|
||||||
}
|
|
||||||
|
|
||||||
fn state_mut(&mut self) -> &mut State<DB> {
|
|
||||||
&mut self.state
|
|
||||||
}
|
|
||||||
|
|
||||||
fn into_state(self) -> reth::revm::db::State<Self::DB> {
|
|
||||||
self.state
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sol!(
|
sol!(
|
||||||
|
|||||||
@ -41,9 +41,10 @@ use reth_node_ethereum::{
|
|||||||
node::{EthereumAddOns, EthereumPayloadBuilder},
|
node::{EthereumAddOns, EthereumPayloadBuilder},
|
||||||
BasicBlockExecutorProvider, EthExecutionStrategyFactory, EthereumNode,
|
BasicBlockExecutorProvider, EthExecutionStrategyFactory, EthereumNode,
|
||||||
};
|
};
|
||||||
use reth_primitives::{EthPrimitives, TransactionSigned};
|
use reth_primitives::{EthPrimitives, Recovered, TransactionSigned};
|
||||||
use reth_tracing::{RethTracer, Tracer};
|
use reth_tracing::{RethTracer, Tracer};
|
||||||
use std::{
|
use std::{
|
||||||
|
borrow::Borrow,
|
||||||
convert::Infallible,
|
convert::Infallible,
|
||||||
sync::{Arc, OnceLock},
|
sync::{Arc, OnceLock},
|
||||||
};
|
};
|
||||||
@ -105,8 +106,11 @@ impl ConfigureEvmEnv for MyEvmConfig {
|
|||||||
type TxEnv = TxEnv;
|
type TxEnv = TxEnv;
|
||||||
type Spec = SpecId;
|
type Spec = SpecId;
|
||||||
|
|
||||||
fn tx_env(&self, transaction: &Self::Transaction, signer: Address) -> Self::TxEnv {
|
fn tx_env<T: Borrow<Self::Transaction>>(
|
||||||
self.inner.tx_env(transaction, signer)
|
&self,
|
||||||
|
transaction: impl Borrow<Recovered<T>>,
|
||||||
|
) -> Self::TxEnv {
|
||||||
|
self.inner.tx_env(transaction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn evm_env(&self, header: &Self::Header) -> EvmEnv {
|
fn evm_env(&self, header: &Self::Header) -> EvmEnv {
|
||||||
|
|||||||
@ -33,10 +33,10 @@ use reth_node_ethereum::{
|
|||||||
evm::EthEvm, node::EthereumAddOns, BasicBlockExecutorProvider, EthEvmConfig,
|
evm::EthEvm, node::EthereumAddOns, BasicBlockExecutorProvider, EthEvmConfig,
|
||||||
EthExecutionStrategyFactory, EthereumNode,
|
EthExecutionStrategyFactory, EthereumNode,
|
||||||
};
|
};
|
||||||
use reth_primitives::{EthPrimitives, TransactionSigned};
|
use reth_primitives::{EthPrimitives, Recovered, TransactionSigned};
|
||||||
use reth_tracing::{RethTracer, Tracer};
|
use reth_tracing::{RethTracer, Tracer};
|
||||||
use schnellru::{ByLength, LruMap};
|
use schnellru::{ByLength, LruMap};
|
||||||
use std::{collections::HashMap, convert::Infallible, sync::Arc};
|
use std::{borrow::Borrow, collections::HashMap, convert::Infallible, sync::Arc};
|
||||||
|
|
||||||
/// Type alias for the LRU cache used within the [`PrecompileCache`].
|
/// Type alias for the LRU cache used within the [`PrecompileCache`].
|
||||||
type PrecompileLRUCache = LruMap<(SpecId, Bytes, u64), Result<InterpreterResult, PrecompileErrors>>;
|
type PrecompileLRUCache = LruMap<(SpecId, Bytes, u64), Result<InterpreterResult, PrecompileErrors>>;
|
||||||
@ -186,8 +186,11 @@ impl ConfigureEvmEnv for MyEvmConfig {
|
|||||||
type TxEnv = TxEnv;
|
type TxEnv = TxEnv;
|
||||||
type Spec = SpecId;
|
type Spec = SpecId;
|
||||||
|
|
||||||
fn tx_env(&self, transaction: &Self::Transaction, signer: Address) -> Self::TxEnv {
|
fn tx_env<T: Borrow<Self::Transaction>>(
|
||||||
self.inner.tx_env(transaction, signer)
|
&self,
|
||||||
|
transaction: impl Borrow<Recovered<T>>,
|
||||||
|
) -> Self::TxEnv {
|
||||||
|
self.inner.tx_env(transaction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn evm_env(&self, header: &Self::Header) -> EvmEnv {
|
fn evm_env(&self, header: &Self::Header) -> EvmEnv {
|
||||||
|
|||||||
Reference in New Issue
Block a user