mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
refactor(consensus, evm): move post-execution validation to consensus (#8321)
This commit is contained in:
@ -17,8 +17,12 @@ reth-primitives.workspace = true
|
||||
reth-revm.workspace = true
|
||||
reth-interfaces.workspace = true
|
||||
reth-provider.workspace = true
|
||||
reth-consensus-common.workspace = true
|
||||
|
||||
# Optimism
|
||||
reth-optimism-consensus.workspace = true
|
||||
|
||||
# revm
|
||||
revm.workspace = true
|
||||
revm-primitives.workspace = true
|
||||
|
||||
@ -35,4 +39,5 @@ optimism = [
|
||||
"reth-provider/optimism",
|
||||
"reth-interfaces/optimism",
|
||||
"revm-primitives/optimism",
|
||||
"reth-optimism-consensus/optimism",
|
||||
]
|
||||
|
||||
@ -1,9 +1,6 @@
|
||||
//! Optimism block executor.
|
||||
|
||||
use crate::{
|
||||
l1::ensure_create2_deployer, verify::verify_receipts, OptimismBlockExecutionError,
|
||||
OptimismEvmConfig,
|
||||
};
|
||||
use crate::{l1::ensure_create2_deployer, OptimismBlockExecutionError, OptimismEvmConfig};
|
||||
use reth_evm::{
|
||||
execute::{
|
||||
BatchBlockExecutionOutput, BatchExecutor, BlockExecutionInput, BlockExecutionOutput,
|
||||
@ -15,9 +12,10 @@ use reth_interfaces::{
|
||||
executor::{BlockExecutionError, BlockValidationError},
|
||||
provider::ProviderError,
|
||||
};
|
||||
use reth_optimism_consensus::validate_block_post_execution;
|
||||
use reth_primitives::{
|
||||
BlockNumber, BlockWithSenders, ChainSpec, GotExpected, Hardfork, Header, PruneModes, Receipt,
|
||||
Receipts, TxType, Withdrawals, U256,
|
||||
BlockNumber, BlockWithSenders, ChainSpec, Hardfork, Header, PruneModes, Receipt, Receipts,
|
||||
TxType, Withdrawals, U256,
|
||||
};
|
||||
use reth_revm::{
|
||||
batch::{BlockBatchRecord, BlockExecutorStats},
|
||||
@ -30,7 +28,7 @@ use revm_primitives::{
|
||||
BlockEnv, CfgEnvWithHandlerCfg, EnvWithHandlerCfg, ResultAndState,
|
||||
};
|
||||
use std::sync::Arc;
|
||||
use tracing::{debug, trace};
|
||||
use tracing::trace;
|
||||
|
||||
/// Provides executors to execute regular ethereum blocks
|
||||
#[derive(Debug, Clone)]
|
||||
@ -157,12 +155,12 @@ where
|
||||
transaction_gas_limit: transaction.gas_limit(),
|
||||
block_available_gas,
|
||||
}
|
||||
.into());
|
||||
.into())
|
||||
}
|
||||
|
||||
// An optimism block should never contain blob transactions.
|
||||
if matches!(transaction.tx_type(), TxType::Eip4844) {
|
||||
return Err(OptimismBlockExecutionError::BlobTransactionRejected.into());
|
||||
return Err(OptimismBlockExecutionError::BlobTransactionRejected.into())
|
||||
}
|
||||
|
||||
// Cache the depositor account prior to the state transition for the deposit nonce.
|
||||
@ -221,16 +219,6 @@ where
|
||||
}
|
||||
drop(evm);
|
||||
|
||||
// Check if gas used matches the value set in header.
|
||||
if block.gas_used != cumulative_gas_used {
|
||||
let receipts = Receipts::from_block_receipt(receipts);
|
||||
return Err(BlockValidationError::BlockGasUsed {
|
||||
gas: GotExpected { got: cumulative_gas_used, expected: block.gas_used },
|
||||
gas_spent_by_tx: receipts.gas_spent_by_tx()?,
|
||||
}
|
||||
.into());
|
||||
}
|
||||
|
||||
Ok((receipts, cumulative_gas_used))
|
||||
}
|
||||
}
|
||||
@ -292,8 +280,8 @@ where
|
||||
///
|
||||
/// Returns the receipts of the transactions in the block and the total gas used.
|
||||
///
|
||||
/// Returns an error if execution fails or receipt verification fails.
|
||||
fn execute_and_verify(
|
||||
/// Returns an error if execution fails.
|
||||
fn execute_without_verification(
|
||||
&mut self,
|
||||
block: &BlockWithSenders,
|
||||
total_difficulty: U256,
|
||||
@ -312,23 +300,6 @@ where
|
||||
// 3. apply post execution changes
|
||||
self.post_execution(block, total_difficulty)?;
|
||||
|
||||
// Before Byzantium, receipts contained state root that would mean that expensive
|
||||
// operation as hashing that is required for state root got calculated in every
|
||||
// transaction This was replaced with is_success flag.
|
||||
// See more about EIP here: https://eips.ethereum.org/EIPS/eip-658
|
||||
if self.chain_spec().is_byzantium_active_at_block(block.header.number) {
|
||||
if let Err(error) = verify_receipts(
|
||||
block.header.receipts_root,
|
||||
block.header.logs_bloom,
|
||||
receipts.iter(),
|
||||
self.chain_spec(),
|
||||
block.timestamp,
|
||||
) {
|
||||
debug!(target: "evm", %error, ?receipts, "receipts verification failed");
|
||||
return Err(error);
|
||||
};
|
||||
}
|
||||
|
||||
Ok((receipts, gas_used))
|
||||
}
|
||||
|
||||
@ -383,7 +354,7 @@ where
|
||||
/// State changes are committed to the database.
|
||||
fn execute(mut self, input: Self::Input<'_>) -> Result<Self::Output, Self::Error> {
|
||||
let BlockExecutionInput { block, total_difficulty } = input;
|
||||
let (receipts, gas_used) = self.execute_and_verify(block, total_difficulty)?;
|
||||
let (receipts, gas_used) = self.execute_without_verification(block, total_difficulty)?;
|
||||
|
||||
// NOTE: we need to merge keep the reverts for the bundle retention
|
||||
self.state.merge_transitions(BundleRetention::Reverts);
|
||||
@ -426,9 +397,12 @@ where
|
||||
type Output = BatchBlockExecutionOutput;
|
||||
type Error = BlockExecutionError;
|
||||
|
||||
fn execute_one(&mut self, input: Self::Input<'_>) -> Result<(), Self::Error> {
|
||||
fn execute_and_verify_one(&mut self, input: Self::Input<'_>) -> Result<(), Self::Error> {
|
||||
let BlockExecutionInput { block, total_difficulty } = input;
|
||||
let (receipts, _gas_used) = self.executor.execute_and_verify(block, total_difficulty)?;
|
||||
let (receipts, _gas_used) =
|
||||
self.executor.execute_without_verification(block, total_difficulty)?;
|
||||
|
||||
validate_block_post_execution(block, self.executor.chain_spec(), &receipts)?;
|
||||
|
||||
// prepare the state according to the prune mode
|
||||
let retention = self.batch_record.bundle_retention(block.number);
|
||||
@ -557,7 +531,7 @@ mod tests {
|
||||
|
||||
// Attempt to execute a block with one deposit and one non-deposit transaction
|
||||
executor
|
||||
.execute_one(
|
||||
.execute_and_verify_one(
|
||||
(
|
||||
&BlockWithSenders {
|
||||
block: Block {
|
||||
@ -638,7 +612,7 @@ mod tests {
|
||||
|
||||
// attempt to execute an empty block with parent beacon block root, this should not fail
|
||||
executor
|
||||
.execute_one(
|
||||
.execute_and_verify_one(
|
||||
(
|
||||
&BlockWithSenders {
|
||||
block: Block {
|
||||
|
||||
@ -23,7 +23,6 @@ pub mod l1;
|
||||
pub use l1::*;
|
||||
|
||||
mod error;
|
||||
pub mod verify;
|
||||
pub use error::OptimismBlockExecutionError;
|
||||
|
||||
/// Optimism-related EVM configuration.
|
||||
|
||||
@ -1,58 +0,0 @@
|
||||
//! Helpers for verifying the receipts.
|
||||
|
||||
use reth_interfaces::executor::{BlockExecutionError, BlockValidationError};
|
||||
use reth_primitives::{
|
||||
proofs::calculate_receipt_root_optimism, Bloom, ChainSpec, GotExpected, Receipt,
|
||||
ReceiptWithBloom, B256,
|
||||
};
|
||||
|
||||
/// Verify the calculated receipts root against the expected receipts root.
|
||||
pub fn verify_receipts<'a>(
|
||||
expected_receipts_root: B256,
|
||||
expected_logs_bloom: Bloom,
|
||||
receipts: impl Iterator<Item = &'a Receipt> + Clone,
|
||||
chain_spec: &ChainSpec,
|
||||
timestamp: u64,
|
||||
) -> Result<(), BlockExecutionError> {
|
||||
// Calculate receipts root.
|
||||
let receipts_with_bloom = receipts.map(|r| r.clone().into()).collect::<Vec<ReceiptWithBloom>>();
|
||||
let receipts_root =
|
||||
calculate_receipt_root_optimism(&receipts_with_bloom, chain_spec, timestamp);
|
||||
|
||||
// Create header log bloom.
|
||||
let logs_bloom = receipts_with_bloom.iter().fold(Bloom::ZERO, |bloom, r| bloom | r.bloom);
|
||||
|
||||
compare_receipts_root_and_logs_bloom(
|
||||
receipts_root,
|
||||
logs_bloom,
|
||||
expected_receipts_root,
|
||||
expected_logs_bloom,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Compare the calculated receipts root with the expected receipts root, also compare
|
||||
/// the calculated logs bloom with the expected logs bloom.
|
||||
pub fn compare_receipts_root_and_logs_bloom(
|
||||
calculated_receipts_root: B256,
|
||||
calculated_logs_bloom: Bloom,
|
||||
expected_receipts_root: B256,
|
||||
expected_logs_bloom: Bloom,
|
||||
) -> Result<(), BlockExecutionError> {
|
||||
if calculated_receipts_root != expected_receipts_root {
|
||||
return Err(BlockValidationError::ReceiptRootDiff(
|
||||
GotExpected { got: calculated_receipts_root, expected: expected_receipts_root }.into(),
|
||||
)
|
||||
.into())
|
||||
}
|
||||
|
||||
if calculated_logs_bloom != expected_logs_bloom {
|
||||
return Err(BlockValidationError::BloomLogDiff(
|
||||
GotExpected { got: calculated_logs_bloom, expected: expected_logs_bloom }.into(),
|
||||
)
|
||||
.into())
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Reference in New Issue
Block a user