feat: expose InvalidTxError in BlockExecutionError (#14597)

This commit is contained in:
Arsenii Kulikov
2025-02-20 13:22:22 +04:00
committed by GitHub
parent d075995205
commit 7ee8461bac
9 changed files with 45 additions and 24 deletions

5
Cargo.lock generated
View File

@ -261,7 +261,7 @@ dependencies = [
[[package]] [[package]]
name = "alloy-evm" name = "alloy-evm"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/alloy-rs/evm?rev=b77a39a#b77a39aa954a95b1c0385905b7d39c9d096b0a1b" source = "git+https://github.com/alloy-rs/evm?rev=3a57c0d#3a57c0db813d45ddf9b5dcbe4756ae2ce3fc2569"
dependencies = [ dependencies = [
"alloy-primitives", "alloy-primitives",
"revm", "revm",
@ -368,7 +368,7 @@ dependencies = [
[[package]] [[package]]
name = "alloy-op-evm" name = "alloy-op-evm"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/alloy-rs/evm?rev=b77a39a#b77a39aa954a95b1c0385905b7d39c9d096b0a1b" source = "git+https://github.com/alloy-rs/evm?rev=3a57c0d#3a57c0db813d45ddf9b5dcbe4756ae2ce3fc2569"
dependencies = [ dependencies = [
"alloy-evm", "alloy-evm",
"alloy-primitives", "alloy-primitives",
@ -7792,6 +7792,7 @@ name = "reth-execution-errors"
version = "1.2.0" version = "1.2.0"
dependencies = [ dependencies = [
"alloy-eips", "alloy-eips",
"alloy-evm",
"alloy-primitives", "alloy-primitives",
"alloy-rlp", "alloy-rlp",
"nybbles", "nybbles",

View File

@ -623,8 +623,8 @@ snmalloc-rs = { version = "0.3.7", features = ["build_cc"] }
crunchy = "=0.2.2" crunchy = "=0.2.2"
[patch.crates-io] [patch.crates-io]
alloy-evm = { git = "https://github.com/alloy-rs/evm", rev = "b77a39a" } alloy-evm = { git = "https://github.com/alloy-rs/evm", rev = "3a57c0d" }
alloy-op-evm = { git = "https://github.com/alloy-rs/evm", rev = "b77a39a" } alloy-op-evm = { git = "https://github.com/alloy-rs/evm", rev = "3a57c0d" }
revm = { git = "https://github.com/bluealloy/revm", rev = "a8a9893b" } revm = { git = "https://github.com/bluealloy/revm", rev = "a8a9893b" }
revm-bytecode = { git = "https://github.com/bluealloy/revm", rev = "a8a9893b" } revm-bytecode = { git = "https://github.com/bluealloy/revm", rev = "a8a9893b" }

View File

@ -13,8 +13,8 @@ reth-tracing = { path = "../../crates/tracing" }
reth-node-api = { path = "../../crates/node/api" } reth-node-api = { path = "../../crates/node/api" }
[patch.crates-io] [patch.crates-io]
alloy-evm = { git = "https://github.com/alloy-rs/evm", rev = "048248c" } alloy-evm = { git = "https://github.com/alloy-rs/evm", rev = "3a57c0d" }
alloy-op-evm = { git = "https://github.com/alloy-rs/evm", rev = "048248c" } alloy-op-evm = { git = "https://github.com/alloy-rs/evm", rev = "3a57c0d" }
revm = { git = "https://github.com/bluealloy/revm", rev = "a8b9b1e" } revm = { git = "https://github.com/bluealloy/revm", rev = "a8b9b1e" }
revm-bytecode = { git = "https://github.com/bluealloy/revm", rev = "a8b9b1e" } revm-bytecode = { git = "https://github.com/bluealloy/revm", rev = "a8b9b1e" }

View File

@ -11,7 +11,7 @@ use reth_chainspec::EthChainSpec;
use reth_engine_primitives::{ use reth_engine_primitives::{
BeaconEngineMessage, BeaconOnNewPayloadError, EngineTypes, OnForkChoiceUpdated, BeaconEngineMessage, BeaconOnNewPayloadError, EngineTypes, OnForkChoiceUpdated,
}; };
use reth_errors::{BlockExecutionError, BlockValidationError, RethError, RethResult}; use reth_errors::{BlockExecutionError, RethError, RethResult};
use reth_ethereum_forks::EthereumHardforks; use reth_ethereum_forks::EthereumHardforks;
use reth_evm::{ use reth_evm::{
state_change::post_block_withdrawals_balance_increments, system_calls::SystemCaller, state_change::post_block_withdrawals_balance_increments, system_calls::SystemCaller,
@ -320,11 +320,7 @@ where
continue continue
} }
// Treat error as fatal // Treat error as fatal
Err(error) => { Err(error) => return Err(RethError::Execution(BlockExecutionError::other(error))),
return Err(RethError::Execution(BlockExecutionError::Validation(
BlockValidationError::EVM { hash: *tx.tx_hash(), error: Box::new(error) },
)))
}
}; };
evm.db_mut().commit(exec_result.state); evm.db_mut().commit(exec_result.state);

View File

@ -67,8 +67,8 @@ mod size_asserts {
}; };
} }
static_assert_size!(RethError, 56); static_assert_size!(RethError, 64);
static_assert_size!(BlockExecutionError, 56); static_assert_size!(BlockExecutionError, 64);
static_assert_size!(ConsensusError, 48); static_assert_size!(ConsensusError, 48);
static_assert_size!(DatabaseError, 32); static_assert_size!(DatabaseError, 32);
static_assert_size!(ProviderError, 48); static_assert_size!(ProviderError, 48);

View File

@ -154,10 +154,8 @@ where
let hash = tx.hash(); let hash = tx.hash();
// Execute transaction. // Execute transaction.
let result_and_state = self.evm.transact(tx_env).map_err(move |err| { let result_and_state =
// Ensure hash is calculated for error log, if not already done self.evm.transact(tx_env).map_err(move |err| BlockExecutionError::evm(err, *hash))?;
BlockValidationError::EVM { hash: *hash, error: Box::new(err) }
})?;
self.system_caller self.system_caller
.on_state(StateChangeSource::Transaction(self.receipts.len()), &result_and_state.state); .on_state(StateChangeSource::Transaction(self.receipts.len()), &result_and_state.state);
let ResultAndState { result, state } = result_and_state; let ResultAndState { result, state } = result_and_state;

View File

@ -14,6 +14,7 @@ workspace = true
# reth # reth
reth-storage-errors.workspace = true reth-storage-errors.workspace = true
alloy-evm.workspace = true
alloy-primitives.workspace = true alloy-primitives.workspace = true
alloy-rlp.workspace = true alloy-rlp.workspace = true
alloy-eips.workspace = true alloy-eips.workspace = true
@ -33,4 +34,5 @@ std = [
"nybbles/std", "nybbles/std",
"revm-database-interface/std", "revm-database-interface/std",
"reth-storage-errors/std", "reth-storage-errors/std",
"alloy-evm/std",
] ]

View File

@ -16,6 +16,7 @@ use alloc::{
string::{String, ToString}, string::{String, ToString},
}; };
use alloy_eips::BlockNumHash; use alloy_eips::BlockNumHash;
use alloy_evm::{EvmError, InvalidTxError};
use alloy_primitives::B256; use alloy_primitives::B256;
use reth_storage_errors::provider::ProviderError; use reth_storage_errors::provider::ProviderError;
use thiserror::Error; use thiserror::Error;
@ -28,11 +29,11 @@ pub use trie::*;
pub enum BlockValidationError { pub enum BlockValidationError {
/// EVM error with transaction hash and message /// EVM error with transaction hash and message
#[error("EVM reported invalid transaction ({hash}): {error}")] #[error("EVM reported invalid transaction ({hash}): {error}")]
EVM { InvalidTx {
/// The hash of the transaction /// The hash of the transaction
hash: B256, hash: B256,
/// The EVM error. /// The EVM error.
error: Box<dyn core::error::Error + Send + Sync>, error: Box<dyn InvalidTxError>,
}, },
/// Error when incrementing balance in post execution /// Error when incrementing balance in post execution
#[error("incrementing balance in post execution failed")] #[error("incrementing balance in post execution failed")]
@ -141,6 +142,21 @@ impl BlockExecutionError {
pub const fn is_state_root_error(&self) -> bool { pub const fn is_state_root_error(&self) -> bool {
matches!(self, Self::Validation(BlockValidationError::StateRoot(_))) matches!(self, Self::Validation(BlockValidationError::StateRoot(_)))
} }
/// Handles an EVM error occured when executing a transaction.
///
/// If an error matches [`EvmError::InvalidTransaction`], it will be wrapped into
/// [`BlockValidationError::InvalidTx`], otherwise into [`InternalBlockExecutionError::EVM`].
pub fn evm<E: EvmError>(error: E, hash: B256) -> Self {
match error.try_into_invalid_tx_err() {
Ok(err) => {
Self::Validation(BlockValidationError::InvalidTx { hash, error: Box::new(err) })
}
Err(err) => {
Self::Internal(InternalBlockExecutionError::EVM { hash, error: Box::new(err) })
}
}
}
} }
impl From<ProviderError> for BlockExecutionError { impl From<ProviderError> for BlockExecutionError {
@ -164,6 +180,16 @@ pub enum InternalBlockExecutionError {
/// The fork on the other chain /// The fork on the other chain
other_chain_fork: Box<BlockNumHash>, other_chain_fork: Box<BlockNumHash>,
}, },
/// EVM error occurred when executing transaction. This is different from
/// [`BlockValidationError::InvalidTx`] because it will only contain EVM errors which are not
/// transaction validation errors and are assumed to be fatal.
#[error("internal EVM error occurred when executing transaction {hash}: {error}")]
EVM {
/// The hash of the transaction
hash: B256,
/// The EVM error.
error: Box<dyn core::error::Error + Send + Sync>,
},
/// Error when fetching data from the db. /// Error when fetching data from the db.
#[error(transparent)] #[error(transparent)]
Provider(#[from] ProviderError), Provider(#[from] ProviderError),

View File

@ -202,10 +202,8 @@ where
let hash = tx.tx_hash(); let hash = tx.tx_hash();
// Execute transaction. // Execute transaction.
let result_and_state = self.evm.transact(tx_env).map_err(move |err| { let result_and_state =
// Ensure hash is calculated for error log, if not already done self.evm.transact(tx_env).map_err(move |err| BlockExecutionError::evm(err, *hash))?;
BlockValidationError::EVM { hash: *hash, error: Box::new(err) }
})?;
trace!( trace!(
target: "evm", target: "evm",