Skip to content

Commit

Permalink
refactor: extract optimism receipts hashing logic to `reth-optimism-c…
Browse files Browse the repository at this point in the history
  • Loading branch information
klkvr committed Sep 26, 2024
1 parent 4a05826 commit 353fd60
Show file tree
Hide file tree
Showing 14 changed files with 80 additions and 94 deletions.
5 changes: 3 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion crates/consensus/auto-seal/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,14 @@ 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"] }
tokio-stream.workspace = true
tracing.workspace = true

[features]
optimism = ["reth-provider/optimism"]
optimism = ["reth-provider/optimism", "reth-optimism-consensus"]
8 changes: 7 additions & 1 deletion crates/consensus/auto-seal/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"))]
Expand Down
3 changes: 1 addition & 2 deletions crates/evm/execution-types/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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 = []
17 changes: 7 additions & 10 deletions crates/evm/execution-types/src/execution_outcome.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<B256> {
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.
Expand Down
2 changes: 2 additions & 0 deletions crates/optimism/consensus/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
37 changes: 36 additions & 1 deletion crates/optimism/consensus/src/proof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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::<Vec<_>>();

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::*;
Expand Down
1 change: 1 addition & 0 deletions crates/optimism/payload/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
9 changes: 4 additions & 5 deletions crates/optimism/payload/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand Down Expand Up @@ -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");

Expand Down
1 change: 1 addition & 0 deletions crates/optimism/rpc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
15 changes: 9 additions & 6 deletions crates/optimism/rpc/src/eth/pending_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
Expand Down Expand Up @@ -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::<u64>(),
)
.generic_receipts_root_slow(block_number, |receipts| {
calculate_receipt_root_no_memo_optimism(
receipts,
self.provider().chain_spec().as_ref(),
block_env.timestamp.to::<u64>(),
)
})
.expect("Block is present")
}
}
5 changes: 0 additions & 5 deletions crates/primitives/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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",
Expand All @@ -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",
Expand Down
41 changes: 0 additions & 41 deletions crates/primitives/src/proofs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::<Vec<_>>();

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
Expand Down
25 changes: 5 additions & 20 deletions crates/primitives/src/receipt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<B256> {
Some(crate::proofs::calculate_receipt_root_no_memo(
&self.receipt_vec[index].iter().map(Option::as_ref).collect::<Option<Vec<_>>>()?,
))
}

/// 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<B256> {
Some(crate::proofs::calculate_receipt_root_no_memo_optimism(
&self.receipt_vec[index].iter().map(Option::as_ref).collect::<Option<Vec<_>>>()?,
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<B256> {
let receipts =
self.receipt_vec[index].iter().map(Option::as_ref).collect::<Option<Vec<_>>>()?;
Some(f(receipts.as_slice()))
}
}

Expand Down

0 comments on commit 353fd60

Please sign in to comment.