diff --git a/Cargo.lock b/Cargo.lock index ed12e6bf0de6..a02679addc75 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6255,6 +6255,7 @@ dependencies = [ "reth-execution-types", "reth-network-p2p", "reth-network-peers", + "reth-optimism-consensus", "reth-primitives", "reth-provider", "reth-revm", @@ -7368,7 +7369,6 @@ version = "1.0.7" dependencies = [ "alloy-eips", "alloy-primitives", - "reth-chainspec", "reth-execution-errors", "reth-primitives", "reth-trie", @@ -8117,6 +8117,7 @@ dependencies = [ "reth-evm", "reth-evm-optimism", "reth-execution-types", + "reth-optimism-consensus", "reth-optimism-forks", "reth-payload-builder", "reth-payload-primitives", @@ -8163,6 +8164,7 @@ dependencies = [ "reth-node-api", "reth-node-builder", "reth-optimism-chainspec", + "reth-optimism-consensus", "reth-optimism-forks", "reth-primitives", "reth-provider", @@ -8262,7 +8264,6 @@ dependencies = [ "reth-codecs", "reth-ethereum-forks", "reth-optimism-chainspec", - "reth-optimism-forks", "reth-primitives-traits", "reth-static-file-types", "reth-trie-common", diff --git a/crates/consensus/auto-seal/Cargo.toml b/crates/consensus/auto-seal/Cargo.toml index d712071a1927..b4b281230336 100644 --- a/crates/consensus/auto-seal/Cargo.toml +++ b/crates/consensus/auto-seal/Cargo.toml @@ -35,6 +35,9 @@ alloy-primitives.workspace = true revm-primitives.workspace = true alloy-rpc-types-engine.workspace = true +# optimism +reth-optimism-consensus = { workspace = true, optional = true } + # async futures-util.workspace = true tokio = { workspace = true, features = ["sync", "time"] } @@ -42,4 +45,4 @@ tokio-stream.workspace = true tracing.workspace = true [features] -optimism = ["reth-provider/optimism"] +optimism = ["reth-provider/optimism", "reth-optimism-consensus"] diff --git a/crates/consensus/auto-seal/src/lib.rs b/crates/consensus/auto-seal/src/lib.rs index fea15f84d510..db418285cf3e 100644 --- a/crates/consensus/auto-seal/src/lib.rs +++ b/crates/consensus/auto-seal/src/lib.rs @@ -419,7 +419,13 @@ impl StorageInner { header.receipts_root = { #[cfg(feature = "optimism")] let receipts_root = execution_outcome - .optimism_receipts_root_slow(header.number, &chain_spec, header.timestamp) + .generic_receipts_root_slow(header.number, |receipts| { + reth_optimism_consensus::calculate_receipt_root_no_memo_optimism( + receipts, + &chain_spec, + header.timestamp, + ) + }) .expect("Receipts is present"); #[cfg(not(feature = "optimism"))] diff --git a/crates/evm/execution-types/Cargo.toml b/crates/evm/execution-types/Cargo.toml index 352eeb79f12e..c286f07906bb 100644 --- a/crates/evm/execution-types/Cargo.toml +++ b/crates/evm/execution-types/Cargo.toml @@ -12,7 +12,6 @@ workspace = true [dependencies] reth-primitives.workspace = true -reth-chainspec = { workspace = true, optional = true } reth-execution-errors.workspace = true reth-trie.workspace = true @@ -31,6 +30,6 @@ alloy-eips.workspace = true [features] default = ["std"] -optimism = ["dep:reth-chainspec"] +optimism = [] serde = ["dep:serde", "reth-trie/serde", "revm/serde"] std = [] diff --git a/crates/evm/execution-types/src/execution_outcome.rs b/crates/evm/execution-types/src/execution_outcome.rs index 47caa3b101f0..3b21f36dd13c 100644 --- a/crates/evm/execution-types/src/execution_outcome.rs +++ b/crates/evm/execution-types/src/execution_outcome.rs @@ -196,24 +196,21 @@ impl ExecutionOutcome { #[cfg(feature = "optimism")] panic!("This should not be called in optimism mode. Use `optimism_receipts_root_slow` instead."); #[cfg(not(feature = "optimism"))] - self.receipts.root_slow(self.block_number_to_index(_block_number)?) + self.receipts.root_slow( + self.block_number_to_index(_block_number)?, + reth_primitives::proofs::calculate_receipt_root_no_memo, + ) } /// Returns the receipt root for all recorded receipts. /// Note: this function calculated Bloom filters for every receipt and created merkle trees /// of receipt. This is a expensive operation. - #[cfg(feature = "optimism")] - pub fn optimism_receipts_root_slow( + pub fn generic_receipts_root_slow( &self, block_number: BlockNumber, - chain_spec: impl reth_chainspec::Hardforks, - timestamp: u64, + f: impl FnOnce(&[&Receipt]) -> B256, ) -> Option { - self.receipts.optimism_root_slow( - self.block_number_to_index(block_number)?, - chain_spec, - timestamp, - ) + self.receipts.root_slow(self.block_number_to_index(block_number)?, f) } /// Returns reference to receipts. diff --git a/crates/optimism/consensus/src/lib.rs b/crates/optimism/consensus/src/lib.rs index 1f529a9a927f..d040d32e04d1 100644 --- a/crates/optimism/consensus/src/lib.rs +++ b/crates/optimism/consensus/src/lib.rs @@ -25,6 +25,8 @@ use reth_primitives::{ use std::{sync::Arc, time::SystemTime}; mod proof; +pub use proof::calculate_receipt_root_no_memo_optimism; + mod validation; pub use validation::validate_block_post_execution; diff --git a/crates/optimism/consensus/src/proof.rs b/crates/optimism/consensus/src/proof.rs index 383902659989..b283356016c2 100644 --- a/crates/optimism/consensus/src/proof.rs +++ b/crates/optimism/consensus/src/proof.rs @@ -3,7 +3,7 @@ use alloy_primitives::B256; use reth_chainspec::ChainSpec; use reth_optimism_forks::OptimismHardfork; -use reth_primitives::ReceiptWithBloom; +use reth_primitives::{Receipt, ReceiptWithBloom, ReceiptWithBloomRef}; use reth_trie_common::root::ordered_trie_root_with_encoder; /// Calculates the receipt root for a header. @@ -37,6 +37,41 @@ pub(crate) fn calculate_receipt_root_optimism( ordered_trie_root_with_encoder(receipts, |r, buf| r.encode_inner(buf, false)) } +/// Calculates the receipt root for a header for the reference type of [Receipt]. +/// +/// NOTE: Prefer calculate receipt root optimism if you have log blooms memoized. +pub fn calculate_receipt_root_no_memo_optimism( + receipts: &[&Receipt], + chain_spec: impl reth_chainspec::Hardforks, + timestamp: u64, +) -> B256 { + // There is a minor bug in op-geth and op-erigon where in the Regolith hardfork, + // the receipt root calculation does not include the deposit nonce in the receipt + // encoding. In the Regolith Hardfork, we must strip the deposit nonce from the + // receipts before calculating the receipt root. This was corrected in the Canyon + // hardfork. + if chain_spec.is_fork_active_at_timestamp(OptimismHardfork::Regolith, timestamp) && + !chain_spec.is_fork_active_at_timestamp(OptimismHardfork::Canyon, timestamp) + { + let receipts = receipts + .iter() + .map(|r| { + let mut r = (*r).clone(); + r.deposit_nonce = None; + r + }) + .collect::>(); + + return ordered_trie_root_with_encoder(&receipts, |r, buf| { + ReceiptWithBloomRef::from(r).encode_inner(buf, false) + }) + } + + ordered_trie_root_with_encoder(receipts, |r, buf| { + ReceiptWithBloomRef::from(*r).encode_inner(buf, false) + }) +} + #[cfg(test)] mod tests { use super::*; diff --git a/crates/optimism/payload/Cargo.toml b/crates/optimism/payload/Cargo.toml index e64b72610d99..e58b26ee83df 100644 --- a/crates/optimism/payload/Cargo.toml +++ b/crates/optimism/payload/Cargo.toml @@ -29,6 +29,7 @@ reth-chain-state.workspace = true # op-reth reth-evm-optimism.workspace = true +reth-optimism-consensus.workspace = true reth-optimism-forks.workspace = true # ethereum diff --git a/crates/optimism/payload/src/builder.rs b/crates/optimism/payload/src/builder.rs index 18c1ece8ffec..84e69cb92e73 100644 --- a/crates/optimism/payload/src/builder.rs +++ b/crates/optimism/payload/src/builder.rs @@ -11,6 +11,7 @@ use reth_evm::{ NextBlockEnvAttributes, }; use reth_execution_types::ExecutionOutcome; +use reth_optimism_consensus::calculate_receipt_root_no_memo_optimism; use reth_optimism_forks::OptimismHardfork; use reth_payload_primitives::{PayloadBuilderAttributes, PayloadBuilderError}; use reth_primitives::{ @@ -443,11 +444,9 @@ where Vec::new(), ); let receipts_root = execution_outcome - .optimism_receipts_root_slow( - block_number, - &chain_spec, - attributes.payload_attributes.timestamp, - ) + .generic_receipts_root_slow(block_number, |receipts| { + calculate_receipt_root_no_memo_optimism(receipts, &chain_spec, attributes.timestamp()) + }) .expect("Number is in range"); let logs_bloom = execution_outcome.block_logs_bloom(block_number).expect("Number is in range"); diff --git a/crates/optimism/rpc/Cargo.toml b/crates/optimism/rpc/Cargo.toml index 443830cc5321..e82ff1827652 100644 --- a/crates/optimism/rpc/Cargo.toml +++ b/crates/optimism/rpc/Cargo.toml @@ -29,6 +29,7 @@ reth-chainspec.workspace = true # op-reth reth-evm-optimism.workspace = true +reth-optimism-consensus.workspace = true reth-optimism-forks.workspace = true # ethereum diff --git a/crates/optimism/rpc/src/eth/pending_block.rs b/crates/optimism/rpc/src/eth/pending_block.rs index c96dff40b091..5b716f39320a 100644 --- a/crates/optimism/rpc/src/eth/pending_block.rs +++ b/crates/optimism/rpc/src/eth/pending_block.rs @@ -4,6 +4,7 @@ use alloy_primitives::{BlockNumber, B256}; use reth_chainspec::EthereumHardforks; use reth_evm::ConfigureEvm; use reth_node_api::{FullNodeComponents, NodeTypes}; +use reth_optimism_consensus::calculate_receipt_root_no_memo_optimism; use reth_primitives::{ revm_primitives::BlockEnv, BlockNumberOrTag, Header, Receipt, SealedBlockWithSenders, }; @@ -79,16 +80,18 @@ where fn receipts_root( &self, - _block_env: &BlockEnv, + block_env: &BlockEnv, execution_outcome: &ExecutionOutcome, block_number: BlockNumber, ) -> B256 { execution_outcome - .optimism_receipts_root_slow( - block_number, - self.provider().chain_spec().as_ref(), - _block_env.timestamp.to::(), - ) + .generic_receipts_root_slow(block_number, |receipts| { + calculate_receipt_root_no_memo_optimism( + receipts, + self.provider().chain_spec().as_ref(), + block_env.timestamp.to::(), + ) + }) .expect("Block is present") } } diff --git a/crates/primitives/Cargo.toml b/crates/primitives/Cargo.toml index 72de34e3f38e..9745159e8f52 100644 --- a/crates/primitives/Cargo.toml +++ b/crates/primitives/Cargo.toml @@ -18,12 +18,10 @@ reth-ethereum-forks.workspace = true reth-static-file-types.workspace = true reth-trie-common.workspace = true revm-primitives = { workspace = true, features = ["serde"] } -reth-chainspec = { workspace = true, optional = true } reth-codecs = { workspace = true, optional = true } # op-reth reth-optimism-chainspec = { workspace = true, optional = true } -reth-optimism-forks = { workspace = true, optional = true } # ethereum alloy-consensus.workspace = true @@ -96,7 +94,6 @@ asm-keccak = ["alloy-primitives/asm-keccak"] arbitrary = [ "reth-primitives-traits/arbitrary", "revm-primitives/arbitrary", - "reth-chainspec?/arbitrary", "reth-ethereum-forks/arbitrary", "alloy-eips/arbitrary", "dep:arbitrary", @@ -111,12 +108,10 @@ c-kzg = [ "alloy-consensus/kzg", ] optimism = [ - "reth-chainspec/optimism", "revm-primitives/optimism", "reth-codecs?/optimism", "dep:reth-optimism-chainspec", "dep:op-alloy-consensus", - "reth-optimism-forks", ] alloy-compat = [ "dep:alloy-rpc-types", diff --git a/crates/primitives/src/proofs.rs b/crates/primitives/src/proofs.rs index 7f41fa9bd20f..a19564de0938 100644 --- a/crates/primitives/src/proofs.rs +++ b/crates/primitives/src/proofs.rs @@ -49,47 +49,6 @@ pub fn calculate_receipt_root_no_memo(receipts: &[&Receipt]) -> B256 { }) } -/// Calculates the receipt root for a header for the reference type of [Receipt]. -/// -/// NOTE: Prefer calculate receipt root optimism if you have log blooms memoized. -#[cfg(feature = "optimism")] -pub fn calculate_receipt_root_no_memo_optimism( - receipts: &[&Receipt], - chain_spec: impl reth_chainspec::Hardforks, - timestamp: u64, -) -> B256 { - // There is a minor bug in op-geth and op-erigon where in the Regolith hardfork, - // the receipt root calculation does not include the deposit nonce in the receipt - // encoding. In the Regolith Hardfork, we must strip the deposit nonce from the - // receipts before calculating the receipt root. This was corrected in the Canyon - // hardfork. - - if chain_spec - .is_fork_active_at_timestamp(reth_optimism_forks::OptimismHardfork::Regolith, timestamp) && - !chain_spec.is_fork_active_at_timestamp( - reth_optimism_forks::OptimismHardfork::Canyon, - timestamp, - ) - { - let receipts = receipts - .iter() - .map(|r| { - let mut r = (*r).clone(); - r.deposit_nonce = None; - r - }) - .collect::>(); - - return ordered_trie_root_with_encoder(&receipts, |r, buf| { - ReceiptWithBloomRef::from(r).encode_inner(buf, false) - }) - } - - ordered_trie_root_with_encoder(receipts, |r, buf| { - ReceiptWithBloomRef::from(*r).encode_inner(buf, false) - }) -} - /// Calculates the root hash for ommer/uncle headers. pub fn calculate_ommers_root(ommers: &[Header]) -> B256 { // Check if `ommers` list is empty diff --git a/crates/primitives/src/receipt.rs b/crates/primitives/src/receipt.rs index 6b1b62ba6ffb..aa9b6c6d7c23 100644 --- a/crates/primitives/src/receipt.rs +++ b/crates/primitives/src/receipt.rs @@ -100,26 +100,11 @@ impl Receipts { self.receipt_vec.push(receipts); } - /// Retrieves the receipt root for all recorded receipts from index. - pub fn root_slow(&self, index: usize) -> Option { - Some(crate::proofs::calculate_receipt_root_no_memo( - &self.receipt_vec[index].iter().map(Option::as_ref).collect::>>()?, - )) - } - - /// Retrieves the receipt root for all recorded receipts from index. - #[cfg(feature = "optimism")] - pub fn optimism_root_slow( - &self, - index: usize, - chain_spec: impl reth_chainspec::Hardforks, - timestamp: u64, - ) -> Option { - Some(crate::proofs::calculate_receipt_root_no_memo_optimism( - &self.receipt_vec[index].iter().map(Option::as_ref).collect::>>()?, - chain_spec, - timestamp, - )) + /// Retrieves all recorded receipts from index and calculates the root using the given closure. + pub fn root_slow(&self, index: usize, f: impl FnOnce(&[&Receipt]) -> B256) -> Option { + let receipts = + self.receipt_vec[index].iter().map(Option::as_ref).collect::>>()?; + Some(f(receipts.as_slice())) } }