From cd0a2f34bcdd0e4ce86c915d3299848c3ba18ac7 Mon Sep 17 00:00:00 2001 From: Dan Cline <6798349+Rjected@users.noreply.github.com> Date: Fri, 9 Feb 2024 12:55:08 -0500 Subject: [PATCH] chore: remove op-flagged arguments from receipt root calc (#6517) --- crates/blockchain-tree/src/blockchain_tree.rs | 8 +++- crates/consensus/auto-seal/src/lib.rs | 45 ++++++++++++++++-- crates/primitives/src/proofs.rs | 47 +++++++++++-------- crates/primitives/src/receipt.rs | 10 ++-- crates/revm/src/optimism/processor.rs | 33 +++++++++++-- crates/revm/src/processor.rs | 47 ++++++++++++------- 6 files changed, 141 insertions(+), 49 deletions(-) diff --git a/crates/blockchain-tree/src/blockchain_tree.rs b/crates/blockchain-tree/src/blockchain_tree.rs index 13dd54ae0a..c0af4fa195 100644 --- a/crates/blockchain-tree/src/blockchain_tree.rs +++ b/crates/blockchain-tree/src/blockchain_tree.rs @@ -1243,10 +1243,14 @@ mod tests { use reth_db::{tables, test_utils::TempDatabase, transaction::DbTxMut, DatabaseEnv}; use reth_interfaces::test_utils::TestConsensus; use reth_node_ethereum::EthEvmConfig; + #[cfg(not(feature = "optimism"))] + use reth_primitives::proofs::calculate_receipt_root; + #[cfg(feature = "optimism")] + use reth_primitives::proofs::calculate_receipt_root_optimism; use reth_primitives::{ constants::{EIP1559_INITIAL_BASE_FEE, EMPTY_ROOT_HASH, ETHEREUM_BLOCK_GAS_LIMIT}, keccak256, - proofs::{calculate_receipt_root, calculate_transaction_root, state_root_unhashed}, + proofs::{calculate_transaction_root, state_root_unhashed}, revm_primitives::AccountInfo, stage::StageCheckpoint, Account, Address, ChainSpecBuilder, Genesis, GenesisAccount, Header, Signature, @@ -1466,7 +1470,7 @@ mod tests { let receipts_root = calculate_receipt_root(&receipts); #[cfg(feature = "optimism")] - let receipts_root = calculate_receipt_root(&receipts, &chain_spec, 0); + let receipts_root = calculate_receipt_root_optimism(&receipts, &chain_spec, 0); SealedBlockWithSenders::new( SealedBlock { diff --git a/crates/consensus/auto-seal/src/lib.rs b/crates/consensus/auto-seal/src/lib.rs index 95f0c7f8d3..3fb6c02ca2 100644 --- a/crates/consensus/auto-seal/src/lib.rs +++ b/crates/consensus/auto-seal/src/lib.rs @@ -345,13 +345,17 @@ impl StorageInner { /// Fills in the post-execution header fields based on the given BundleState and gas used. /// In doing this, the state root is calculated and the final header is returned. + /// + /// This is optimism-specific and contains the `ChainSpec` so the proper state root can be + /// calculated. + #[cfg(feature = "optimism")] pub(crate) fn complete_header( &self, mut header: Header, bundle_state: &BundleStateWithReceipts, client: &S, gas_used: u64, - #[cfg(feature = "optimism")] chain_spec: &ChainSpec, + chain_spec: &ChainSpec, ) -> Result { let receipts = bundle_state.receipts_by_block(header.number); header.receipts_root = if receipts.is_empty() { @@ -363,11 +367,9 @@ impl StorageInner { .collect::>(); header.logs_bloom = receipts_with_bloom.iter().fold(Bloom::ZERO, |bloom, r| bloom | r.bloom); - proofs::calculate_receipt_root( + proofs::calculate_receipt_root_optimism( &receipts_with_bloom, - #[cfg(feature = "optimism")] chain_spec, - #[cfg(feature = "optimism")] header.timestamp, ) }; @@ -384,6 +386,41 @@ impl StorageInner { Ok(header) } + /// Fills in the post-execution header fields based on the given BundleState and gas used. + /// In doing this, the state root is calculated and the final header is returned. + #[cfg(not(feature = "optimism"))] + pub(crate) fn complete_header( + &self, + mut header: Header, + bundle_state: &BundleStateWithReceipts, + client: &S, + gas_used: u64, + ) -> Result { + let receipts = bundle_state.receipts_by_block(header.number); + header.receipts_root = if receipts.is_empty() { + EMPTY_RECEIPTS + } else { + let receipts_with_bloom = receipts + .iter() + .map(|r| (*r).clone().expect("receipts have not been pruned").into()) + .collect::>(); + header.logs_bloom = + receipts_with_bloom.iter().fold(Bloom::ZERO, |bloom, r| bloom | r.bloom); + proofs::calculate_receipt_root(&receipts_with_bloom) + }; + + header.gas_used = gas_used; + + // calculate the state root + let state_root = client + .latest() + .map_err(|_| BlockExecutionError::ProviderError)? + .state_root(bundle_state) + .unwrap(); + header.state_root = state_root; + Ok(header) + } + /// Builds and executes a new block with the given transactions, on the provided [EVMProcessor]. /// /// This returns the header of the executed block, as well as the poststate from execution. diff --git a/crates/primitives/src/proofs.rs b/crates/primitives/src/proofs.rs index 096221e259..20958c3f11 100644 --- a/crates/primitives/src/proofs.rs +++ b/crates/primitives/src/proofs.rs @@ -69,14 +69,13 @@ pub fn calculate_withdrawals_root(withdrawals: &[Withdrawal]) -> B256 { } /// Calculates the receipt root for a header. -#[cfg(not(feature = "optimism"))] pub fn calculate_receipt_root(receipts: &[ReceiptWithBloom]) -> B256 { ordered_trie_root_with_encoder(receipts, |r, buf| r.encode_inner(buf, false)) } /// Calculates the receipt root for a header. #[cfg(feature = "optimism")] -pub fn calculate_receipt_root( +pub fn calculate_receipt_root_optimism( receipts: &[ReceiptWithBloom], chain_spec: &crate::ChainSpec, timestamp: u64, @@ -109,7 +108,6 @@ pub fn calculate_receipt_root( /// Calculates the receipt root for a header for the reference type of [Receipt]. /// /// NOTE: Prefer [calculate_receipt_root] if you have log blooms memoized. -#[cfg(not(feature = "optimism"))] pub fn calculate_receipt_root_ref(receipts: &[&Receipt]) -> B256 { ordered_trie_root_with_encoder(receipts, |r, buf| { ReceiptWithBloomRef::from(*r).encode_inner(buf, false) @@ -120,7 +118,7 @@ pub fn calculate_receipt_root_ref(receipts: &[&Receipt]) -> B256 { /// /// NOTE: Prefer [calculate_receipt_root] if you have log blooms memoized. #[cfg(feature = "optimism")] -pub fn calculate_receipt_root_ref( +pub fn calculate_receipt_root_ref_optimism( receipts: &[&Receipt], chain_spec: &crate::ChainSpec, timestamp: u64, @@ -263,11 +261,10 @@ pub mod triehash { #[cfg(test)] mod tests { use super::*; + #[cfg(not(feature = "optimism"))] + use crate::proofs::calculate_receipt_root; use crate::{ - bloom, - constants::EMPTY_ROOT_HASH, - hex_literal::hex, - proofs::{calculate_receipt_root, calculate_transaction_root}, + bloom, constants::EMPTY_ROOT_HASH, hex_literal::hex, proofs::calculate_transaction_root, Address, Block, GenesisAccount, Log, Receipt, ReceiptWithBloom, TxType, B256, GOERLI, HOLESKY, MAINNET, SEPOLIA, U256, }; @@ -543,13 +540,14 @@ mod tests { bloom: Bloom(hex!("00000000000000000000000000000000400000000000000000000000000000000000004000000000000001000000000000000002000000000100000000000000000000000000000000000008000000000000000000000000000000000000000004000000020000000000000000000800000000000000000000000010200100200008000002000000000000000000800000000000000000000002000000000000000000000000000000080000000000000000000000004000000000000000000000000002000000000000000000000000000000000000200000000000000020002000000000000000002000000000000000000000000000000000000000000000").into()), }, ]; - let root = calculate_receipt_root(&receipts, OP_GOERLI.as_ref(), case.1); + let root = calculate_receipt_root_optimism(&receipts, OP_GOERLI.as_ref(), case.1); assert_eq!(root, case.2); } } + #[cfg(feature = "optimism")] #[test] - fn check_receipt_root() { + fn check_receipt_root_optimism() { let logs = vec![Log { address: Address::ZERO, topics: vec![], data: Default::default() }]; let bloom = bloom!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001"); let receipt = ReceiptWithBloom { @@ -558,21 +556,32 @@ mod tests { success: true, cumulative_gas_used: 102068, logs, - #[cfg(feature = "optimism")] deposit_nonce: None, - #[cfg(feature = "optimism")] deposit_receipt_version: None, }, bloom, }; let receipt = vec![receipt]; - let root = calculate_receipt_root( - &receipt, - #[cfg(feature = "optimism")] - crate::OP_GOERLI.as_ref(), - #[cfg(feature = "optimism")] - 0, - ); + let root = calculate_receipt_root_optimism(&receipt, crate::OP_GOERLI.as_ref(), 0); + assert_eq!(root, b256!("fe70ae4a136d98944951b2123859698d59ad251a381abc9960fa81cae3d0d4a0")); + } + + #[cfg(not(feature = "optimism"))] + #[test] + fn check_receipt_root_optimism() { + let logs = vec![Log { address: Address::ZERO, topics: vec![], data: Default::default() }]; + let bloom = bloom!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001"); + let receipt = ReceiptWithBloom { + receipt: Receipt { + tx_type: TxType::EIP2930, + success: true, + cumulative_gas_used: 102068, + logs, + }, + bloom, + }; + let receipt = vec![receipt]; + let root = calculate_receipt_root(&receipt); assert_eq!(root, b256!("fe70ae4a136d98944951b2123859698d59ad251a381abc9960fa81cae3d0d4a0")); } diff --git a/crates/primitives/src/receipt.rs b/crates/primitives/src/receipt.rs index 46dd862f7c..2c78747089 100644 --- a/crates/primitives/src/receipt.rs +++ b/crates/primitives/src/receipt.rs @@ -1,8 +1,10 @@ +#[cfg(not(feature = "optimism"))] +use crate::proofs::calculate_receipt_root_ref; +#[cfg(feature = "optimism")] +use crate::proofs::calculate_receipt_root_ref_optimism; use crate::{ compression::{RECEIPT_COMPRESSOR, RECEIPT_DECOMPRESSOR}, - logs_bloom, - proofs::calculate_receipt_root_ref, - Bloom, Log, PruneSegmentError, TxType, B256, + logs_bloom, Bloom, Log, PruneSegmentError, TxType, B256, }; use alloy_rlp::{length_of_length, Decodable, Encodable}; use bytes::{Buf, BufMut, BytesMut}; @@ -110,7 +112,7 @@ impl Receipts { chain_spec: &crate::ChainSpec, timestamp: u64, ) -> Option { - Some(calculate_receipt_root_ref( + Some(calculate_receipt_root_ref_optimism( &self.receipt_vec[index].iter().map(Option::as_ref).collect::>>()?, chain_spec, timestamp, diff --git a/crates/revm/src/optimism/processor.rs b/crates/revm/src/optimism/processor.rs index c1e4e964dc..1fb5e84fee 100644 --- a/crates/revm/src/optimism/processor.rs +++ b/crates/revm/src/optimism/processor.rs @@ -1,16 +1,43 @@ -use crate::processor::{verify_receipt, EVMProcessor}; +use crate::processor::{compare_receipts_root_and_logs_bloom, EVMProcessor}; use reth_interfaces::executor::{ BlockExecutionError, BlockValidationError, OptimismBlockExecutionError, }; use reth_node_api::ConfigureEvmEnv; use reth_primitives::{ - revm_primitives::ResultAndState, BlockWithSenders, Hardfork, Receipt, TxType, U256, + proofs::calculate_receipt_root_optimism, revm_primitives::ResultAndState, BlockWithSenders, + Bloom, ChainSpec, Hardfork, Receipt, ReceiptWithBloom, TxType, B256, U256, }; use reth_provider::{BlockExecutor, BlockExecutorStats, BundleStateWithReceipts}; use revm::DatabaseCommit; use std::time::Instant; use tracing::{debug, trace}; +/// Verify the calculated receipts root against the expected receipts root. +pub fn verify_receipt_optimism<'a>( + expected_receipts_root: B256, + expected_logs_bloom: Bloom, + receipts: impl Iterator + Clone, + chain_spec: &ChainSpec, + timestamp: u64, +) -> Result<(), BlockExecutionError> { + // Calculate receipts root. + let receipts_with_bloom = receipts.map(|r| r.clone().into()).collect::>(); + 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(()) +} + impl<'a, EvmConfig> BlockExecutor for EVMProcessor<'a, EvmConfig> where EvmConfig: ConfigureEvmEnv, @@ -38,7 +65,7 @@ where // See more about EIP here: https://eips.ethereum.org/EIPS/eip-658 if self.chain_spec.fork(Hardfork::Byzantium).active_at_block(block.header.number) { let time = Instant::now(); - if let Err(error) = verify_receipt( + if let Err(error) = verify_receipt_optimism( block.header.receipts_root, block.header.logs_bloom, receipts.iter(), diff --git a/crates/revm/src/processor.rs b/crates/revm/src/processor.rs index 1872d1eef3..ffe7cf05a8 100644 --- a/crates/revm/src/processor.rs +++ b/crates/revm/src/processor.rs @@ -530,35 +530,48 @@ where } } -/// Verify receipts +/// Calculate the receipts root, and copmare it against against the expected receipts root and logs +/// bloom. pub fn verify_receipt<'a>( expected_receipts_root: B256, expected_logs_bloom: Bloom, receipts: impl Iterator + Clone, - #[cfg(feature = "optimism")] chain_spec: &ChainSpec, - #[cfg(feature = "optimism")] timestamp: u64, ) -> Result<(), BlockExecutionError> { - // Check receipts root. + // Calculate receipts root. let receipts_with_bloom = receipts.map(|r| r.clone().into()).collect::>(); - let receipts_root = reth_primitives::proofs::calculate_receipt_root( - &receipts_with_bloom, - #[cfg(feature = "optimism")] - chain_spec, - #[cfg(feature = "optimism")] - timestamp, - ); - if receipts_root != expected_receipts_root { + let receipts_root = reth_primitives::proofs::calculate_receipt_root(&receipts_with_bloom); + + // 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 copmare +/// 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: receipts_root, expected: expected_receipts_root }.into(), + GotExpected { got: calculated_receipts_root, expected: expected_receipts_root }.into(), ) .into()) } - // Create header log bloom. - let logs_bloom = receipts_with_bloom.iter().fold(Bloom::ZERO, |bloom, r| bloom | r.bloom); - if logs_bloom != expected_logs_bloom { + if calculated_logs_bloom != expected_logs_bloom { return Err(BlockValidationError::BloomLogDiff( - GotExpected { got: logs_bloom, expected: expected_logs_bloom }.into(), + GotExpected { got: calculated_logs_bloom, expected: expected_logs_bloom }.into(), ) .into()) }