From c4d7b591834055bdf3afed96b696e0a2cef0f383 Mon Sep 17 00:00:00 2001 From: joshieDo <93316087+joshieDo@users.noreply.github.com> Date: Tue, 15 Oct 2024 22:04:20 +0900 Subject: [PATCH 001/113] perf(rpc): add optional block argument to `trace_block_until_with_inspector` (#11631) --- crates/rpc/rpc-eth-api/src/helpers/trace.rs | 22 +++++++++++++++++---- crates/rpc/rpc/src/otterscan.rs | 1 + crates/rpc/rpc/src/trace.rs | 17 ++++++++++++---- 3 files changed, 32 insertions(+), 8 deletions(-) diff --git a/crates/rpc/rpc-eth-api/src/helpers/trace.rs b/crates/rpc/rpc-eth-api/src/helpers/trace.rs index 457cbb4811f3..981de8fa6c45 100644 --- a/crates/rpc/rpc-eth-api/src/helpers/trace.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/trace.rs @@ -1,12 +1,14 @@ //! Loads a pending block from database. Helper trait for `eth_` call and trace RPC methods. +use std::sync::Arc; + use crate::FromEvmError; use alloy_primitives::B256; use alloy_rpc_types::{BlockId, TransactionInfo}; use futures::Future; use reth_chainspec::ChainSpecProvider; use reth_evm::{system_calls::SystemCaller, ConfigureEvm, ConfigureEvmEnv}; -use reth_primitives::Header; +use reth_primitives::{Header, SealedBlockWithSenders}; use reth_revm::database::StateProviderDatabase; use reth_rpc_eth_types::{ cache::db::{StateCacheDb, StateCacheDbRefMutWrapper, StateProviderTraitObjWrapper}, @@ -247,6 +249,7 @@ pub trait Trace: LoadState { fn trace_block_until( &self, block_id: BlockId, + block: Option>, highest_index: Option, config: TracingInspectorConfig, f: F, @@ -266,6 +269,7 @@ pub trait Trace: LoadState { { self.trace_block_until_with_inspector( block_id, + block, highest_index, move || TracingInspector::new(config), f, @@ -285,6 +289,7 @@ pub trait Trace: LoadState { fn trace_block_until_with_inspector( &self, block_id: BlockId, + block: Option>, highest_index: Option, mut inspector_setup: Setup, f: F, @@ -305,8 +310,15 @@ pub trait Trace: LoadState { R: Send + 'static, { async move { + let block = async { + if block.is_some() { + return Ok(block) + } + self.block_with_senders(block_id).await + }; + let ((cfg, block_env, _), block) = - futures::try_join!(self.evm_env_at(block_id), self.block_with_senders(block_id))?; + futures::try_join!(self.evm_env_at(block_id), block)?; let Some(block) = block else { return Ok(None) }; @@ -409,6 +421,7 @@ pub trait Trace: LoadState { fn trace_block_with( &self, block_id: BlockId, + block: Option>, config: TracingInspectorConfig, f: F, ) -> impl Future>, Self::Error>> + Send @@ -427,7 +440,7 @@ pub trait Trace: LoadState { + 'static, R: Send + 'static, { - self.trace_block_until(block_id, None, config, f) + self.trace_block_until(block_id, block, None, config, f) } /// Executes all transactions of a block and returns a list of callback results invoked for each @@ -447,6 +460,7 @@ pub trait Trace: LoadState { fn trace_block_inspector( &self, block_id: BlockId, + block: Option>, insp_setup: Setup, f: F, ) -> impl Future>, Self::Error>> + Send @@ -467,6 +481,6 @@ pub trait Trace: LoadState { Insp: for<'a, 'b> Inspector> + Send + 'static, R: Send + 'static, { - self.trace_block_until_with_inspector(block_id, None, insp_setup, f) + self.trace_block_until_with_inspector(block_id, block, None, insp_setup, f) } } diff --git a/crates/rpc/rpc/src/otterscan.rs b/crates/rpc/rpc/src/otterscan.rs index 31db343a104f..45722978f9f5 100644 --- a/crates/rpc/rpc/src/otterscan.rs +++ b/crates/rpc/rpc/src/otterscan.rs @@ -334,6 +334,7 @@ where .eth .trace_block_with( num.into(), + None, TracingInspectorConfig::default_parity(), |tx_info, inspector, _, _, _| { Ok(inspector.into_parity_builder().into_localized_transaction_traces(tx_info)) diff --git a/crates/rpc/rpc/src/trace.rs b/crates/rpc/rpc/src/trace.rs index 0cd94ef15b89..8ac532ff341d 100644 --- a/crates/rpc/rpc/src/trace.rs +++ b/crates/rpc/rpc/src/trace.rs @@ -1,5 +1,3 @@ -use std::sync::Arc; - use alloy_primitives::{map::HashSet, Bytes, B256, U256}; use alloy_rpc_types::{ state::{EvmOverrides, StateOverride}, @@ -37,6 +35,7 @@ use revm_inspectors::{ opcode::OpcodeGasInspector, tracing::{parity::populate_state_diff, TracingInspector, TracingInspectorConfig}, }; +use std::sync::Arc; use tokio::sync::{AcquireError, OwnedSemaphorePermit}; /// `trace` API implementation. @@ -278,14 +277,21 @@ where } // fetch all blocks in that range - let blocks = self.provider().block_range(start..=end).map_err(Eth::Error::from_eth_err)?; + let blocks = self + .provider() + .sealed_block_with_senders_range(start..=end) + .map_err(Eth::Error::from_eth_err)? + .into_iter() + .map(Arc::new) + .collect::>(); // trace all blocks let mut block_traces = Vec::with_capacity(blocks.len()); for block in &blocks { let matcher = matcher.clone(); let traces = self.eth_api().trace_block_until( - block.number.into(), + block.hash().into(), + Some(block.clone()), None, TracingInspectorConfig::default_parity(), move |tx_info, inspector, _, _, _| { @@ -369,6 +375,7 @@ where ) -> Result>, Eth::Error> { let traces = self.eth_api().trace_block_with( block_id, + None, TracingInspectorConfig::default_parity(), |tx_info, inspector, _, _, _| { let traces = @@ -405,6 +412,7 @@ where self.eth_api() .trace_block_with( block_id, + None, TracingInspectorConfig::from_parity_config(&trace_types), move |tx_info, inspector, res, state, db| { let mut full_trace = @@ -460,6 +468,7 @@ where .eth_api() .trace_block_inspector( block_id, + None, OpcodeGasInspector::default, move |tx_info, inspector, _res, _, _| { let trace = TransactionOpcodeGas { From a235f7214c588ab79af7996a07524cfbf5d2628b Mon Sep 17 00:00:00 2001 From: Roman Krasiuk Date: Tue, 15 Oct 2024 15:53:43 +0200 Subject: [PATCH 002/113] feat(trie): sparse trie (#11741) --- Cargo.lock | 15 + crates/trie/sparse/Cargo.toml | 32 ++ crates/trie/sparse/benches/root.rs | 191 +++++++++ crates/trie/sparse/src/errors.rs | 49 +++ crates/trie/sparse/src/lib.rs | 9 + crates/trie/sparse/src/state.rs | 131 ++++++ crates/trie/sparse/src/trie.rs | 627 +++++++++++++++++++++++++++++ crates/trie/trie/src/prefix_set.rs | 2 +- 8 files changed, 1055 insertions(+), 1 deletion(-) create mode 100644 crates/trie/sparse/benches/root.rs create mode 100644 crates/trie/sparse/src/errors.rs create mode 100644 crates/trie/sparse/src/state.rs create mode 100644 crates/trie/sparse/src/trie.rs diff --git a/Cargo.lock b/Cargo.lock index 828444080432..7ee37e080aed 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9221,6 +9221,21 @@ dependencies = [ [[package]] name = "reth-trie-sparse" version = "1.1.0" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "assert_matches", + "criterion", + "itertools 0.13.0", + "proptest", + "rayon", + "reth-primitives", + "reth-trie", + "reth-trie-common", + "smallvec", + "thiserror", + "tracing", +] [[package]] name = "revm" diff --git a/crates/trie/sparse/Cargo.toml b/crates/trie/sparse/Cargo.toml index 4ebb56145e1f..c31bbe2df2fe 100644 --- a/crates/trie/sparse/Cargo.toml +++ b/crates/trie/sparse/Cargo.toml @@ -10,3 +10,35 @@ description = "Sparse MPT implementation" [lints] workspace = true + + +[dependencies] +# reth +reth-primitives.workspace = true +reth-trie-common.workspace = true +reth-trie.workspace = true + +# alloy +alloy-primitives.workspace = true +alloy-rlp.workspace = true + +# tracing +tracing.workspace = true + +# misc +thiserror.workspace = true +rayon.workspace = true +smallvec = { workspace = true, features = ["const_new"] } + +[dev-dependencies] +reth-primitives = { workspace = true, features = ["test-utils", "arbitrary"] } +reth-trie-common = { workspace = true, features = ["test-utils", "arbitrary"] } +reth-trie = { workspace = true, features = ["test-utils"] } +assert_matches.workspace = true +itertools.workspace = true +proptest.workspace = true +criterion.workspace = true + +[[bench]] +name = "root" +harness = false diff --git a/crates/trie/sparse/benches/root.rs b/crates/trie/sparse/benches/root.rs new file mode 100644 index 000000000000..4078eb7af314 --- /dev/null +++ b/crates/trie/sparse/benches/root.rs @@ -0,0 +1,191 @@ +#![allow(missing_docs, unreachable_pub)] +use alloy_primitives::{map::HashMap, B256, U256}; +use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion}; +use itertools::Itertools; +use proptest::{prelude::*, strategy::ValueTree, test_runner::TestRunner}; +use reth_trie::{ + hashed_cursor::{noop::NoopHashedStorageCursor, HashedPostStateStorageCursor}, + node_iter::{TrieElement, TrieNodeIter}, + trie_cursor::{noop::NoopStorageTrieCursor, InMemoryStorageTrieCursor}, + updates::StorageTrieUpdates, + walker::TrieWalker, + HashedStorage, +}; +use reth_trie_common::{HashBuilder, Nibbles}; +use reth_trie_sparse::SparseTrie; + +pub fn calculate_root_from_leaves(c: &mut Criterion) { + let mut group = c.benchmark_group("calculate root from leaves"); + group.sample_size(20); + + for size in [1_000, 5_000, 10_000, 100_000] { + let state = generate_test_data(size); + + // hash builder + group.bench_function(BenchmarkId::new("hash builder", size), |b| { + b.iter_with_setup(HashBuilder::default, |mut hb| { + for (key, value) in state.iter().sorted_by_key(|(key, _)| *key) { + hb.add_leaf(Nibbles::unpack(key), &alloy_rlp::encode_fixed_size(value)); + } + hb.root(); + }) + }); + + // sparse trie + group.bench_function(BenchmarkId::new("sparse trie", size), |b| { + b.iter_with_setup(SparseTrie::revealed_empty, |mut sparse| { + for (key, value) in &state { + sparse + .update_leaf( + Nibbles::unpack(key), + alloy_rlp::encode_fixed_size(value).to_vec(), + ) + .unwrap(); + } + sparse.root().unwrap(); + }) + }); + } +} + +pub fn calculate_root_from_leaves_repeated(c: &mut Criterion) { + let mut group = c.benchmark_group("calculate root from leaves repeated"); + group.sample_size(20); + + for init_size in [1_000, 10_000, 100_000] { + let init_state = generate_test_data(init_size); + + for update_size in [100, 1_000, 5_000, 10_000] { + for num_updates in [1, 3, 5, 10] { + let updates = + (0..num_updates).map(|_| generate_test_data(update_size)).collect::>(); + + // hash builder + let benchmark_id = BenchmarkId::new( + "hash builder", + format!("init size {init_size} | update size {update_size} | num updates {num_updates}"), + ); + group.bench_function(benchmark_id, |b| { + b.iter_with_setup( + || { + let init_storage = HashedStorage::from_iter(false, init_state.clone()); + let storage_updates = updates + .clone() + .into_iter() + .map(|update| HashedStorage::from_iter(false, update)) + .collect::>(); + + let mut hb = HashBuilder::default().with_updates(true); + for (key, value) in init_state.iter().sorted_by_key(|(key, _)| *key) { + hb.add_leaf( + Nibbles::unpack(key), + &alloy_rlp::encode_fixed_size(value), + ); + } + hb.root(); + + let (_, updates) = hb.split(); + let trie_updates = StorageTrieUpdates::new(updates); + (init_storage, storage_updates, trie_updates) + }, + |(init_storage, storage_updates, mut trie_updates)| { + let mut storage = init_storage; + for update in storage_updates { + storage.extend(&update); + + let prefix_set = update.construct_prefix_set().freeze(); + let storage_sorted = storage.clone().into_sorted(); + let trie_updates_sorted = trie_updates.clone().into_sorted(); + + let walker = TrieWalker::new( + InMemoryStorageTrieCursor::new( + B256::ZERO, + NoopStorageTrieCursor::default(), + Some(&trie_updates_sorted), + ), + prefix_set, + ); + let mut node_iter = TrieNodeIter::new( + walker, + HashedPostStateStorageCursor::new( + NoopHashedStorageCursor::default(), + Some(&storage_sorted), + ), + ); + + let mut hb = HashBuilder::default().with_updates(true); + while let Some(node) = node_iter.try_next().unwrap() { + match node { + TrieElement::Branch(node) => { + hb.add_branch( + node.key, + node.value, + node.children_are_in_trie, + ); + } + TrieElement::Leaf(hashed_slot, value) => { + hb.add_leaf( + Nibbles::unpack(hashed_slot), + alloy_rlp::encode_fixed_size(&value).as_ref(), + ); + } + } + } + hb.root(); + + trie_updates.finalize(node_iter.walker, hb); + } + }, + ) + }); + + // sparse trie + let benchmark_id = BenchmarkId::new( + "sparse trie", + format!("init size {init_size} | update size {update_size} | num updates {num_updates}"), + ); + group.bench_function(benchmark_id, |b| { + b.iter_with_setup( + || { + let mut sparse = SparseTrie::revealed_empty(); + for (key, value) in &init_state { + sparse + .update_leaf( + Nibbles::unpack(key), + alloy_rlp::encode_fixed_size(value).to_vec(), + ) + .unwrap(); + } + sparse.root().unwrap(); + sparse + }, + |mut sparse| { + for update in &updates { + for (key, value) in update { + sparse + .update_leaf( + Nibbles::unpack(key), + alloy_rlp::encode_fixed_size(value).to_vec(), + ) + .unwrap(); + } + sparse.root().unwrap(); + } + }, + ) + }); + } + } + } +} + +fn generate_test_data(size: usize) -> HashMap { + let mut runner = TestRunner::new(ProptestConfig::default()); + proptest::collection::hash_map(any::(), any::(), size) + .new_tree(&mut runner) + .unwrap() + .current() +} + +criterion_group!(root, calculate_root_from_leaves, calculate_root_from_leaves_repeated); +criterion_main!(root); diff --git a/crates/trie/sparse/src/errors.rs b/crates/trie/sparse/src/errors.rs new file mode 100644 index 000000000000..f60d1736c06f --- /dev/null +++ b/crates/trie/sparse/src/errors.rs @@ -0,0 +1,49 @@ +//! Errors for sparse trie. + +use alloy_primitives::{Bytes, B256}; +use reth_trie::Nibbles; +use thiserror::Error; + +/// Result type with [`SparseStateTrieError`] as error. +pub type SparseStateTrieResult = Result; + +/// Error encountered in [`crate::SparseStateTrie`]. +#[derive(Error, Debug)] +pub enum SparseStateTrieError { + /// Encountered invalid root node. + #[error("invalid root node at {path:?}: {node:?}")] + InvalidRootNode { + /// Path to first proof node. + path: Nibbles, + /// Encoded first proof node. + node: Bytes, + }, + /// Sparse trie error. + #[error(transparent)] + Sparse(#[from] SparseTrieError), + /// RLP error. + #[error(transparent)] + Rlp(#[from] alloy_rlp::Error), +} + +/// Result type with [`SparseTrieError`] as error. +pub type SparseTrieResult = Result; + +/// Error encountered in [`crate::SparseTrie`]. +#[derive(Error, Debug)] +pub enum SparseTrieError { + /// Sparse trie is still blind. Thrown on attempt to update it. + #[error("sparse trie is blind")] + Blind, + /// Encountered blinded node on update. + #[error("attempted to update blind node at {path:?}: {hash}")] + BlindedNode { + /// Blind node path. + path: Nibbles, + /// Node hash + hash: B256, + }, + /// RLP error. + #[error(transparent)] + Rlp(#[from] alloy_rlp::Error), +} diff --git a/crates/trie/sparse/src/lib.rs b/crates/trie/sparse/src/lib.rs index 5d3d4a5b6f8d..b3cb2c5fdffa 100644 --- a/crates/trie/sparse/src/lib.rs +++ b/crates/trie/sparse/src/lib.rs @@ -1 +1,10 @@ //! The implementation of sparse MPT. + +mod state; +pub use state::*; + +mod trie; +pub use trie::*; + +mod errors; +pub use errors::*; diff --git a/crates/trie/sparse/src/state.rs b/crates/trie/sparse/src/state.rs new file mode 100644 index 000000000000..cfb17ef36ff1 --- /dev/null +++ b/crates/trie/sparse/src/state.rs @@ -0,0 +1,131 @@ +use crate::{SparseStateTrieError, SparseStateTrieResult, SparseTrie}; +use alloy_primitives::{ + map::{HashMap, HashSet}, + Bytes, B256, +}; +use alloy_rlp::Decodable; +use reth_trie::{Nibbles, TrieNode}; + +/// Sparse state trie representing lazy-loaded Ethereum state trie. +#[derive(Default, Debug)] +pub struct SparseStateTrie { + /// Sparse account trie. + pub(crate) state: SparseTrie, + /// Sparse storage tries. + #[allow(dead_code)] + pub(crate) storages: HashMap, + /// Collection of revealed account and storage keys. + #[allow(dead_code)] + pub(crate) revealed: HashMap>, +} + +impl SparseStateTrie { + /// Create state trie from state trie. + pub fn from_state(state: SparseTrie) -> Self { + Self { state, ..Default::default() } + } + + /// Returns `true` if account was already revealed. + pub fn is_account_revealed(&self, account: &B256) -> bool { + self.revealed.contains_key(account) + } + + /// Returns `true` if storage slot for account was already revealed. + pub fn is_storage_slot_revealed(&self, account: &B256, slot: &B256) -> bool { + self.revealed.get(account).map_or(false, |slots| slots.contains(slot)) + } + + /// Reveal unknown trie paths from provided leaf path and its proof. + /// NOTE: This method does not extensively validate the proof. + pub fn reveal_account( + &mut self, + account: B256, + proof: impl IntoIterator, + ) -> SparseStateTrieResult<()> { + let mut proof = proof.into_iter().peekable(); + + // reveal root and initialize the trie if not already + let Some((path, node)) = proof.next() else { return Ok(()) }; + if !path.is_empty() { + return Err(SparseStateTrieError::InvalidRootNode { path, node }) + } + + // Decode root node and perform sanity check. + let root_node = TrieNode::decode(&mut &node[..])?; + if matches!(root_node, TrieNode::EmptyRoot) && proof.peek().is_some() { + return Err(SparseStateTrieError::InvalidRootNode { path, node }) + } + + // Reveal root node if it wasn't already. + let trie = self.state.reveal_root(root_node)?; + + // add the remaining proof nodes + for (path, bytes) in proof { + let node = TrieNode::decode(&mut &bytes[..])?; + trie.reveal_node(path, node)?; + } + + // Mark leaf path as revealed. + self.revealed.entry(account).or_default(); + + Ok(()) + } + + /// Update the leaf node. + pub fn update_leaf(&mut self, path: Nibbles, value: Vec) -> SparseStateTrieResult<()> { + self.state.update_leaf(path, value)?; + Ok(()) + } + + /// Returns sparse trie root if the trie has been revealed. + pub fn root(&mut self) -> Option { + self.state.root() + } +} + +#[cfg(test)] +mod tests { + use super::*; + use alloy_primitives::Bytes; + use alloy_rlp::EMPTY_STRING_CODE; + use assert_matches::assert_matches; + use reth_trie::HashBuilder; + use reth_trie_common::proof::ProofRetainer; + + #[test] + fn sparse_trie_reveal_empty() { + let retainer = ProofRetainer::from_iter([Nibbles::default()]); + let mut hash_builder = HashBuilder::default().with_proof_retainer(retainer); + hash_builder.root(); + let proofs = hash_builder.take_proof_nodes(); + assert_eq!(proofs.len(), 1); + + let mut sparse = SparseStateTrie::default(); + assert_eq!(sparse.state, SparseTrie::Blind); + sparse.reveal_account(Default::default(), proofs.into_inner()).unwrap(); + assert_eq!(sparse.state, SparseTrie::revealed_empty()); + } + + #[test] + fn reveal_first_node_not_root() { + let mut sparse = SparseStateTrie::default(); + let proof = [(Nibbles::from_nibbles([0x1]), Bytes::from([EMPTY_STRING_CODE]))]; + assert_matches!( + sparse.reveal_account(Default::default(), proof), + Err(SparseStateTrieError::InvalidRootNode { .. }) + ); + } + + #[test] + fn reveal_invalid_proof_with_empty_root() { + let mut sparse = SparseStateTrie::default(); + let proof = [ + (Nibbles::default(), Bytes::from([EMPTY_STRING_CODE])), + (Nibbles::from_nibbles([0x1]), Bytes::new()), + ]; + assert_matches!( + sparse.reveal_account(Default::default(), proof), + Err(SparseStateTrieError::InvalidRootNode { .. }) + ); + } +} diff --git a/crates/trie/sparse/src/trie.rs b/crates/trie/sparse/src/trie.rs new file mode 100644 index 000000000000..1b83e07e48d6 --- /dev/null +++ b/crates/trie/sparse/src/trie.rs @@ -0,0 +1,627 @@ +use crate::{SparseTrieError, SparseTrieResult}; +use alloy_primitives::{hex, keccak256, map::HashMap, B256}; +use alloy_rlp::Decodable; +use reth_trie::{ + prefix_set::{PrefixSet, PrefixSetMut}, + RlpNode, +}; +use reth_trie_common::{ + BranchNodeRef, ExtensionNodeRef, LeafNodeRef, Nibbles, TrieMask, TrieNode, CHILD_INDEX_RANGE, + EMPTY_ROOT_HASH, +}; +use smallvec::SmallVec; +use std::{collections::HashSet, fmt}; + +/// Inner representation of the sparse trie. +/// Sparse trie is blind by default until nodes are revealed. +#[derive(PartialEq, Eq, Default, Debug)] +pub enum SparseTrie { + /// None of the trie nodes are known. + #[default] + Blind, + /// The trie nodes have been revealed. + Revealed(RevealedSparseTrie), +} + +impl SparseTrie { + /// Creates new revealed empty trie. + pub fn revealed_empty() -> Self { + Self::Revealed(RevealedSparseTrie::default()) + } + + /// Returns `true` if the sparse trie has no revealed nodes. + pub const fn is_blind(&self) -> bool { + matches!(self, Self::Blind) + } + + /// Returns mutable reference to revealed sparse trie if the trie is not blind. + pub fn as_revealed_mut(&mut self) -> Option<&mut RevealedSparseTrie> { + if let Self::Revealed(revealed) = self { + Some(revealed) + } else { + None + } + } + + /// Reveals the root node if the trie is blinded. + /// + /// # Returns + /// + /// Mutable reference to [`RevealedSparseTrie`]. + pub fn reveal_root(&mut self, root: TrieNode) -> SparseTrieResult<&mut RevealedSparseTrie> { + if self.is_blind() { + *self = Self::Revealed(RevealedSparseTrie::from_root(root)?) + } + Ok(self.as_revealed_mut().unwrap()) + } + + /// Update the leaf node. + pub fn update_leaf(&mut self, path: Nibbles, value: Vec) -> SparseTrieResult<()> { + let revealed = self.as_revealed_mut().ok_or(SparseTrieError::Blind)?; + revealed.update_leaf(path, value)?; + Ok(()) + } + + /// Calculates and returns the trie root if the trie has been revealed. + pub fn root(&mut self) -> Option { + Some(self.as_revealed_mut()?.root()) + } +} + +/// The representation of revealed sparse trie. +#[derive(PartialEq, Eq)] +pub struct RevealedSparseTrie { + /// All trie nodes. + nodes: HashMap, + /// All leaf values. + values: HashMap>, + /// Prefix set. + prefix_set: PrefixSetMut, + /// Reusable buffer for RLP encoding of nodes. + rlp_buf: Vec, +} + +impl fmt::Debug for RevealedSparseTrie { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("RevealedSparseTrie") + .field("nodes", &self.nodes) + .field("values", &self.values) + .field("prefix_set", &self.prefix_set) + .field("rlp_buf", &hex::encode(&self.rlp_buf)) + .finish() + } +} + +impl Default for RevealedSparseTrie { + fn default() -> Self { + Self { + nodes: HashMap::from_iter([(Nibbles::default(), SparseNode::Empty)]), + values: HashMap::default(), + prefix_set: PrefixSetMut::default(), + rlp_buf: Vec::new(), + } + } +} + +impl RevealedSparseTrie { + /// Create new revealed sparse trie from the given root node. + pub fn from_root(node: TrieNode) -> SparseTrieResult { + let mut this = Self { + nodes: HashMap::default(), + values: HashMap::default(), + prefix_set: PrefixSetMut::default(), + rlp_buf: Vec::new(), + }; + this.reveal_node(Nibbles::default(), node)?; + Ok(this) + } + + /// Reveal the trie node only if it was not known already. + pub fn reveal_node(&mut self, path: Nibbles, node: TrieNode) -> SparseTrieResult<()> { + // TODO: revise all inserts to not overwrite existing entries + match node { + TrieNode::EmptyRoot => { + debug_assert!(path.is_empty()); + self.nodes.insert(path, SparseNode::Empty); + } + TrieNode::Branch(branch) => { + let mut stack_ptr = branch.as_ref().first_child_index(); + for idx in CHILD_INDEX_RANGE { + if branch.state_mask.is_bit_set(idx) { + let mut child_path = path.clone(); + child_path.push_unchecked(idx); + self.reveal_node_or_hash(child_path, &branch.stack[stack_ptr])?; + stack_ptr += 1; + } + } + self.nodes + .insert(path, SparseNode::Branch { state_mask: branch.state_mask, hash: None }); + } + TrieNode::Extension(ext) => { + let mut child_path = path.clone(); + child_path.extend_from_slice_unchecked(&ext.key); + self.reveal_node_or_hash(child_path, &ext.child)?; + self.nodes.insert(path, SparseNode::Extension { key: ext.key, hash: None }); + } + TrieNode::Leaf(leaf) => { + let mut full = path.clone(); + full.extend_from_slice_unchecked(&leaf.key); + self.values.insert(full, leaf.value); + self.nodes.insert(path, SparseNode::new_leaf(leaf.key)); + } + } + + Ok(()) + } + + fn reveal_node_or_hash(&mut self, path: Nibbles, child: &[u8]) -> SparseTrieResult<()> { + if child.len() == B256::len_bytes() + 1 { + // TODO: revise insert to not overwrite existing entries + self.nodes.insert(path, SparseNode::Hash(B256::from_slice(&child[1..]))); + return Ok(()) + } + + self.reveal_node(path, TrieNode::decode(&mut &child[..])?) + } + + /// Update the leaf node with provided value. + pub fn update_leaf(&mut self, path: Nibbles, value: Vec) -> SparseTrieResult<()> { + self.prefix_set.insert(path.clone()); + let existing = self.values.insert(path.clone(), value); + if existing.is_some() { + // trie structure unchanged, return immediately + return Ok(()) + } + + let mut current = Nibbles::default(); + while let Some(node) = self.nodes.get_mut(¤t) { + match node { + SparseNode::Empty => { + *node = SparseNode::new_leaf(path); + break + } + SparseNode::Hash(hash) => { + return Err(SparseTrieError::BlindedNode { path: current, hash: *hash }) + } + SparseNode::Leaf { key: current_key, .. } => { + current.extend_from_slice_unchecked(current_key); + + // this leaf is being updated + if current == path { + unreachable!("we already checked leaf presence in the beginning"); + } + + // find the common prefix + let common = current.common_prefix_length(&path); + + // update existing node + let new_ext_key = current.slice(current.len() - current_key.len()..common); + *node = SparseNode::new_ext(new_ext_key); + + // create a branch node and corresponding leaves + self.nodes.insert( + current.slice(..common), + SparseNode::new_split_branch(current[common], path[common]), + ); + self.nodes.insert( + path.slice(..=common), + SparseNode::new_leaf(path.slice(common + 1..)), + ); + self.nodes.insert( + current.slice(..=common), + SparseNode::new_leaf(current.slice(common + 1..)), + ); + + break; + } + SparseNode::Extension { key, .. } => { + current.extend_from_slice(key); + if !path.starts_with(¤t) { + // find the common prefix + let common = current.common_prefix_length(&path); + + *key = current.slice(current.len() - key.len()..common); + + // create state mask for new branch node + // NOTE: this might overwrite the current extension node + let branch = SparseNode::new_split_branch(current[common], path[common]); + self.nodes.insert(current.slice(..common), branch); + + // create new leaf + let new_leaf = SparseNode::new_leaf(path.slice(common + 1..)); + self.nodes.insert(path.slice(..=common), new_leaf); + + // recreate extension to previous child if needed + let key = current.slice(common + 1..); + if !key.is_empty() { + self.nodes.insert(current.slice(..=common), SparseNode::new_ext(key)); + } + + break; + } + } + SparseNode::Branch { state_mask, .. } => { + let nibble = path[current.len()]; + current.push_unchecked(nibble); + if !state_mask.is_bit_set(nibble) { + state_mask.set_bit(nibble); + let new_leaf = SparseNode::new_leaf(path.slice(current.len()..)); + self.nodes.insert(current, new_leaf); + break; + } + } + }; + } + + Ok(()) + } + + /// Remove leaf node from the trie. + pub fn remove_leaf(&mut self, _path: Nibbles) { + unimplemented!() + } + + /// Return the root of the sparse trie. + /// Updates all remaining dirty nodes before calculating the root. + pub fn root(&mut self) -> B256 { + // take the current prefix set. + let mut prefix_set = std::mem::take(&mut self.prefix_set).freeze(); + let root_rlp = self.rlp_node(Nibbles::default(), &mut prefix_set); + if root_rlp.len() == B256::len_bytes() + 1 { + B256::from_slice(&root_rlp[1..]) + } else { + keccak256(root_rlp) + } + } + + /// Update node hashes only if their path exceeds the provided level. + pub fn update_rlp_node_level(&mut self, min_len: usize) { + let mut paths = Vec::from([Nibbles::default()]); + let mut targets = HashSet::::default(); + + while let Some(mut path) = paths.pop() { + match self.nodes.get(&path).unwrap() { + SparseNode::Empty | SparseNode::Hash(_) => {} + SparseNode::Leaf { .. } => { + targets.insert(path); + } + SparseNode::Extension { key, .. } => { + if path.len() >= min_len { + targets.insert(path); + } else { + path.extend_from_slice_unchecked(key); + paths.push(path); + } + } + SparseNode::Branch { state_mask, .. } => { + if path.len() >= min_len { + targets.insert(path); + } else { + for bit in CHILD_INDEX_RANGE { + if state_mask.is_bit_set(bit) { + let mut child_path = path.clone(); + child_path.push_unchecked(bit); + paths.push(child_path); + } + } + } + } + } + } + + let mut prefix_set = self.prefix_set.clone().freeze(); + for target in targets { + self.rlp_node(target, &mut prefix_set); + } + } + + fn rlp_node(&mut self, path: Nibbles, prefix_set: &mut PrefixSet) -> RlpNode { + // stack of paths we need rlp nodes for + let mut path_stack = Vec::from([path]); + // stack of rlp nodes + let mut rlp_node_stack = Vec::<(Nibbles, RlpNode)>::new(); + // reusable branch child path + let mut branch_child_buf = SmallVec::<[Nibbles; 16]>::new_const(); + // reusable branch value stack + let mut branch_value_stack_buf = SmallVec::<[RlpNode; 16]>::new_const(); + + 'main: while let Some(path) = path_stack.pop() { + let rlp_node = match self.nodes.get_mut(&path).unwrap() { + SparseNode::Empty => RlpNode::word_rlp(&EMPTY_ROOT_HASH), + SparseNode::Hash(hash) => RlpNode::word_rlp(hash), + SparseNode::Leaf { key, hash } => { + self.rlp_buf.clear(); + let mut path = path.clone(); + path.extend_from_slice_unchecked(key); + if let Some(hash) = hash.filter(|_| !prefix_set.contains(&path)) { + RlpNode::word_rlp(&hash) + } else { + let value = self.values.get(&path).unwrap(); + let rlp_node = LeafNodeRef { key, value }.rlp(&mut self.rlp_buf); + if rlp_node.len() == B256::len_bytes() + 1 { + *hash = Some(B256::from_slice(&rlp_node[1..])); + } + rlp_node + } + } + SparseNode::Extension { key, hash } => { + let mut child_path = path.clone(); + child_path.extend_from_slice_unchecked(key); + if let Some(hash) = hash.filter(|_| !prefix_set.contains(&path)) { + RlpNode::word_rlp(&hash) + } else if rlp_node_stack.last().map_or(false, |e| e.0 == child_path) { + let (_, child) = rlp_node_stack.pop().unwrap(); + self.rlp_buf.clear(); + let rlp_node = ExtensionNodeRef::new(key, &child).rlp(&mut self.rlp_buf); + if rlp_node.len() == B256::len_bytes() + 1 { + *hash = Some(B256::from_slice(&rlp_node[1..])); + } + rlp_node + } else { + path_stack.extend([path, child_path]); // need to get rlp node for child first + continue + } + } + SparseNode::Branch { state_mask, hash } => { + if let Some(hash) = hash.filter(|_| !prefix_set.contains(&path)) { + rlp_node_stack.push((path, RlpNode::word_rlp(&hash))); + continue + } + + branch_child_buf.clear(); + for bit in CHILD_INDEX_RANGE { + if state_mask.is_bit_set(bit) { + let mut child = path.clone(); + child.push_unchecked(bit); + branch_child_buf.push(child); + } + } + + branch_value_stack_buf.clear(); + for child_path in &branch_child_buf { + if rlp_node_stack.last().map_or(false, |e| &e.0 == child_path) { + let (_, child) = rlp_node_stack.pop().unwrap(); + branch_value_stack_buf.push(child); + } else { + debug_assert!(branch_value_stack_buf.is_empty()); + path_stack.push(path); + path_stack.extend(branch_child_buf.drain(..)); + continue 'main + } + } + + self.rlp_buf.clear(); + let rlp_node = BranchNodeRef::new(&branch_value_stack_buf, *state_mask) + .rlp(&mut self.rlp_buf); + if rlp_node.len() == B256::len_bytes() + 1 { + *hash = Some(B256::from_slice(&rlp_node[1..])); + } + rlp_node + } + }; + rlp_node_stack.push((path, rlp_node)); + } + + rlp_node_stack.pop().unwrap().1 + } +} + +/// Enum representing trie nodes in sparse trie. +#[derive(PartialEq, Eq, Clone, Debug)] +pub enum SparseNode { + /// Empty trie node. + Empty, + /// The hash of the node that was not revealed. + Hash(B256), + /// Sparse leaf node with remaining key suffix. + Leaf { + /// Remaining key suffix for the leaf node. + key: Nibbles, + /// Pre-computed hash of the sparse node. + /// Can be reused unless this trie path has been updated. + hash: Option, + }, + /// Sparse extension node with key. + Extension { + /// The key slice stored by this extension node. + key: Nibbles, + /// Pre-computed hash of the sparse node. + /// Can be reused unless this trie path has been updated. + hash: Option, + }, + /// Sparse branch node with state mask. + Branch { + /// The bitmask representing children present in the branch node. + state_mask: TrieMask, + /// Pre-computed hash of the sparse node. + /// Can be reused unless this trie path has been updated. + hash: Option, + }, +} + +impl SparseNode { + /// Create new sparse node from [`TrieNode`]. + pub fn from_node(node: TrieNode) -> Self { + match node { + TrieNode::EmptyRoot => Self::Empty, + TrieNode::Leaf(leaf) => Self::new_leaf(leaf.key), + TrieNode::Extension(ext) => Self::new_ext(ext.key), + TrieNode::Branch(branch) => Self::new_branch(branch.state_mask), + } + } + + /// Create new [`SparseNode::Branch`] from state mask. + pub const fn new_branch(state_mask: TrieMask) -> Self { + Self::Branch { state_mask, hash: None } + } + + /// Create new [`SparseNode::Branch`] with two bits set. + pub const fn new_split_branch(bit_a: u8, bit_b: u8) -> Self { + let state_mask = TrieMask::new( + // set bits for both children + (1u16 << bit_a) | (1u16 << bit_b), + ); + Self::Branch { state_mask, hash: None } + } + + /// Create new [`SparseNode::Extension`] from the key slice. + pub const fn new_ext(key: Nibbles) -> Self { + Self::Extension { key, hash: None } + } + + /// Create new [`SparseNode::Leaf`] from leaf key and value. + pub const fn new_leaf(key: Nibbles) -> Self { + Self::Leaf { key, hash: None } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use alloy_primitives::U256; + use itertools::Itertools; + use proptest::prelude::*; + use reth_trie_common::HashBuilder; + + #[test] + fn sparse_trie_is_blind() { + assert!(SparseTrie::default().is_blind()); + assert!(!SparseTrie::revealed_empty().is_blind()); + } + + #[test] + fn sparse_trie_empty_update_one() { + let path = Nibbles::unpack(B256::with_last_byte(42)); + let value = alloy_rlp::encode_fixed_size(&U256::from(1)); + + let mut hash_builder = HashBuilder::default(); + hash_builder.add_leaf(path.clone(), &value); + let expected = hash_builder.root(); + + let mut sparse = RevealedSparseTrie::default(); + sparse.update_leaf(path, value.to_vec()).unwrap(); + let root = sparse.root(); + assert_eq!(root, expected); + } + + #[test] + fn sparse_trie_empty_update_multiple_lower_nibbles() { + let paths = (0..=16).map(|b| Nibbles::unpack(B256::with_last_byte(b))).collect::>(); + let value = alloy_rlp::encode_fixed_size(&U256::from(1)); + + let mut hash_builder = HashBuilder::default(); + for path in &paths { + hash_builder.add_leaf(path.clone(), &value); + } + let expected = hash_builder.root(); + + let mut sparse = RevealedSparseTrie::default(); + for path in &paths { + sparse.update_leaf(path.clone(), value.to_vec()).unwrap(); + } + let root = sparse.root(); + assert_eq!(root, expected); + } + + #[test] + fn sparse_trie_empty_update_multiple_upper_nibbles() { + let paths = (239..=255).map(|b| Nibbles::unpack(B256::repeat_byte(b))).collect::>(); + let value = alloy_rlp::encode_fixed_size(&U256::from(1)); + + let mut hash_builder = HashBuilder::default(); + for path in &paths { + hash_builder.add_leaf(path.clone(), &value); + } + let expected = hash_builder.root(); + + let mut sparse = RevealedSparseTrie::default(); + for path in &paths { + sparse.update_leaf(path.clone(), value.to_vec()).unwrap(); + } + let root = sparse.root(); + assert_eq!(root, expected); + } + + #[test] + fn sparse_trie_empty_update_multiple() { + let paths = (0..=255) + .map(|b| { + Nibbles::unpack(if b % 2 == 0 { + B256::repeat_byte(b) + } else { + B256::with_last_byte(b) + }) + }) + .collect::>(); + let value = alloy_rlp::encode_fixed_size(&U256::from(1)); + + let mut hash_builder = HashBuilder::default(); + for path in paths.iter().sorted_unstable_by_key(|key| *key) { + hash_builder.add_leaf(path.clone(), &value); + } + let expected = hash_builder.root(); + + let mut sparse = RevealedSparseTrie::default(); + for path in &paths { + sparse.update_leaf(path.clone(), value.to_vec()).unwrap(); + } + let root = sparse.root(); + assert_eq!(root, expected); + } + + #[test] + fn sparse_trie_empty_update_repeated() { + let paths = (0..=255).map(|b| Nibbles::unpack(B256::repeat_byte(b))).collect::>(); + let old_value = alloy_rlp::encode_fixed_size(&U256::from(1)); + let new_value = alloy_rlp::encode_fixed_size(&U256::from(2)); + + let mut hash_builder = HashBuilder::default(); + for path in paths.iter().sorted_unstable_by_key(|key| *key) { + hash_builder.add_leaf(path.clone(), &old_value); + } + let expected = hash_builder.root(); + + let mut sparse = RevealedSparseTrie::default(); + for path in &paths { + sparse.update_leaf(path.clone(), old_value.to_vec()).unwrap(); + } + let root = sparse.root(); + assert_eq!(root, expected); + + let mut hash_builder = HashBuilder::default(); + for path in paths.iter().sorted_unstable_by_key(|key| *key) { + hash_builder.add_leaf(path.clone(), &new_value); + } + let expected = hash_builder.root(); + + for path in &paths { + sparse.update_leaf(path.clone(), new_value.to_vec()).unwrap(); + } + let root = sparse.root(); + assert_eq!(root, expected); + } + + #[test] + fn sparse_trie_empty_update_fuzz() { + proptest!(ProptestConfig::with_cases(10), |(updates: Vec>)| { + let mut state = std::collections::BTreeMap::default(); + let mut sparse = RevealedSparseTrie::default(); + + for update in updates { + for (key, value) in &update { + sparse.update_leaf(Nibbles::unpack(key), alloy_rlp::encode_fixed_size(value).to_vec()).unwrap(); + } + let root = sparse.root(); + + state.extend(update); + let mut hash_builder = HashBuilder::default(); + for (key, value) in &state { + hash_builder.add_leaf(Nibbles::unpack(key), &alloy_rlp::encode_fixed_size(value)); + } + let expected = hash_builder.root(); + + assert_eq!(root, expected); + } + }); + } +} diff --git a/crates/trie/trie/src/prefix_set.rs b/crates/trie/trie/src/prefix_set.rs index af0fb173d98a..da912fbbdad9 100644 --- a/crates/trie/trie/src/prefix_set.rs +++ b/crates/trie/trie/src/prefix_set.rs @@ -82,7 +82,7 @@ pub struct TriePrefixSets { /// assert!(prefix_set.contains(&[0xa, 0xb])); /// assert!(prefix_set.contains(&[0xa, 0xb, 0xc])); /// ``` -#[derive(Clone, Default, Debug)] +#[derive(PartialEq, Eq, Clone, Default, Debug)] pub struct PrefixSetMut { /// Flag indicating that any entry should be considered changed. /// If set, the keys will be discarded. From 6fb271036dbaf0ab9c9215959baec5833ac1cc88 Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Tue, 15 Oct 2024 18:51:40 +0400 Subject: [PATCH 003/113] feat: move RPC launch to add-ons (#11532) --- Cargo.lock | 21 +- crates/e2e-test-utils/src/lib.rs | 14 +- crates/e2e-test-utils/src/node.rs | 8 +- crates/ethereum/node/src/node.rs | 27 +- crates/ethereum/node/tests/e2e/dev.rs | 8 +- crates/exex/test-utils/src/lib.rs | 4 +- crates/node/api/Cargo.toml | 7 + crates/node/api/src/node.rs | 75 +++-- crates/node/builder/src/builder/add_ons.rs | 16 +- crates/node/builder/src/builder/mod.rs | 30 +- crates/node/builder/src/builder/states.rs | 109 +++---- crates/node/builder/src/handle.rs | 10 +- crates/node/builder/src/launch/engine.rs | 62 +--- crates/node/builder/src/launch/mod.rs | 65 +--- crates/node/builder/src/lib.rs | 5 +- crates/node/builder/src/node.rs | 48 ++- crates/node/builder/src/rpc.rs | 318 ++++++++++++++------ crates/optimism/bin/src/main.rs | 29 +- crates/optimism/node/src/node.rs | 45 ++- crates/optimism/node/tests/e2e/utils.rs | 6 +- crates/optimism/rpc/src/eth/mod.rs | 22 +- crates/optimism/rpc/src/eth/transaction.rs | 10 +- crates/rpc/rpc-builder/src/eth.rs | 8 +- crates/rpc/rpc-builder/src/lib.rs | 1 + crates/rpc/rpc-eth-types/src/builder/ctx.rs | 62 +--- crates/rpc/rpc/src/eth/core.rs | 24 +- examples/custom-engine-types/src/main.rs | 7 +- 27 files changed, 535 insertions(+), 506 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7ee37e080aed..59e8f2b27fba 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4464,7 +4464,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" dependencies = [ "cfg-if", - "windows-targets 0.48.5", + "windows-targets 0.52.6", ] [[package]] @@ -7787,9 +7787,14 @@ dependencies = [ name = "reth-node-api" version = "1.1.0" dependencies = [ + "alloy-rpc-types-engine", + "eyre", + "reth-beacon-consensus", + "reth-consensus", "reth-engine-primitives", "reth-evm", "reth-network-api", + "reth-node-core", "reth-node-types", "reth-payload-builder", "reth-payload-primitives", @@ -9577,9 +9582,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e696e35370c65c9c541198af4543ccd580cf17fc25d8e05c5a242b202488c55" +checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" [[package]] name = "rustls-platform-verifier" @@ -9621,9 +9626,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" +checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" [[package]] name = "rusty-fork" @@ -9660,9 +9665,9 @@ dependencies = [ [[package]] name = "scc" -version = "2.2.1" +version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "553f8299af7450cda9a52d3a370199904e7a46b5ffd1bef187c4a6af3bb6db69" +checksum = "f2c1f7fc6deb21665a9060dfc7d271be784669295a31babdcd4dd2c79ae8cbfb" dependencies = [ "sdd", ] @@ -11367,7 +11372,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] diff --git a/crates/e2e-test-utils/src/lib.rs b/crates/e2e-test-utils/src/lib.rs index 998b48e70431..48e56910e6c0 100644 --- a/crates/e2e-test-utils/src/lib.rs +++ b/crates/e2e-test-utils/src/lib.rs @@ -7,15 +7,13 @@ use reth::{ args::{DiscoveryArgs, NetworkArgs, RpcServerArgs}, builder::{NodeBuilder, NodeConfig, NodeHandle}, network::PeersHandleProvider, - rpc::api::eth::{helpers::AddDevSigners, FullEthApiServer}, tasks::TaskManager, }; use reth_chainspec::{EthChainSpec, EthereumHardforks}; use reth_db::{test_utils::TempDatabase, DatabaseEnv}; use reth_node_builder::{ - components::NodeComponentsBuilder, rpc::EthApiBuilderProvider, FullNodeTypesAdapter, Node, - NodeAdapter, NodeAddOns, NodeComponents, NodeTypesWithDBAdapter, NodeTypesWithEngine, - RethFullAdapter, + components::NodeComponentsBuilder, rpc::RethRpcAddOns, FullNodeTypesAdapter, Node, NodeAdapter, + NodeComponents, NodeTypesWithDBAdapter, NodeTypesWithEngine, RethFullAdapter, }; use reth_provider::providers::BlockchainProvider; use tracing::{span, Level}; @@ -56,10 +54,7 @@ where TmpNodeAdapter, Components: NodeComponents, Network: PeersHandleProvider>, >, - N::AddOns: NodeAddOns< - Adapter, - EthApi: FullEthApiServer + AddDevSigners + EthApiBuilderProvider>, - >, + N::AddOns: RethRpcAddOns>, { let tasks = TaskManager::current(); let exec = tasks.executor(); @@ -115,7 +110,8 @@ type TmpNodeAdapter = FullNodeTypesAdapter< BlockchainProvider>, >; -type Adapter = NodeAdapter< +/// Type alias for a `NodeAdapter` +pub type Adapter = NodeAdapter< RethFullAdapter, <>>::ComponentsBuilder as NodeComponentsBuilder< RethFullAdapter, diff --git a/crates/e2e-test-utils/src/node.rs b/crates/e2e-test-utils/src/node.rs index 2ea39348f5de..c22913ba2363 100644 --- a/crates/e2e-test-utils/src/node.rs +++ b/crates/e2e-test-utils/src/node.rs @@ -18,7 +18,7 @@ use reth::{ }, }; use reth_chainspec::EthereumHardforks; -use reth_node_builder::{NodeAddOns, NodeTypesWithEngine}; +use reth_node_builder::{rpc::RethRpcAddOns, NodeTypesWithEngine}; use reth_stages_types::StageId; use tokio_stream::StreamExt; @@ -32,7 +32,7 @@ use crate::{ pub struct NodeTestContext where Node: FullNodeComponents, - AddOns: NodeAddOns, + AddOns: RethRpcAddOns, { /// The core structure representing the full node. pub inner: FullNode, @@ -52,7 +52,7 @@ where Node: FullNodeComponents, Node::Types: NodeTypesWithEngine, Node::Network: PeersHandleProvider, - AddOns: NodeAddOns, + AddOns: RethRpcAddOns, { /// Creates a new test node pub async fn new(node: FullNode) -> eyre::Result { @@ -67,7 +67,7 @@ where canonical_stream: node.provider.canonical_state_stream(), _marker: PhantomData::, }, - rpc: RpcTestContext { inner: node.rpc_registry }, + rpc: RpcTestContext { inner: node.add_ons_handle.rpc_registry }, }) } diff --git a/crates/ethereum/node/src/node.rs b/crates/ethereum/node/src/node.rs index f17658bb32da..82f313fbb0b2 100644 --- a/crates/ethereum/node/src/node.rs +++ b/crates/ethereum/node/src/node.rs @@ -11,14 +11,15 @@ use reth_ethereum_engine_primitives::{ }; use reth_evm_ethereum::execute::EthExecutorProvider; use reth_network::NetworkHandle; -use reth_node_api::{ConfigureEvm, EngineValidator, FullNodeComponents, NodeAddOns}; +use reth_node_api::{ConfigureEvm, EngineValidator, FullNodeComponents, NodeTypesWithDB}; use reth_node_builder::{ components::{ ComponentsBuilder, ConsensusBuilder, EngineValidatorBuilder, ExecutorBuilder, NetworkBuilder, PayloadServiceBuilder, PoolBuilder, }, node::{FullNodeTypes, NodeTypes, NodeTypesWithEngine}, - BuilderContext, Node, PayloadBuilderConfig, PayloadTypes, + rpc::RpcAddOns, + BuilderContext, Node, NodeAdapter, NodeComponentsBuilder, PayloadBuilderConfig, PayloadTypes, }; use reth_payload_builder::{PayloadBuilderHandle, PayloadBuilderService}; use reth_primitives::Header; @@ -77,17 +78,19 @@ impl NodeTypesWithEngine for EthereumNode { } /// Add-ons w.r.t. l1 ethereum. -#[derive(Debug, Clone, Default)] -#[non_exhaustive] -pub struct EthereumAddOns; - -impl NodeAddOns for EthereumAddOns { - type EthApi = EthApi; -} +pub type EthereumAddOns = RpcAddOns< + N, + EthApi< + ::Provider, + ::Pool, + NetworkHandle, + ::Evm, + >, +>; impl Node for EthereumNode where - Types: NodeTypesWithEngine, + Types: NodeTypesWithDB + NodeTypesWithEngine, N: FullNodeTypes, { type ComponentsBuilder = ComponentsBuilder< @@ -100,7 +103,9 @@ where EthereumEngineValidatorBuilder, >; - type AddOns = EthereumAddOns; + type AddOns = EthereumAddOns< + NodeAdapter>::Components>, + >; fn components_builder(&self) -> Self::ComponentsBuilder { Self::components() diff --git a/crates/ethereum/node/tests/e2e/dev.rs b/crates/ethereum/node/tests/e2e/dev.rs index 6b4733b6f9b4..cad2fb34e5de 100644 --- a/crates/ethereum/node/tests/e2e/dev.rs +++ b/crates/ethereum/node/tests/e2e/dev.rs @@ -6,8 +6,10 @@ use futures::StreamExt; use reth::{args::DevArgs, core::rpc::eth::helpers::EthTransactions}; use reth_chainspec::ChainSpec; use reth_e2e_test_utils::setup; -use reth_node_api::{FullNodeComponents, NodeAddOns}; -use reth_node_builder::{EngineNodeLauncher, FullNode, NodeBuilder, NodeConfig, NodeHandle}; +use reth_node_api::FullNodeComponents; +use reth_node_builder::{ + rpc::RethRpcAddOns, EngineNodeLauncher, FullNode, NodeBuilder, NodeConfig, NodeHandle, +}; use reth_node_ethereum::{node::EthereumAddOns, EthereumNode}; use reth_provider::{providers::BlockchainProvider2, CanonStateSubscriptions}; use reth_tasks::TaskManager; @@ -53,7 +55,7 @@ async fn can_run_dev_node_new_engine() -> eyre::Result<()> { async fn assert_chain_advances(node: FullNode) where N: FullNodeComponents, - AddOns: NodeAddOns, + AddOns: RethRpcAddOns, { let mut notifications = node.provider.canonical_state_stream(); diff --git a/crates/exex/test-utils/src/lib.rs b/crates/exex/test-utils/src/lib.rs index e219f55031db..9e17013c4a5e 100644 --- a/crates/exex/test-utils/src/lib.rs +++ b/crates/exex/test-utils/src/lib.rs @@ -142,7 +142,9 @@ where TestConsensusBuilder, EthereumEngineValidatorBuilder, >; - type AddOns = EthereumAddOns; + type AddOns = EthereumAddOns< + NodeAdapter>::Components>, + >; fn components_builder(&self) -> Self::ComponentsBuilder { ComponentsBuilder::default() diff --git a/crates/node/api/Cargo.toml b/crates/node/api/Cargo.toml index e7685acc84fd..c2c3eb46326b 100644 --- a/crates/node/api/Cargo.toml +++ b/crates/node/api/Cargo.toml @@ -12,6 +12,8 @@ workspace = true [dependencies] # reth +reth-beacon-consensus.workspace = true +reth-consensus.workspace = true reth-evm.workspace = true reth-provider.workspace = true reth-engine-primitives.workspace = true @@ -23,3 +25,8 @@ reth-rpc-eth-api.workspace = true reth-network-api.workspace = true reth-node-types.workspace = true reth-primitives.workspace = true +reth-node-core.workspace = true + +alloy-rpc-types-engine.workspace = true + +eyre.workspace = true \ No newline at end of file diff --git a/crates/node/api/src/node.rs b/crates/node/api/src/node.rs index ce6b16c8ffcd..40c2a3a60b08 100644 --- a/crates/node/api/src/node.rs +++ b/crates/node/api/src/node.rs @@ -1,14 +1,18 @@ //! Traits for configuring a node. -use std::marker::PhantomData; +use std::{future::Future, marker::PhantomData}; +use alloy_rpc_types_engine::JwtSecret; +use reth_beacon_consensus::BeaconConsensusEngineHandle; +use reth_consensus::Consensus; +use reth_engine_primitives::EngineValidator; use reth_evm::execute::BlockExecutorProvider; use reth_network_api::FullNetwork; -use reth_node_types::{NodeTypesWithDB, NodeTypesWithEngine}; +use reth_node_core::node_config::NodeConfig; +use reth_node_types::{NodeTypes, NodeTypesWithDB, NodeTypesWithEngine}; use reth_payload_builder::PayloadBuilderHandle; use reth_primitives::Header; use reth_provider::FullProvider; -use reth_rpc_eth_api::EthApiTypes; use reth_tasks::TaskExecutor; use reth_transaction_pool::TransactionPool; @@ -54,9 +58,15 @@ pub trait FullNodeComponents: FullNodeTypes + Clone + 'static { /// The type that knows how to execute blocks. type Executor: BlockExecutorProvider; + /// The consensus type of the node. + type Consensus: Consensus + Clone + Unpin + 'static; + /// Network API. type Network: FullNetwork; + /// Validator for the engine API. + type EngineValidator: EngineValidator<::Engine>; + /// Returns the transaction pool of the node. fn pool(&self) -> &Self::Pool; @@ -66,8 +76,8 @@ pub trait FullNodeComponents: FullNodeTypes + Clone + 'static { /// Returns the node's executor type. fn block_executor(&self) -> &Self::Executor; - /// Returns the provider of the node. - fn provider(&self) -> &Self::Provider; + /// Returns the node's consensus type. + fn consensus(&self) -> &Self::Consensus; /// Returns the handle to the network fn network(&self) -> &Self::Network; @@ -77,37 +87,46 @@ pub trait FullNodeComponents: FullNodeTypes + Clone + 'static { &self, ) -> &PayloadBuilderHandle<::Engine>; + /// Returns the engine validator. + fn engine_validator(&self) -> &Self::EngineValidator; + + /// Returns the provider of the node. + fn provider(&self) -> &Self::Provider; + /// Returns handle to runtime. fn task_executor(&self) -> &TaskExecutor; } -/// Customizable node add-on types. -pub trait NodeAddOns: Send + Sync + Unpin + Clone + 'static { - /// The core `eth` namespace API type to install on the RPC server (see - /// `reth_rpc_eth_api::EthApiServer`). - type EthApi: EthApiTypes + Send + Clone; -} - -impl NodeAddOns for () { - type EthApi = (); +/// Context passed to [`NodeAddOns::launch_add_ons`], +#[derive(Debug)] +pub struct AddOnsContext<'a, N: FullNodeComponents> { + /// Node with all configured components. + pub node: &'a N, + /// Node configuration. + pub config: &'a NodeConfig<::ChainSpec>, + /// Handle to the beacon consensus engine. + pub beacon_engine_handle: + &'a BeaconConsensusEngineHandle<::Engine>, + /// JWT secret for the node. + pub jwt_secret: &'a JwtSecret, } -/// Returns the builder for type. -pub trait BuilderProvider: Send { - /// Context required to build type. - type Ctx<'a>; - - /// Returns builder for type. - #[allow(clippy::type_complexity)] - fn builder() -> Box Fn(Self::Ctx<'a>) -> Self + Send>; +/// Customizable node add-on types. +pub trait NodeAddOns: Send { + /// Handle to add-ons. + type Handle: Send + Sync + Clone; + + /// Configures and launches the add-ons. + fn launch_add_ons( + self, + ctx: AddOnsContext<'_, N>, + ) -> impl Future> + Send; } -impl BuilderProvider for () { - type Ctx<'a> = (); +impl NodeAddOns for () { + type Handle = (); - fn builder() -> Box Fn(Self::Ctx<'a>) -> Self + Send> { - Box::new(noop_builder) + async fn launch_add_ons(self, _components: AddOnsContext<'_, N>) -> eyre::Result { + Ok(()) } } - -const fn noop_builder(_: ()) {} diff --git a/crates/node/builder/src/builder/add_ons.rs b/crates/node/builder/src/builder/add_ons.rs index 26d7553bb86d..7be0411b2f01 100644 --- a/crates/node/builder/src/builder/add_ons.rs +++ b/crates/node/builder/src/builder/add_ons.rs @@ -1,8 +1,8 @@ //! Node add-ons. Depend on core [`NodeComponents`](crate::NodeComponents). -use reth_node_api::{EthApiTypes, FullNodeComponents, NodeAddOns}; +use reth_node_api::{FullNodeComponents, NodeAddOns}; -use crate::{exex::BoxedLaunchExEx, hooks::NodeHooks, rpc::RpcHooks}; +use crate::{exex::BoxedLaunchExEx, hooks::NodeHooks}; /// Additional node extensions. /// @@ -12,16 +12,6 @@ pub struct AddOns> { pub hooks: NodeHooks, /// The `ExExs` (execution extensions) of the node. pub exexs: Vec<(String, Box>)>, - /// Additional RPC add-ons. - pub rpc: RpcAddOns, /// Additional captured addons. - pub addons: AddOns, -} - -/// Captures node specific addons that can be installed on top of the type configured node and are -/// required for launching the node, such as RPC. -#[derive(Default)] -pub struct RpcAddOns { - /// Additional RPC hooks. - pub hooks: RpcHooks, + pub add_ons: AddOns, } diff --git a/crates/node/builder/src/builder/mod.rs b/crates/node/builder/src/builder/mod.rs index fb94413fe756..82d8d96f6f55 100644 --- a/crates/node/builder/src/builder/mod.rs +++ b/crates/node/builder/src/builder/mod.rs @@ -13,7 +13,7 @@ use crate::{ common::WithConfigs, components::NodeComponentsBuilder, node::FullNode, - rpc::{EthApiBuilderProvider, RethRpcServerHandles, RpcContext}, + rpc::{RethRpcAddOns, RethRpcServerHandles, RpcContext}, DefaultNodeLauncher, LaunchNode, Node, NodeHandle, }; use futures::Future; @@ -37,7 +37,6 @@ use reth_node_core::{ dirs::{ChainPath, DataDirPath}, node_config::NodeConfig, primitives::Head, - rpc::eth::{helpers::AddDevSigners, FullEthApiServer}, }; use reth_primitives::revm_primitives::EnvKzgSettings; use reth_provider::{providers::BlockchainProvider, ChainSpecProvider, FullProvider}; @@ -358,19 +357,11 @@ where > where N: Node, ChainSpec = ChainSpec>, - N::AddOns: NodeAddOns< + N::AddOns: RethRpcAddOns< NodeAdapter< RethFullAdapter, >>::Components, >, - EthApi: EthApiBuilderProvider< - NodeAdapter< - RethFullAdapter, - >>::Components, - > - > - + FullEthApiServer - + AddDevSigners >, { self.node(node).launch().await @@ -418,7 +409,7 @@ impl WithLaunchContext> where T: FullNodeTypes, CB: NodeComponentsBuilder, - AO: NodeAddOns, EthApi: FullEthApiServer + AddDevSigners>, + AO: RethRpcAddOns>, { /// Returns a reference to the node builder's config. pub const fn config(&self) -> &NodeConfig<::ChainSpec> { @@ -466,6 +457,14 @@ where Self { builder: self.builder.on_node_started(hook), task_executor: self.task_executor } } + /// Modifies the addons with the given closure. + pub fn map_add_ons(self, f: F) -> Self + where + F: FnOnce(AO) -> AO, + { + Self { builder: self.builder.map_add_ons(f), task_executor: self.task_executor } + } + /// Sets the hook that is run once the rpc server is started. pub fn on_rpc_started(self, hook: F) -> Self where @@ -553,12 +552,7 @@ where DB: Database + DatabaseMetrics + DatabaseMetadata + Clone + Unpin + 'static, T: NodeTypesWithEngine, CB: NodeComponentsBuilder>, - AO: NodeAddOns< - NodeAdapter, CB::Components>, - EthApi: EthApiBuilderProvider, CB::Components>> - + FullEthApiServer - + AddDevSigners, - >, + AO: RethRpcAddOns, CB::Components>>, { /// Launches the node with the [`DefaultNodeLauncher`] that sets up engine API consensus and rpc pub async fn launch( diff --git a/crates/node/builder/src/builder/states.rs b/crates/node/builder/src/builder/states.rs index 80930ef743cd..c4da466f23e9 100644 --- a/crates/node/builder/src/builder/states.rs +++ b/crates/node/builder/src/builder/states.rs @@ -11,10 +11,7 @@ use reth_exex::ExExContext; use reth_node_api::{ FullNodeComponents, FullNodeTypes, NodeAddOns, NodeTypes, NodeTypesWithDB, NodeTypesWithEngine, }; -use reth_node_core::{ - node_config::NodeConfig, - rpc::eth::{helpers::AddDevSigners, FullEthApiServer}, -}; +use reth_node_core::node_config::NodeConfig; use reth_payload_builder::PayloadBuilderHandle; use reth_tasks::TaskExecutor; @@ -22,8 +19,8 @@ use crate::{ components::{NodeComponents, NodeComponentsBuilder}, hooks::NodeHooks, launch::LaunchNode, - rpc::{EthApiBuilderProvider, RethRpcServerHandles, RpcContext, RpcHooks}, - AddOns, FullNode, RpcAddOns, + rpc::{RethRpcAddOns, RethRpcServerHandles, RpcContext}, + AddOns, FullNode, }; /// A node builder that also has the configured types. @@ -54,12 +51,7 @@ impl NodeBuilderWithTypes { config, adapter, components_builder, - add_ons: AddOns { - hooks: NodeHooks::default(), - rpc: RpcAddOns { hooks: RpcHooks::default() }, - exexs: Vec::new(), - addons: (), - }, + add_ons: AddOns { hooks: NodeHooks::default(), exexs: Vec::new(), add_ons: () }, } } } @@ -83,8 +75,8 @@ impl fmt::Debug for NodeTypesAdapter { } } -/// Container for the node's types and the components and other internals that can be used by addons -/// of the node. +/// Container for the node's types and the components and other internals that can be used by +/// addons of the node. pub struct NodeAdapter> { /// The components of the node. pub components: C, @@ -104,6 +96,8 @@ impl> FullNodeComponents for NodeAdapter< type Evm = C::Evm; type Executor = C::Executor; type Network = C::Network; + type Consensus = C::Consensus; + type EngineValidator = C::EngineValidator; fn pool(&self) -> &Self::Pool { self.components.pool() @@ -132,6 +126,14 @@ impl> FullNodeComponents for NodeAdapter< fn task_executor(&self) -> &TaskExecutor { &self.task_executor } + + fn consensus(&self) -> &Self::Consensus { + self.components.consensus() + } + + fn engine_validator(&self) -> &Self::EngineValidator { + self.components.engine_validator() + } } impl> Clone for NodeAdapter { @@ -169,7 +171,7 @@ where { /// Advances the state of the node builder to the next state where all customizable /// [`NodeAddOns`] types are configured. - pub fn with_add_ons(self, addons: AO) -> NodeBuilderWithComponents + pub fn with_add_ons(self, add_ons: AO) -> NodeBuilderWithComponents where AO: NodeAddOns>, { @@ -179,12 +181,7 @@ where config, adapter, components_builder, - add_ons: AddOns { - hooks: NodeHooks::default(), - rpc: RpcAddOns { hooks: RpcHooks::default() }, - exexs: Vec::new(), - addons, - }, + add_ons: AddOns { hooks: NodeHooks::default(), exexs: Vec::new(), add_ons }, } } } @@ -215,31 +212,6 @@ where self } - /// Sets the hook that is run once the rpc server is started. - pub fn on_rpc_started(mut self, hook: F) -> Self - where - F: FnOnce( - RpcContext<'_, NodeAdapter, AO::EthApi>, - RethRpcServerHandles, - ) -> eyre::Result<()> - + Send - + 'static, - { - self.add_ons.rpc.hooks.set_on_rpc_started(hook); - self - } - - /// Sets the hook that is run to configure the rpc modules. - pub fn extend_rpc_modules(mut self, hook: F) -> Self - where - F: FnOnce(RpcContext<'_, NodeAdapter, AO::EthApi>) -> eyre::Result<()> - + Send - + 'static, - { - self.add_ons.rpc.hooks.set_extend_rpc_modules(hook); - self - } - /// Installs an `ExEx` (Execution Extension) in the node. /// /// # Note @@ -269,18 +241,22 @@ where pub const fn check_launch(self) -> Self { self } + + /// Modifies the addons with the given closure. + pub fn map_add_ons(mut self, f: F) -> Self + where + F: FnOnce(AO) -> AO, + { + self.add_ons.add_ons = f(self.add_ons.add_ons); + self + } } impl NodeBuilderWithComponents where T: FullNodeTypes, CB: NodeComponentsBuilder, - AO: NodeAddOns< - NodeAdapter, - EthApi: EthApiBuilderProvider> - + FullEthApiServer - + AddDevSigners, - >, + AO: RethRpcAddOns>, { /// Launches the node with the given launcher. pub async fn launch_with(self, launcher: L) -> eyre::Result @@ -289,4 +265,33 @@ where { launcher.launch_node(self).await } + + /// Sets the hook that is run once the rpc server is started. + pub fn on_rpc_started(self, hook: F) -> Self + where + F: FnOnce( + RpcContext<'_, NodeAdapter, AO::EthApi>, + RethRpcServerHandles, + ) -> eyre::Result<()> + + Send + + 'static, + { + self.map_add_ons(|mut add_ons| { + add_ons.hooks_mut().set_on_rpc_started(hook); + add_ons + }) + } + + /// Sets the hook that is run to configure the rpc modules. + pub fn extend_rpc_modules(self, hook: F) -> Self + where + F: FnOnce(RpcContext<'_, NodeAdapter, AO::EthApi>) -> eyre::Result<()> + + Send + + 'static, + { + self.map_add_ons(|mut add_ons| { + add_ons.hooks_mut().set_extend_rpc_modules(hook); + add_ons + }) + } } diff --git a/crates/node/builder/src/handle.rs b/crates/node/builder/src/handle.rs index c81aa9420dde..2997a8687afd 100644 --- a/crates/node/builder/src/handle.rs +++ b/crates/node/builder/src/handle.rs @@ -1,13 +1,13 @@ use std::fmt; -use reth_node_api::{FullNodeComponents, NodeAddOns}; +use reth_node_api::FullNodeComponents; use reth_node_core::exit::NodeExitFuture; -use crate::node::FullNode; +use crate::{node::FullNode, rpc::RethRpcAddOns}; /// A Handle to the launched node. #[must_use = "Needs to await the node exit future"] -pub struct NodeHandle> { +pub struct NodeHandle> { /// All node components. pub node: FullNode, /// The exit future of the node. @@ -17,7 +17,7 @@ pub struct NodeHandle> { impl NodeHandle where Node: FullNodeComponents, - AddOns: NodeAddOns, + AddOns: RethRpcAddOns, { /// Waits for the node to exit, if it was configured to exit. pub async fn wait_for_node_exit(self) -> eyre::Result<()> { @@ -28,7 +28,7 @@ where impl fmt::Debug for NodeHandle where Node: FullNodeComponents, - AddOns: NodeAddOns, + AddOns: RethRpcAddOns, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("NodeHandle") diff --git a/crates/node/builder/src/launch/engine.rs b/crates/node/builder/src/launch/engine.rs index f9e26f202fc4..3de651cdcd0b 100644 --- a/crates/node/builder/src/launch/engine.rs +++ b/crates/node/builder/src/launch/engine.rs @@ -1,6 +1,5 @@ //! Engine node related functionality. -use alloy_rpc_types::engine::ClientVersionV1; use futures::{future::Either, stream, stream_select, StreamExt}; use reth_beacon_consensus::{ hooks::{EngineHooks, StaticFileHook}, @@ -20,21 +19,17 @@ use reth_exex::ExExManagerHandle; use reth_network::{NetworkSyncUpdater, SyncState}; use reth_network_api::{BlockDownloaderProvider, NetworkEventListenerProvider}; use reth_node_api::{ - BuiltPayload, FullNodeTypes, NodeAddOns, NodeTypesWithEngine, PayloadAttributesBuilder, - PayloadTypes, + BuiltPayload, FullNodeTypes, NodeTypesWithEngine, PayloadAttributesBuilder, PayloadTypes, }; use reth_node_core::{ dirs::{ChainPath, DataDirPath}, exit::NodeExitFuture, primitives::Head, - rpc::eth::{helpers::AddDevSigners, FullEthApiServer}, - version::{CARGO_PKG_VERSION, CLIENT_CODE, NAME_CLIENT, VERGEN_GIT_SHA}, }; use reth_node_events::{cl::ConsensusLayerHealthEvents, node}; use reth_payload_primitives::PayloadBuilder; use reth_primitives::EthereumHardforks; use reth_provider::providers::{BlockchainProvider2, ProviderNodeTypes}; -use reth_rpc_engine_api::{capabilities::EngineCapabilities, EngineApi}; use reth_tasks::TaskExecutor; use reth_tokio_util::EventSender; use reth_tracing::tracing::{debug, error, info}; @@ -45,9 +40,9 @@ use tokio_stream::wrappers::UnboundedReceiverStream; use crate::{ common::{Attached, LaunchContextWith, WithConfigs}, hooks::NodeHooks, - rpc::{launch_rpc_servers, EthApiBuilderProvider}, + rpc::{RethRpcAddOns, RpcHandle}, setup::build_networked_pipeline, - AddOns, ExExLauncher, FullNode, LaunchContext, LaunchNode, NodeAdapter, + AddOns, AddOnsContext, ExExLauncher, FullNode, LaunchContext, LaunchNode, NodeAdapter, NodeBuilderWithComponents, NodeComponents, NodeComponentsBuilder, NodeHandle, NodeTypesAdapter, }; @@ -78,12 +73,7 @@ where Types: ProviderNodeTypes + NodeTypesWithEngine, T: FullNodeTypes>, CB: NodeComponentsBuilder, - AO: NodeAddOns< - NodeAdapter, - EthApi: EthApiBuilderProvider> - + FullEthApiServer - + AddDevSigners, - >, + AO: RethRpcAddOns>, LocalPayloadAttributesBuilder: PayloadAttributesBuilder< <::Engine as PayloadTypes>::PayloadAttributes, >, @@ -98,7 +88,7 @@ where let NodeBuilderWithComponents { adapter: NodeTypesAdapter { database }, components_builder, - add_ons: AddOns { hooks, rpc, exexs: installed_exex, .. }, + add_ons: AddOns { hooks, exexs: installed_exex, add_ons }, config, } = target; let NodeHooks { on_component_initialized, on_node_started, .. } = hooks; @@ -292,37 +282,18 @@ where ), ); - let client = ClientVersionV1 { - code: CLIENT_CODE, - name: NAME_CLIENT.to_string(), - version: CARGO_PKG_VERSION.to_string(), - commit: VERGEN_GIT_SHA.to_string(), - }; - let engine_api = EngineApi::new( - ctx.blockchain_db().clone(), - ctx.chain_spec(), - beacon_engine_handle, - ctx.components().payload_builder().clone().into(), - ctx.components().pool().clone(), - Box::new(ctx.task_executor().clone()), - client, - EngineCapabilities::default(), - ctx.components().engine_validator().clone(), - ); - info!(target: "reth::cli", "Engine API handler initialized"); - // extract the jwt secret from the args if possible let jwt_secret = ctx.auth_jwt_secret()?; - // Start RPC servers - let (rpc_server_handles, rpc_registry) = launch_rpc_servers( - ctx.node_adapter().clone(), - engine_api, - ctx.node_config(), - jwt_secret, - rpc, - ) - .await?; + let add_ons_ctx = AddOnsContext { + node: ctx.node_adapter(), + config: ctx.node_config(), + beacon_engine_handle: &beacon_engine_handle, + jwt_secret: &jwt_secret, + }; + + let RpcHandle { rpc_server_handles, rpc_registry } = + add_ons.launch_add_ons(add_ons_ctx).await?; // TODO: migrate to devmode with https://github.com/paradigmxyz/reth/issues/10104 if let Some(maybe_custom_etherscan_url) = ctx.node_config().debug.etherscan.clone() { @@ -442,13 +413,12 @@ where provider: ctx.node_adapter().provider.clone(), payload_builder: ctx.components().payload_builder().clone(), task_executor: ctx.task_executor().clone(), - rpc_server_handles, - rpc_registry, config: ctx.node_config().clone(), data_dir: ctx.data_dir().clone(), + add_ons_handle: RpcHandle { rpc_server_handles, rpc_registry }, }; // Notify on node started - on_node_started.on_event(full_node.clone())?; + on_node_started.on_event(FullNode::clone(&full_node))?; let handle = NodeHandle { node_exit_future: NodeExitFuture::new( diff --git a/crates/node/builder/src/launch/mod.rs b/crates/node/builder/src/launch/mod.rs index 3188cde4b157..36aa55541e00 100644 --- a/crates/node/builder/src/launch/mod.rs +++ b/crates/node/builder/src/launch/mod.rs @@ -12,7 +12,6 @@ pub use exex::ExExLauncher; use std::{future::Future, sync::Arc}; use alloy_primitives::utils::format_ether; -use alloy_rpc_types::engine::ClientVersionV1; use futures::{future::Either, stream, stream_select, StreamExt}; use reth_beacon_consensus::{ hooks::{EngineHooks, PruneHook, StaticFileHook}, @@ -25,17 +24,14 @@ use reth_engine_util::EngineMessageStreamExt; use reth_exex::ExExManagerHandle; use reth_network::{BlockDownloaderProvider, NetworkEventListenerProvider}; use reth_node_api::{ - FullNodeComponents, FullNodeTypes, NodeAddOns, NodeTypesWithDB, NodeTypesWithEngine, + AddOnsContext, FullNodeComponents, FullNodeTypes, NodeTypesWithDB, NodeTypesWithEngine, }; use reth_node_core::{ dirs::{ChainPath, DataDirPath}, exit::NodeExitFuture, - rpc::eth::{helpers::AddDevSigners, FullEthApiServer}, - version::{CARGO_PKG_VERSION, CLIENT_CODE, NAME_CLIENT, VERGEN_GIT_SHA}, }; use reth_node_events::{cl::ConsensusLayerHealthEvents, node}; use reth_provider::providers::BlockchainProvider; -use reth_rpc_engine_api::{capabilities::EngineCapabilities, EngineApi}; use reth_tasks::TaskExecutor; use reth_tracing::tracing::{debug, info}; use reth_transaction_pool::TransactionPool; @@ -47,19 +43,18 @@ use crate::{ components::{NodeComponents, NodeComponentsBuilder}, hooks::NodeHooks, node::FullNode, - rpc::EthApiBuilderProvider, + rpc::{RethRpcAddOns, RpcHandle}, AddOns, NodeBuilderWithComponents, NodeHandle, }; /// Alias for [`reth_rpc_eth_types::EthApiBuilderCtx`], adapter for [`FullNodeComponents`]. -pub type EthApiBuilderCtx = reth_rpc_eth_types::EthApiBuilderCtx< +pub type EthApiBuilderCtx = reth_rpc_eth_types::EthApiBuilderCtx< ::Provider, ::Pool, ::Evm, ::Network, TaskExecutor, ::Provider, - Eth, >; /// A general purpose trait that launches a new node of any kind. @@ -109,12 +104,7 @@ where Types: NodeTypesWithDB + NodeTypesWithEngine, T: FullNodeTypes, Types = Types>, CB: NodeComponentsBuilder, - AO: NodeAddOns< - NodeAdapter, - EthApi: EthApiBuilderProvider> - + FullEthApiServer - + AddDevSigners, - >, + AO: RethRpcAddOns>, { type Node = NodeHandle, AO>; @@ -126,7 +116,7 @@ where let NodeBuilderWithComponents { adapter: NodeTypesAdapter { database }, components_builder, - add_ons: AddOns { hooks, rpc, exexs: installed_exex, .. }, + add_ons: AddOns { hooks, exexs: installed_exex, add_ons }, config, } = target; let NodeHooks { on_component_initialized, on_node_started, .. } = hooks; @@ -336,42 +326,18 @@ where ), ); - let client = ClientVersionV1 { - code: CLIENT_CODE, - name: NAME_CLIENT.to_string(), - version: CARGO_PKG_VERSION.to_string(), - commit: VERGEN_GIT_SHA.to_string(), - }; - let engine_api = EngineApi::new( - ctx.blockchain_db().clone(), - ctx.chain_spec(), - beacon_engine_handle, - ctx.components().payload_builder().clone().into(), - ctx.components().pool().clone(), - Box::new(ctx.task_executor().clone()), - client, - EngineCapabilities::default(), - ctx.components().engine_validator().clone(), - ); - info!(target: "reth::cli", "Engine API handler initialized"); - // extract the jwt secret from the args if possible let jwt_secret = ctx.auth_jwt_secret()?; - // Start RPC servers - let (rpc_server_handles, rpc_registry) = crate::rpc::launch_rpc_servers( - ctx.node_adapter().clone(), - engine_api, - ctx.node_config(), - jwt_secret, - rpc, - ) - .await?; + let add_ons_ctx = AddOnsContext { + node: ctx.node_adapter(), + config: ctx.node_config(), + beacon_engine_handle: &beacon_engine_handle, + jwt_secret: &jwt_secret, + }; - // in dev mode we generate 20 random dev-signer accounts - if ctx.is_dev() { - rpc_registry.eth_api().with_dev_accounts(); - } + let RpcHandle { rpc_server_handles, rpc_registry } = + add_ons.launch_add_ons(add_ons_ctx).await?; // Run consensus engine to completion let (tx, rx) = oneshot::channel(); @@ -431,13 +397,12 @@ where provider: ctx.node_adapter().provider.clone(), payload_builder: ctx.components().payload_builder().clone(), task_executor: ctx.task_executor().clone(), - rpc_server_handles, - rpc_registry, config: ctx.node_config().clone(), data_dir: ctx.data_dir().clone(), + add_ons_handle: RpcHandle { rpc_server_handles, rpc_registry }, }; // Notify on node started - on_node_started.on_event(full_node.clone())?; + on_node_started.on_event(FullNode::clone(&full_node))?; let handle = NodeHandle { node_exit_future: NodeExitFuture::new( diff --git a/crates/node/builder/src/lib.rs b/crates/node/builder/src/lib.rs index cfe16074a59d..899317f158c6 100644 --- a/crates/node/builder/src/lib.rs +++ b/crates/node/builder/src/lib.rs @@ -20,10 +20,7 @@ pub mod components; pub use components::{NodeComponents, NodeComponentsBuilder}; mod builder; -pub use builder::{ - add_ons::{AddOns, RpcAddOns}, - *, -}; +pub use builder::{add_ons::AddOns, *}; mod launch; pub use launch::{engine::EngineNodeLauncher, *}; diff --git a/crates/node/builder/src/node.rs b/crates/node/builder/src/node.rs index 3a70c08c1031..3e3d5b696c39 100644 --- a/crates/node/builder/src/node.rs +++ b/crates/node/builder/src/node.rs @@ -1,7 +1,11 @@ // re-export the node api types pub use reth_node_api::{FullNodeTypes, NodeTypes, NodeTypesWithEngine}; -use std::{marker::PhantomData, sync::Arc}; +use std::{ + marker::PhantomData, + ops::{Deref, DerefMut}, + sync::Arc, +}; use reth_node_api::{EngineTypes, FullNodeComponents}; use reth_node_core::{ @@ -14,11 +18,7 @@ use reth_provider::ChainSpecProvider; use reth_rpc_builder::{auth::AuthServerHandle, RpcServerHandle}; use reth_tasks::TaskExecutor; -use crate::{ - components::NodeComponentsBuilder, - rpc::{RethRpcServerHandles, RpcRegistry}, - NodeAdapter, NodeAddOns, -}; +use crate::{components::NodeComponentsBuilder, rpc::RethRpcAddOns, NodeAdapter, NodeAddOns}; /// A [`crate::Node`] is a [`NodeTypesWithEngine`] that comes with preconfigured components. /// @@ -84,7 +84,7 @@ impl Node for AnyNode where N: FullNodeTypes + Clone, C: NodeComponentsBuilder + Clone + Sync + Unpin + 'static, - AO: NodeAddOns>, + AO: NodeAddOns> + Clone + Sync + Unpin + 'static, { type ComponentsBuilder = C; type AddOns = AO; @@ -117,14 +117,12 @@ pub struct FullNode> { pub payload_builder: PayloadBuilderHandle<::Engine>, /// Task executor for the node. pub task_executor: TaskExecutor, - /// Handles to the node's rpc servers - pub rpc_server_handles: RethRpcServerHandles, - /// The configured rpc namespaces - pub rpc_registry: RpcRegistry, /// The initial node config. pub config: NodeConfig<::ChainSpec>, /// The data dir of the node. pub data_dir: ChainPath, + /// The handle to launched add-ons + pub add_ons_handle: AddOns::Handle, } impl> Clone for FullNode { @@ -137,10 +135,9 @@ impl> Clone for FullNode Arc<::ChainSpec> { self.provider.chain_spec() } +} +impl FullNode +where + Engine: EngineTypes, + Node: FullNodeComponents>, + AddOns: RethRpcAddOns, +{ /// Returns the [`RpcServerHandle`] to the started rpc server. pub const fn rpc_server_handle(&self) -> &RpcServerHandle { - &self.rpc_server_handles.rpc + &self.add_ons_handle.rpc_server_handles.rpc } /// Returns the [`AuthServerHandle`] to the started authenticated engine API server. pub const fn auth_server_handle(&self) -> &AuthServerHandle { - &self.rpc_server_handles.auth + &self.add_ons_handle.rpc_server_handles.auth } /// Returns the [`EngineApiClient`] interface for the authenticated engine API. @@ -188,3 +192,17 @@ where self.auth_server_handle().ipc_client().await } } + +impl> Deref for FullNode { + type Target = AddOns::Handle; + + fn deref(&self) -> &Self::Target { + &self.add_ons_handle + } +} + +impl> DerefMut for FullNode { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.add_ons_handle + } +} diff --git a/crates/node/builder/src/rpc.rs b/crates/node/builder/src/rpc.rs index cb8d8f355dac..d8cce9217efc 100644 --- a/crates/node/builder/src/rpc.rs +++ b/crates/node/builder/src/rpc.rs @@ -1,31 +1,35 @@ //! Builder support for rpc components. use std::{ - fmt, + fmt::{self, Debug}, + marker::PhantomData, ops::{Deref, DerefMut}, }; +use alloy_rpc_types::engine::ClientVersionV1; use futures::TryFutureExt; -use reth_node_api::{BuilderProvider, FullNodeComponents, NodeTypes, NodeTypesWithEngine}; +use reth_node_api::{ + AddOnsContext, FullNodeComponents, NodeAddOns, NodeTypes, NodeTypesWithEngine, +}; use reth_node_core::{ node_config::NodeConfig, - rpc::{ - api::EngineApiServer, - eth::{EthApiTypes, FullEthApiServer}, - }, + rpc::eth::{EthApiTypes, FullEthApiServer}, + version::{CARGO_PKG_VERSION, CLIENT_CODE, NAME_CLIENT, VERGEN_GIT_SHA}, }; use reth_payload_builder::PayloadBuilderHandle; use reth_provider::providers::ProviderNodeTypes; +use reth_rpc::EthApi; +use reth_rpc_api::eth::helpers::AddDevSigners; use reth_rpc_builder::{ auth::{AuthRpcModule, AuthServerHandle}, config::RethRpcServerConfig, RpcModuleBuilder, RpcRegistryInner, RpcServerHandle, TransportRpcModules, }; -use reth_rpc_layer::JwtSecret; +use reth_rpc_engine_api::{capabilities::EngineCapabilities, EngineApi}; use reth_tasks::TaskExecutor; use reth_tracing::tracing::{debug, info}; -use crate::{EthApiBuilderCtx, RpcAddOns}; +use crate::EthApiBuilderCtx; /// Contains the handles to the spawned RPC servers. /// @@ -292,102 +296,232 @@ where } } -/// Launch the rpc servers. -pub async fn launch_rpc_servers( - node: Node, - engine_api: Engine, - config: &NodeConfig<::ChainSpec>, - jwt_secret: JwtSecret, - add_ons: RpcAddOns, -) -> eyre::Result<(RethRpcServerHandles, RpcRegistry)> +/// Handle to the launched RPC servers. +#[derive(Clone)] +pub struct RpcHandle { + /// Handles to launched servers. + pub rpc_server_handles: RethRpcServerHandles, + /// Configured RPC modules. + pub rpc_registry: RpcRegistry, +} + +impl Deref for RpcHandle { + type Target = RpcRegistry; + + fn deref(&self) -> &Self::Target { + &self.rpc_registry + } +} + +impl Debug for RpcHandle where - Node: FullNodeComponents + Clone, - Engine: EngineApiServer<::Engine>, - EthApi: EthApiBuilderProvider + FullEthApiServer, + RpcRegistry: Debug, { - let auth_config = config.rpc.auth_server_config(jwt_secret)?; - let module_config = config.rpc.transport_rpc_module_config(); - debug!(target: "reth::cli", http=?module_config.http(), ws=?module_config.ws(), "Using RPC module config"); - - let (mut modules, mut auth_module, registry) = RpcModuleBuilder::default() - .with_provider(node.provider().clone()) - .with_pool(node.pool().clone()) - .with_network(node.network().clone()) - .with_events(node.provider().clone()) - .with_executor(node.task_executor().clone()) - .with_evm_config(node.evm_config().clone()) - .with_block_executor(node.block_executor().clone()) - .build_with_auth_server(module_config, engine_api, EthApi::eth_api_builder()); - - let mut registry = RpcRegistry { registry }; - let ctx = RpcContext { - node: node.clone(), - config, - registry: &mut registry, - modules: &mut modules, - auth_module: &mut auth_module, - }; - - let RpcAddOns { hooks, .. } = add_ons; - let RpcHooks { on_rpc_started, extend_rpc_modules } = hooks; - - extend_rpc_modules.extend_rpc_modules(ctx)?; - - let server_config = config.rpc.rpc_server_config(); - let cloned_modules = modules.clone(); - let launch_rpc = server_config.start(&cloned_modules).map_ok(|handle| { - if let Some(path) = handle.ipc_endpoint() { - info!(target: "reth::cli", %path, "RPC IPC server started"); - } - if let Some(addr) = handle.http_local_addr() { - info!(target: "reth::cli", url=%addr, "RPC HTTP server started"); - } - if let Some(addr) = handle.ws_local_addr() { - info!(target: "reth::cli", url=%addr, "RPC WS server started"); - } - handle - }); - - let launch_auth = auth_module.clone().start_server(auth_config).map_ok(|handle| { - let addr = handle.local_addr(); - if let Some(ipc_endpoint) = handle.ipc_endpoint() { - info!(target: "reth::cli", url=%addr, ipc_endpoint=%ipc_endpoint,"RPC auth server started"); - } else { - info!(target: "reth::cli", url=%addr, "RPC auth server started"); + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("RpcHandle") + .field("rpc_server_handles", &self.rpc_server_handles) + .field("rpc_registry", &self.rpc_registry) + .finish() + } +} + +/// Node add-ons containing RPC server configuration, with customizable eth API handler. +#[allow(clippy::type_complexity)] +pub struct RpcAddOns { + /// Additional RPC add-ons. + pub hooks: RpcHooks, + /// Builder for `EthApi` + eth_api_builder: Box) -> EthApi + Send + Sync>, + _pd: PhantomData<(Node, EthApi)>, +} + +impl Debug for RpcAddOns { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("RpcAddOns") + .field("hooks", &self.hooks) + .field("eth_api_builder", &"...") + .finish() + } +} + +impl RpcAddOns { + /// Creates a new instance of the RPC add-ons. + pub fn new( + eth_api_builder: impl FnOnce(&EthApiBuilderCtx) -> EthApi + Send + Sync + 'static, + ) -> Self { + Self { + hooks: RpcHooks::default(), + eth_api_builder: Box::new(eth_api_builder), + _pd: PhantomData, } - handle - }); + } - // launch servers concurrently - let (rpc, auth) = futures::future::try_join(launch_rpc, launch_auth).await?; - let handles = RethRpcServerHandles { rpc, auth }; + /// Sets the hook that is run once the rpc server is started. + pub fn on_rpc_started(mut self, hook: F) -> Self + where + F: FnOnce(RpcContext<'_, Node, EthApi>, RethRpcServerHandles) -> eyre::Result<()> + + Send + + 'static, + { + self.hooks.set_on_rpc_started(hook); + self + } - let ctx = RpcContext { - node, - config, - registry: &mut registry, - modules: &mut modules, - auth_module: &mut auth_module, - }; + /// Sets the hook that is run to configure the rpc modules. + pub fn extend_rpc_modules(mut self, hook: F) -> Self + where + F: FnOnce(RpcContext<'_, Node, EthApi>) -> eyre::Result<()> + Send + 'static, + { + self.hooks.set_extend_rpc_modules(hook); + self + } +} + +impl> Default + for RpcAddOns +{ + fn default() -> Self { + Self::new(EthApi::build) + } +} - on_rpc_started.on_rpc_started(ctx, handles.clone())?; +impl NodeAddOns for RpcAddOns +where + N: FullNodeComponents, + EthApi: EthApiTypes + FullEthApiServer + AddDevSigners + Unpin + 'static, +{ + type Handle = RpcHandle; + + async fn launch_add_ons(self, ctx: AddOnsContext<'_, N>) -> eyre::Result { + let AddOnsContext { node, config, beacon_engine_handle, jwt_secret } = ctx; + + let client = ClientVersionV1 { + code: CLIENT_CODE, + name: NAME_CLIENT.to_string(), + version: CARGO_PKG_VERSION.to_string(), + commit: VERGEN_GIT_SHA.to_string(), + }; + + let engine_api = EngineApi::new( + node.provider().clone(), + config.chain.clone(), + beacon_engine_handle.clone(), + node.payload_builder().clone().into(), + node.pool().clone(), + Box::new(node.task_executor().clone()), + client, + EngineCapabilities::default(), + node.engine_validator().clone(), + ); + info!(target: "reth::cli", "Engine API handler initialized"); + + let auth_config = config.rpc.auth_server_config(*jwt_secret)?; + let module_config = config.rpc.transport_rpc_module_config(); + debug!(target: "reth::cli", http=?module_config.http(), ws=?module_config.ws(), "Using RPC module config"); + + let (mut modules, mut auth_module, registry) = RpcModuleBuilder::default() + .with_provider(node.provider().clone()) + .with_pool(node.pool().clone()) + .with_network(node.network().clone()) + .with_events(node.provider().clone()) + .with_executor(node.task_executor().clone()) + .with_evm_config(node.evm_config().clone()) + .with_block_executor(node.block_executor().clone()) + .build_with_auth_server(module_config, engine_api, self.eth_api_builder); + + // in dev mode we generate 20 random dev-signer accounts + if config.dev.dev { + registry.eth_api().with_dev_accounts(); + } - Ok((handles, registry)) + let mut registry = RpcRegistry { registry }; + let ctx = RpcContext { + node: node.clone(), + config, + registry: &mut registry, + modules: &mut modules, + auth_module: &mut auth_module, + }; + + let RpcHooks { on_rpc_started, extend_rpc_modules } = self.hooks; + + extend_rpc_modules.extend_rpc_modules(ctx)?; + + let server_config = config.rpc.rpc_server_config(); + let cloned_modules = modules.clone(); + let launch_rpc = server_config.start(&cloned_modules).map_ok(|handle| { + if let Some(path) = handle.ipc_endpoint() { + info!(target: "reth::cli", %path, "RPC IPC server started"); + } + if let Some(addr) = handle.http_local_addr() { + info!(target: "reth::cli", url=%addr, "RPC HTTP server started"); + } + if let Some(addr) = handle.ws_local_addr() { + info!(target: "reth::cli", url=%addr, "RPC WS server started"); + } + handle + }); + + let launch_auth = auth_module.clone().start_server(auth_config).map_ok(|handle| { + let addr = handle.local_addr(); + if let Some(ipc_endpoint) = handle.ipc_endpoint() { + info!(target: "reth::cli", url=%addr, ipc_endpoint=%ipc_endpoint,"RPC auth server started"); + } else { + info!(target: "reth::cli", url=%addr, "RPC auth server started"); + } + handle + }); + + // launch servers concurrently + let (rpc, auth) = futures::future::try_join(launch_rpc, launch_auth).await?; + + let handles = RethRpcServerHandles { rpc, auth }; + + let ctx = RpcContext { + node: node.clone(), + config, + registry: &mut registry, + modules: &mut modules, + auth_module: &mut auth_module, + }; + + on_rpc_started.on_rpc_started(ctx, handles.clone())?; + + Ok(RpcHandle { rpc_server_handles: handles, rpc_registry: registry }) + } } -/// Provides builder for the core `eth` API type. -pub trait EthApiBuilderProvider: BuilderProvider + EthApiTypes { - /// Returns the eth api builder. - #[allow(clippy::type_complexity)] - fn eth_api_builder() -> Box) -> Self + Send>; +/// Helper trait implemented for add-ons producing [`RpcHandle`]. Used by common node launcher +/// implementations. +pub trait RethRpcAddOns: + NodeAddOns> +{ + /// eth API implementation. + type EthApi: EthApiTypes; + + /// Returns a mutable reference to RPC hooks. + fn hooks_mut(&mut self) -> &mut RpcHooks; } -impl EthApiBuilderProvider for F +impl RethRpcAddOns for RpcAddOns where - N: FullNodeComponents, - for<'a> F: BuilderProvider = &'a EthApiBuilderCtx> + EthApiTypes, + Self: NodeAddOns>, { - fn eth_api_builder() -> Box) -> Self + Send> { - F::builder() + type EthApi = EthApi; + + fn hooks_mut(&mut self) -> &mut RpcHooks { + &mut self.hooks + } +} + +/// A `EthApi` that knows how to build itself from [`EthApiBuilderCtx`]. +pub trait EthApiBuilder: 'static { + /// Builds the `EthApi` from the given context. + fn build(ctx: &EthApiBuilderCtx) -> Self; +} + +impl EthApiBuilder for EthApi { + fn build(ctx: &EthApiBuilderCtx) -> Self { + Self::with_spawner(ctx) } } diff --git a/crates/optimism/bin/src/main.rs b/crates/optimism/bin/src/main.rs index 6822a6a50ec4..c6d3e32b7cf1 100644 --- a/crates/optimism/bin/src/main.rs +++ b/crates/optimism/bin/src/main.rs @@ -6,7 +6,6 @@ use clap::Parser; use reth_node_builder::{engine_tree_config::TreeConfig, EngineNodeLauncher}; use reth_optimism_cli::{chainspec::OpChainSpecParser, Cli}; use reth_optimism_node::{args::RollupArgs, node::OptimismAddOns, OptimismNode}; -use reth_optimism_rpc::SequencerClient; use reth_provider::providers::BlockchainProvider2; use tracing as _; @@ -34,17 +33,7 @@ fn main() { let handle = builder .with_types_and_provider::>() .with_components(OptimismNode::components(rollup_args)) - .with_add_ons(OptimismAddOns::new(sequencer_http_arg.clone())) - .extend_rpc_modules(move |ctx| { - // register sequencer tx forwarder - if let Some(sequencer_http) = sequencer_http_arg { - ctx.registry - .eth_api() - .set_sequencer_client(SequencerClient::new(sequencer_http))?; - } - - Ok(()) - }) + .with_add_ons(OptimismAddOns::new(sequencer_http_arg)) .launch_with_fn(|builder| { let launcher = EngineNodeLauncher::new( builder.task_executor().clone(), @@ -58,20 +47,8 @@ fn main() { handle.node_exit_future.await } false => { - let handle = builder - .node(OptimismNode::new(rollup_args.clone())) - .extend_rpc_modules(move |ctx| { - // register sequencer tx forwarder - if let Some(sequencer_http) = sequencer_http_arg { - ctx.registry - .eth_api() - .set_sequencer_client(SequencerClient::new(sequencer_http))?; - } - - Ok(()) - }) - .launch() - .await?; + let handle = + builder.node(OptimismNode::new(rollup_args.clone())).launch().await?; handle.node_exit_future.await } diff --git a/crates/optimism/node/src/node.rs b/crates/optimism/node/src/node.rs index b6e64f7e0e43..648da85d0bb4 100644 --- a/crates/optimism/node/src/node.rs +++ b/crates/optimism/node/src/node.rs @@ -13,7 +13,8 @@ use reth_node_builder::{ NetworkBuilder, PayloadServiceBuilder, PoolBuilder, PoolBuilderConfigOverrides, }, node::{FullNodeTypes, NodeTypes, NodeTypesWithEngine}, - BuilderContext, Node, PayloadBuilderConfig, + rpc::{RethRpcAddOns, RpcAddOns, RpcHandle}, + BuilderContext, Node, NodeAdapter, NodeComponentsBuilder, PayloadBuilderConfig, }; use reth_optimism_chainspec::OpChainSpec; use reth_optimism_consensus::OptimismBeaconConsensus; @@ -97,7 +98,9 @@ where OptimismEngineValidatorBuilder, >; - type AddOns = OptimismAddOns; + type AddOns = OptimismAddOns< + NodeAdapter>::Components>, + >; fn components_builder(&self) -> Self::ComponentsBuilder { let Self { args } = self; @@ -119,25 +122,43 @@ impl NodeTypesWithEngine for OptimismNode { } /// Add-ons w.r.t. optimism. -#[derive(Debug, Clone)] -pub struct OptimismAddOns { - sequencer_http: Option, +#[derive(Debug)] +pub struct OptimismAddOns(pub RpcAddOns>); + +impl Default for OptimismAddOns { + fn default() -> Self { + Self::new(None) + } } -impl OptimismAddOns { +impl OptimismAddOns { /// Create a new instance with the given `sequencer_http` URL. - pub const fn new(sequencer_http: Option) -> Self { - Self { sequencer_http } + pub fn new(sequencer_http: Option) -> Self { + Self(RpcAddOns::new(move |ctx| OpEthApi::new(ctx, sequencer_http))) } +} + +impl>> NodeAddOns + for OptimismAddOns +{ + type Handle = RpcHandle>; - /// Returns the sequencer HTTP URL. - pub fn sequencer_http(&self) -> Option<&str> { - self.sequencer_http.as_deref() + async fn launch_add_ons( + self, + ctx: reth_node_api::AddOnsContext<'_, N>, + ) -> eyre::Result { + self.0.launch_add_ons(ctx).await } } -impl NodeAddOns for OptimismAddOns { +impl>> RethRpcAddOns + for OptimismAddOns +{ type EthApi = OpEthApi; + + fn hooks_mut(&mut self) -> &mut reth_node_builder::rpc::RpcHooks { + self.0.hooks_mut() + } } /// A regular optimism evm and executor builder. diff --git a/crates/optimism/node/tests/e2e/utils.rs b/crates/optimism/node/tests/e2e/utils.rs index 863bf254e494..8ea8df380b0b 100644 --- a/crates/optimism/node/tests/e2e/utils.rs +++ b/crates/optimism/node/tests/e2e/utils.rs @@ -1,7 +1,9 @@ use alloy_genesis::Genesis; use alloy_primitives::{Address, B256}; use reth::{rpc::types::engine::PayloadAttributes, tasks::TaskManager}; -use reth_e2e_test_utils::{transaction::TransactionTestContext, wallet::Wallet, NodeHelperType}; +use reth_e2e_test_utils::{ + transaction::TransactionTestContext, wallet::Wallet, Adapter, NodeHelperType, +}; use reth_optimism_chainspec::OpChainSpecBuilder; use reth_optimism_node::{ node::OptimismAddOns, OptimismBuiltPayload, OptimismNode, OptimismPayloadBuilderAttributes, @@ -11,7 +13,7 @@ use std::sync::Arc; use tokio::sync::Mutex; /// Optimism Node Helper type -pub(crate) type OpNode = NodeHelperType; +pub(crate) type OpNode = NodeHelperType>>; pub(crate) async fn setup(num_nodes: usize) -> eyre::Result<(Vec, TaskManager, Wallet)> { let genesis: Genesis = serde_json::from_str(include_str!("../assets/genesis.json")).unwrap(); diff --git a/crates/optimism/rpc/src/eth/mod.rs b/crates/optimism/rpc/src/eth/mod.rs index 57ce44100f26..d65dd8edd1d5 100644 --- a/crates/optimism/rpc/src/eth/mod.rs +++ b/crates/optimism/rpc/src/eth/mod.rs @@ -17,7 +17,7 @@ use op_alloy_network::Optimism; use reth_chainspec::EthereumHardforks; use reth_evm::ConfigureEvm; use reth_network_api::NetworkInfo; -use reth_node_api::{BuilderProvider, FullNodeComponents, FullNodeTypes, NodeTypes}; +use reth_node_api::{FullNodeComponents, FullNodeTypes, NodeTypes}; use reth_node_builder::EthApiBuilderCtx; use reth_primitives::Header; use reth_provider::{ @@ -38,7 +38,6 @@ use reth_tasks::{ TaskSpawner, }; use reth_transaction_pool::TransactionPool; -use tokio::sync::OnceCell; use crate::{OpEthApiError, OpTxBuilder, SequencerClient}; @@ -67,13 +66,12 @@ pub struct OpEthApi { inner: Arc>, /// Sequencer client, configured to forward submitted transactions to sequencer of given OP /// network. - sequencer_client: Arc>, + sequencer_client: Option, } impl OpEthApi { /// Creates a new instance for given context. - #[allow(clippy::type_complexity)] - pub fn with_spawner(ctx: &EthApiBuilderCtx) -> Self { + pub fn new(ctx: &EthApiBuilderCtx, sequencer_http: Option) -> Self { let blocking_task_pool = BlockingTaskPool::build().expect("failed to build blocking task pool"); @@ -93,7 +91,7 @@ impl OpEthApi { ctx.config.proof_permits, ); - Self { inner: Arc::new(inner), sequencer_client: Arc::new(OnceCell::new()) } + Self { inner: Arc::new(inner), sequencer_client: sequencer_http.map(SequencerClient::new) } } } @@ -246,18 +244,6 @@ where } } -impl BuilderProvider for OpEthApi -where - Self: Send, - N: FullNodeComponents, -{ - type Ctx<'a> = &'a EthApiBuilderCtx; - - fn builder() -> Box Fn(Self::Ctx<'a>) -> Self + Send> { - Box::new(Self::with_spawner) - } -} - impl fmt::Debug for OpEthApi { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("OpEthApi").finish_non_exhaustive() diff --git a/crates/optimism/rpc/src/eth/transaction.rs b/crates/optimism/rpc/src/eth/transaction.rs index ab7525016a1a..36556905e8ac 100644 --- a/crates/optimism/rpc/src/eth/transaction.rs +++ b/crates/optimism/rpc/src/eth/transaction.rs @@ -81,17 +81,9 @@ impl OpEthApi where N: FullNodeComponents, { - /// Sets a [`SequencerClient`] for `eth_sendRawTransaction` to forward transactions to. - pub fn set_sequencer_client( - &self, - sequencer_client: SequencerClient, - ) -> Result<(), tokio::sync::SetError> { - self.sequencer_client.set(sequencer_client) - } - /// Returns the [`SequencerClient`] if one is set. pub fn raw_tx_forwarder(&self) -> Option { - self.sequencer_client.get().cloned() + self.sequencer_client.clone() } } diff --git a/crates/rpc/rpc-builder/src/eth.rs b/crates/rpc/rpc-builder/src/eth.rs index 920268a98549..613652678a20 100644 --- a/crates/rpc/rpc-builder/src/eth.rs +++ b/crates/rpc/rpc-builder/src/eth.rs @@ -1,5 +1,3 @@ -use std::marker::PhantomData; - use reth_evm::ConfigureEvm; use reth_primitives::Header; use reth_provider::{BlockReader, CanonStateSubscriptions, EvmEnvProvider, StateProviderFactory}; @@ -11,9 +9,8 @@ use reth_rpc_eth_types::{ use reth_tasks::TaskSpawner; /// Alias for `eth` namespace API builder. -pub type DynEthApiBuilder = Box< - dyn Fn(&EthApiBuilderCtx) -> EthApi, ->; +pub type DynEthApiBuilder = + Box) -> EthApi>; /// Handlers for core, filter and pubsub `eth` namespace APIs. #[derive(Debug, Clone)] @@ -87,7 +84,6 @@ where executor, events, cache, - _rpc_ty_builders: PhantomData, }; let api = eth_api_builder(&ctx); diff --git a/crates/rpc/rpc-builder/src/lib.rs b/crates/rpc/rpc-builder/src/lib.rs index e49105ab7d7d..6a1240b64f8e 100644 --- a/crates/rpc/rpc-builder/src/lib.rs +++ b/crates/rpc/rpc-builder/src/lib.rs @@ -152,6 +152,7 @@ use std::{ collections::HashMap, + fmt::Debug, net::{Ipv4Addr, SocketAddr, SocketAddrV4}, time::{Duration, SystemTime, UNIX_EPOCH}, }; diff --git a/crates/rpc/rpc-eth-types/src/builder/ctx.rs b/crates/rpc/rpc-eth-types/src/builder/ctx.rs index cb2750b6e54f..2132dd0e22c4 100644 --- a/crates/rpc/rpc-eth-types/src/builder/ctx.rs +++ b/crates/rpc/rpc-eth-types/src/builder/ctx.rs @@ -1,7 +1,5 @@ //! Context required for building `eth` namespace APIs. -use std::marker::PhantomData; - use reth_chain_state::CanonStateSubscriptions; use reth_chainspec::ChainSpecProvider; use reth_storage_api::BlockReaderIdExt; @@ -14,7 +12,7 @@ use crate::{ /// Context for building the `eth` namespace API. #[derive(Debug, Clone)] -pub struct EthApiBuilderCtx { +pub struct EthApiBuilderCtx { /// Database handle. pub provider: Provider, /// Mempool handle. @@ -31,12 +29,10 @@ pub struct EthApiBuilderCtx, } -impl - EthApiBuilderCtx +impl + EthApiBuilderCtx where Provider: BlockReaderIdExt + Clone, { @@ -46,53 +42,14 @@ where Provider: ChainSpecProvider + 'static, Tasks: TaskSpawner, Events: CanonStateSubscriptions, - { - FeeHistoryCacheBuilder::build(self) - } - - /// Returns a new [`GasPriceOracle`] for the context. - pub fn new_gas_price_oracle(&self) -> GasPriceOracle { - GasPriceOracleBuilder::build(self) - } -} - -/// Builds `eth_` core api component [`GasPriceOracle`], for given context. -#[derive(Debug)] -pub struct GasPriceOracleBuilder; - -impl GasPriceOracleBuilder { - /// Builds a [`GasPriceOracle`], for given context. - pub fn build( - ctx: &EthApiBuilderCtx, - ) -> GasPriceOracle - where - Provider: BlockReaderIdExt + Clone, - { - GasPriceOracle::new(ctx.provider.clone(), ctx.config.gas_oracle, ctx.cache.clone()) - } -} - -/// Builds `eth_` core api component [`FeeHistoryCache`], for given context. -#[derive(Debug)] -pub struct FeeHistoryCacheBuilder; - -impl FeeHistoryCacheBuilder { - /// Builds a [`FeeHistoryCache`], for given context. - pub fn build( - ctx: &EthApiBuilderCtx, - ) -> FeeHistoryCache - where - Provider: ChainSpecProvider + BlockReaderIdExt + Clone + 'static, - Tasks: TaskSpawner, - Events: CanonStateSubscriptions, { let fee_history_cache = - FeeHistoryCache::new(ctx.cache.clone(), ctx.config.fee_history_cache); + FeeHistoryCache::new(self.cache.clone(), self.config.fee_history_cache); - let new_canonical_blocks = ctx.events.canonical_state_stream(); + let new_canonical_blocks = self.events.canonical_state_stream(); let fhc = fee_history_cache.clone(); - let provider = ctx.provider.clone(); - ctx.executor.spawn_critical( + let provider = self.provider.clone(); + self.executor.spawn_critical( "cache canonical blocks for fee history task", Box::pin(async move { fee_history_cache_new_blocks_task(fhc, new_canonical_blocks, provider).await; @@ -101,4 +58,9 @@ impl FeeHistoryCacheBuilder { fee_history_cache } + + /// Returns a new [`GasPriceOracle`] for the context. + pub fn new_gas_price_oracle(&self) -> GasPriceOracle { + GasPriceOracle::new(self.provider.clone(), self.config.gas_oracle, self.cache.clone()) + } } diff --git a/crates/rpc/rpc/src/eth/core.rs b/crates/rpc/rpc/src/eth/core.rs index 304266f6a8b3..6da46804005c 100644 --- a/crates/rpc/rpc/src/eth/core.rs +++ b/crates/rpc/rpc/src/eth/core.rs @@ -6,7 +6,6 @@ use std::sync::Arc; use alloy_network::AnyNetwork; use alloy_primitives::U256; use derive_more::Deref; -use reth_node_api::{BuilderProvider, FullNodeComponents}; use reth_primitives::BlockNumberOrTag; use reth_provider::{BlockReaderIdExt, CanonStateSubscriptions, ChainSpecProvider}; use reth_rpc_eth_api::{ @@ -19,7 +18,7 @@ use reth_rpc_eth_types::{ }; use reth_tasks::{ pool::{BlockingTaskGuard, BlockingTaskPool}, - TaskExecutor, TaskSpawner, TokioTaskExecutor, + TaskSpawner, TokioTaskExecutor, }; use tokio::sync::Mutex; @@ -95,7 +94,7 @@ where { /// Creates a new, shareable instance. pub fn with_spawner( - ctx: &EthApiBuilderCtx, + ctx: &EthApiBuilderCtx, ) -> Self where Tasks: TaskSpawner + Clone + 'static, @@ -163,25 +162,6 @@ where } } -impl BuilderProvider for EthApi -where - N: FullNodeComponents, -{ - type Ctx<'a> = &'a EthApiBuilderCtx< - N::Provider, - N::Pool, - N::Evm, - N::Network, - TaskExecutor, - N::Provider, - Self, - >; - - fn builder() -> Box Fn(Self::Ctx<'a>) -> Self + Send> { - Box::new(Self::with_spawner) - } -} - /// Container type `EthApi` #[allow(missing_debug_implementations)] pub struct EthApiInner { diff --git a/examples/custom-engine-types/src/main.rs b/examples/custom-engine-types/src/main.rs index 34f8186be7f8..f833da86236e 100644 --- a/examples/custom-engine-types/src/main.rs +++ b/examples/custom-engine-types/src/main.rs @@ -36,7 +36,8 @@ use reth::{ builder::{ components::{ComponentsBuilder, EngineValidatorBuilder, PayloadServiceBuilder}, node::{NodeTypes, NodeTypesWithEngine}, - BuilderContext, FullNodeTypes, Node, NodeBuilder, PayloadBuilderConfig, + BuilderContext, FullNodeTypes, Node, NodeAdapter, NodeBuilder, NodeComponentsBuilder, + PayloadBuilderConfig, }, providers::{CanonStateSubscriptions, StateProviderFactory}, tasks::TaskManager, @@ -241,7 +242,9 @@ where EthereumConsensusBuilder, CustomEngineValidatorBuilder, >; - type AddOns = EthereumAddOns; + type AddOns = EthereumAddOns< + NodeAdapter>::Components>, + >; fn components_builder(&self) -> Self::ComponentsBuilder { ComponentsBuilder::default() From 5aceb3e11ed97be89a2cea338f904fc0afbc6dd4 Mon Sep 17 00:00:00 2001 From: Thomas Coratger <60488569+tcoratger@users.noreply.github.com> Date: Tue, 15 Oct 2024 17:27:26 +0200 Subject: [PATCH 004/113] primitives: rm redundant `chain_id` function for Transaction (#11751) --- Cargo.lock | 1 + crates/primitives/src/alloy_compat.rs | 2 +- crates/primitives/src/transaction/mod.rs | 21 ++++++------------- crates/rpc/rpc-types-compat/Cargo.toml | 1 + .../rpc-types-compat/src/transaction/mod.rs | 1 + crates/rpc/rpc/src/eth/helpers/types.rs | 1 + crates/transaction-pool/Cargo.toml | 5 ++--- crates/transaction-pool/src/traits.rs | 1 + testing/testing-utils/src/generators.rs | 2 +- 9 files changed, 15 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 59e8f2b27fba..b3cd1538507c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8835,6 +8835,7 @@ dependencies = [ name = "reth-rpc-types-compat" version = "1.1.0" dependencies = [ + "alloy-consensus", "alloy-eips", "alloy-primitives", "alloy-rlp", diff --git a/crates/primitives/src/alloy_compat.rs b/crates/primitives/src/alloy_compat.rs index 65099967e6e9..c9bdfad89f57 100644 --- a/crates/primitives/src/alloy_compat.rs +++ b/crates/primitives/src/alloy_compat.rs @@ -5,7 +5,7 @@ use crate::{ Transaction, TransactionSigned, TransactionSignedEcRecovered, TransactionSignedNoHash, TxType, }; use alloc::{string::ToString, vec::Vec}; -use alloy_consensus::{TxEip1559, TxEip2930, TxEip4844, TxLegacy}; +use alloy_consensus::{Transaction as _, TxEip1559, TxEip2930, TxEip4844, TxLegacy}; use alloy_primitives::{Parity, TxKind}; use alloy_rlp::Error as RlpError; use alloy_serde::WithOtherFields; diff --git a/crates/primitives/src/transaction/mod.rs b/crates/primitives/src/transaction/mod.rs index 0cb860ff6b86..0463cd9ea7e1 100644 --- a/crates/primitives/src/transaction/mod.rs +++ b/crates/primitives/src/transaction/mod.rs @@ -4,7 +4,10 @@ use crate::BlockHashOrNumber; use alloy_eips::eip7702::SignedAuthorization; use alloy_primitives::{keccak256, Address, ChainId, TxKind, B256, U256}; -use alloy_consensus::{SignableTransaction, TxEip1559, TxEip2930, TxEip4844, TxEip7702, TxLegacy}; +use alloy_consensus::{ + SignableTransaction, Transaction as AlloyTransaction, TxEip1559, TxEip2930, TxEip4844, + TxEip7702, TxLegacy, +}; use alloy_eips::{ eip2718::{Decodable2718, Eip2718Error, Eip2718Result, Encodable2718}, eip2930::AccessList, @@ -197,19 +200,6 @@ impl Transaction { } } - /// Get `chain_id`. - pub const fn chain_id(&self) -> Option { - match self { - Self::Legacy(TxLegacy { chain_id, .. }) => *chain_id, - Self::Eip2930(TxEip2930 { chain_id, .. }) | - Self::Eip1559(TxEip1559 { chain_id, .. }) | - Self::Eip4844(TxEip4844 { chain_id, .. }) | - Self::Eip7702(TxEip7702 { chain_id, .. }) => Some(*chain_id), - #[cfg(feature = "optimism")] - Self::Deposit(_) => None, - } - } - /// Sets the transaction's chain id to the provided value. pub fn set_chain_id(&mut self, chain_id: u64) { match self { @@ -824,7 +814,7 @@ impl Encodable for Transaction { } } -impl alloy_consensus::Transaction for Transaction { +impl AlloyTransaction for Transaction { fn chain_id(&self) -> Option { match self { Self::Legacy(tx) => tx.chain_id(), @@ -1974,6 +1964,7 @@ mod tests { transaction::{signature::Signature, TxEip1559, TxKind, TxLegacy}, Transaction, TransactionSigned, TransactionSignedEcRecovered, TransactionSignedNoHash, }; + use alloy_consensus::Transaction as _; use alloy_eips::eip2718::{Decodable2718, Encodable2718}; use alloy_primitives::{address, b256, bytes, hex, Address, Bytes, Parity, B256, U256}; use alloy_rlp::{Decodable, Encodable, Error as RlpError}; diff --git a/crates/rpc/rpc-types-compat/Cargo.toml b/crates/rpc/rpc-types-compat/Cargo.toml index 81b4def204f9..8e436f0d3934 100644 --- a/crates/rpc/rpc-types-compat/Cargo.toml +++ b/crates/rpc/rpc-types-compat/Cargo.toml @@ -24,6 +24,7 @@ alloy-rpc-types.workspace = true alloy-rpc-types-eth = { workspace = true, default-features = false, features = ["serde"] } alloy-serde.workspace = true alloy-rpc-types-engine.workspace = true +alloy-consensus.workspace = true [dev-dependencies] serde_json.workspace = true \ No newline at end of file diff --git a/crates/rpc/rpc-types-compat/src/transaction/mod.rs b/crates/rpc/rpc-types-compat/src/transaction/mod.rs index 9bb2a8b5d92a..a489a588617a 100644 --- a/crates/rpc/rpc-types-compat/src/transaction/mod.rs +++ b/crates/rpc/rpc-types-compat/src/transaction/mod.rs @@ -4,6 +4,7 @@ mod signature; pub use signature::*; use std::fmt; +use alloy_consensus::Transaction as _; use alloy_rpc_types::{ request::{TransactionInput, TransactionRequest}, Transaction, TransactionInfo, diff --git a/crates/rpc/rpc/src/eth/helpers/types.rs b/crates/rpc/rpc/src/eth/helpers/types.rs index d2b9c268e240..982afdcac0ad 100644 --- a/crates/rpc/rpc/src/eth/helpers/types.rs +++ b/crates/rpc/rpc/src/eth/helpers/types.rs @@ -1,5 +1,6 @@ //! L1 `eth` API types. +use alloy_consensus::Transaction as _; use alloy_network::{AnyNetwork, Network}; use alloy_primitives::{Address, TxKind}; use alloy_rpc_types::{Transaction, TransactionInfo}; diff --git a/crates/transaction-pool/Cargo.toml b/crates/transaction-pool/Cargo.toml index 41abbb4b6b7e..887543b521aa 100644 --- a/crates/transaction-pool/Cargo.toml +++ b/crates/transaction-pool/Cargo.toml @@ -27,6 +27,7 @@ revm.workspace = true alloy-eips.workspace = true alloy-primitives.workspace = true alloy-rlp.workspace = true +alloy-consensus.workspace = true # async/futures futures-util.workspace = true @@ -54,7 +55,6 @@ rand = { workspace = true, optional = true } paste = { workspace = true, optional = true } proptest = { workspace = true, optional = true } proptest-arbitrary-interop = { workspace = true, optional = true } -alloy-consensus = { workspace = true, optional = true } [dev-dependencies] reth-primitives = { workspace = true, features = ["arbitrary"] } @@ -69,12 +69,11 @@ pprof = { workspace = true, features = ["criterion", "flamegraph"] } assert_matches.workspace = true tempfile.workspace = true serde_json.workspace = true -alloy-consensus.workspace = true [features] default = ["serde"] serde = ["dep:serde"] -test-utils = ["rand", "paste", "serde", "alloy-consensus"] +test-utils = ["rand", "paste", "serde"] arbitrary = ["proptest", "reth-primitives/arbitrary", "proptest-arbitrary-interop"] [[bench]] diff --git a/crates/transaction-pool/src/traits.rs b/crates/transaction-pool/src/traits.rs index 07fe9b9c206e..9a6eda03d9da 100644 --- a/crates/transaction-pool/src/traits.rs +++ b/crates/transaction-pool/src/traits.rs @@ -7,6 +7,7 @@ use crate::{ validate::ValidPoolTransaction, AllTransactionsEvents, }; +use alloy_consensus::Transaction as _; use alloy_eips::{eip2718::Encodable2718, eip2930::AccessList, eip4844::BlobAndProofV1}; use alloy_primitives::{Address, TxHash, TxKind, B256, U256}; use futures_util::{ready, Stream}; diff --git a/testing/testing-utils/src/generators.rs b/testing/testing-utils/src/generators.rs index 70d6cc02b655..d07af00ce4c2 100644 --- a/testing/testing-utils/src/generators.rs +++ b/testing/testing-utils/src/generators.rs @@ -1,6 +1,6 @@ //! Generators for different data structures like block headers, block bodies and ranges of those. -use alloy_consensus::TxLegacy; +use alloy_consensus::{Transaction as _, TxLegacy}; use alloy_eips::{ eip6110::DepositRequest, eip7002::WithdrawalRequest, eip7251::ConsolidationRequest, }; From 04f5b53462cd9f981db9348efe23e4d81cec0012 Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Tue, 15 Oct 2024 17:47:04 +0200 Subject: [PATCH 005/113] chore: touchups PayloadOrAttributes (#11749) --- crates/payload/primitives/src/payload.rs | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/crates/payload/primitives/src/payload.rs b/crates/payload/primitives/src/payload.rs index 41c2ef1efc23..fc685559e087 100644 --- a/crates/payload/primitives/src/payload.rs +++ b/crates/payload/primitives/src/payload.rs @@ -3,8 +3,10 @@ use alloy_primitives::B256; use alloy_rpc_types::engine::ExecutionPayload; /// Either an [`ExecutionPayload`] or a types that implements the [`PayloadAttributes`] trait. +/// +/// This is a helper type to unify pre-validation of version specific fields of the engine API. #[derive(Debug)] -pub enum PayloadOrAttributes<'a, AttributesType> { +pub enum PayloadOrAttributes<'a, Attributes> { /// An [`ExecutionPayload`] and optional parent beacon block root. ExecutionPayload { /// The inner execution payload @@ -13,13 +15,10 @@ pub enum PayloadOrAttributes<'a, AttributesType> { parent_beacon_block_root: Option, }, /// A payload attributes type. - PayloadAttributes(&'a AttributesType), + PayloadAttributes(&'a Attributes), } -impl<'a, AttributesType> PayloadOrAttributes<'a, AttributesType> -where - AttributesType: PayloadAttributes, -{ +impl<'a, Attributes> PayloadOrAttributes<'a, Attributes> { /// Construct a [`PayloadOrAttributes`] from an [`ExecutionPayload`] and optional parent beacon /// block root. pub const fn from_execution_payload( @@ -29,6 +28,16 @@ where Self::ExecutionPayload { payload, parent_beacon_block_root } } + /// Construct a [`PayloadOrAttributes::PayloadAttributes`] variant + pub const fn from_attributes(attributes: &'a Attributes) -> Self { + Self::PayloadAttributes(attributes) + } +} + +impl PayloadOrAttributes<'_, Attributes> +where + Attributes: PayloadAttributes, +{ /// Return the withdrawals for the payload or attributes. pub fn withdrawals(&self) -> Option<&Vec> { match self { From 77a382f59b2437e1b0dcefe66bddfeccc4020f06 Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Tue, 15 Oct 2024 18:21:08 +0200 Subject: [PATCH 006/113] chore: allow missing const (#11750) --- crates/net/peers/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/net/peers/src/lib.rs b/crates/net/peers/src/lib.rs index e80331f90468..1d60994d8e1b 100644 --- a/crates/net/peers/src/lib.rs +++ b/crates/net/peers/src/lib.rs @@ -117,6 +117,7 @@ pub enum AnyNode { impl AnyNode { /// Returns the peer id of the node. + #[allow(clippy::missing_const_for_fn)] pub fn peer_id(&self) -> PeerId { match self { Self::NodeRecord(record) => record.id, @@ -127,6 +128,7 @@ impl AnyNode { } /// Returns the full node record if available. + #[allow(clippy::missing_const_for_fn)] pub fn node_record(&self) -> Option { match self { Self::NodeRecord(record) => Some(*record), From 7b1b1fcb3b632d8c877a3e761a77ae4d513c0c2a Mon Sep 17 00:00:00 2001 From: nk_ysg Date: Wed, 16 Oct 2024 00:24:25 +0800 Subject: [PATCH 007/113] chore(stage test): use with_capacity (#11759) --- crates/stages/stages/src/stages/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/stages/stages/src/stages/mod.rs b/crates/stages/stages/src/stages/mod.rs index 17ffcf2e90eb..4b9f9295103e 100644 --- a/crates/stages/stages/src/stages/mod.rs +++ b/crates/stages/stages/src/stages/mod.rs @@ -263,7 +263,7 @@ mod tests { ); db.insert_blocks(blocks.iter(), StorageKind::Static)?; - let mut receipts = Vec::new(); + let mut receipts = Vec::with_capacity(blocks.len()); let mut tx_num = 0u64; for block in &blocks { let mut block_receipts = Vec::with_capacity(block.body.transactions.len()); From 7f92760655e887f7282a4027465f4cdb4f66ef9a Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Tue, 15 Oct 2024 22:43:56 +0400 Subject: [PATCH 008/113] fix: `estimateGas` edge case (#11764) --- crates/rpc/rpc-eth-api/src/helpers/call.rs | 6 +++++- crates/rpc/rpc-eth-api/src/helpers/error.rs | 10 ++++++++++ crates/rpc/rpc-eth-types/src/error.rs | 5 +++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/crates/rpc/rpc-eth-api/src/helpers/call.rs b/crates/rpc/rpc-eth-api/src/helpers/call.rs index cb5c4e79a732..6784f9327f09 100644 --- a/crates/rpc/rpc-eth-api/src/helpers/call.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/call.rs @@ -888,7 +888,11 @@ pub trait Call: LoadState + SpawnBlocking { // Execute transaction and handle potential gas errors, adjusting limits accordingly. match self.transact(&mut db, env.clone()) { Err(err) if err.is_gas_too_high() => { - // Increase the lowest gas limit if gas is too high + // Decrease the highest gas limit if gas is too high + highest_gas_limit = mid_gas_limit; + } + Err(err) if err.is_gas_too_low() => { + // Increase the lowest gas limit if gas is too low lowest_gas_limit = mid_gas_limit; } // Handle other cases, including successful transactions. diff --git a/crates/rpc/rpc-eth-api/src/helpers/error.rs b/crates/rpc/rpc-eth-api/src/helpers/error.rs index 041a019052bd..1d991b8e65b6 100644 --- a/crates/rpc/rpc-eth-api/src/helpers/error.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/error.rs @@ -59,6 +59,16 @@ pub trait AsEthApiError { false } + + /// Returns `true` if error is + /// [`RpcInvalidTransactionError::GasTooLow`](reth_rpc_eth_types::RpcInvalidTransactionError::GasTooLow). + fn is_gas_too_low(&self) -> bool { + if let Some(err) = self.as_err() { + return err.is_gas_too_low() + } + + false + } } impl AsEthApiError for EthApiError { diff --git a/crates/rpc/rpc-eth-types/src/error.rs b/crates/rpc/rpc-eth-types/src/error.rs index 212fca36d9c9..b38b3122708b 100644 --- a/crates/rpc/rpc-eth-types/src/error.rs +++ b/crates/rpc/rpc-eth-types/src/error.rs @@ -151,6 +151,11 @@ impl EthApiError { pub const fn is_gas_too_high(&self) -> bool { matches!(self, Self::InvalidTransaction(RpcInvalidTransactionError::GasTooHigh)) } + + /// Returns `true` if error is [`RpcInvalidTransactionError::GasTooLow`] + pub const fn is_gas_too_low(&self) -> bool { + matches!(self, Self::InvalidTransaction(RpcInvalidTransactionError::GasTooLow)) + } } impl From for jsonrpsee_types::error::ErrorObject<'static> { From 4144d6ea24e1ff528cde86982bce269b3dba179a Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Tue, 15 Oct 2024 21:17:31 +0200 Subject: [PATCH 009/113] chore: add get_database_args (#11766) --- crates/node/core/src/args/database.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/crates/node/core/src/args/database.rs b/crates/node/core/src/args/database.rs index 09e9de82f52d..da96deb70c1b 100644 --- a/crates/node/core/src/args/database.rs +++ b/crates/node/core/src/args/database.rs @@ -6,6 +6,7 @@ use clap::{ error::ErrorKind, Arg, Args, Command, Error, }; +use reth_db::ClientVersion; use reth_storage_errors::db::LogLevel; /// Parameters for database configuration @@ -24,7 +25,15 @@ pub struct DatabaseArgs { impl DatabaseArgs { /// Returns default database arguments with configured log level and client version. pub fn database_args(&self) -> reth_db::mdbx::DatabaseArguments { - reth_db::mdbx::DatabaseArguments::new(default_client_version()) + self.get_database_args(default_client_version()) + } + + /// Returns the database arguments with configured log level and given client version. + pub const fn get_database_args( + &self, + client_version: ClientVersion, + ) -> reth_db::mdbx::DatabaseArguments { + reth_db::mdbx::DatabaseArguments::new(client_version) .with_log_level(self.log_level) .with_exclusive(self.exclusive) } From 78415ff7c586eb11097d5181153e7b7d2c092aac Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Tue, 15 Oct 2024 21:18:21 +0200 Subject: [PATCH 010/113] chore: include hash in trace (#11762) --- crates/optimism/rpc/src/eth/transaction.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/optimism/rpc/src/eth/transaction.rs b/crates/optimism/rpc/src/eth/transaction.rs index 36556905e8ac..e161504f8405 100644 --- a/crates/optimism/rpc/src/eth/transaction.rs +++ b/crates/optimism/rpc/src/eth/transaction.rs @@ -40,7 +40,7 @@ where // On optimism, transactions are forwarded directly to the sequencer to be included in // blocks that it builds. if let Some(client) = self.raw_tx_forwarder().as_ref() { - tracing::debug!( target: "rpc::eth", "forwarding raw transaction to"); + tracing::debug!(target: "rpc::eth", hash = %pool_transaction.hash(), "forwarding raw transaction to sequencer"); let _ = client.forward_raw_transaction(&tx).await.inspect_err(|err| { tracing::debug!(target: "rpc::eth", %err, hash=% *pool_transaction.hash(), "failed to forward raw transaction"); }); From d4be773f5f71b49e7e40de3dd747a80af18daf74 Mon Sep 17 00:00:00 2001 From: "0xriazaka.eth" <168359025+0xriazaka@users.noreply.github.com> Date: Tue, 15 Oct 2024 21:47:23 +0100 Subject: [PATCH 011/113] chore: move tests in reth_execution_types::chain to reth-evm-optimism (#11115) Co-authored-by: Emilia Hane Co-authored-by: Matthias Seitz --- crates/evm/execution-types/src/chain.rs | 12 +--- crates/optimism/evm/Cargo.toml | 1 + crates/optimism/evm/src/lib.rs | 82 ++++++++++++++++++++++++- 3 files changed, 83 insertions(+), 12 deletions(-) diff --git a/crates/evm/execution-types/src/chain.rs b/crates/evm/execution-types/src/chain.rs index 30f1f4cd2fc3..d3ed2913ea3b 100644 --- a/crates/evm/execution-types/src/chain.rs +++ b/crates/evm/execution-types/src/chain.rs @@ -656,7 +656,6 @@ pub(super) mod serde_bincode_compat { mod tests { use super::*; use alloy_primitives::B256; - use reth_primitives::{Receipt, Receipts, TxType}; use revm::primitives::{AccountInfo, HashMap}; #[test] @@ -789,7 +788,10 @@ mod tests { } #[test] + #[cfg(not(feature = "optimism"))] fn receipts_by_block_hash() { + use reth_primitives::{Receipt, Receipts, TxType}; + // Create a default SealedBlockWithSenders object let block = SealedBlockWithSenders::default(); @@ -811,10 +813,6 @@ mod tests { cumulative_gas_used: 46913, logs: vec![], success: true, - #[cfg(feature = "optimism")] - deposit_nonce: Some(18), - #[cfg(feature = "optimism")] - deposit_receipt_version: Some(34), }; // Create another random receipt object, receipt2 @@ -823,10 +821,6 @@ mod tests { cumulative_gas_used: 1325345, logs: vec![], success: true, - #[cfg(feature = "optimism")] - deposit_nonce: Some(18), - #[cfg(feature = "optimism")] - deposit_receipt_version: Some(34), }; // Create a Receipts object with a vector of receipt vectors diff --git a/crates/optimism/evm/Cargo.toml b/crates/optimism/evm/Cargo.toml index 76fa3ce69e4d..72231716ff92 100644 --- a/crates/optimism/evm/Cargo.toml +++ b/crates/optimism/evm/Cargo.toml @@ -42,6 +42,7 @@ tracing.workspace = true alloy-eips.workspace = true reth-revm = { workspace = true, features = ["test-utils"] } +reth-primitives = { workspace = true, features = ["test-utils"] } reth-optimism-chainspec.workspace = true alloy-genesis.workspace = true alloy-consensus.workspace = true diff --git a/crates/optimism/evm/src/lib.rs b/crates/optimism/evm/src/lib.rs index 63d0ee6b4f4e..f3de053f780b 100644 --- a/crates/optimism/evm/src/lib.rs +++ b/crates/optimism/evm/src/lib.rs @@ -204,12 +204,13 @@ mod tests { use super::*; use alloy_genesis::Genesis; use alloy_primitives::{B256, U256}; - use reth_chainspec::{Chain, ChainSpec}; + use reth_chainspec::ChainSpec; use reth_evm::execute::ProviderError; + use reth_execution_types::{Chain, ExecutionOutcome}; use reth_optimism_chainspec::BASE_MAINNET; use reth_primitives::{ revm_primitives::{BlockEnv, CfgEnv, SpecId}, - Header, KECCAK_EMPTY, + Header, Receipt, Receipts, SealedBlockWithSenders, TxType, KECCAK_EMPTY, }; use reth_revm::{ db::{CacheDB, EmptyDBTyped}, @@ -237,7 +238,7 @@ mod tests { // Build the ChainSpec for Ethereum mainnet, activating London, Paris, and Shanghai // hardforks let chain_spec = ChainSpec::builder() - .chain(Chain::mainnet()) + .chain(0.into()) .genesis(Genesis::default()) .london_activated() .paris_activated() @@ -540,4 +541,79 @@ mod tests { // Optimism in handler assert_eq!(evm.handler.cfg, HandlerCfg { spec_id: SpecId::ECOTONE, is_optimism: true }); } + + #[test] + fn receipts_by_block_hash() { + // Create a default SealedBlockWithSenders object + let block = SealedBlockWithSenders::default(); + + // Define block hashes for block1 and block2 + let block1_hash = B256::new([0x01; 32]); + let block2_hash = B256::new([0x02; 32]); + + // Clone the default block into block1 and block2 + let mut block1 = block.clone(); + let mut block2 = block; + + // Set the hashes of block1 and block2 + block1.block.header.set_block_number(10); + block1.block.header.set_hash(block1_hash); + + block2.block.header.set_block_number(11); + block2.block.header.set_hash(block2_hash); + + // Create a random receipt object, receipt1 + let receipt1 = Receipt { + tx_type: TxType::Legacy, + cumulative_gas_used: 46913, + logs: vec![], + success: true, + deposit_nonce: Some(18), + deposit_receipt_version: Some(34), + }; + + // Create another random receipt object, receipt2 + let receipt2 = Receipt { + tx_type: TxType::Legacy, + cumulative_gas_used: 1325345, + logs: vec![], + success: true, + deposit_nonce: Some(18), + deposit_receipt_version: Some(34), + }; + + // Create a Receipts object with a vector of receipt vectors + let receipts = + Receipts { receipt_vec: vec![vec![Some(receipt1.clone())], vec![Some(receipt2)]] }; + + // Create an ExecutionOutcome object with the created bundle, receipts, an empty requests + // vector, and first_block set to 10 + let execution_outcome = ExecutionOutcome { + bundle: Default::default(), + receipts, + requests: vec![], + first_block: 10, + }; + + // Create a Chain object with a BTreeMap of blocks mapped to their block numbers, + // including block1_hash and block2_hash, and the execution_outcome + let chain = Chain::new([block1, block2], execution_outcome.clone(), None); + + // Assert that the proper receipt vector is returned for block1_hash + assert_eq!(chain.receipts_by_block_hash(block1_hash), Some(vec![&receipt1])); + + // Create an ExecutionOutcome object with a single receipt vector containing receipt1 + let execution_outcome1 = ExecutionOutcome { + bundle: Default::default(), + receipts: Receipts { receipt_vec: vec![vec![Some(receipt1)]] }, + requests: vec![], + first_block: 10, + }; + + // Assert that the execution outcome at the first block contains only the first receipt + assert_eq!(chain.execution_outcome_at_block(10), Some(execution_outcome1)); + + // Assert that the execution outcome at the tip block contains the whole execution outcome + assert_eq!(chain.execution_outcome_at_block(11), Some(execution_outcome)); + } } From 3f3a7ef0237282862157e33776563b6a371ac3cb Mon Sep 17 00:00:00 2001 From: nk_ysg Date: Wed, 16 Oct 2024 15:57:28 +0800 Subject: [PATCH 012/113] unify &Option to Option<&T> (#11755) --- crates/cli/commands/src/db/get.rs | 7 +++---- crates/rpc/rpc-builder/src/lib.rs | 4 ++-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/crates/cli/commands/src/db/get.rs b/crates/cli/commands/src/db/get.rs index 5b794feeada2..4006d1660aa3 100644 --- a/crates/cli/commands/src/db/get.rs +++ b/crates/cli/commands/src/db/get.rs @@ -132,9 +132,8 @@ pub(crate) fn table_key(key: &str) -> Result { } /// Get an instance of subkey for given dupsort table -fn table_subkey(subkey: &Option) -> Result { - serde_json::from_str::(&subkey.clone().unwrap_or_default()) - .map_err(|e| eyre::eyre!(e)) +fn table_subkey(subkey: Option<&str>) -> Result { + serde_json::from_str::(subkey.unwrap_or_default()).map_err(|e| eyre::eyre!(e)) } struct GetValueViewer<'a, N: NodeTypesWithDB> { @@ -175,7 +174,7 @@ impl TableViewer<()> for GetValueViewer<'_, N> { let key = table_key::(&self.key)?; // process dupsort table - let subkey = table_subkey::(&self.subkey)?; + let subkey = table_subkey::(self.subkey.as_deref())?; match self.tool.get_dup::(key, subkey)? { Some(content) => { diff --git a/crates/rpc/rpc-builder/src/lib.rs b/crates/rpc/rpc-builder/src/lib.rs index 6a1240b64f8e..cd93aeb620e3 100644 --- a/crates/rpc/rpc-builder/src/lib.rs +++ b/crates/rpc/rpc-builder/src/lib.rs @@ -676,8 +676,8 @@ impl RpcModuleConfigBuilder { } /// Get a reference to the eth namespace config, if any - pub const fn get_eth(&self) -> &Option { - &self.eth + pub const fn get_eth(&self) -> Option<&EthConfig> { + self.eth.as_ref() } /// Get a mutable reference to the eth namespace config, if any From b8147708ad6ad997c14c2a11b4ed5196bdd38e4b Mon Sep 17 00:00:00 2001 From: Kien Trinh <51135161+kien6034@users.noreply.github.com> Date: Wed, 16 Oct 2024 15:05:56 +0700 Subject: [PATCH 013/113] feat(txpool): function to return the next free nonce (#11744) Co-authored-by: Matthias Seitz --- crates/transaction-pool/src/identifier.rs | 5 +++ crates/transaction-pool/src/lib.rs | 8 ++++ crates/transaction-pool/src/noop.rs | 8 ++++ crates/transaction-pool/src/pool/mod.rs | 11 +++++ crates/transaction-pool/src/pool/txpool.rs | 51 ++++++++++++++++++++++ crates/transaction-pool/src/traits.rs | 15 +++++++ 6 files changed, 98 insertions(+) diff --git a/crates/transaction-pool/src/identifier.rs b/crates/transaction-pool/src/identifier.rs index 97d4bda8d03b..c50d39ae495a 100644 --- a/crates/transaction-pool/src/identifier.rs +++ b/crates/transaction-pool/src/identifier.rs @@ -59,6 +59,11 @@ impl SenderId { pub const fn start_bound(self) -> std::ops::Bound { std::ops::Bound::Included(TransactionId::new(self, 0)) } + + /// Converts the sender to a [`TransactionId`] with the given nonce. + pub const fn into_id(self, nonce: u64) -> TransactionId { + TransactionId::new(self, nonce) + } } impl From for SenderId { diff --git a/crates/transaction-pool/src/lib.rs b/crates/transaction-pool/src/lib.rs index 75465afac1a1..2cffcd33fa8b 100644 --- a/crates/transaction-pool/src/lib.rs +++ b/crates/transaction-pool/src/lib.rs @@ -510,6 +510,14 @@ where self.pool.get_highest_transaction_by_sender(sender) } + fn get_highest_consecutive_transaction_by_sender( + &self, + sender: Address, + on_chain_nonce: u64, + ) -> Option>> { + self.pool.get_highest_consecutive_transaction_by_sender(sender, on_chain_nonce) + } + fn get_transaction_by_sender_and_nonce( &self, sender: Address, diff --git a/crates/transaction-pool/src/noop.rs b/crates/transaction-pool/src/noop.rs index 681aa9896abb..4464ae1fc8a5 100644 --- a/crates/transaction-pool/src/noop.rs +++ b/crates/transaction-pool/src/noop.rs @@ -227,6 +227,14 @@ impl TransactionPool for NoopTransactionPool { None } + fn get_highest_consecutive_transaction_by_sender( + &self, + _sender: Address, + _on_chain_nonce: u64, + ) -> Option>> { + None + } + fn get_transaction_by_sender_and_nonce( &self, _sender: Address, diff --git a/crates/transaction-pool/src/pool/mod.rs b/crates/transaction-pool/src/pool/mod.rs index 44dd5a8d525f..64e6dad6793f 100644 --- a/crates/transaction-pool/src/pool/mod.rs +++ b/crates/transaction-pool/src/pool/mod.rs @@ -785,6 +785,17 @@ where self.get_pool_data().get_highest_transaction_by_sender(sender_id) } + /// Returns the transaction with the highest nonce that is executable given the on chain nonce. + pub(crate) fn get_highest_consecutive_transaction_by_sender( + &self, + sender: Address, + on_chain_nonce: u64, + ) -> Option>> { + let sender_id = self.get_sender_id(sender); + self.get_pool_data() + .get_highest_consecutive_transaction_by_sender(sender_id.into_id(on_chain_nonce)) + } + /// Returns all transactions that where submitted with the given [`TransactionOrigin`] pub(crate) fn get_transactions_by_origin( &self, diff --git a/crates/transaction-pool/src/pool/txpool.rs b/crates/transaction-pool/src/pool/txpool.rs index 7aaa77df49f4..c470faf3a1bf 100644 --- a/crates/transaction-pool/src/pool/txpool.rs +++ b/crates/transaction-pool/src/pool/txpool.rs @@ -108,6 +108,27 @@ impl TxPool { self.all().txs_iter(sender).last().map(|(_, tx)| Arc::clone(&tx.transaction)) } + /// Returns the transaction with the highest nonce that is executable given the on chain nonce. + /// + /// Note: The next pending pooled transaction must have the on chain nonce. + pub(crate) fn get_highest_consecutive_transaction_by_sender( + &self, + on_chain: TransactionId, + ) -> Option>> { + let mut last_consecutive_tx = None; + + let mut next_expected_nonce = on_chain.nonce; + for (id, tx) in self.all().descendant_txs_inclusive(&on_chain) { + if next_expected_nonce != id.nonce { + break + } + next_expected_nonce = id.next_nonce(); + last_consecutive_tx = Some(tx); + } + + last_consecutive_tx.map(|tx| Arc::clone(&tx.transaction)) + } + /// Returns access to the [`AllTransactions`] container. pub(crate) const fn all(&self) -> &AllTransactions { &self.all_transactions @@ -2755,6 +2776,36 @@ mod tests { assert_eq!(highest_tx.as_ref().transaction, tx1); } + #[test] + fn get_highest_consecutive_transaction_by_sender() { + // Set up a mock transaction factory and a new transaction pool. + let mut pool = TxPool::new(MockOrdering::default(), PoolConfig::default()); + let mut f = MockTransactionFactory::default(); + + // Create transactions with nonces 0, 1, 2, 4, 5. + let sender = Address::random(); + let txs: Vec<_> = vec![0, 1, 2, 4, 5]; + for nonce in txs { + let mut mock_tx = MockTransaction::eip1559(); + mock_tx.set_sender(sender); + mock_tx.set_nonce(nonce); + + let validated_tx = f.validated(mock_tx); + pool.add_transaction(validated_tx, U256::from(1000), 0).unwrap(); + } + + // Get last consecutive transaction + let sender_id = f.ids.sender_id(&sender).unwrap(); + let next_tx = pool.get_highest_consecutive_transaction_by_sender(sender_id.into_id(0)); + assert_eq!(next_tx.map(|tx| tx.nonce()), Some(2), "Expected nonce 2 for on-chain nonce 0"); + + let next_tx = pool.get_highest_consecutive_transaction_by_sender(sender_id.into_id(4)); + assert_eq!(next_tx.map(|tx| tx.nonce()), Some(5), "Expected nonce 5 for on-chain nonce 4"); + + let next_tx = pool.get_highest_consecutive_transaction_by_sender(sender_id.into_id(5)); + assert_eq!(next_tx.map(|tx| tx.nonce()), Some(5), "Expected nonce 5 for on-chain nonce 5"); + } + #[test] fn discard_nonce_too_low() { let mut f = MockTransactionFactory::default(); diff --git a/crates/transaction-pool/src/traits.rs b/crates/transaction-pool/src/traits.rs index 9a6eda03d9da..d19381935ec4 100644 --- a/crates/transaction-pool/src/traits.rs +++ b/crates/transaction-pool/src/traits.rs @@ -357,6 +357,21 @@ pub trait TransactionPool: Send + Sync + Clone { sender: Address, ) -> Option>>; + /// Returns the transaction with the highest nonce that is executable given the on chain nonce. + /// In other words the highest non nonce gapped transaction. + /// + /// Note: The next pending pooled transaction must have the on chain nonce. + /// + /// For example, for a given on chain nonce of `5`, the next transaction must have that nonce. + /// If the pool contains txs `[5,6,7]` this returns tx `7`. + /// If the pool contains txs `[6,7]` this returns `None` because the next valid nonce (5) is + /// missing, which means txs `[6,7]` are nonce gapped. + fn get_highest_consecutive_transaction_by_sender( + &self, + sender: Address, + on_chain_nonce: u64, + ) -> Option>>; + /// Returns a transaction sent by a given user and a nonce fn get_transaction_by_sender_and_nonce( &self, From 183cea4577714b451d9e3e1ef4a89016a79cf832 Mon Sep 17 00:00:00 2001 From: joshieDo <93316087+joshieDo@users.noreply.github.com> Date: Wed, 16 Oct 2024 17:13:30 +0900 Subject: [PATCH 014/113] chore(provider): move `state_provider_from_state` to `BlockState` impl (#11777) --- crates/chain-state/src/in_memory.rs | 24 ++++++++----------- .../src/providers/blockchain_provider.rs | 2 +- 2 files changed, 11 insertions(+), 15 deletions(-) diff --git a/crates/chain-state/src/in_memory.rs b/crates/chain-state/src/in_memory.rs index fb67608ebda7..f157da5ff450 100644 --- a/crates/chain-state/src/in_memory.rs +++ b/crates/chain-state/src/in_memory.rs @@ -504,20 +504,6 @@ impl CanonicalInMemoryState { self.inner.canon_state_notification_sender.send(event).ok(); } - /// Return state provider with reference to in-memory blocks that overlay database state. - /// - /// This merges the state of all blocks that are part of the chain that the requested block is - /// the head of. This includes all blocks that connect back to the canonical block on disk. - pub fn state_provider_from_state( - &self, - state: &BlockState, - historical: StateProviderBox, - ) -> MemoryOverlayStateProvider { - let in_memory = state.chain().into_iter().map(|block_state| block_state.block()).collect(); - - MemoryOverlayStateProvider::new(historical, in_memory) - } - /// Return state provider with reference to in-memory blocks that overlay database state. /// /// This merges the state of all blocks that are part of the chain that the requested block is @@ -723,6 +709,16 @@ impl BlockState { pub fn iter(self: Arc) -> impl Iterator> { std::iter::successors(Some(self), |state| state.parent.clone()) } + + /// Return state provider with reference to in-memory blocks that overlay database state. + /// + /// This merges the state of all blocks that are part of the chain that the this block is + /// the head of. This includes all blocks that connect back to the canonical block on disk. + pub fn state_provider(&self, historical: StateProviderBox) -> MemoryOverlayStateProvider { + let in_memory = self.chain().into_iter().map(|block_state| block_state.block()).collect(); + + MemoryOverlayStateProvider::new(historical, in_memory) + } } /// Represents an executed block stored in-memory. diff --git a/crates/storage/provider/src/providers/blockchain_provider.rs b/crates/storage/provider/src/providers/blockchain_provider.rs index 9b88cab136f5..3013be0603c8 100644 --- a/crates/storage/provider/src/providers/blockchain_provider.rs +++ b/crates/storage/provider/src/providers/blockchain_provider.rs @@ -402,7 +402,7 @@ impl BlockchainProvider2 { ) -> ProviderResult { let anchor_hash = state.anchor().hash; let latest_historical = self.database.history_by_block_hash(anchor_hash)?; - Ok(self.canonical_in_memory_state.state_provider_from_state(state, latest_historical)) + Ok(state.state_provider(latest_historical)) } /// Fetches data from either in-memory state or persistent storage for a range of transactions. From a6358d2e6fd90ecb7c225733fcca9a7587a60d58 Mon Sep 17 00:00:00 2001 From: joshieDo <93316087+joshieDo@users.noreply.github.com> Date: Wed, 16 Oct 2024 17:52:56 +0900 Subject: [PATCH 015/113] feat(provider): add `*StateProviderRef` creation methods to `DatabaseProvider` (#11776) --- .../src/providers/database/provider.rs | 74 +++++++++++++++++-- .../src/providers/state/historical.rs | 18 +++++ 2 files changed, 84 insertions(+), 8 deletions(-) diff --git a/crates/storage/provider/src/providers/database/provider.rs b/crates/storage/provider/src/providers/database/provider.rs index 3b074a5afffa..8140700fabac 100644 --- a/crates/storage/provider/src/providers/database/provider.rs +++ b/crates/storage/provider/src/providers/database/provider.rs @@ -9,12 +9,12 @@ use crate::{ AccountReader, BlockExecutionReader, BlockExecutionWriter, BlockHashReader, BlockNumReader, BlockReader, BlockWriter, BundleStateInit, ChainStateBlockReader, ChainStateBlockWriter, DBProvider, EvmEnvProvider, HashingWriter, HeaderProvider, HeaderSyncGap, - HeaderSyncGapProvider, HistoricalStateProvider, HistoryWriter, LatestStateProvider, - OriginalValuesKnown, ProviderError, PruneCheckpointReader, PruneCheckpointWriter, - RequestsProvider, RevertsInit, StageCheckpointReader, StateChangeWriter, StateProviderBox, - StateReader, StateWriter, StaticFileProviderFactory, StatsReader, StorageReader, - StorageTrieWriter, TransactionVariant, TransactionsProvider, TransactionsProviderExt, - TrieWriter, WithdrawalsProvider, + HeaderSyncGapProvider, HistoricalStateProvider, HistoricalStateProviderRef, HistoryWriter, + LatestStateProvider, LatestStateProviderRef, OriginalValuesKnown, ProviderError, + PruneCheckpointReader, PruneCheckpointWriter, RequestsProvider, RevertsInit, + StageCheckpointReader, StateChangeWriter, StateProviderBox, StateReader, StateWriter, + StaticFileProviderFactory, StatsReader, StorageReader, StorageTrieWriter, TransactionVariant, + TransactionsProvider, TransactionsProviderExt, TrieWriter, WithdrawalsProvider, }; use alloy_eips::BlockHashOrNumber; use alloy_primitives::{keccak256, Address, BlockHash, BlockNumber, TxHash, TxNumber, B256, U256}; @@ -47,7 +47,7 @@ use reth_primitives::{ }; use reth_prune_types::{PruneCheckpoint, PruneModes, PruneSegment}; use reth_stages_types::{StageCheckpoint, StageId}; -use reth_storage_api::{StorageChangeSetReader, TryIntoHistoricalStateProvider}; +use reth_storage_api::{StateProvider, StorageChangeSetReader, TryIntoHistoricalStateProvider}; use reth_storage_errors::provider::{ProviderResult, RootMismatch}; use reth_trie::{ prefix_set::{PrefixSet, PrefixSetMut, TriePrefixSets}, @@ -68,7 +68,7 @@ use std::{ time::{Duration, Instant}, }; use tokio::sync::watch; -use tracing::{debug, error, warn}; +use tracing::{debug, error, trace, warn}; /// A [`DatabaseProvider`] that holds a read-only database transaction. pub type DatabaseProviderRO = DatabaseProvider<::TX, Spec>; @@ -145,6 +145,64 @@ impl DatabaseProvider { } } +impl DatabaseProvider { + /// State provider for latest block + pub fn latest<'a>(&'a self) -> ProviderResult> { + trace!(target: "providers::db", "Returning latest state provider"); + Ok(Box::new(LatestStateProviderRef::new(&self.tx, self.static_file_provider.clone()))) + } + + /// Storage provider for state at that given block hash + pub fn history_by_block_hash<'a>( + &'a self, + block_hash: BlockHash, + ) -> ProviderResult> { + let mut block_number = + self.block_number(block_hash)?.ok_or(ProviderError::BlockHashNotFound(block_hash))?; + if block_number == self.best_block_number().unwrap_or_default() && + block_number == self.last_block_number().unwrap_or_default() + { + return Ok(Box::new(LatestStateProviderRef::new( + &self.tx, + self.static_file_provider.clone(), + ))) + } + + // +1 as the changeset that we want is the one that was applied after this block. + block_number += 1; + + let account_history_prune_checkpoint = + self.get_prune_checkpoint(PruneSegment::AccountHistory)?; + let storage_history_prune_checkpoint = + self.get_prune_checkpoint(PruneSegment::StorageHistory)?; + + let mut state_provider = HistoricalStateProviderRef::new( + &self.tx, + block_number, + self.static_file_provider.clone(), + ); + + // If we pruned account or storage history, we can't return state on every historical block. + // Instead, we should cap it at the latest prune checkpoint for corresponding prune segment. + if let Some(prune_checkpoint_block_number) = + account_history_prune_checkpoint.and_then(|checkpoint| checkpoint.block_number) + { + state_provider = state_provider.with_lowest_available_account_history_block_number( + prune_checkpoint_block_number + 1, + ); + } + if let Some(prune_checkpoint_block_number) = + storage_history_prune_checkpoint.and_then(|checkpoint| checkpoint.block_number) + { + state_provider = state_provider.with_lowest_available_storage_history_block_number( + prune_checkpoint_block_number + 1, + ); + } + + Ok(Box::new(state_provider)) + } +} + impl StaticFileProviderFactory for DatabaseProvider { /// Returns a static file provider fn static_file_provider(&self) -> StaticFileProvider { diff --git a/crates/storage/provider/src/providers/state/historical.rs b/crates/storage/provider/src/providers/state/historical.rs index 781a11f6deca..640041e0801f 100644 --- a/crates/storage/provider/src/providers/state/historical.rs +++ b/crates/storage/provider/src/providers/state/historical.rs @@ -227,6 +227,24 @@ impl<'b, TX: DbTx> HistoricalStateProviderRef<'b, TX> { Ok(HistoryInfo::NotYetWritten) } } + + /// Set the lowest block number at which the account history is available. + pub const fn with_lowest_available_account_history_block_number( + mut self, + block_number: BlockNumber, + ) -> Self { + self.lowest_available_blocks.account_history_block_number = Some(block_number); + self + } + + /// Set the lowest block number at which the storage history is available. + pub const fn with_lowest_available_storage_history_block_number( + mut self, + block_number: BlockNumber, + ) -> Self { + self.lowest_available_blocks.storage_history_block_number = Some(block_number); + self + } } impl AccountReader for HistoricalStateProviderRef<'_, TX> { From a14a9fd8b037ba839c94946fb7fd091bb1202eb5 Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Wed, 16 Oct 2024 10:59:20 +0200 Subject: [PATCH 016/113] chore: add chain_id shortcut (#11782) --- crates/chainspec/src/api.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/crates/chainspec/src/api.rs b/crates/chainspec/src/api.rs index 39a6716eedde..f7061ff18fe7 100644 --- a/crates/chainspec/src/api.rs +++ b/crates/chainspec/src/api.rs @@ -14,9 +14,14 @@ pub trait EthChainSpec: Send + Sync + Unpin + Debug { // todo: make chain spec type generic over hardfork //type Hardfork: Clone + Copy + 'static; - /// Chain id. + /// Returns the [`Chain`] object this spec targets. fn chain(&self) -> Chain; + /// Returns the chain id number + fn chain_id(&self) -> u64 { + self.chain().id() + } + /// Get the [`BaseFeeParams`] for the chain at the given block. fn base_fee_params_at_block(&self, block_number: u64) -> BaseFeeParams; From 323d8edfb924af27ce0644419371850d7ca96027 Mon Sep 17 00:00:00 2001 From: Federico Gimenez Date: Wed, 16 Oct 2024 11:02:23 +0200 Subject: [PATCH 017/113] feat: implement batch executor (#11753) --- Cargo.lock | 2 + crates/evm/Cargo.toml | 8 +- crates/evm/src/execute.rs | 171 +++++++++++++++++++++++++++-------- crates/evm/src/test_utils.rs | 45 ++++++++- 4 files changed, 184 insertions(+), 42 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b3cd1538507c..59f7ad35380b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7359,12 +7359,14 @@ dependencies = [ "metrics", "parking_lot 0.12.3", "reth-chainspec", + "reth-consensus", "reth-execution-errors", "reth-execution-types", "reth-metrics", "reth-primitives", "reth-primitives-traits", "reth-prune-types", + "reth-revm", "reth-storage-errors", "revm", "revm-primitives", diff --git a/crates/evm/Cargo.toml b/crates/evm/Cargo.toml index 20070d421e97..6081eae420cc 100644 --- a/crates/evm/Cargo.toml +++ b/crates/evm/Cargo.toml @@ -13,16 +13,18 @@ workspace = true [dependencies] # reth reth-chainspec.workspace = true +reth-consensus.workspace = true reth-execution-errors.workspace = true +reth-execution-types.workspace = true +reth-metrics = { workspace = true, optional = true } reth-primitives.workspace = true reth-primitives-traits.workspace = true -revm-primitives.workspace = true reth-prune-types.workspace = true -reth-metrics = { workspace = true, optional = true } +reth-revm.workspace = true reth-storage-errors.workspace = true -reth-execution-types.workspace = true revm.workspace = true +revm-primitives.workspace = true # alloy alloy-primitives.workspace = true diff --git a/crates/evm/src/execute.rs b/crates/evm/src/execute.rs index eb77d054bdcd..9413c709d1e7 100644 --- a/crates/evm/src/execute.rs +++ b/crates/evm/src/execute.rs @@ -7,15 +7,17 @@ pub use reth_execution_errors::{ pub use reth_execution_types::{BlockExecutionInput, BlockExecutionOutput, ExecutionOutcome}; pub use reth_storage_errors::provider::ProviderError; -use alloc::{boxed::Box, vec::Vec}; +use crate::system_calls::OnStateHook; +use alloc::{boxed::Box, sync::Arc, vec::Vec}; use alloy_primitives::BlockNumber; use core::{fmt::Display, marker::PhantomData}; +use reth_chainspec::ChainSpec; +use reth_consensus::ConsensusError; use reth_primitives::{BlockWithSenders, Receipt, Request}; use reth_prune_types::PruneModes; +use reth_revm::batch::BlockBatchRecord; use revm::{db::BundleState, State}; -use revm_primitives::db::Database; - -use crate::system_calls::OnStateHook; +use revm_primitives::{db::Database, U256}; /// A general purpose executor trait that executes an input (e.g. block) and produces an output /// (e.g. state changes and receipts). @@ -170,25 +172,49 @@ pub trait BlockExecutionStrategy { type Error: From + core::error::Error; /// Applies any necessary changes before executing the block's transactions. - fn apply_pre_execution_changes(&mut self) -> Result<(), Self::Error>; + fn apply_pre_execution_changes( + &mut self, + block: &BlockWithSenders, + total_difficulty: U256, + ) -> Result<(), Self::Error>; /// Executes all transactions in the block. fn execute_transactions( &mut self, block: &BlockWithSenders, + total_difficulty: U256, ) -> Result<(Vec, u64), Self::Error>; /// Applies any necessary changes after executing the block's transactions. - fn apply_post_execution_changes(&mut self) -> Result, Self::Error>; + fn apply_post_execution_changes( + &mut self, + block: &BlockWithSenders, + total_difficulty: U256, + receipts: &[Receipt], + ) -> Result, Self::Error>; /// Returns a reference to the current state. fn state_ref(&self) -> &State; + /// Returns a mutable reference to the current state. + fn state_mut(&mut self) -> &mut State; + /// Sets a hook to be called after each state change during execution. fn with_state_hook(&mut self, hook: Option>); /// Returns the final bundle state. - fn finish(&self) -> BundleState; + fn finish(&mut self) -> BundleState; + + /// Returns the strategy chain spec. + fn chain_spec(&self) -> Arc; + + /// Validate a block with regard to execution results. + fn validate_block_post_execution( + &self, + block: &BlockWithSenders, + receipts: &[Receipt], + requests: &[Request], + ) -> Result<(), ConsensusError>; } /// A strategy factory that can create block execution strategies. @@ -250,7 +276,8 @@ where DB: Database + Display>, { let strategy = self.strategy_factory.create_strategy(db); - GenericBatchExecutor::new(strategy) + let batch_record = BlockBatchRecord::default(); + GenericBatchExecutor::new(strategy, batch_record) } } @@ -261,7 +288,8 @@ pub struct GenericBlockExecutor where S: BlockExecutionStrategy, { - strategy: S, + /// Block execution strategy. + pub(crate) strategy: S, _phantom: PhantomData, } @@ -285,11 +313,12 @@ where type Error = S::Error; fn execute(mut self, input: Self::Input<'_>) -> Result { - let BlockExecutionInput { block, total_difficulty: _ } = input; + let BlockExecutionInput { block, total_difficulty } = input; - self.strategy.apply_pre_execution_changes()?; - let (receipts, gas_used) = self.strategy.execute_transactions(block)?; - let requests = self.strategy.apply_post_execution_changes()?; + self.strategy.apply_pre_execution_changes(block, total_difficulty)?; + let (receipts, gas_used) = self.strategy.execute_transactions(block, total_difficulty)?; + let requests = + self.strategy.apply_post_execution_changes(block, total_difficulty, &receipts)?; let state = self.strategy.finish(); Ok(BlockExecutionOutput { state, receipts, requests, gas_used }) @@ -303,11 +332,12 @@ where where F: FnMut(&State), { - let BlockExecutionInput { block, total_difficulty: _ } = input; + let BlockExecutionInput { block, total_difficulty } = input; - self.strategy.apply_pre_execution_changes()?; - let (receipts, gas_used) = self.strategy.execute_transactions(block)?; - let requests = self.strategy.apply_post_execution_changes()?; + self.strategy.apply_pre_execution_changes(block, total_difficulty)?; + let (receipts, gas_used) = self.strategy.execute_transactions(block, total_difficulty)?; + let requests = + self.strategy.apply_post_execution_changes(block, total_difficulty, &receipts)?; state(self.strategy.state_ref()); @@ -324,13 +354,14 @@ where where H: OnStateHook + 'static, { - let BlockExecutionInput { block, total_difficulty: _ } = input; + let BlockExecutionInput { block, total_difficulty } = input; self.strategy.with_state_hook(Some(Box::new(state_hook))); - self.strategy.apply_pre_execution_changes()?; - let (receipts, gas_used) = self.strategy.execute_transactions(block)?; - let requests = self.strategy.apply_post_execution_changes()?; + self.strategy.apply_pre_execution_changes(block, total_difficulty)?; + let (receipts, gas_used) = self.strategy.execute_transactions(block, total_difficulty)?; + let requests = + self.strategy.apply_post_execution_changes(block, total_difficulty, &receipts)?; let state = self.strategy.finish(); @@ -341,15 +372,24 @@ where /// A generic batch executor that uses a [`BlockExecutionStrategy`] to /// execute batches. #[allow(missing_debug_implementations)] -pub struct GenericBatchExecutor { - _strategy: S, +pub struct GenericBatchExecutor +where + S: BlockExecutionStrategy, +{ + /// Batch execution strategy. + pub(crate) strategy: S, + /// Keeps track of batch execution receipts and requests. + batch_record: BlockBatchRecord, _phantom: PhantomData, } -impl GenericBatchExecutor { +impl GenericBatchExecutor +where + S: BlockExecutionStrategy, +{ /// Creates a new `GenericBatchExecutor` with the given strategy. - pub const fn new(_strategy: S) -> Self { - Self { _strategy, _phantom: PhantomData } + pub const fn new(strategy: S, batch_record: BlockBatchRecord) -> Self { + Self { strategy, batch_record, _phantom: PhantomData } } } @@ -362,24 +402,52 @@ where type Output = ExecutionOutcome; type Error = BlockExecutionError; - fn execute_and_verify_one(&mut self, _input: Self::Input<'_>) -> Result<(), Self::Error> { - todo!() + fn execute_and_verify_one(&mut self, input: Self::Input<'_>) -> Result<(), Self::Error> { + let BlockExecutionInput { block, total_difficulty } = input; + + if self.batch_record.first_block().is_none() { + self.batch_record.set_first_block(block.number); + } + + self.strategy.apply_pre_execution_changes(block, total_difficulty)?; + let (receipts, _gas_used) = self.strategy.execute_transactions(block, total_difficulty)?; + let requests = + self.strategy.apply_post_execution_changes(block, total_difficulty, &receipts)?; + + self.strategy.validate_block_post_execution(block, &receipts, &requests)?; + + // prepare the state according to the prune mode + let retention = self.batch_record.bundle_retention(block.number); + self.strategy.state_mut().merge_transitions(retention); + + // store receipts in the set + self.batch_record.save_receipts(receipts)?; + + // store requests in the set + self.batch_record.save_requests(requests); + + Ok(()) } - fn finalize(self) -> Self::Output { - todo!() + fn finalize(mut self) -> Self::Output { + ExecutionOutcome::new( + self.strategy.state_mut().take_bundle(), + self.batch_record.take_receipts(), + self.batch_record.first_block().unwrap_or_default(), + self.batch_record.take_requests(), + ) } - fn set_tip(&mut self, _tip: BlockNumber) { - todo!() + fn set_tip(&mut self, tip: BlockNumber) { + self.batch_record.set_tip(tip); } - fn set_prune_modes(&mut self, _prune_modes: PruneModes) { - todo!() + fn set_prune_modes(&mut self, prune_modes: PruneModes) { + self.batch_record.set_prune_modes(prune_modes); } fn size_hint(&self) -> Option { - None + Some(self.strategy.state_ref().bundle_state.size_hint()) } } @@ -522,18 +590,28 @@ mod tests { impl BlockExecutionStrategy for TestExecutorStrategy { type Error = BlockExecutionError; - fn apply_pre_execution_changes(&mut self) -> Result<(), Self::Error> { + fn apply_pre_execution_changes( + &mut self, + _block: &BlockWithSenders, + _total_difficulty: U256, + ) -> Result<(), Self::Error> { Ok(()) } fn execute_transactions( &mut self, _block: &BlockWithSenders, + _total_difficulty: U256, ) -> Result<(Vec, u64), Self::Error> { Ok(self.execute_transactions_result.clone()) } - fn apply_post_execution_changes(&mut self) -> Result, Self::Error> { + fn apply_post_execution_changes( + &mut self, + _block: &BlockWithSenders, + _total_difficulty: U256, + _receipts: &[Receipt], + ) -> Result, Self::Error> { Ok(self.apply_post_execution_changes_result.clone()) } @@ -541,11 +619,28 @@ mod tests { &self.state } + fn state_mut(&mut self) -> &mut State { + &mut self.state + } + fn with_state_hook(&mut self, _hook: Option>) {} - fn finish(&self) -> BundleState { + fn finish(&mut self) -> BundleState { self.finish_result.clone() } + + fn chain_spec(&self) -> Arc { + MAINNET.clone() + } + + fn validate_block_post_execution( + &self, + _block: &BlockWithSenders, + _receipts: &[Receipt], + _requests: &[Request], + ) -> Result<(), ConsensusError> { + Ok(()) + } } #[derive(Clone)] diff --git a/crates/evm/src/test_utils.rs b/crates/evm/src/test_utils.rs index fc620bb42c33..a033c8023a96 100644 --- a/crates/evm/src/test_utils.rs +++ b/crates/evm/src/test_utils.rs @@ -2,7 +2,8 @@ use crate::{ execute::{ - BatchExecutor, BlockExecutionInput, BlockExecutionOutput, BlockExecutorProvider, Executor, + BatchExecutor, BlockExecutionInput, BlockExecutionOutput, BlockExecutionStrategy, + BlockExecutorProvider, Executor, GenericBatchExecutor, GenericBlockExecutor, }, system_calls::OnStateHook, }; @@ -110,3 +111,45 @@ impl BatchExecutor for MockExecutorProvider { None } } + +impl GenericBlockExecutor +where + S: BlockExecutionStrategy, +{ + /// Provides safe read access to the state + pub fn with_state(&self, f: F) -> R + where + F: FnOnce(&State) -> R, + { + f(self.strategy.state_ref()) + } + + /// Provides safe write access to the state + pub fn with_state_mut(&mut self, f: F) -> R + where + F: FnOnce(&mut State) -> R, + { + f(self.strategy.state_mut()) + } +} + +impl GenericBatchExecutor +where + S: BlockExecutionStrategy, +{ + /// Provides safe read access to the state + pub fn with_state(&self, f: F) -> R + where + F: FnOnce(&State) -> R, + { + f(self.strategy.state_ref()) + } + + /// Provides safe write access to the state + pub fn with_state_mut(&mut self, f: F) -> R + where + F: FnOnce(&mut State) -> R, + { + f(self.strategy.state_mut()) + } +} From 0f903b1e204ead35616bba24447a09b316763793 Mon Sep 17 00:00:00 2001 From: Federico Gimenez Date: Wed, 16 Oct 2024 11:40:33 +0200 Subject: [PATCH 018/113] feat: add EthExecutionStrategy (#11584) --- Cargo.lock | 1 + crates/ethereum/evm/Cargo.toml | 2 + crates/ethereum/evm/src/lib.rs | 1 + crates/ethereum/evm/src/strategy.rs | 1179 +++++++++++++++++++++++++++ crates/evm/src/execute.rs | 10 +- 5 files changed, 1184 insertions(+), 9 deletions(-) create mode 100644 crates/ethereum/evm/src/strategy.rs diff --git a/Cargo.lock b/Cargo.lock index 59f7ad35380b..eb0bb2a3d023 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7382,6 +7382,7 @@ dependencies = [ "alloy-primitives", "alloy-sol-types", "reth-chainspec", + "reth-consensus", "reth-ethereum-consensus", "reth-ethereum-forks", "reth-evm", diff --git a/crates/ethereum/evm/Cargo.toml b/crates/ethereum/evm/Cargo.toml index 61ce0a23b904..a19cbc018c72 100644 --- a/crates/ethereum/evm/Cargo.toml +++ b/crates/ethereum/evm/Cargo.toml @@ -20,6 +20,7 @@ reth-revm.workspace = true reth-ethereum-consensus.workspace = true reth-prune-types.workspace = true reth-execution-types.workspace = true +reth-consensus.workspace = true # Ethereum revm-primitives.workspace = true @@ -31,6 +32,7 @@ alloy-sol-types.workspace = true [dev-dependencies] reth-testing-utils.workspace = true +reth-evm = { workspace = true, features = ["test-utils"] } reth-revm = { workspace = true, features = ["test-utils"] } reth-primitives = { workspace = true, features = ["secp256k1"] } secp256k1.workspace = true diff --git a/crates/ethereum/evm/src/lib.rs b/crates/ethereum/evm/src/lib.rs index cede8008b3cf..ed18a24fb191 100644 --- a/crates/ethereum/evm/src/lib.rs +++ b/crates/ethereum/evm/src/lib.rs @@ -33,6 +33,7 @@ use reth_ethereum_forks::EthereumHardfork; use reth_primitives::constants::EIP1559_INITIAL_BASE_FEE; pub mod execute; +pub mod strategy; /// Ethereum DAO hardfork state change data. pub mod dao_fork; diff --git a/crates/ethereum/evm/src/strategy.rs b/crates/ethereum/evm/src/strategy.rs new file mode 100644 index 000000000000..52f58a8b0a80 --- /dev/null +++ b/crates/ethereum/evm/src/strategy.rs @@ -0,0 +1,1179 @@ +//! Ethereum block execution strategy, + +use crate::{ + dao_fork::{DAO_HARDFORK_BENEFICIARY, DAO_HARDKFORK_ACCOUNTS}, + EthEvmConfig, +}; +use alloc::sync::Arc; +use core::fmt::Display; +use reth_chainspec::{ChainSpec, EthereumHardfork, EthereumHardforks, MAINNET}; +use reth_consensus::ConsensusError; +use reth_ethereum_consensus::validate_block_post_execution; +use reth_evm::{ + execute::{ + BlockExecutionError, BlockExecutionStrategy, BlockExecutionStrategyFactory, + BlockValidationError, ProviderError, + }, + system_calls::{OnStateHook, SystemCaller}, + ConfigureEvm, ConfigureEvmEnv, +}; +use reth_primitives::{BlockWithSenders, Header, Receipt, Request}; +use reth_revm::{ + db::{states::bundle_state::BundleRetention, BundleState}, + state_change::post_block_balance_increments, + Database, DatabaseCommit, State, +}; +use revm_primitives::{BlockEnv, CfgEnvWithHandlerCfg, EnvWithHandlerCfg, ResultAndState, U256}; + +/// Factory for [`EthExecutionStrategy`]. +#[derive(Debug, Clone)] +pub struct EthExecutionStrategyFactory { + /// The chainspec + chain_spec: Arc, + /// How to create an EVM. + evm_config: EvmConfig, +} + +impl EthExecutionStrategyFactory { + /// Creates a new default ethereum executor strategy factory. + pub fn ethereum(chain_spec: Arc) -> Self { + Self::new(chain_spec.clone(), EthEvmConfig::new(chain_spec)) + } + + /// Returns a new factory for the mainnet. + pub fn mainnet() -> Self { + Self::ethereum(MAINNET.clone()) + } +} + +impl EthExecutionStrategyFactory { + /// Creates a new executor strategy factory. + pub const fn new(chain_spec: Arc, evm_config: EvmConfig) -> Self { + Self { chain_spec, evm_config } + } +} + +impl BlockExecutionStrategyFactory for EthExecutionStrategyFactory { + type Strategy + Display>> = EthExecutionStrategy; + + fn create_strategy(&self, db: DB) -> Self::Strategy + where + DB: Database + Display>, + { + let state = + State::builder().with_database(db).with_bundle_update().without_state_clear().build(); + EthExecutionStrategy::new(state, self.chain_spec.clone(), self.evm_config.clone()) + } +} + +/// Block execution strategy for Ethereum. +#[allow(missing_debug_implementations)] +pub struct EthExecutionStrategy { + /// The chainspec + chain_spec: Arc, + /// How to create an EVM. + evm_config: EvmConfig, + /// Current state for block execution. + state: State, + /// Utility to call system smart contracts. + system_caller: SystemCaller, +} + +impl EthExecutionStrategy { + /// Creates a new [`EthExecutionStrategy`] + pub fn new(state: State, chain_spec: Arc, evm_config: EthEvmConfig) -> Self { + let system_caller = SystemCaller::new(evm_config.clone(), (*chain_spec).clone()); + Self { state, chain_spec, evm_config, system_caller } + } +} + +impl EthExecutionStrategy +where + DB: Database + Display>, + EvmConfig: ConfigureEvm
, +{ + /// Configures a new evm configuration and block environment for the given block. + /// + /// # Caution + /// + /// This does not initialize the tx environment. + fn evm_env_for_block(&self, header: &Header, total_difficulty: U256) -> EnvWithHandlerCfg { + let mut cfg = CfgEnvWithHandlerCfg::new(Default::default(), Default::default()); + let mut block_env = BlockEnv::default(); + self.evm_config.fill_cfg_and_block_env(&mut cfg, &mut block_env, header, total_difficulty); + + EnvWithHandlerCfg::new_with_cfg_env(cfg, block_env, Default::default()) + } +} + +impl BlockExecutionStrategy for EthExecutionStrategy +where + DB: Database + Display>, +{ + type Error = BlockExecutionError; + + fn apply_pre_execution_changes( + &mut self, + block: &BlockWithSenders, + total_difficulty: U256, + ) -> Result<(), Self::Error> { + // Set state clear flag if the block is after the Spurious Dragon hardfork. + let state_clear_flag = + (*self.chain_spec).is_spurious_dragon_active_at_block(block.header.number); + self.state.set_state_clear_flag(state_clear_flag); + + let env = self.evm_env_for_block(&block.header, total_difficulty); + let mut evm = self.evm_config.evm_with_env(&mut self.state, env); + + self.system_caller.apply_pre_execution_changes(block, &mut evm)?; + + Ok(()) + } + + fn execute_transactions( + &mut self, + block: &BlockWithSenders, + total_difficulty: U256, + ) -> Result<(Vec, u64), Self::Error> { + let env = self.evm_env_for_block(&block.header, total_difficulty); + let mut evm = self.evm_config.evm_with_env(&mut self.state, env); + + let mut cumulative_gas_used = 0; + let mut receipts = Vec::with_capacity(block.body.transactions.len()); + for (sender, transaction) in block.transactions_with_sender() { + // The sum of the transaction’s gas limit, Tg, and the gas utilized in this block prior, + // must be no greater than the block’s gasLimit. + let block_available_gas = block.header.gas_limit - cumulative_gas_used; + if transaction.gas_limit() > block_available_gas { + return Err(BlockValidationError::TransactionGasLimitMoreThanAvailableBlockGas { + transaction_gas_limit: transaction.gas_limit(), + block_available_gas, + } + .into()) + } + + self.evm_config.fill_tx_env(evm.tx_mut(), transaction, *sender); + + // Execute transaction. + let result_and_state = evm.transact().map_err(move |err| { + let new_err = err.map_db_err(|e| e.into()); + // Ensure hash is calculated for error log, if not already done + BlockValidationError::EVM { + hash: transaction.recalculate_hash(), + error: Box::new(new_err), + } + })?; + self.system_caller.on_state(&result_and_state); + let ResultAndState { result, state } = result_and_state; + evm.db_mut().commit(state); + + // append gas used + cumulative_gas_used += result.gas_used(); + + // Push transaction changeset and calculate header bloom filter for receipt. + receipts.push( + #[allow(clippy::needless_update)] // side-effect of optimism fields + Receipt { + tx_type: transaction.tx_type(), + // Success flag was added in `EIP-658: Embedding transaction status code in + // receipts`. + success: result.is_success(), + cumulative_gas_used, + // convert to reth log + logs: result.into_logs(), + ..Default::default() + }, + ); + } + Ok((receipts, cumulative_gas_used)) + } + + fn apply_post_execution_changes( + &mut self, + block: &BlockWithSenders, + total_difficulty: U256, + receipts: &[Receipt], + ) -> Result, Self::Error> { + let env = self.evm_env_for_block(&block.header, total_difficulty); + let mut evm = self.evm_config.evm_with_env(&mut self.state, env); + + let requests = if self.chain_spec.is_prague_active_at_timestamp(block.timestamp) { + // Collect all EIP-6110 deposits + let deposit_requests = + crate::eip6110::parse_deposits_from_receipts(&self.chain_spec, receipts)?; + + let post_execution_requests = + self.system_caller.apply_post_execution_changes(&mut evm)?; + + [deposit_requests, post_execution_requests].concat() + } else { + vec![] + }; + drop(evm); + + let mut balance_increments = + post_block_balance_increments(&self.chain_spec, block, total_difficulty); + + // Irregular state change at Ethereum DAO hardfork + if self.chain_spec.fork(EthereumHardfork::Dao).transitions_at_block(block.number) { + // drain balances from hardcoded addresses. + let drained_balance: u128 = self + .state + .drain_balances(DAO_HARDKFORK_ACCOUNTS) + .map_err(|_| BlockValidationError::IncrementBalanceFailed)? + .into_iter() + .sum(); + + // return balance to DAO beneficiary. + *balance_increments.entry(DAO_HARDFORK_BENEFICIARY).or_default() += drained_balance; + } + // increment balances + self.state + .increment_balances(balance_increments) + .map_err(|_| BlockValidationError::IncrementBalanceFailed)?; + + Ok(requests) + } + + fn state_ref(&self) -> &State { + &self.state + } + + fn state_mut(&mut self) -> &mut State { + &mut self.state + } + + fn with_state_hook(&mut self, hook: Option>) { + self.system_caller.with_state_hook(hook); + } + + fn finish(&mut self) -> BundleState { + self.state.merge_transitions(BundleRetention::Reverts); + self.state.take_bundle() + } + + fn validate_block_post_execution( + &self, + block: &BlockWithSenders, + receipts: &[Receipt], + requests: &[Request], + ) -> Result<(), ConsensusError> { + validate_block_post_execution(block, &self.chain_spec.clone(), receipts, requests) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use alloy_consensus::{TxLegacy, EMPTY_ROOT_HASH}; + use alloy_eips::{ + eip2935::{HISTORY_STORAGE_ADDRESS, HISTORY_STORAGE_CODE}, + eip4788::{BEACON_ROOTS_ADDRESS, BEACON_ROOTS_CODE, SYSTEM_ADDRESS}, + eip7002::{WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS, WITHDRAWAL_REQUEST_PREDEPLOY_CODE}, + }; + use alloy_primitives::{b256, fixed_bytes, keccak256, Bytes, TxKind, B256}; + use reth_chainspec::{ChainSpecBuilder, ForkCondition}; + use reth_evm::execute::{ + BatchExecutor, BlockExecutorProvider, Executor, GenericBlockExecutorProvider, + }; + use reth_execution_types::BlockExecutionOutput; + use reth_primitives::{ + constants::ETH_TO_WEI, public_key_to_address, Account, Block, BlockBody, Transaction, + }; + use reth_revm::{ + database::StateProviderDatabase, test_utils::StateProviderTest, TransitionState, + }; + use reth_testing_utils::generators::{self, sign_tx_with_key_pair}; + use revm_primitives::BLOCKHASH_SERVE_WINDOW; + use secp256k1::{Keypair, Secp256k1}; + use std::collections::HashMap; + + fn create_state_provider_with_beacon_root_contract() -> StateProviderTest { + let mut db = StateProviderTest::default(); + + let beacon_root_contract_account = Account { + balance: U256::ZERO, + bytecode_hash: Some(keccak256(BEACON_ROOTS_CODE.clone())), + nonce: 1, + }; + + db.insert_account( + BEACON_ROOTS_ADDRESS, + beacon_root_contract_account, + Some(BEACON_ROOTS_CODE.clone()), + HashMap::default(), + ); + + db + } + + fn create_state_provider_with_withdrawal_requests_contract() -> StateProviderTest { + let mut db = StateProviderTest::default(); + + let withdrawal_requests_contract_account = Account { + nonce: 1, + balance: U256::ZERO, + bytecode_hash: Some(keccak256(WITHDRAWAL_REQUEST_PREDEPLOY_CODE.clone())), + }; + + db.insert_account( + WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS, + withdrawal_requests_contract_account, + Some(WITHDRAWAL_REQUEST_PREDEPLOY_CODE.clone()), + HashMap::default(), + ); + + db + } + + fn executor_provider( + chain_spec: Arc, + ) -> GenericBlockExecutorProvider { + let strategy_factory = + EthExecutionStrategyFactory::new(chain_spec.clone(), EthEvmConfig::new(chain_spec)); + + GenericBlockExecutorProvider::new(strategy_factory) + } + + #[test] + fn eip_4788_non_genesis_call() { + let mut header = + Header { timestamp: 1, number: 1, excess_blob_gas: Some(0), ..Header::default() }; + + let db = create_state_provider_with_beacon_root_contract(); + + let chain_spec = Arc::new( + ChainSpecBuilder::from(&*MAINNET) + .shanghai_activated() + .with_fork(EthereumHardfork::Cancun, ForkCondition::Timestamp(1)) + .build(), + ); + + let provider = executor_provider(chain_spec); + + let mut executor = provider.batch_executor(StateProviderDatabase::new(&db)); + + // attempt to execute a block without parent beacon block root, expect err + let err = executor + .execute_and_verify_one( + ( + &BlockWithSenders { + block: Block { + header: header.clone(), + body: BlockBody { + transactions: vec![], + ommers: vec![], + withdrawals: None, + requests: None, + }, + }, + senders: vec![], + }, + U256::ZERO, + ) + .into(), + ) + .expect_err( + "Executing cancun block without parent beacon block root field should fail", + ); + + assert_eq!( + err.as_validation().unwrap().clone(), + BlockValidationError::MissingParentBeaconBlockRoot + ); + + // fix header, set a gas limit + header.parent_beacon_block_root = Some(B256::with_last_byte(0x69)); + + // Now execute a block with the fixed header, ensure that it does not fail + executor + .execute_and_verify_one( + ( + &BlockWithSenders { + block: Block { + header: header.clone(), + body: BlockBody { + transactions: vec![], + ommers: vec![], + withdrawals: None, + requests: None, + }, + }, + senders: vec![], + }, + U256::ZERO, + ) + .into(), + ) + .unwrap(); + + // check the actual storage of the contract - it should be: + // * The storage value at header.timestamp % HISTORY_BUFFER_LENGTH should be + // header.timestamp + // * The storage value at header.timestamp % HISTORY_BUFFER_LENGTH + HISTORY_BUFFER_LENGTH + // // should be parent_beacon_block_root + let history_buffer_length = 8191u64; + let timestamp_index = header.timestamp % history_buffer_length; + let parent_beacon_block_root_index = + timestamp_index % history_buffer_length + history_buffer_length; + + let timestamp_storage = executor.with_state_mut(|state| { + state.storage(BEACON_ROOTS_ADDRESS, U256::from(timestamp_index)).unwrap() + }); + assert_eq!(timestamp_storage, U256::from(header.timestamp)); + + // get parent beacon block root storage and compare + let parent_beacon_block_root_storage = executor.with_state_mut(|state| { + state + .storage(BEACON_ROOTS_ADDRESS, U256::from(parent_beacon_block_root_index)) + .expect("storage value should exist") + }); + assert_eq!(parent_beacon_block_root_storage, U256::from(0x69)); + } + + #[test] + fn eip_4788_no_code_cancun() { + // This test ensures that we "silently fail" when cancun is active and there is no code at + // // BEACON_ROOTS_ADDRESS + let header = Header { + timestamp: 1, + number: 1, + parent_beacon_block_root: Some(B256::with_last_byte(0x69)), + excess_blob_gas: Some(0), + ..Header::default() + }; + + let db = StateProviderTest::default(); + + // DON'T deploy the contract at genesis + let chain_spec = Arc::new( + ChainSpecBuilder::from(&*MAINNET) + .shanghai_activated() + .with_fork(EthereumHardfork::Cancun, ForkCondition::Timestamp(1)) + .build(), + ); + + let provider = executor_provider(chain_spec); + + // attempt to execute an empty block with parent beacon block root, this should not fail + provider + .batch_executor(StateProviderDatabase::new(&db)) + .execute_and_verify_one( + ( + &BlockWithSenders { + block: Block { + header, + body: BlockBody { + transactions: vec![], + ommers: vec![], + withdrawals: None, + requests: None, + }, + }, + senders: vec![], + }, + U256::ZERO, + ) + .into(), + ) + .expect( + "Executing a block with no transactions while cancun is active should not fail", + ); + } + + #[test] + fn eip_4788_empty_account_call() { + // This test ensures that we do not increment the nonce of an empty SYSTEM_ADDRESS account + // // during the pre-block call + + let mut db = create_state_provider_with_beacon_root_contract(); + + // insert an empty SYSTEM_ADDRESS + db.insert_account(SYSTEM_ADDRESS, Account::default(), None, HashMap::default()); + + let chain_spec = Arc::new( + ChainSpecBuilder::from(&*MAINNET) + .shanghai_activated() + .with_fork(EthereumHardfork::Cancun, ForkCondition::Timestamp(1)) + .build(), + ); + + let provider = executor_provider(chain_spec); + + // construct the header for block one + let header = Header { + timestamp: 1, + number: 1, + parent_beacon_block_root: Some(B256::with_last_byte(0x69)), + excess_blob_gas: Some(0), + ..Header::default() + }; + + let mut executor = provider.batch_executor(StateProviderDatabase::new(&db)); + + // attempt to execute an empty block with parent beacon block root, this should not fail + executor + .execute_and_verify_one( + ( + &BlockWithSenders { + block: Block { + header, + body: BlockBody { + transactions: vec![], + ommers: vec![], + withdrawals: None, + requests: None, + }, + }, + senders: vec![], + }, + U256::ZERO, + ) + .into(), + ) + .expect( + "Executing a block with no transactions while cancun is active should not fail", + ); + + // ensure that the nonce of the system address account has not changed + let nonce = + executor.with_state_mut(|state| state.basic(SYSTEM_ADDRESS).unwrap().unwrap().nonce); + assert_eq!(nonce, 0); + } + + #[test] + fn eip_4788_genesis_call() { + let db = create_state_provider_with_beacon_root_contract(); + + // activate cancun at genesis + let chain_spec = Arc::new( + ChainSpecBuilder::from(&*MAINNET) + .shanghai_activated() + .with_fork(EthereumHardfork::Cancun, ForkCondition::Timestamp(0)) + .build(), + ); + + let mut header = chain_spec.genesis_header().clone(); + let provider = executor_provider(chain_spec); + let mut executor = provider.batch_executor(StateProviderDatabase::new(&db)); + + // attempt to execute the genesis block with non-zero parent beacon block root, expect err + header.parent_beacon_block_root = Some(B256::with_last_byte(0x69)); + let _err = executor + .execute_and_verify_one( + ( + &BlockWithSenders { + block: Block { header: header.clone(), body: Default::default() }, + senders: vec![], + }, + U256::ZERO, + ) + .into(), + ) + .expect_err( + "Executing genesis cancun block with non-zero parent beacon block root field + should fail", + ); + + // fix header + header.parent_beacon_block_root = Some(B256::ZERO); + + // now try to process the genesis block again, this time ensuring that a system contract + // call does not occur + executor + .execute_and_verify_one( + ( + &BlockWithSenders { + block: Block { header, body: Default::default() }, + senders: vec![], + }, + U256::ZERO, + ) + .into(), + ) + .unwrap(); + + // there is no system contract call so there should be NO STORAGE CHANGES + // this means we'll check the transition state + let transition_state = executor.with_state_mut(|state| { + state + .transition_state + .take() + .expect("the evm should be initialized with bundle updates") + }); + + // assert that it is the default (empty) transition state + assert_eq!(transition_state, TransitionState::default()); + } + + #[test] + fn eip_4788_high_base_fee() { + // This test ensures that if we have a base fee, then we don't return an error when the + // system contract is called, due to the gas price being less than the base fee. + let header = Header { + timestamp: 1, + number: 1, + parent_beacon_block_root: Some(B256::with_last_byte(0x69)), + base_fee_per_gas: Some(u64::MAX), + excess_blob_gas: Some(0), + ..Header::default() + }; + + let db = create_state_provider_with_beacon_root_contract(); + + let chain_spec = Arc::new( + ChainSpecBuilder::from(&*MAINNET) + .shanghai_activated() + .with_fork(EthereumHardfork::Cancun, ForkCondition::Timestamp(1)) + .build(), + ); + + let provider = executor_provider(chain_spec); + + // execute header + let mut executor = provider.batch_executor(StateProviderDatabase::new(&db)); + + // Now execute a block with the fixed header, ensure that it does not fail + executor + .execute_and_verify_one( + ( + &BlockWithSenders { + block: Block { header: header.clone(), body: Default::default() }, + senders: vec![], + }, + U256::ZERO, + ) + .into(), + ) + .unwrap(); + + // check the actual storage of the contract - it should be: + // * The storage value at header.timestamp % HISTORY_BUFFER_LENGTH should be + // header.timestamp + // * The storage value at header.timestamp % HISTORY_BUFFER_LENGTH + HISTORY_BUFFER_LENGTH + // // should be parent_beacon_block_root + let history_buffer_length = 8191u64; + let timestamp_index = header.timestamp % history_buffer_length; + let parent_beacon_block_root_index = + timestamp_index % history_buffer_length + history_buffer_length; + + // get timestamp storage and compare + let timestamp_storage = executor.with_state_mut(|state| { + state.storage(BEACON_ROOTS_ADDRESS, U256::from(timestamp_index)).unwrap() + }); + assert_eq!(timestamp_storage, U256::from(header.timestamp)); + + // get parent beacon block root storage and compare + let parent_beacon_block_root_storage = executor.with_state_mut(|state| { + state.storage(BEACON_ROOTS_ADDRESS, U256::from(parent_beacon_block_root_index)).unwrap() + }); + assert_eq!(parent_beacon_block_root_storage, U256::from(0x69)); + } + + /// Create a state provider with blockhashes and the EIP-2935 system contract. + fn create_state_provider_with_block_hashes(latest_block: u64) -> StateProviderTest { + let mut db = StateProviderTest::default(); + for block_number in 0..=latest_block { + db.insert_block_hash(block_number, keccak256(block_number.to_string())); + } + + let blockhashes_contract_account = Account { + balance: U256::ZERO, + bytecode_hash: Some(keccak256(HISTORY_STORAGE_CODE.clone())), + nonce: 1, + }; + + db.insert_account( + HISTORY_STORAGE_ADDRESS, + blockhashes_contract_account, + Some(HISTORY_STORAGE_CODE.clone()), + HashMap::default(), + ); + + db + } + #[test] + fn eip_2935_pre_fork() { + let db = create_state_provider_with_block_hashes(1); + + let chain_spec = Arc::new( + ChainSpecBuilder::from(&*MAINNET) + .shanghai_activated() + .with_fork(EthereumHardfork::Prague, ForkCondition::Never) + .build(), + ); + + let provider = executor_provider(chain_spec); + let mut executor = provider.batch_executor(StateProviderDatabase::new(&db)); + + // construct the header for block one + let header = Header { timestamp: 1, number: 1, ..Header::default() }; + + // attempt to execute an empty block, this should not fail + executor + .execute_and_verify_one( + ( + &BlockWithSenders { + block: Block { header, body: Default::default() }, + senders: vec![], + }, + U256::ZERO, + ) + .into(), + ) + .expect( + "Executing a block with no transactions while Prague is active should not fail", + ); + + // ensure that the block hash was *not* written to storage, since this is before the fork + // was activated + // + // we load the account first, because revm expects it to be + // loaded + executor.with_state_mut(|state| state.basic(HISTORY_STORAGE_ADDRESS).unwrap()); + assert!(executor.with_state_mut(|state| state + .storage(HISTORY_STORAGE_ADDRESS, U256::ZERO) + .unwrap() + .is_zero())); + } + + #[test] + fn eip_2935_fork_activation_genesis() { + let db = create_state_provider_with_block_hashes(0); + + let chain_spec = Arc::new( + ChainSpecBuilder::from(&*MAINNET) + .shanghai_activated() + .with_fork(EthereumHardfork::Prague, ForkCondition::Timestamp(0)) + .build(), + ); + + let header = chain_spec.genesis_header().clone(); + let provider = executor_provider(chain_spec); + let mut executor = provider.batch_executor(StateProviderDatabase::new(&db)); + + // attempt to execute genesis block, this should not fail + executor + .execute_and_verify_one( + ( + &BlockWithSenders { + block: Block { header, body: Default::default() }, + senders: vec![], + }, + U256::ZERO, + ) + .into(), + ) + .expect( + "Executing a block with no transactions while Prague is active should not fail", + ); + + // ensure that the block hash was *not* written to storage, since there are no blocks + // preceding genesis + // + // we load the account first, because revm expects it to be + // loaded + executor.with_state_mut(|state| state.basic(HISTORY_STORAGE_ADDRESS).unwrap()); + assert!(executor.with_state_mut(|state| state + .storage(HISTORY_STORAGE_ADDRESS, U256::ZERO) + .unwrap() + .is_zero())); + } + + #[test] + fn eip_2935_fork_activation_within_window_bounds() { + let fork_activation_block = (BLOCKHASH_SERVE_WINDOW - 10) as u64; + let db = create_state_provider_with_block_hashes(fork_activation_block); + + let chain_spec = Arc::new( + ChainSpecBuilder::from(&*MAINNET) + .shanghai_activated() + .with_fork(EthereumHardfork::Prague, ForkCondition::Timestamp(1)) + .build(), + ); + + let header = Header { + parent_hash: B256::random(), + timestamp: 1, + number: fork_activation_block, + requests_root: Some(EMPTY_ROOT_HASH), + ..Header::default() + }; + let provider = executor_provider(chain_spec); + let mut executor = provider.batch_executor(StateProviderDatabase::new(&db)); + + // attempt to execute the fork activation block, this should not fail + executor + .execute_and_verify_one( + ( + &BlockWithSenders { + block: Block { header, body: Default::default() }, + senders: vec![], + }, + U256::ZERO, + ) + .into(), + ) + .expect( + "Executing a block with no transactions while Prague is active should not fail", + ); + + // the hash for the ancestor of the fork activation block should be present + assert!(executor + .with_state_mut(|state| state.basic(HISTORY_STORAGE_ADDRESS).unwrap().is_some())); + assert_ne!( + executor.with_state_mut(|state| state + .storage(HISTORY_STORAGE_ADDRESS, U256::from(fork_activation_block - 1)) + .unwrap()), + U256::ZERO + ); + + // the hash of the block itself should not be in storage + assert!(executor.with_state_mut(|state| state + .storage(HISTORY_STORAGE_ADDRESS, U256::from(fork_activation_block)) + .unwrap() + .is_zero())); + } + + #[test] + fn eip_2935_fork_activation_outside_window_bounds() { + let fork_activation_block = (BLOCKHASH_SERVE_WINDOW + 256) as u64; + let db = create_state_provider_with_block_hashes(fork_activation_block); + + let chain_spec = Arc::new( + ChainSpecBuilder::from(&*MAINNET) + .shanghai_activated() + .with_fork(EthereumHardfork::Prague, ForkCondition::Timestamp(1)) + .build(), + ); + + let provider = executor_provider(chain_spec); + let mut executor = provider.batch_executor(StateProviderDatabase::new(&db)); + + let header = Header { + parent_hash: B256::random(), + timestamp: 1, + number: fork_activation_block, + requests_root: Some(EMPTY_ROOT_HASH), + ..Header::default() + }; + + // attempt to execute the fork activation block, this should not fail + executor + .execute_and_verify_one( + ( + &BlockWithSenders { + block: Block { header, body: Default::default() }, + senders: vec![], + }, + U256::ZERO, + ) + .into(), + ) + .expect( + "Executing a block with no transactions while Prague is active should not fail", + ); + + // the hash for the ancestor of the fork activation block should be present + assert!(executor + .with_state_mut(|state| state.basic(HISTORY_STORAGE_ADDRESS).unwrap().is_some())); + assert_ne!( + executor.with_state_mut(|state| state + .storage( + HISTORY_STORAGE_ADDRESS, + U256::from(fork_activation_block % BLOCKHASH_SERVE_WINDOW as u64 - 1) + ) + .unwrap()), + U256::ZERO + ); + } + + #[test] + fn eip_2935_state_transition_inside_fork() { + let db = create_state_provider_with_block_hashes(2); + + let chain_spec = Arc::new( + ChainSpecBuilder::from(&*MAINNET) + .shanghai_activated() + .with_fork(EthereumHardfork::Prague, ForkCondition::Timestamp(0)) + .build(), + ); + + let mut header = chain_spec.genesis_header().clone(); + header.requests_root = Some(EMPTY_ROOT_HASH); + let header_hash = header.hash_slow(); + + let provider = executor_provider(chain_spec); + let mut executor = provider.batch_executor(StateProviderDatabase::new(&db)); + + // attempt to execute the genesis block, this should not fail + executor + .execute_and_verify_one( + ( + &BlockWithSenders { + block: Block { header, body: Default::default() }, + senders: vec![], + }, + U256::ZERO, + ) + .into(), + ) + .expect( + "Executing a block with no transactions while Prague is active should not fail", + ); + + // nothing should be written as the genesis has no ancestors + // + // we load the account first, because revm expects it to be + // loaded + executor.with_state_mut(|state| state.basic(HISTORY_STORAGE_ADDRESS).unwrap()); + assert!(executor.with_state_mut(|state| state + .storage(HISTORY_STORAGE_ADDRESS, U256::ZERO) + .unwrap() + .is_zero())); + + // attempt to execute block 1, this should not fail + let header = Header { + parent_hash: header_hash, + timestamp: 1, + number: 1, + requests_root: Some(EMPTY_ROOT_HASH), + ..Header::default() + }; + let header_hash = header.hash_slow(); + + executor + .execute_and_verify_one( + ( + &BlockWithSenders { + block: Block { header, body: Default::default() }, + senders: vec![], + }, + U256::ZERO, + ) + .into(), + ) + .expect( + "Executing a block with no transactions while Prague is active should not fail", + ); + + // the block hash of genesis should now be in storage, but not block 1 + assert!(executor + .with_state_mut(|state| state.basic(HISTORY_STORAGE_ADDRESS).unwrap().is_some())); + assert_ne!( + executor.with_state_mut(|state| state + .storage(HISTORY_STORAGE_ADDRESS, U256::ZERO) + .unwrap()), + U256::ZERO + ); + assert!(executor.with_state_mut(|state| state + .storage(HISTORY_STORAGE_ADDRESS, U256::from(1)) + .unwrap() + .is_zero())); + + // attempt to execute block 2, this should not fail + let header = Header { + parent_hash: header_hash, + timestamp: 1, + number: 2, + requests_root: Some(EMPTY_ROOT_HASH), + ..Header::default() + }; + + executor + .execute_and_verify_one( + ( + &BlockWithSenders { + block: Block { header, body: Default::default() }, + senders: vec![], + }, + U256::ZERO, + ) + .into(), + ) + .expect( + "Executing a block with no transactions while Prague is active should not fail", + ); + + // the block hash of genesis and block 1 should now be in storage, but not block 2 + assert!(executor + .with_state_mut(|state| state.basic(HISTORY_STORAGE_ADDRESS).unwrap().is_some())); + assert_ne!( + executor.with_state_mut(|state| state + .storage(HISTORY_STORAGE_ADDRESS, U256::ZERO) + .unwrap()), + U256::ZERO + ); + assert_ne!( + executor.with_state_mut(|state| state + .storage(HISTORY_STORAGE_ADDRESS, U256::from(1)) + .unwrap()), + U256::ZERO + ); + assert!(executor.with_state_mut(|state| state + .storage(HISTORY_STORAGE_ADDRESS, U256::from(2)) + .unwrap() + .is_zero())); + } + + #[test] + fn eip_7002() { + let chain_spec = Arc::new( + ChainSpecBuilder::from(&*MAINNET) + .shanghai_activated() + .with_fork(EthereumHardfork::Prague, ForkCondition::Timestamp(0)) + .build(), + ); + + let mut db = create_state_provider_with_withdrawal_requests_contract(); + + let secp = Secp256k1::new(); + let sender_key_pair = Keypair::new(&secp, &mut generators::rng()); + let sender_address = public_key_to_address(sender_key_pair.public_key()); + + db.insert_account( + sender_address, + Account { nonce: 1, balance: U256::from(ETH_TO_WEI), bytecode_hash: None }, + None, + HashMap::default(), + ); + + // https://github.com/lightclient/7002asm/blob/e0d68e04d15f25057af7b6d180423d94b6b3bdb3/test/Contract.t.sol.in#L49-L64 + let validator_public_key = fixed_bytes!("111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111"); + let withdrawal_amount = fixed_bytes!("2222222222222222"); + let input: Bytes = [&validator_public_key[..], &withdrawal_amount[..]].concat().into(); + assert_eq!(input.len(), 56); + + let mut header = chain_spec.genesis_header().clone(); + header.gas_limit = 1_500_000; + header.gas_used = 134_807; + header.receipts_root = + b256!("b31a3e47b902e9211c4d349af4e4c5604ce388471e79ca008907ae4616bb0ed3"); + + let tx = sign_tx_with_key_pair( + sender_key_pair, + Transaction::Legacy(TxLegacy { + chain_id: Some(chain_spec.chain.id()), + nonce: 1, + gas_price: header.base_fee_per_gas.unwrap().into(), + gas_limit: 134_807, + to: TxKind::Call(WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS), + // `MIN_WITHDRAWAL_REQUEST_FEE` + value: U256::from(1), + input, + }), + ); + + let provider = executor_provider(chain_spec); + + let executor = provider.executor(StateProviderDatabase::new(&db)); + + let BlockExecutionOutput { receipts, requests, .. } = executor + .execute( + ( + &Block { + header, + body: BlockBody { transactions: vec![tx], ..Default::default() }, + } + .with_recovered_senders() + .unwrap(), + U256::ZERO, + ) + .into(), + ) + .unwrap(); + + let receipt = receipts.first().unwrap(); + assert!(receipt.success); + + let request = requests.first().unwrap(); + let withdrawal_request = request.as_withdrawal_request().unwrap(); + assert_eq!(withdrawal_request.source_address, sender_address); + assert_eq!(withdrawal_request.validator_pubkey, validator_public_key); + assert_eq!(withdrawal_request.amount, u64::from_be_bytes(withdrawal_amount.into())); + } + + #[test] + fn block_gas_limit_error() { + // Create a chain specification with fork conditions set for Prague + let chain_spec = Arc::new( + ChainSpecBuilder::from(&*MAINNET) + .shanghai_activated() + .with_fork(EthereumHardfork::Prague, ForkCondition::Timestamp(0)) + .build(), + ); + + // Create a state provider with the withdrawal requests contract pre-deployed + let mut db = create_state_provider_with_withdrawal_requests_contract(); + + // Initialize Secp256k1 for key pair generation + let secp = Secp256k1::new(); + // Generate a new key pair for the sender + let sender_key_pair = Keypair::new(&secp, &mut generators::rng()); + // Get the sender's address from the public key + let sender_address = public_key_to_address(sender_key_pair.public_key()); + + // Insert the sender account into the state with a nonce of 1 and a balance of 1 ETH in Wei + db.insert_account( + sender_address, + Account { nonce: 1, balance: U256::from(ETH_TO_WEI), bytecode_hash: None }, + None, + HashMap::default(), + ); + + // Define the validator public key and withdrawal amount as fixed bytes + let validator_public_key = fixed_bytes!("111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111"); + let withdrawal_amount = fixed_bytes!("2222222222222222"); + // Concatenate the validator public key and withdrawal amount into a single byte array + let input: Bytes = [&validator_public_key[..], &withdrawal_amount[..]].concat().into(); + // Ensure the input length is 56 bytes + assert_eq!(input.len(), 56); + + // Create a genesis block header with a specified gas limit and gas used + let mut header = chain_spec.genesis_header().clone(); + header.gas_limit = 1_500_000; + header.gas_used = 134_807; + header.receipts_root = + b256!("b31a3e47b902e9211c4d349af4e4c5604ce388471e79ca008907ae4616bb0ed3"); + + // Create a transaction with a gas limit higher than the block gas limit + let tx = sign_tx_with_key_pair( + sender_key_pair, + Transaction::Legacy(TxLegacy { + chain_id: Some(chain_spec.chain.id()), + nonce: 1, + gas_price: header.base_fee_per_gas.unwrap().into(), + gas_limit: 2_500_000, // higher than block gas limit + to: TxKind::Call(WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS), + value: U256::from(1), + input, + }), + ); + + // Create an executor from the state provider + let executor = executor_provider(chain_spec).executor(StateProviderDatabase::new(&db)); + + // Execute the block and capture the result + let exec_result = executor.execute( + ( + &Block { header, body: BlockBody { transactions: vec![tx], ..Default::default() } } + .with_recovered_senders() + .unwrap(), + U256::ZERO, + ) + .into(), + ); + + // Check if the execution result is an error and assert the specific error type + match exec_result { + Ok(_) => panic!("Expected block gas limit error"), + Err(err) => assert_eq!( + *err.as_validation().unwrap(), + BlockValidationError::TransactionGasLimitMoreThanAvailableBlockGas { + transaction_gas_limit: 2_500_000, + block_available_gas: 1_500_000, + } + ), + } + } +} diff --git a/crates/evm/src/execute.rs b/crates/evm/src/execute.rs index 9413c709d1e7..859dacd8a67f 100644 --- a/crates/evm/src/execute.rs +++ b/crates/evm/src/execute.rs @@ -8,10 +8,9 @@ pub use reth_execution_types::{BlockExecutionInput, BlockExecutionOutput, Execut pub use reth_storage_errors::provider::ProviderError; use crate::system_calls::OnStateHook; -use alloc::{boxed::Box, sync::Arc, vec::Vec}; +use alloc::{boxed::Box, vec::Vec}; use alloy_primitives::BlockNumber; use core::{fmt::Display, marker::PhantomData}; -use reth_chainspec::ChainSpec; use reth_consensus::ConsensusError; use reth_primitives::{BlockWithSenders, Receipt, Request}; use reth_prune_types::PruneModes; @@ -205,9 +204,6 @@ pub trait BlockExecutionStrategy { /// Returns the final bundle state. fn finish(&mut self) -> BundleState; - /// Returns the strategy chain spec. - fn chain_spec(&self) -> Arc; - /// Validate a block with regard to execution results. fn validate_block_post_execution( &self, @@ -629,10 +625,6 @@ mod tests { self.finish_result.clone() } - fn chain_spec(&self) -> Arc { - MAINNET.clone() - } - fn validate_block_post_execution( &self, _block: &BlockWithSenders, From e454b2402b0f9fe936620d9302edc94f9f8d5782 Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Wed, 16 Oct 2024 11:44:15 +0200 Subject: [PATCH 019/113] chore: use highest known nonce (#11784) --- crates/transaction-pool/src/pool/txpool.rs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/crates/transaction-pool/src/pool/txpool.rs b/crates/transaction-pool/src/pool/txpool.rs index c470faf3a1bf..c89aca830f0a 100644 --- a/crates/transaction-pool/src/pool/txpool.rs +++ b/crates/transaction-pool/src/pool/txpool.rs @@ -110,13 +110,21 @@ impl TxPool { /// Returns the transaction with the highest nonce that is executable given the on chain nonce. /// + /// If the pool already tracks a higher nonce for the given sender, then this nonce is used + /// instead. + /// /// Note: The next pending pooled transaction must have the on chain nonce. pub(crate) fn get_highest_consecutive_transaction_by_sender( &self, - on_chain: TransactionId, + mut on_chain: TransactionId, ) -> Option>> { let mut last_consecutive_tx = None; + // ensure this operates on the most recent + if let Some(current) = self.sender_info.get(&on_chain.sender) { + on_chain.nonce = on_chain.nonce.max(current.state_nonce); + } + let mut next_expected_nonce = on_chain.nonce; for (id, tx) in self.all().descendant_txs_inclusive(&on_chain) { if next_expected_nonce != id.nonce { @@ -2784,7 +2792,7 @@ mod tests { // Create transactions with nonces 0, 1, 2, 4, 5. let sender = Address::random(); - let txs: Vec<_> = vec![0, 1, 2, 4, 5]; + let txs: Vec<_> = vec![0, 1, 2, 4, 5, 8, 9]; for nonce in txs { let mut mock_tx = MockTransaction::eip1559(); mock_tx.set_sender(sender); @@ -2804,6 +2812,13 @@ mod tests { let next_tx = pool.get_highest_consecutive_transaction_by_sender(sender_id.into_id(5)); assert_eq!(next_tx.map(|tx| tx.nonce()), Some(5), "Expected nonce 5 for on-chain nonce 5"); + + // update the tracked nonce + let mut info = SenderInfo::default(); + info.update(8, U256::ZERO); + pool.sender_info.insert(sender_id, info); + let next_tx = pool.get_highest_consecutive_transaction_by_sender(sender_id.into_id(5)); + assert_eq!(next_tx.map(|tx| tx.nonce()), Some(9), "Expected nonce 9 for on-chain nonce 8"); } #[test] From f49a4ae185d0f02e548af4434b9cfc14df79af85 Mon Sep 17 00:00:00 2001 From: Federico Gimenez Date: Wed, 16 Oct 2024 12:13:46 +0200 Subject: [PATCH 020/113] feat: add OpExecutionStrategy (#11761) --- Cargo.lock | 1 + crates/evm/src/execute.rs | 2 +- crates/evm/src/test_utils.rs | 7 +- crates/optimism/evm/Cargo.toml | 2 + crates/optimism/evm/src/lib.rs | 2 + crates/optimism/evm/src/strategy.rs | 491 ++++++++++++++++++++++++++++ 6 files changed, 503 insertions(+), 2 deletions(-) create mode 100644 crates/optimism/evm/src/strategy.rs diff --git a/Cargo.lock b/Cargo.lock index eb0bb2a3d023..4d23c5b42bf9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8105,6 +8105,7 @@ dependencies = [ "alloy-primitives", "op-alloy-consensus", "reth-chainspec", + "reth-consensus", "reth-ethereum-forks", "reth-evm", "reth-execution-errors", diff --git a/crates/evm/src/execute.rs b/crates/evm/src/execute.rs index 859dacd8a67f..704b6a23ad5a 100644 --- a/crates/evm/src/execute.rs +++ b/crates/evm/src/execute.rs @@ -375,7 +375,7 @@ where /// Batch execution strategy. pub(crate) strategy: S, /// Keeps track of batch execution receipts and requests. - batch_record: BlockBatchRecord, + pub(crate) batch_record: BlockBatchRecord, _phantom: PhantomData, } diff --git a/crates/evm/src/test_utils.rs b/crates/evm/src/test_utils.rs index a033c8023a96..5ae7ed45b712 100644 --- a/crates/evm/src/test_utils.rs +++ b/crates/evm/src/test_utils.rs @@ -11,7 +11,7 @@ use alloy_primitives::BlockNumber; use parking_lot::Mutex; use reth_execution_errors::BlockExecutionError; use reth_execution_types::ExecutionOutcome; -use reth_primitives::{BlockWithSenders, Receipt}; +use reth_primitives::{BlockWithSenders, Receipt, Receipts}; use reth_prune_types::PruneModes; use reth_storage_errors::provider::ProviderError; use revm::State; @@ -152,4 +152,9 @@ where { f(self.strategy.state_mut()) } + + /// Accessor for batch executor receipts. + pub const fn receipts(&self) -> &Receipts { + self.batch_record.receipts() + } } diff --git a/crates/optimism/evm/Cargo.toml b/crates/optimism/evm/Cargo.toml index 72231716ff92..afaca32b63ee 100644 --- a/crates/optimism/evm/Cargo.toml +++ b/crates/optimism/evm/Cargo.toml @@ -20,6 +20,7 @@ reth-revm.workspace = true reth-execution-errors.workspace = true reth-execution-types.workspace = true reth-prune-types.workspace = true +reth-consensus.workspace = true # ethereum alloy-primitives.workspace = true @@ -41,6 +42,7 @@ tracing.workspace = true [dev-dependencies] alloy-eips.workspace = true +reth-evm = { workspace = true, features = ["test-utils"] } reth-revm = { workspace = true, features = ["test-utils"] } reth-primitives = { workspace = true, features = ["test-utils"] } reth-optimism-chainspec.workspace = true diff --git a/crates/optimism/evm/src/lib.rs b/crates/optimism/evm/src/lib.rs index f3de053f780b..4d0f9d89ff41 100644 --- a/crates/optimism/evm/src/lib.rs +++ b/crates/optimism/evm/src/lib.rs @@ -33,6 +33,8 @@ use revm_primitives::{ BlobExcessGasAndPrice, BlockEnv, Bytes, CfgEnv, Env, HandlerCfg, OptimismFields, SpecId, TxKind, }; +pub mod strategy; + /// Optimism-related EVM configuration. #[derive(Debug, Clone)] pub struct OptimismEvmConfig { diff --git a/crates/optimism/evm/src/strategy.rs b/crates/optimism/evm/src/strategy.rs new file mode 100644 index 000000000000..4fc06c39686f --- /dev/null +++ b/crates/optimism/evm/src/strategy.rs @@ -0,0 +1,491 @@ +//! Optimism block execution strategy, + +use crate::{l1::ensure_create2_deployer, OptimismBlockExecutionError, OptimismEvmConfig}; +use reth_chainspec::EthereumHardforks; +use reth_consensus::ConsensusError; +use reth_evm::{ + execute::{ + BlockExecutionError, BlockExecutionStrategy, BlockExecutionStrategyFactory, + BlockValidationError, ProviderError, + }, + system_calls::{OnStateHook, SystemCaller}, + ConfigureEvm, ConfigureEvmEnv, +}; +use reth_optimism_chainspec::OpChainSpec; +use reth_optimism_consensus::validate_block_post_execution; +use reth_optimism_forks::OptimismHardfork; +use reth_primitives::{BlockWithSenders, Header, Receipt, Request, TxType}; +use reth_revm::{ + db::{states::bundle_state::BundleRetention, BundleState}, + state_change::post_block_balance_increments, + Database, State, +}; +use revm_primitives::{ + db::DatabaseCommit, BlockEnv, CfgEnvWithHandlerCfg, EnvWithHandlerCfg, ResultAndState, U256, +}; +use std::{fmt::Display, sync::Arc}; +use tracing::trace; + +/// Factory for [`OpExecutionStrategy`]. +#[derive(Debug, Clone)] +pub struct OpExecutionStrategyFactory { + /// The chainspec + chain_spec: Arc, + /// How to create an EVM. + evm_config: EvmConfig, +} + +impl OpExecutionStrategyFactory { + /// Creates a new default optimism executor strategy factory. + pub fn optimism(chain_spec: Arc) -> Self { + Self::new(chain_spec.clone(), OptimismEvmConfig::new(chain_spec)) + } +} + +impl OpExecutionStrategyFactory { + /// Creates a new executor strategy factory. + pub const fn new(chain_spec: Arc, evm_config: EvmConfig) -> Self { + Self { chain_spec, evm_config } + } +} + +impl BlockExecutionStrategyFactory for OpExecutionStrategyFactory { + type Strategy + Display>> = OpExecutionStrategy; + + fn create_strategy(&self, db: DB) -> Self::Strategy + where + DB: Database + Display>, + { + let state = + State::builder().with_database(db).with_bundle_update().without_state_clear().build(); + OpExecutionStrategy::new(state, self.chain_spec.clone(), self.evm_config.clone()) + } +} + +/// Block execution strategy for Optimism. +#[allow(missing_debug_implementations)] +pub struct OpExecutionStrategy { + /// The chainspec + chain_spec: Arc, + /// How to create an EVM. + evm_config: EvmConfig, + /// Current state for block execution. + state: State, + /// Utility to call system smart contracts. + system_caller: SystemCaller, +} + +impl OpExecutionStrategy { + /// Creates a new [`OpExecutionStrategy`] + pub fn new( + state: State, + chain_spec: Arc, + evm_config: OptimismEvmConfig, + ) -> Self { + let system_caller = SystemCaller::new(evm_config.clone(), (*chain_spec).clone()); + Self { state, chain_spec, evm_config, system_caller } + } +} + +impl OpExecutionStrategy { + /// Configures a new evm configuration and block environment for the given block. + /// + /// Caution: this does not initialize the tx environment. + fn evm_env_for_block(&self, header: &Header, total_difficulty: U256) -> EnvWithHandlerCfg { + let mut cfg = CfgEnvWithHandlerCfg::new(Default::default(), Default::default()); + let mut block_env = BlockEnv::default(); + self.evm_config.fill_cfg_and_block_env(&mut cfg, &mut block_env, header, total_difficulty); + + EnvWithHandlerCfg::new_with_cfg_env(cfg, block_env, Default::default()) + } +} + +impl BlockExecutionStrategy for OpExecutionStrategy +where + DB: Database + Display>, +{ + type Error = BlockExecutionError; + + fn apply_pre_execution_changes( + &mut self, + block: &BlockWithSenders, + total_difficulty: U256, + ) -> Result<(), Self::Error> { + // Set state clear flag if the block is after the Spurious Dragon hardfork. + let state_clear_flag = + (*self.chain_spec).is_spurious_dragon_active_at_block(block.header.number); + self.state.set_state_clear_flag(state_clear_flag); + + let env = self.evm_env_for_block(&block.header, total_difficulty); + let mut evm = self.evm_config.evm_with_env(&mut self.state, env); + + self.system_caller.apply_beacon_root_contract_call( + block.timestamp, + block.number, + block.parent_beacon_block_root, + &mut evm, + )?; + + // Ensure that the create2deployer is force-deployed at the canyon transition. Optimism + // blocks will always have at least a single transaction in them (the L1 info transaction), + // so we can safely assume that this will always be triggered upon the transition and that + // the above check for empty blocks will never be hit on OP chains. + ensure_create2_deployer(self.chain_spec.clone(), block.timestamp, evm.db_mut()) + .map_err(|_| OptimismBlockExecutionError::ForceCreate2DeployerFail)?; + + Ok(()) + } + + fn execute_transactions( + &mut self, + block: &BlockWithSenders, + total_difficulty: U256, + ) -> Result<(Vec, u64), Self::Error> { + let env = self.evm_env_for_block(&block.header, total_difficulty); + let mut evm = self.evm_config.evm_with_env(&mut self.state, env); + + let is_regolith = + self.chain_spec.fork(OptimismHardfork::Regolith).active_at_timestamp(block.timestamp); + + let mut cumulative_gas_used = 0; + let mut receipts = Vec::with_capacity(block.body.transactions.len()); + for (sender, transaction) in block.transactions_with_sender() { + // The sum of the transaction’s gas limit, Tg, and the gas utilized in this block prior, + // must be no greater than the block’s gasLimit. + let block_available_gas = block.header.gas_limit - cumulative_gas_used; + if transaction.gas_limit() > block_available_gas && + (is_regolith || !transaction.is_system_transaction()) + { + return Err(BlockValidationError::TransactionGasLimitMoreThanAvailableBlockGas { + transaction_gas_limit: transaction.gas_limit(), + block_available_gas, + } + .into()) + } + + // An optimism block should never contain blob transactions. + if matches!(transaction.tx_type(), TxType::Eip4844) { + return Err(OptimismBlockExecutionError::BlobTransactionRejected.into()) + } + + // Cache the depositor account prior to the state transition for the deposit nonce. + // + // Note that this *only* needs to be done post-regolith hardfork, as deposit nonces + // were not introduced in Bedrock. In addition, regular transactions don't have deposit + // nonces, so we don't need to touch the DB for those. + let depositor = (is_regolith && transaction.is_deposit()) + .then(|| { + evm.db_mut() + .load_cache_account(*sender) + .map(|acc| acc.account_info().unwrap_or_default()) + }) + .transpose() + .map_err(|_| OptimismBlockExecutionError::AccountLoadFailed(*sender))?; + + self.evm_config.fill_tx_env(evm.tx_mut(), transaction, *sender); + + // Execute transaction. + let result_and_state = evm.transact().map_err(move |err| { + let new_err = err.map_db_err(|e| e.into()); + // Ensure hash is calculated for error log, if not already done + BlockValidationError::EVM { + hash: transaction.recalculate_hash(), + error: Box::new(new_err), + } + })?; + + trace!( + target: "evm", + ?transaction, + "Executed transaction" + ); + self.system_caller.on_state(&result_and_state); + let ResultAndState { result, state } = result_and_state; + evm.db_mut().commit(state); + + // append gas used + cumulative_gas_used += result.gas_used(); + + // Push transaction changeset and calculate header bloom filter for receipt. + receipts.push(Receipt { + tx_type: transaction.tx_type(), + // Success flag was added in `EIP-658: Embedding transaction status code in + // receipts`. + success: result.is_success(), + cumulative_gas_used, + logs: result.into_logs(), + deposit_nonce: depositor.map(|account| account.nonce), + // The deposit receipt version was introduced in Canyon to indicate an update to how + // receipt hashes should be computed when set. The state transition process ensures + // this is only set for post-Canyon deposit transactions. + deposit_receipt_version: (transaction.is_deposit() && + self.chain_spec + .is_fork_active_at_timestamp(OptimismHardfork::Canyon, block.timestamp)) + .then_some(1), + }); + } + + Ok((receipts, cumulative_gas_used)) + } + + fn apply_post_execution_changes( + &mut self, + block: &BlockWithSenders, + total_difficulty: U256, + _receipts: &[Receipt], + ) -> Result, Self::Error> { + let balance_increments = + post_block_balance_increments(&self.chain_spec.clone(), block, total_difficulty); + // increment balances + self.state + .increment_balances(balance_increments) + .map_err(|_| BlockValidationError::IncrementBalanceFailed)?; + + Ok(vec![]) + } + + fn state_ref(&self) -> &State { + &self.state + } + + fn state_mut(&mut self) -> &mut State { + &mut self.state + } + + fn with_state_hook(&mut self, hook: Option>) { + self.system_caller.with_state_hook(hook); + } + + fn finish(&mut self) -> BundleState { + self.state.merge_transitions(BundleRetention::Reverts); + self.state.take_bundle() + } + + fn validate_block_post_execution( + &self, + block: &BlockWithSenders, + receipts: &[Receipt], + _requests: &[Request], + ) -> Result<(), ConsensusError> { + validate_block_post_execution(block, &self.chain_spec.clone(), receipts) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::OpChainSpec; + use alloy_consensus::TxEip1559; + use alloy_primitives::{b256, Address, StorageKey, StorageValue}; + use reth_chainspec::MIN_TRANSACTION_GAS; + use reth_evm::execute::{BatchExecutor, BlockExecutorProvider, GenericBlockExecutorProvider}; + use reth_optimism_chainspec::{optimism_deposit_tx_signature, OpChainSpecBuilder}; + use reth_primitives::{Account, Block, BlockBody, Signature, Transaction, TransactionSigned}; + use reth_revm::{ + database::StateProviderDatabase, test_utils::StateProviderTest, L1_BLOCK_CONTRACT, + }; + use std::{collections::HashMap, str::FromStr}; + + fn create_op_state_provider() -> StateProviderTest { + let mut db = StateProviderTest::default(); + + let l1_block_contract_account = + Account { balance: U256::ZERO, bytecode_hash: None, nonce: 1 }; + + let mut l1_block_storage = HashMap::default(); + // base fee + l1_block_storage.insert(StorageKey::with_last_byte(1), StorageValue::from(1000000000)); + // l1 fee overhead + l1_block_storage.insert(StorageKey::with_last_byte(5), StorageValue::from(188)); + // l1 fee scalar + l1_block_storage.insert(StorageKey::with_last_byte(6), StorageValue::from(684000)); + // l1 free scalars post ecotone + l1_block_storage.insert( + StorageKey::with_last_byte(3), + StorageValue::from_str( + "0x0000000000000000000000000000000000001db0000d27300000000000000005", + ) + .unwrap(), + ); + + db.insert_account(L1_BLOCK_CONTRACT, l1_block_contract_account, None, l1_block_storage); + + db + } + + fn executor_provider( + chain_spec: Arc, + ) -> GenericBlockExecutorProvider { + let strategy_factory = + OpExecutionStrategyFactory::new(chain_spec.clone(), OptimismEvmConfig::new(chain_spec)); + + GenericBlockExecutorProvider::new(strategy_factory) + } + + #[test] + fn op_deposit_fields_pre_canyon() { + let header = Header { + timestamp: 1, + number: 1, + gas_limit: 1_000_000, + gas_used: 42_000, + receipts_root: b256!( + "83465d1e7d01578c0d609be33570f91242f013e9e295b0879905346abbd63731" + ), + ..Default::default() + }; + + let mut db = create_op_state_provider(); + + let addr = Address::ZERO; + let account = Account { balance: U256::MAX, ..Account::default() }; + db.insert_account(addr, account, None, HashMap::default()); + + let chain_spec = Arc::new(OpChainSpecBuilder::base_mainnet().regolith_activated().build()); + + let tx = TransactionSigned::from_transaction_and_signature( + Transaction::Eip1559(TxEip1559 { + chain_id: chain_spec.chain.id(), + nonce: 0, + gas_limit: MIN_TRANSACTION_GAS, + to: addr.into(), + ..Default::default() + }), + Signature::test_signature(), + ); + + let tx_deposit = TransactionSigned::from_transaction_and_signature( + Transaction::Deposit(op_alloy_consensus::TxDeposit { + from: addr, + to: addr.into(), + gas_limit: MIN_TRANSACTION_GAS, + ..Default::default() + }), + Signature::test_signature(), + ); + + let provider = executor_provider(chain_spec); + let mut executor = provider.batch_executor(StateProviderDatabase::new(&db)); + + // make sure the L1 block contract state is preloaded. + executor.with_state_mut(|state| { + state.load_cache_account(L1_BLOCK_CONTRACT).unwrap(); + }); + + // Attempt to execute a block with one deposit and one non-deposit transaction + executor + .execute_and_verify_one( + ( + &BlockWithSenders { + block: Block { + header, + body: BlockBody { + transactions: vec![tx, tx_deposit], + ..Default::default() + }, + }, + senders: vec![addr, addr], + }, + U256::ZERO, + ) + .into(), + ) + .unwrap(); + + let receipts = executor.receipts(); + let tx_receipt = receipts[0][0].as_ref().unwrap(); + let deposit_receipt = receipts[0][1].as_ref().unwrap(); + + // deposit_receipt_version is not present in pre canyon transactions + assert!(deposit_receipt.deposit_receipt_version.is_none()); + assert!(tx_receipt.deposit_receipt_version.is_none()); + + // deposit_nonce is present only in deposit transactions + assert!(deposit_receipt.deposit_nonce.is_some()); + assert!(tx_receipt.deposit_nonce.is_none()); + } + + #[test] + fn op_deposit_fields_post_canyon() { + // ensure_create2_deployer will fail if timestamp is set to less then 2 + let header = Header { + timestamp: 2, + number: 1, + gas_limit: 1_000_000, + gas_used: 42_000, + receipts_root: b256!( + "fffc85c4004fd03c7bfbe5491fae98a7473126c099ac11e8286fd0013f15f908" + ), + ..Default::default() + }; + + let mut db = create_op_state_provider(); + let addr = Address::ZERO; + let account = Account { balance: U256::MAX, ..Account::default() }; + + db.insert_account(addr, account, None, HashMap::default()); + + let chain_spec = Arc::new(OpChainSpecBuilder::base_mainnet().canyon_activated().build()); + + let tx = TransactionSigned::from_transaction_and_signature( + Transaction::Eip1559(TxEip1559 { + chain_id: chain_spec.chain.id(), + nonce: 0, + gas_limit: MIN_TRANSACTION_GAS, + to: addr.into(), + ..Default::default() + }), + Signature::test_signature(), + ); + + let tx_deposit = TransactionSigned::from_transaction_and_signature( + Transaction::Deposit(op_alloy_consensus::TxDeposit { + from: addr, + to: addr.into(), + gas_limit: MIN_TRANSACTION_GAS, + ..Default::default() + }), + optimism_deposit_tx_signature(), + ); + + let provider = executor_provider(chain_spec); + let mut executor = provider.batch_executor(StateProviderDatabase::new(&db)); + + // make sure the L1 block contract state is preloaded. + executor.with_state_mut(|state| { + state.load_cache_account(L1_BLOCK_CONTRACT).unwrap(); + }); + + // attempt to execute an empty block with parent beacon block root, this should not fail + executor + .execute_and_verify_one( + ( + &BlockWithSenders { + block: Block { + header, + body: BlockBody { + transactions: vec![tx, tx_deposit], + ..Default::default() + }, + }, + senders: vec![addr, addr], + }, + U256::ZERO, + ) + .into(), + ) + .expect("Executing a block while canyon is active should not fail"); + + let receipts = executor.receipts(); + let tx_receipt = receipts[0][0].as_ref().unwrap(); + let deposit_receipt = receipts[0][1].as_ref().unwrap(); + + // deposit_receipt_version is set to 1 for post canyon deposit transactions + assert_eq!(deposit_receipt.deposit_receipt_version, Some(1)); + assert!(tx_receipt.deposit_receipt_version.is_none()); + + // deposit_nonce is present only in deposit transactions + assert!(deposit_receipt.deposit_nonce.is_some()); + assert!(tx_receipt.deposit_nonce.is_none()); + } +} From d421931b7ec86759a0bf1aa2cb7e9b6263f14c9a Mon Sep 17 00:00:00 2001 From: Thomas Coratger <60488569+tcoratger@users.noreply.github.com> Date: Wed, 16 Oct 2024 12:31:23 +0200 Subject: [PATCH 021/113] trie: simplify usage of `HashedStorage` with default (#11662) --- crates/storage/provider/src/providers/bundle_state_provider.rs | 2 +- crates/trie/parallel/src/parallel_root.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/storage/provider/src/providers/bundle_state_provider.rs b/crates/storage/provider/src/providers/bundle_state_provider.rs index 296dae8c6ab7..be6549033cde 100644 --- a/crates/storage/provider/src/providers/bundle_state_provider.rs +++ b/crates/storage/provider/src/providers/bundle_state_provider.rs @@ -43,7 +43,7 @@ impl BundleStateProvider account.storage.iter().map(|(slot, value)| (slot, &value.present_value)), ) }) - .unwrap_or_else(|| HashedStorage::new(false)) + .unwrap_or_default() } } diff --git a/crates/trie/parallel/src/parallel_root.rs b/crates/trie/parallel/src/parallel_root.rs index a64b8351446e..e432b91062ca 100644 --- a/crates/trie/parallel/src/parallel_root.rs +++ b/crates/trie/parallel/src/parallel_root.rs @@ -320,7 +320,7 @@ mod tests { hashed_state .storages .entry(hashed_address) - .or_insert_with(|| HashedStorage::new(false)) + .or_insert_with(HashedStorage::default) .storage .insert(hashed_slot, *value); } From 248b6b5905e9c44b5e0c2af6abae450898801beb Mon Sep 17 00:00:00 2001 From: greged93 <82421016+greged93@users.noreply.github.com> Date: Wed, 16 Oct 2024 12:39:25 +0200 Subject: [PATCH 022/113] fix: task executor metrics (#11738) --- bin/reth/src/cli/mod.rs | 5 +++++ crates/cli/commands/src/node.rs | 5 ----- crates/tasks/src/lib.rs | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/bin/reth/src/cli/mod.rs b/bin/reth/src/cli/mod.rs index cca801da36b2..01f8f73e7b1b 100644 --- a/bin/reth/src/cli/mod.rs +++ b/bin/reth/src/cli/mod.rs @@ -18,6 +18,7 @@ use reth_db::DatabaseEnv; use reth_ethereum_cli::chainspec::EthereumChainSpecParser; use reth_node_builder::{NodeBuilder, WithLaunchContext}; use reth_node_ethereum::{EthExecutorProvider, EthereumNode}; +use reth_node_metrics::recorder::install_prometheus_recorder; use reth_tracing::FileWorkerGuard; use std::{ffi::OsString, fmt, future::Future, sync::Arc}; use tracing::info; @@ -145,6 +146,10 @@ impl, Ext: clap::Args + fmt::Debug> Cl let _guard = self.init_tracing()?; info!(target: "reth::cli", "Initialized tracing, debug log directory: {}", self.logs.log_file_directory); + // Install the prometheus recorder to be sure to record task + // executor's metrics + let _ = install_prometheus_recorder(); + let runner = CliRunner::default(); match self.command { Commands::Node(command) => { diff --git a/crates/cli/commands/src/node.rs b/crates/cli/commands/src/node.rs index 5b1a87e068b3..b099a2c05222 100644 --- a/crates/cli/commands/src/node.rs +++ b/crates/cli/commands/src/node.rs @@ -16,7 +16,6 @@ use reth_node_core::{ node_config::NodeConfig, version, }; -use reth_node_metrics::recorder::install_prometheus_recorder; use std::{ffi::OsString, fmt, future::Future, net::SocketAddr, path::PathBuf, sync::Arc}; /// Start the node @@ -180,10 +179,6 @@ impl< pruning, }; - // Register the prometheus recorder before creating the database, - // because database init needs it to register metrics. - let _ = install_prometheus_recorder(); - let data_dir = node_config.datadir(); let db_path = data_dir.db(); diff --git a/crates/tasks/src/lib.rs b/crates/tasks/src/lib.rs index a0070698fcff..28b5eaba9ffb 100644 --- a/crates/tasks/src/lib.rs +++ b/crates/tasks/src/lib.rs @@ -288,7 +288,7 @@ pub struct TaskExecutor { on_shutdown: Shutdown, /// Sender half for sending panic signals to this type panicked_tasks_tx: UnboundedSender, - // Task Executor Metrics + /// Task Executor Metrics metrics: TaskExecutorMetrics, /// How many [`GracefulShutdown`] tasks are currently active graceful_tasks: Arc, From 87399ae2c17d83c9d874eaf3f0b902310414359e Mon Sep 17 00:00:00 2001 From: Federico Gimenez Date: Wed, 16 Oct 2024 13:20:42 +0200 Subject: [PATCH 023/113] chore: rename executor and provider Generic -> Basic (#11788) --- crates/ethereum/evm/src/strategy.rs | 6 ++--- crates/evm/src/execute.rs | 36 ++++++++++++++--------------- crates/evm/src/test_utils.rs | 8 +++---- crates/optimism/evm/src/strategy.rs | 6 ++--- 4 files changed, 28 insertions(+), 28 deletions(-) diff --git a/crates/ethereum/evm/src/strategy.rs b/crates/ethereum/evm/src/strategy.rs index 52f58a8b0a80..1c284e068d03 100644 --- a/crates/ethereum/evm/src/strategy.rs +++ b/crates/ethereum/evm/src/strategy.rs @@ -274,7 +274,7 @@ mod tests { use alloy_primitives::{b256, fixed_bytes, keccak256, Bytes, TxKind, B256}; use reth_chainspec::{ChainSpecBuilder, ForkCondition}; use reth_evm::execute::{ - BatchExecutor, BlockExecutorProvider, Executor, GenericBlockExecutorProvider, + BasicBlockExecutorProvider, BatchExecutor, BlockExecutorProvider, Executor, }; use reth_execution_types::BlockExecutionOutput; use reth_primitives::{ @@ -328,11 +328,11 @@ mod tests { fn executor_provider( chain_spec: Arc, - ) -> GenericBlockExecutorProvider { + ) -> BasicBlockExecutorProvider { let strategy_factory = EthExecutionStrategyFactory::new(chain_spec.clone(), EthEvmConfig::new(chain_spec)); - GenericBlockExecutorProvider::new(strategy_factory) + BasicBlockExecutorProvider::new(strategy_factory) } #[test] diff --git a/crates/evm/src/execute.rs b/crates/evm/src/execute.rs index 704b6a23ad5a..f52325b43e8f 100644 --- a/crates/evm/src/execute.rs +++ b/crates/evm/src/execute.rs @@ -227,7 +227,7 @@ pub trait BlockExecutionStrategyFactory: Send + Sync + Clone + Unpin + 'static { DB: Database + Display>; } -impl Clone for GenericBlockExecutorProvider +impl Clone for BasicBlockExecutorProvider where F: Clone, { @@ -238,33 +238,33 @@ where /// A generic block executor provider that can create executors using a strategy factory. #[allow(missing_debug_implementations)] -pub struct GenericBlockExecutorProvider { +pub struct BasicBlockExecutorProvider { strategy_factory: F, } -impl GenericBlockExecutorProvider { - /// Creates a new `GenericBlockExecutorProvider` with the given strategy factory. +impl BasicBlockExecutorProvider { + /// Creates a new `BasicBlockExecutorProvider` with the given strategy factory. pub const fn new(strategy_factory: F) -> Self { Self { strategy_factory } } } -impl BlockExecutorProvider for GenericBlockExecutorProvider +impl BlockExecutorProvider for BasicBlockExecutorProvider where F: BlockExecutionStrategyFactory, { type Executor + Display>> = - GenericBlockExecutor, DB>; + BasicBlockExecutor, DB>; type BatchExecutor + Display>> = - GenericBatchExecutor, DB>; + BasicBatchExecutor, DB>; fn executor(&self, db: DB) -> Self::Executor where DB: Database + Display>, { let strategy = self.strategy_factory.create_strategy(db); - GenericBlockExecutor::new(strategy) + BasicBlockExecutor::new(strategy) } fn batch_executor(&self, db: DB) -> Self::BatchExecutor @@ -273,14 +273,14 @@ where { let strategy = self.strategy_factory.create_strategy(db); let batch_record = BlockBatchRecord::default(); - GenericBatchExecutor::new(strategy, batch_record) + BasicBatchExecutor::new(strategy, batch_record) } } /// A generic block executor that uses a [`BlockExecutionStrategy`] to /// execute blocks. #[allow(missing_debug_implementations, dead_code)] -pub struct GenericBlockExecutor +pub struct BasicBlockExecutor where S: BlockExecutionStrategy, { @@ -289,17 +289,17 @@ where _phantom: PhantomData, } -impl GenericBlockExecutor +impl BasicBlockExecutor where S: BlockExecutionStrategy, { - /// Creates a new `GenericBlockExecutor` with the given strategy. + /// Creates a new `BasicBlockExecutor` with the given strategy. pub const fn new(strategy: S) -> Self { Self { strategy, _phantom: PhantomData } } } -impl Executor for GenericBlockExecutor +impl Executor for BasicBlockExecutor where S: BlockExecutionStrategy, DB: Database + Display>, @@ -368,7 +368,7 @@ where /// A generic batch executor that uses a [`BlockExecutionStrategy`] to /// execute batches. #[allow(missing_debug_implementations)] -pub struct GenericBatchExecutor +pub struct BasicBatchExecutor where S: BlockExecutionStrategy, { @@ -379,17 +379,17 @@ where _phantom: PhantomData, } -impl GenericBatchExecutor +impl BasicBatchExecutor where S: BlockExecutionStrategy, { - /// Creates a new `GenericBatchExecutor` with the given strategy. + /// Creates a new `BasicBatchExecutor` with the given strategy. pub const fn new(strategy: S, batch_record: BlockBatchRecord) -> Self { Self { strategy, batch_record, _phantom: PhantomData } } } -impl BatchExecutor for GenericBatchExecutor +impl BatchExecutor for BasicBatchExecutor where S: BlockExecutionStrategy, DB: Database + Display>, @@ -661,7 +661,7 @@ mod tests { .clone(), finish_result: expected_finish_result.clone(), }; - let provider = GenericBlockExecutorProvider::new(strategy_factory); + let provider = BasicBlockExecutorProvider::new(strategy_factory); let db = CacheDB::>::default(); let executor = provider.executor(db); let result = executor.execute(BlockExecutionInput::new(&Default::default(), U256::ZERO)); diff --git a/crates/evm/src/test_utils.rs b/crates/evm/src/test_utils.rs index 5ae7ed45b712..261b36420b4b 100644 --- a/crates/evm/src/test_utils.rs +++ b/crates/evm/src/test_utils.rs @@ -2,8 +2,8 @@ use crate::{ execute::{ - BatchExecutor, BlockExecutionInput, BlockExecutionOutput, BlockExecutionStrategy, - BlockExecutorProvider, Executor, GenericBatchExecutor, GenericBlockExecutor, + BasicBatchExecutor, BasicBlockExecutor, BatchExecutor, BlockExecutionInput, + BlockExecutionOutput, BlockExecutionStrategy, BlockExecutorProvider, Executor, }, system_calls::OnStateHook, }; @@ -112,7 +112,7 @@ impl BatchExecutor for MockExecutorProvider { } } -impl GenericBlockExecutor +impl BasicBlockExecutor where S: BlockExecutionStrategy, { @@ -133,7 +133,7 @@ where } } -impl GenericBatchExecutor +impl BasicBatchExecutor where S: BlockExecutionStrategy, { diff --git a/crates/optimism/evm/src/strategy.rs b/crates/optimism/evm/src/strategy.rs index 4fc06c39686f..33770714c4cb 100644 --- a/crates/optimism/evm/src/strategy.rs +++ b/crates/optimism/evm/src/strategy.rs @@ -278,7 +278,7 @@ mod tests { use alloy_consensus::TxEip1559; use alloy_primitives::{b256, Address, StorageKey, StorageValue}; use reth_chainspec::MIN_TRANSACTION_GAS; - use reth_evm::execute::{BatchExecutor, BlockExecutorProvider, GenericBlockExecutorProvider}; + use reth_evm::execute::{BasicBlockExecutorProvider, BatchExecutor, BlockExecutorProvider}; use reth_optimism_chainspec::{optimism_deposit_tx_signature, OpChainSpecBuilder}; use reth_primitives::{Account, Block, BlockBody, Signature, Transaction, TransactionSigned}; use reth_revm::{ @@ -315,11 +315,11 @@ mod tests { fn executor_provider( chain_spec: Arc, - ) -> GenericBlockExecutorProvider { + ) -> BasicBlockExecutorProvider { let strategy_factory = OpExecutionStrategyFactory::new(chain_spec.clone(), OptimismEvmConfig::new(chain_spec)); - GenericBlockExecutorProvider::new(strategy_factory) + BasicBlockExecutorProvider::new(strategy_factory) } #[test] From eec861fe9fc787900c18fc2d080f73c89620f5e3 Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Wed, 16 Oct 2024 13:59:41 +0200 Subject: [PATCH 024/113] chore: rm unused optimism feature (#11794) --- crates/rpc/rpc/Cargo.toml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/crates/rpc/rpc/Cargo.toml b/crates/rpc/rpc/Cargo.toml index 5399e50ce28a..fe150e36eed5 100644 --- a/crates/rpc/rpc/Cargo.toml +++ b/crates/rpc/rpc/Cargo.toml @@ -98,8 +98,3 @@ jsonrpsee = { workspace = true, features = ["client"] } [features] js-tracer = ["revm-inspectors/js-tracer", "reth-rpc-eth-types/js-tracer"] -optimism = [ - "reth-primitives/optimism", - "reth-provider/optimism", - "reth-revm/optimism", -] From 6f041108767a76d4ee964411bb8e346364444d47 Mon Sep 17 00:00:00 2001 From: Evan Chipman <42247026+evchip@users.noreply.github.com> Date: Wed, 16 Oct 2024 19:25:27 +0700 Subject: [PATCH 025/113] chore: rename SenderId::into_id to SenderId::into_transaction_id (#11793) Co-authored-by: Matthias Seitz --- crates/transaction-pool/src/identifier.rs | 2 +- crates/transaction-pool/src/pool/mod.rs | 5 +++-- crates/transaction-pool/src/pool/txpool.rs | 12 ++++++++---- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/crates/transaction-pool/src/identifier.rs b/crates/transaction-pool/src/identifier.rs index c50d39ae495a..2e5312a210fe 100644 --- a/crates/transaction-pool/src/identifier.rs +++ b/crates/transaction-pool/src/identifier.rs @@ -61,7 +61,7 @@ impl SenderId { } /// Converts the sender to a [`TransactionId`] with the given nonce. - pub const fn into_id(self, nonce: u64) -> TransactionId { + pub const fn into_transaction_id(self, nonce: u64) -> TransactionId { TransactionId::new(self, nonce) } } diff --git a/crates/transaction-pool/src/pool/mod.rs b/crates/transaction-pool/src/pool/mod.rs index 64e6dad6793f..600a8da934ec 100644 --- a/crates/transaction-pool/src/pool/mod.rs +++ b/crates/transaction-pool/src/pool/mod.rs @@ -792,8 +792,9 @@ where on_chain_nonce: u64, ) -> Option>> { let sender_id = self.get_sender_id(sender); - self.get_pool_data() - .get_highest_consecutive_transaction_by_sender(sender_id.into_id(on_chain_nonce)) + self.get_pool_data().get_highest_consecutive_transaction_by_sender( + sender_id.into_transaction_id(on_chain_nonce), + ) } /// Returns all transactions that where submitted with the given [`TransactionOrigin`] diff --git a/crates/transaction-pool/src/pool/txpool.rs b/crates/transaction-pool/src/pool/txpool.rs index c89aca830f0a..9d284392db55 100644 --- a/crates/transaction-pool/src/pool/txpool.rs +++ b/crates/transaction-pool/src/pool/txpool.rs @@ -2804,20 +2804,24 @@ mod tests { // Get last consecutive transaction let sender_id = f.ids.sender_id(&sender).unwrap(); - let next_tx = pool.get_highest_consecutive_transaction_by_sender(sender_id.into_id(0)); + let next_tx = + pool.get_highest_consecutive_transaction_by_sender(sender_id.into_transaction_id(0)); assert_eq!(next_tx.map(|tx| tx.nonce()), Some(2), "Expected nonce 2 for on-chain nonce 0"); - let next_tx = pool.get_highest_consecutive_transaction_by_sender(sender_id.into_id(4)); + let next_tx = + pool.get_highest_consecutive_transaction_by_sender(sender_id.into_transaction_id(4)); assert_eq!(next_tx.map(|tx| tx.nonce()), Some(5), "Expected nonce 5 for on-chain nonce 4"); - let next_tx = pool.get_highest_consecutive_transaction_by_sender(sender_id.into_id(5)); + let next_tx = + pool.get_highest_consecutive_transaction_by_sender(sender_id.into_transaction_id(5)); assert_eq!(next_tx.map(|tx| tx.nonce()), Some(5), "Expected nonce 5 for on-chain nonce 5"); // update the tracked nonce let mut info = SenderInfo::default(); info.update(8, U256::ZERO); pool.sender_info.insert(sender_id, info); - let next_tx = pool.get_highest_consecutive_transaction_by_sender(sender_id.into_id(5)); + let next_tx = + pool.get_highest_consecutive_transaction_by_sender(sender_id.into_transaction_id(5)); assert_eq!(next_tx.map(|tx| tx.nonce()), Some(9), "Expected nonce 9 for on-chain nonce 8"); } From c76d3194446b59581f11072e9cb66307e4aa278e Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Wed, 16 Oct 2024 14:44:19 +0200 Subject: [PATCH 026/113] chore: rm optimism feature from reth-revm (#11797) --- crates/optimism/evm/Cargo.toml | 2 +- crates/optimism/node/Cargo.toml | 1 - crates/optimism/payload/Cargo.toml | 2 +- crates/revm/Cargo.toml | 1 - 4 files changed, 2 insertions(+), 4 deletions(-) diff --git a/crates/optimism/evm/Cargo.toml b/crates/optimism/evm/Cargo.toml index afaca32b63ee..53f9ae033dd3 100644 --- a/crates/optimism/evm/Cargo.toml +++ b/crates/optimism/evm/Cargo.toml @@ -54,5 +54,5 @@ optimism = [ "reth-primitives/optimism", "reth-execution-types/optimism", "reth-optimism-consensus/optimism", - "reth-revm/optimism", + "revm/optimism", ] diff --git a/crates/optimism/node/Cargo.toml b/crates/optimism/node/Cargo.toml index f9e038a3d9e0..8e359e602657 100644 --- a/crates/optimism/node/Cargo.toml +++ b/crates/optimism/node/Cargo.toml @@ -87,7 +87,6 @@ optimism = [ "reth-optimism-evm/optimism", "reth-optimism-payload-builder/optimism", "reth-beacon-consensus/optimism", - "reth-revm/optimism", "revm/optimism", "reth-auto-seal-consensus/optimism", "reth-optimism-rpc/optimism", diff --git a/crates/optimism/payload/Cargo.toml b/crates/optimism/payload/Cargo.toml index 414b2c358118..e1d6fe47d291 100644 --- a/crates/optimism/payload/Cargo.toml +++ b/crates/optimism/payload/Cargo.toml @@ -52,5 +52,5 @@ optimism = [ "reth-primitives/optimism", "reth-provider/optimism", "reth-optimism-evm/optimism", - "reth-revm/optimism", + "revm/optimism", ] diff --git a/crates/revm/Cargo.toml b/crates/revm/Cargo.toml index 9e4501f62770..7ffb06ce960c 100644 --- a/crates/revm/Cargo.toml +++ b/crates/revm/Cargo.toml @@ -36,5 +36,4 @@ default = ["std", "c-kzg"] std = [] c-kzg = ["revm/c-kzg"] test-utils = ["dep:reth-trie"] -optimism = ["revm/optimism"] serde = ["revm/serde"] From 6ad1275e6b86b003eb51f794cd70de41559247f7 Mon Sep 17 00:00:00 2001 From: Emilia Hane Date: Wed, 16 Oct 2024 17:04:23 +0200 Subject: [PATCH 027/113] chore(sdk): move block traits into `reth-primitives-traits` (#11780) --- crates/primitives-traits/src/block.rs | 99 +++++++++++++++++++ .../src}/block/body.rs | 27 +++-- .../src}/block/mod.rs | 76 ++++---------- crates/primitives/src/traits/mod.rs | 7 -- 4 files changed, 135 insertions(+), 74 deletions(-) create mode 100644 crates/primitives-traits/src/block.rs rename crates/{primitives/src/traits => primitives-traits/src}/block/body.rs (84%) rename crates/{primitives/src/traits => primitives-traits/src}/block/mod.rs (58%) delete mode 100644 crates/primitives/src/traits/mod.rs diff --git a/crates/primitives-traits/src/block.rs b/crates/primitives-traits/src/block.rs new file mode 100644 index 000000000000..02f581801c93 --- /dev/null +++ b/crates/primitives-traits/src/block.rs @@ -0,0 +1,99 @@ +//! Block abstraction. + +pub mod body; + +use alloc::fmt; +use core::ops; + +use alloy_consensus::BlockHeader; +use alloy_primitives::{Address, Sealable, B256}; + +use crate::{traits::BlockBody, BlockWithSenders, SealedBlock, SealedHeader}; + +/// Abstraction of block data type. +pub trait Block: + fmt::Debug + + Clone + + PartialEq + + Eq + + Default + + serde::Serialize + + for<'a> serde::Deserialize<'a> + + From<(Self::Header, Self::Body)> + + Into<(Self::Header, Self::Body)> +{ + /// Header part of the block. + type Header: BlockHeader + Sealable; + + /// The block's body contains the transactions in the block. + type Body: BlockBody; + + /// A block and block hash. + type SealedBlock; + + /// A block and addresses of senders of transactions in it. + type BlockWithSenders; + + /// Returns reference to [`BlockHeader`] type. + fn header(&self) -> &Self::Header; + + /// Returns reference to [`BlockBody`] type. + fn body(&self) -> &Self::Body; + + /// Calculate the header hash and seal the block so that it can't be changed. + // todo: can be default impl if sealed block type is made generic over header and body and + // migrated to alloy + fn seal_slow(self) -> Self::SealedBlock; + + /// Seal the block with a known hash. + /// + /// WARNING: This method does not perform validation whether the hash is correct. + // todo: can be default impl if sealed block type is made generic over header and body and + // migrated to alloy + fn seal(self, hash: B256) -> Self::SealedBlock; + + /// Expensive operation that recovers transaction signer. See + /// [`SealedBlockWithSenders`](reth_primitives::SealedBlockWithSenders). + fn senders(&self) -> Option> { + self.body().recover_signers() + } + + /// Transform into a [`BlockWithSenders`]. + /// + /// # Panics + /// + /// If the number of senders does not match the number of transactions in the block + /// and the signer recovery for one of the transactions fails. + /// + /// Note: this is expected to be called with blocks read from disk. + #[track_caller] + fn with_senders_unchecked(self, senders: Vec
) -> Self::BlockWithSenders { + self.try_with_senders_unchecked(senders).expect("stored block is valid") + } + + /// Transform into a [`BlockWithSenders`] using the given senders. + /// + /// If the number of senders does not match the number of transactions in the block, this falls + /// back to manually recovery, but _without ensuring that the signature has a low `s` value_. + /// See also [`TransactionSigned::recover_signer_unchecked`] + /// + /// Returns an error if a signature is invalid. + // todo: can be default impl if block with senders type is made generic over block and migrated + // to alloy + #[track_caller] + fn try_with_senders_unchecked( + self, + senders: Vec
, + ) -> Result; + + /// **Expensive**. Transform into a [`BlockWithSenders`] by recovering senders in the contained + /// transactions. + /// + /// Returns `None` if a transaction is invalid. + // todo: can be default impl if sealed block type is made generic over header and body and + // migrated to alloy + fn with_recovered_senders(self) -> Option; + + /// Calculates a heuristic for the in-memory size of the [`Block`]. + fn size(&self) -> usize; +} diff --git a/crates/primitives/src/traits/block/body.rs b/crates/primitives-traits/src/block/body.rs similarity index 84% rename from crates/primitives/src/traits/block/body.rs rename to crates/primitives-traits/src/block/body.rs index ff8f71b76162..03246c68b454 100644 --- a/crates/primitives/src/traits/block/body.rs +++ b/crates/primitives-traits/src/block/body.rs @@ -3,10 +3,11 @@ use alloc::fmt; use core::ops; -use alloy_consensus::{BlockHeader, Transaction, TxType}; +use alloy_consensus::{BlockHeader,Request, Transaction, TxType}; use alloy_primitives::{Address, B256}; +use alloy_eips::eip1559::Withdrawal; -use crate::{proofs, traits::Block, Requests, Withdrawals}; +use crate::Block; /// Abstraction for block's body. pub trait BlockBody: @@ -27,18 +28,24 @@ pub trait BlockBody: /// Header type (uncle blocks). type Header: BlockHeader; + /// Withdrawals in block. + type Withdrawals: Iterator; + + /// Requests in block. + type Requests: Iterator; + /// Returns reference to transactions in block. fn transactions(&self) -> &[Self::SignedTransaction]; /// Returns [`Withdrawals`] in the block, if any. // todo: branch out into extension trait - fn withdrawals(&self) -> Option<&Withdrawals>; + fn withdrawals(&self) -> Option<&Self::Withdrawals>; /// Returns reference to uncle block headers. fn ommers(&self) -> &[Self::Header]; /// Returns [`Request`] in block, if any. - fn requests(&self) -> Option<&Requests>; + fn requests(&self) -> Option<&Self::Requests>; /// Create a [`Block`] from the body and its header. fn into_block>(self, header: Self::Header) -> T { @@ -53,15 +60,15 @@ pub trait BlockBody: /// Calculate the withdrawals root for the block body, if withdrawals exist. If there are no /// withdrawals, this will return `None`. - fn calculate_withdrawals_root(&self) -> Option { - Some(proofs::calculate_withdrawals_root(self.withdrawals()?)) - } + // todo: can be default impl if `calculate_withdrawals_root` made into a method on + // `Withdrawals` and `Withdrawals` moved to alloy + fn calculate_withdrawals_root(&self) -> Option; /// Calculate the requests root for the block body, if requests exist. If there are no /// requests, this will return `None`. - fn calculate_requests_root(&self) -> Option { - Some(proofs::calculate_requests_root(self.requests()?)) - } + // todo: can be default impl if `calculate_requests_root` made into a method on + // `Requests` and `Requests` moved to alloy + fn calculate_requests_root(&self) -> Option; /// Recover signer addresses for all transactions in the block body. fn recover_signers(&self) -> Option>; diff --git a/crates/primitives/src/traits/block/mod.rs b/crates/primitives-traits/src/block/mod.rs similarity index 58% rename from crates/primitives/src/traits/block/mod.rs rename to crates/primitives-traits/src/block/mod.rs index 451a54c3457c..02f581801c93 100644 --- a/crates/primitives/src/traits/block/mod.rs +++ b/crates/primitives-traits/src/block/mod.rs @@ -28,6 +28,12 @@ pub trait Block: /// The block's body contains the transactions in the block. type Body: BlockBody; + /// A block and block hash. + type SealedBlock; + + /// A block and addresses of senders of transactions in it. + type BlockWithSenders; + /// Returns reference to [`BlockHeader`] type. fn header(&self) -> &Self::Header; @@ -35,20 +41,16 @@ pub trait Block: fn body(&self) -> &Self::Body; /// Calculate the header hash and seal the block so that it can't be changed. - fn seal_slow(self) -> SealedBlock { - let (header, body) = self.into(); - let sealed = header.seal_slow(); - let (header, seal) = sealed.into_parts(); - SealedBlock { header: SealedHeader::new(header, seal), body } - } + // todo: can be default impl if sealed block type is made generic over header and body and + // migrated to alloy + fn seal_slow(self) -> Self::SealedBlock; /// Seal the block with a known hash. /// /// WARNING: This method does not perform validation whether the hash is correct. - fn seal(self, hash: B256) -> SealedBlock { - let (header, body) = self.into(); - SealedBlock { header: SealedHeader::new(header, hash), body } - } + // todo: can be default impl if sealed block type is made generic over header and body and + // migrated to alloy + fn seal(self, hash: B256) -> Self::SealedBlock; /// Expensive operation that recovers transaction signer. See /// [`SealedBlockWithSenders`](reth_primitives::SealedBlockWithSenders). @@ -65,7 +67,7 @@ pub trait Block: /// /// Note: this is expected to be called with blocks read from disk. #[track_caller] - fn with_senders_unchecked(self, senders: Vec
) -> BlockWithSenders { + fn with_senders_unchecked(self, senders: Vec
) -> Self::BlockWithSenders { self.try_with_senders_unchecked(senders).expect("stored block is valid") } @@ -76,62 +78,22 @@ pub trait Block: /// See also [`TransactionSigned::recover_signer_unchecked`] /// /// Returns an error if a signature is invalid. + // todo: can be default impl if block with senders type is made generic over block and migrated + // to alloy #[track_caller] fn try_with_senders_unchecked( self, senders: Vec
, - ) -> Result, Self> { - let senders = if self.body().transactions().len() == senders.len() { - senders - } else { - let Some(senders) = self.body().recover_signers() else { return Err(self) }; - senders - }; - - Ok(BlockWithSenders { block: self, senders }) - } + ) -> Result; /// **Expensive**. Transform into a [`BlockWithSenders`] by recovering senders in the contained /// transactions. /// /// Returns `None` if a transaction is invalid. - fn with_recovered_senders(self) -> Option> { - let senders = self.senders()?; - Some(BlockWithSenders { block: self, senders }) - } + // todo: can be default impl if sealed block type is made generic over header and body and + // migrated to alloy + fn with_recovered_senders(self) -> Option; /// Calculates a heuristic for the in-memory size of the [`Block`]. fn size(&self) -> usize; } - -impl Block for T -where - T: ops::Deref - + fmt::Debug - + Clone - + PartialEq - + Eq - + Default - + serde::Serialize - + for<'a> serde::Deserialize<'a> - + From<(::Header, ::Body)> - + Into<(::Header, ::Body)>, -{ - type Header = ::Header; - type Body = ::Body; - - #[inline] - fn header(&self) -> &Self::Header { - self.deref().header() - } - - #[inline] - fn body(&self) -> &Self::Body { - self.deref().body() - } - - #[inline] - fn size(&self) -> usize { - self.deref().size() - } -} diff --git a/crates/primitives/src/traits/mod.rs b/crates/primitives/src/traits/mod.rs deleted file mode 100644 index 8c84c6729753..000000000000 --- a/crates/primitives/src/traits/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -//! Abstractions of primitive data types - -pub mod block; - -pub use block::{body::BlockBody, Block}; - -pub use alloy_consensus::BlockHeader; From cb7fd084a673bae8c5b5c0c0fbf46b74fe89a23e Mon Sep 17 00:00:00 2001 From: greged93 <82421016+greged93@users.noreply.github.com> Date: Wed, 16 Oct 2024 17:05:59 +0200 Subject: [PATCH 028/113] chore: remove &self from update_estimated_gas_range (#11799) --- crates/rpc/rpc-eth-api/src/helpers/call.rs | 101 ++++++++++----------- 1 file changed, 50 insertions(+), 51 deletions(-) diff --git a/crates/rpc/rpc-eth-api/src/helpers/call.rs b/crates/rpc/rpc-eth-api/src/helpers/call.rs index 6784f9327f09..b43b34305bd9 100644 --- a/crates/rpc/rpc-eth-api/src/helpers/call.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/call.rs @@ -855,7 +855,7 @@ pub trait Call: LoadState + SpawnBlocking { // Update the gas used based on the new result. gas_used = res.result.gas_used(); // Update the gas limit estimates (highest and lowest) based on the execution result. - self.update_estimated_gas_range( + update_estimated_gas_range( res.result, optimistic_gas_limit, &mut highest_gas_limit, @@ -900,7 +900,7 @@ pub trait Call: LoadState + SpawnBlocking { // Unpack the result and environment if the transaction was successful. (res, env) = ethres?; // Update the estimated gas range based on the transaction result. - self.update_estimated_gas_range( + update_estimated_gas_range( res.result, mid_gas_limit, &mut highest_gas_limit, @@ -916,55 +916,6 @@ pub trait Call: LoadState + SpawnBlocking { Ok(U256::from(highest_gas_limit)) } - /// Updates the highest and lowest gas limits for binary search based on the execution result. - /// - /// This function refines the gas limit estimates used in a binary search to find the optimal - /// gas limit for a transaction. It adjusts the highest or lowest gas limits depending on - /// whether the execution succeeded, reverted, or halted due to specific reasons. - #[inline] - fn update_estimated_gas_range( - &self, - result: ExecutionResult, - tx_gas_limit: u64, - highest_gas_limit: &mut u64, - lowest_gas_limit: &mut u64, - ) -> Result<(), Self::Error> { - match result { - ExecutionResult::Success { .. } => { - // Cap the highest gas limit with the succeeding gas limit. - *highest_gas_limit = tx_gas_limit; - } - ExecutionResult::Revert { .. } => { - // Increase the lowest gas limit. - *lowest_gas_limit = tx_gas_limit; - } - ExecutionResult::Halt { reason, .. } => { - match reason { - HaltReason::OutOfGas(_) | HaltReason::InvalidFEOpcode => { - // Both `OutOfGas` and `InvalidEFOpcode` can occur dynamically if the gas - // left is too low. Treat this as an out of gas - // condition, knowing that the call succeeds with a - // higher gas limit. - // - // Common usage of invalid opcode in OpenZeppelin: - // - - // Increase the lowest gas limit. - *lowest_gas_limit = tx_gas_limit; - } - err => { - // These cases should be unreachable because we know the transaction - // succeeds, but if they occur, treat them as an - // error. - return Err(RpcInvalidTransactionError::EvmHalt(err).into_eth_err()) - } - } - } - }; - - Ok(()) - } - /// Executes the requests again after an out of gas error to check if the error is gas related /// or not #[inline] @@ -1163,3 +1114,51 @@ pub trait Call: LoadState + SpawnBlocking { Ok(env) } } + +/// Updates the highest and lowest gas limits for binary search based on the execution result. +/// +/// This function refines the gas limit estimates used in a binary search to find the optimal +/// gas limit for a transaction. It adjusts the highest or lowest gas limits depending on +/// whether the execution succeeded, reverted, or halted due to specific reasons. +#[inline] +fn update_estimated_gas_range( + result: ExecutionResult, + tx_gas_limit: u64, + highest_gas_limit: &mut u64, + lowest_gas_limit: &mut u64, +) -> Result<(), EthApiError> { + match result { + ExecutionResult::Success { .. } => { + // Cap the highest gas limit with the succeeding gas limit. + *highest_gas_limit = tx_gas_limit; + } + ExecutionResult::Revert { .. } => { + // Increase the lowest gas limit. + *lowest_gas_limit = tx_gas_limit; + } + ExecutionResult::Halt { reason, .. } => { + match reason { + HaltReason::OutOfGas(_) | HaltReason::InvalidFEOpcode => { + // Both `OutOfGas` and `InvalidEFOpcode` can occur dynamically if the gas + // left is too low. Treat this as an out of gas + // condition, knowing that the call succeeds with a + // higher gas limit. + // + // Common usage of invalid opcode in OpenZeppelin: + // + + // Increase the lowest gas limit. + *lowest_gas_limit = tx_gas_limit; + } + err => { + // These cases should be unreachable because we know the transaction + // succeeds, but if they occur, treat them as an + // error. + return Err(RpcInvalidTransactionError::EvmHalt(err).into_eth_err()) + } + } + } + }; + + Ok(()) +} From 281307fe4c25fef8cebbffcfff6eaf0f4d190d6b Mon Sep 17 00:00:00 2001 From: Federico Gimenez Date: Wed, 16 Oct 2024 17:47:35 +0200 Subject: [PATCH 029/113] chore(ci): update list of crates excluded from wasm checks (#11787) --- .github/assets/check_wasm.sh | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.github/assets/check_wasm.sh b/.github/assets/check_wasm.sh index 8d53f457af91..1b1c0641fc0a 100755 --- a/.github/assets/check_wasm.sh +++ b/.github/assets/check_wasm.sh @@ -30,12 +30,10 @@ exclude_crates=( reth-engine-util reth-eth-wire reth-ethereum-cli - reth-ethereum-engine reth-ethereum-engine-primitives reth-ethereum-payload-builder reth-etl reth-evm-ethereum - reth-execution-errors reth-exex reth-exex-test-utils reth-ipc @@ -49,7 +47,6 @@ exclude_crates=( reth-node-events reth-node-metrics reth-optimism-cli - reth-optimism-evm reth-optimism-node reth-optimism-payload-builder reth-optimism-rpc @@ -63,9 +60,7 @@ exclude_crates=( reth-rpc-eth-api reth-rpc-eth-types reth-rpc-layer - reth-rpc-types reth-stages - reth-storage-errors reth-engine-local # The following are not supposed to be working reth # all of the crates below From 6b2ec42e48394a8ffa0dc471ec7b2a9ba2a697c4 Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Wed, 16 Oct 2024 18:50:18 +0200 Subject: [PATCH 030/113] docs: clarify max rpc tracing requests (#11796) Co-authored-by: Dan Cline <6798349+Rjected@users.noreply.github.com> --- book/cli/help.rs | 2 +- book/cli/reth/node.md | 4 +++- crates/node/core/src/args/rpc_server.rs | 5 +++++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/book/cli/help.rs b/book/cli/help.rs index e347e1ea5db6..963f53deb0a9 100755 --- a/book/cli/help.rs +++ b/book/cli/help.rs @@ -320,7 +320,7 @@ fn preprocess_help(s: &str) -> Cow<'_, str> { (r"default: reth/.*/\w+", "default: reth//"), // Remove rpc.max-tracing-requests default value ( - r"(rpc.max-tracing-requests \n.*\n.*\n.*)\[default: \d+\]", + r"(rpc.max-tracing-requests \n.*\n.*\n.*\n.*\n.*)\[default: \d+\]", r"$1[default: ]", ), ]; diff --git a/book/cli/reth/node.md b/book/cli/reth/node.md index 73a8063a852b..ea10d9522161 100644 --- a/book/cli/reth/node.md +++ b/book/cli/reth/node.md @@ -331,7 +331,9 @@ RPC: [default: 500] --rpc.max-tracing-requests - Maximum number of concurrent tracing requests + Maximum number of concurrent tracing requests. + + By default this chooses a sensible value based on the number of available cores. Tracing requests are generally CPU bound. Choosing a value that is higher than the available CPU cores can have a negative impact on the performance of the node and affect the node's ability to maintain sync. [default: ] diff --git a/crates/node/core/src/args/rpc_server.rs b/crates/node/core/src/args/rpc_server.rs index 15771e9897ef..382f22d37764 100644 --- a/crates/node/core/src/args/rpc_server.rs +++ b/crates/node/core/src/args/rpc_server.rs @@ -135,6 +135,11 @@ pub struct RpcServerArgs { pub rpc_max_connections: MaxU32, /// Maximum number of concurrent tracing requests. + /// + /// By default this chooses a sensible value based on the number of available cores. + /// Tracing requests are generally CPU bound. + /// Choosing a value that is higher than the available CPU cores can have a negative impact on + /// the performance of the node and affect the node's ability to maintain sync. #[arg(long = "rpc.max-tracing-requests", alias = "rpc-max-tracing-requests", value_name = "COUNT", default_value_t = constants::default_max_tracing_requests())] pub rpc_max_tracing_requests: usize, From 12cab204b50a824bcfb55f6b6d46f2e9cda34c31 Mon Sep 17 00:00:00 2001 From: Roman Krasiuk Date: Wed, 16 Oct 2024 19:21:25 +0200 Subject: [PATCH 031/113] fix(witness): branch node children decoding (#11599) --- crates/trie/db/tests/witness.rs | 52 +++++++++++++++++++++++++++++++++ crates/trie/trie/src/witness.rs | 22 ++++++++++---- 2 files changed, 68 insertions(+), 6 deletions(-) diff --git a/crates/trie/db/tests/witness.rs b/crates/trie/db/tests/witness.rs index 59656383de4c..20f8cfbb9081 100644 --- a/crates/trie/db/tests/witness.rs +++ b/crates/trie/db/tests/witness.rs @@ -6,6 +6,8 @@ use alloy_primitives::{ Address, Bytes, B256, U256, }; use alloy_rlp::EMPTY_STRING_CODE; +use reth_db::{cursor::DbCursorRW, tables}; +use reth_db_api::transaction::DbTxMut; use reth_primitives::{constants::EMPTY_ROOT_HASH, Account, StorageEntry}; use reth_provider::{test_utils::create_test_provider_factory, HashingWriter}; use reth_trie::{proof::Proof, witness::TrieWitness, HashedPostState, HashedStorage, StateRoot}; @@ -91,3 +93,53 @@ fn includes_nodes_for_destroyed_storage_nodes() { assert_eq!(witness.get(&keccak256(node)), Some(node)); } } + +#[test] +fn correctly_decodes_branch_node_values() { + let factory = create_test_provider_factory(); + let provider = factory.provider_rw().unwrap(); + + let address = Address::random(); + let hashed_address = keccak256(address); + let hashed_slot1 = B256::with_last_byte(1); + let hashed_slot2 = B256::with_last_byte(2); + + // Insert account and slots into database + provider.insert_account_for_hashing([(address, Some(Account::default()))]).unwrap(); + let mut hashed_storage_cursor = + provider.tx_ref().cursor_dup_write::().unwrap(); + hashed_storage_cursor + .upsert(hashed_address, StorageEntry { key: hashed_slot1, value: U256::from(1) }) + .unwrap(); + hashed_storage_cursor + .upsert(hashed_address, StorageEntry { key: hashed_slot2, value: U256::from(1) }) + .unwrap(); + + let state_root = StateRoot::from_tx(provider.tx_ref()).root().unwrap(); + let multiproof = Proof::from_tx(provider.tx_ref()) + .multiproof(HashMap::from_iter([( + hashed_address, + HashSet::from_iter([hashed_slot1, hashed_slot2]), + )])) + .unwrap(); + + let witness = TrieWitness::from_tx(provider.tx_ref()) + .compute(HashedPostState { + accounts: HashMap::from([(hashed_address, Some(Account::default()))]), + storages: HashMap::from([( + hashed_address, + HashedStorage::from_iter( + false, + [hashed_slot1, hashed_slot2].map(|hashed_slot| (hashed_slot, U256::from(2))), + ), + )]), + }) + .unwrap(); + assert!(witness.contains_key(&state_root)); + for node in multiproof.account_subtree.values() { + assert_eq!(witness.get(&keccak256(node)), Some(node)); + } + for node in multiproof.storages.iter().flat_map(|(_, storage)| storage.subtree.values()) { + assert_eq!(witness.get(&keccak256(node)), Some(node)); + } +} diff --git a/crates/trie/trie/src/witness.rs b/crates/trie/trie/src/witness.rs index 971f10cfbae1..f3b70e85ad6f 100644 --- a/crates/trie/trie/src/witness.rs +++ b/crates/trie/trie/src/witness.rs @@ -216,9 +216,14 @@ where TrieNode::Branch(branch) => { next_path.push(key[path.len()]); let children = branch_node_children(path.clone(), &branch); - for (child_path, node_hash) in children { + for (child_path, value) in children { if !key.starts_with(&child_path) { - trie_nodes.insert(child_path, Either::Left(node_hash)); + let value = if value.len() < B256::len_bytes() { + Either::Right(value.to_vec()) + } else { + Either::Left(B256::from_slice(&value[1..])) + }; + trie_nodes.insert(child_path, value); } } } @@ -312,8 +317,13 @@ where match TrieNode::decode(&mut &node[..])? { TrieNode::Branch(branch) => { let children = branch_node_children(path, &branch); - for (child_path, branch_hash) in children { - hash_builder.add_branch(child_path, branch_hash, false); + for (child_path, value) in children { + if value.len() < B256::len_bytes() { + hash_builder.add_leaf(child_path, value); + } else { + let hash = B256::from_slice(&value[1..]); + hash_builder.add_branch(child_path, hash, false); + } } break } @@ -343,14 +353,14 @@ where } /// Returned branch node children with keys in order. -fn branch_node_children(prefix: Nibbles, node: &BranchNode) -> Vec<(Nibbles, B256)> { +fn branch_node_children(prefix: Nibbles, node: &BranchNode) -> Vec<(Nibbles, &[u8])> { let mut children = Vec::with_capacity(node.state_mask.count_ones() as usize); let mut stack_ptr = node.as_ref().first_child_index(); for index in CHILD_INDEX_RANGE { if node.state_mask.is_bit_set(index) { let mut child_path = prefix.clone(); child_path.push(index); - children.push((child_path, B256::from_slice(&node.stack[stack_ptr][1..]))); + children.push((child_path, &node.stack[stack_ptr][..])); stack_ptr += 1; } } From 099987fc3d60f1c3bc6ca458242ae46988cba5bd Mon Sep 17 00:00:00 2001 From: Kunal Arora <55632507+aroralanuk@users.noreply.github.com> Date: Wed, 16 Oct 2024 23:00:26 +0530 Subject: [PATCH 032/113] chore(cli): add `default_client_version` to rethCli (#11773) Co-authored-by: Matthias Seitz --- Cargo.lock | 1 + crates/cli/cli/Cargo.toml | 2 +- crates/cli/cli/src/lib.rs | 4 ++++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 4d23c5b42bf9..3211a92c615c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6551,6 +6551,7 @@ dependencies = [ "clap", "eyre", "reth-cli-runner", + "reth-db", "serde_json", "shellexpand", ] diff --git a/crates/cli/cli/Cargo.toml b/crates/cli/cli/Cargo.toml index 7eb1f43b1e58..5da51a1b2f80 100644 --- a/crates/cli/cli/Cargo.toml +++ b/crates/cli/cli/Cargo.toml @@ -14,7 +14,7 @@ workspace = true [dependencies] # reth reth-cli-runner.workspace = true - +reth-db.workspace = true alloy-genesis.workspace = true # misc diff --git a/crates/cli/cli/src/lib.rs b/crates/cli/cli/src/lib.rs index 1db5ebf86b13..f7bf716ea379 100644 --- a/crates/cli/cli/src/lib.rs +++ b/crates/cli/cli/src/lib.rs @@ -10,6 +10,7 @@ use clap::{Error, Parser}; use reth_cli_runner::CliRunner; +use reth_db::ClientVersion; use std::{borrow::Cow, ffi::OsString}; /// The chainspec module defines the different chainspecs that can be used by the node. @@ -66,4 +67,7 @@ pub trait RethCli: Sized { Ok(cli.with_runner(f)) } + + /// The client version of the node. + fn client_version() -> ClientVersion; } From e5cd026e036e7c28fd76253f65a18402e8b8b6f2 Mon Sep 17 00:00:00 2001 From: Roman Krasiuk Date: Wed, 16 Oct 2024 19:49:57 +0200 Subject: [PATCH 033/113] deps: `alloy-trie@0.7.2` (#11807) --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3211a92c615c..a1e11216b3f9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -741,9 +741,9 @@ dependencies = [ [[package]] name = "alloy-trie" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fa8acead43cb238a7b7f47238c71137f4677a0b8d90e7e3be6e6ca59a28194e" +checksum = "cdd7f8b3a7c65ca09b3c7bdd7c7d72d7423d026f5247eda96af53d24e58315c1" dependencies = [ "alloy-primitives", "alloy-rlp", @@ -4464,7 +4464,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" dependencies = [ "cfg-if", - "windows-targets 0.52.6", + "windows-targets 0.48.5", ] [[package]] @@ -11378,7 +11378,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.48.0", ] [[package]] From dcaa432155931267a4010ab09d0d30b94ed30a41 Mon Sep 17 00:00:00 2001 From: Roman Krasiuk Date: Wed, 16 Oct 2024 20:31:58 +0200 Subject: [PATCH 034/113] chore(trie): use `RlpNode::as_hash` (#11808) --- crates/trie/sparse/src/trie.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/crates/trie/sparse/src/trie.rs b/crates/trie/sparse/src/trie.rs index 1b83e07e48d6..2edaaf76b274 100644 --- a/crates/trie/sparse/src/trie.rs +++ b/crates/trie/sparse/src/trie.rs @@ -267,8 +267,8 @@ impl RevealedSparseTrie { // take the current prefix set. let mut prefix_set = std::mem::take(&mut self.prefix_set).freeze(); let root_rlp = self.rlp_node(Nibbles::default(), &mut prefix_set); - if root_rlp.len() == B256::len_bytes() + 1 { - B256::from_slice(&root_rlp[1..]) + if let Some(root_hash) = root_rlp.as_hash() { + root_hash } else { keccak256(root_rlp) } @@ -338,8 +338,8 @@ impl RevealedSparseTrie { } else { let value = self.values.get(&path).unwrap(); let rlp_node = LeafNodeRef { key, value }.rlp(&mut self.rlp_buf); - if rlp_node.len() == B256::len_bytes() + 1 { - *hash = Some(B256::from_slice(&rlp_node[1..])); + if let Some(node_hash) = rlp_node.as_hash() { + *hash = Some(node_hash); } rlp_node } @@ -353,8 +353,8 @@ impl RevealedSparseTrie { let (_, child) = rlp_node_stack.pop().unwrap(); self.rlp_buf.clear(); let rlp_node = ExtensionNodeRef::new(key, &child).rlp(&mut self.rlp_buf); - if rlp_node.len() == B256::len_bytes() + 1 { - *hash = Some(B256::from_slice(&rlp_node[1..])); + if let Some(node_hash) = rlp_node.as_hash() { + *hash = Some(node_hash); } rlp_node } else { @@ -393,8 +393,8 @@ impl RevealedSparseTrie { self.rlp_buf.clear(); let rlp_node = BranchNodeRef::new(&branch_value_stack_buf, *state_mask) .rlp(&mut self.rlp_buf); - if rlp_node.len() == B256::len_bytes() + 1 { - *hash = Some(B256::from_slice(&rlp_node[1..])); + if let Some(node_hash) = rlp_node.as_hash() { + *hash = Some(node_hash); } rlp_node } From 756a47e4e2a8ab350cfc12d6621981312e12f715 Mon Sep 17 00:00:00 2001 From: Roman Krasiuk Date: Wed, 16 Oct 2024 20:33:29 +0200 Subject: [PATCH 035/113] chore: add `shekhirin` to trie code owners (#11809) --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index afb3d6776320..488e6c90cf7f 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -43,6 +43,6 @@ crates/tasks/ @mattsse crates/tokio-util/ @fgimenez @emhane crates/tracing/ @onbjerg crates/transaction-pool/ @mattsse -crates/trie/ @rkrasiuk @Rjected +crates/trie/ @rkrasiuk @Rjected @shekhirin etc/ @Rjected @onbjerg @shekhirin .github/ @onbjerg @gakonst @DaniPopes From a2249b0b04f7e92ea3c4b632c34269d048d7da05 Mon Sep 17 00:00:00 2001 From: Alexey Shekhirin Date: Wed, 16 Oct 2024 20:23:15 +0100 Subject: [PATCH 036/113] fix(exex): filter only WAL files when walking the directory (#11802) --- crates/exex/exex/src/wal/storage.rs | 37 ++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/crates/exex/exex/src/wal/storage.rs b/crates/exex/exex/src/wal/storage.rs index af3a590e5860..aaa4398fd0b6 100644 --- a/crates/exex/exex/src/wal/storage.rs +++ b/crates/exex/exex/src/wal/storage.rs @@ -9,6 +9,8 @@ use reth_exex_types::ExExNotification; use reth_tracing::tracing::debug; use tracing::instrument; +static FILE_EXTENSION: &str = "wal"; + /// The underlying WAL storage backed by a directory of files. /// /// Each notification is represented by a single file that contains a MessagePack-encoded @@ -29,7 +31,7 @@ impl Storage { } fn file_path(&self, id: u32) -> PathBuf { - self.path.join(format!("{id}.wal")) + self.path.join(format!("{id}.{FILE_EXTENSION}")) } fn parse_filename(filename: &str) -> eyre::Result { @@ -70,11 +72,14 @@ impl Storage { for entry in reth_fs_util::read_dir(&self.path)? { let entry = entry?; - let file_name = entry.file_name(); - let file_id = Self::parse_filename(&file_name.to_string_lossy())?; - min_id = min_id.map_or(Some(file_id), |min_id: u32| Some(min_id.min(file_id))); - max_id = max_id.map_or(Some(file_id), |max_id: u32| Some(max_id.max(file_id))); + if entry.path().extension() == Some(FILE_EXTENSION.as_ref()) { + let file_name = entry.file_name(); + let file_id = Self::parse_filename(&file_name.to_string_lossy())?; + + min_id = min_id.map_or(Some(file_id), |min_id: u32| Some(min_id.min(file_id))); + max_id = max_id.map_or(Some(file_id), |max_id: u32| Some(max_id.max(file_id))); + } } Ok(min_id.zip(max_id).map(|(min_id, max_id)| min_id..=max_id)) @@ -167,7 +172,7 @@ impl Storage { #[cfg(test)] mod tests { - use std::sync::Arc; + use std::{fs::File, sync::Arc}; use eyre::OptionExt; use reth_exex_types::ExExNotification; @@ -206,4 +211,24 @@ mod tests { Ok(()) } + + #[test] + fn test_files_range() -> eyre::Result<()> { + let temp_dir = tempfile::tempdir()?; + let storage = Storage::new(&temp_dir)?; + + // Create WAL files + File::create(storage.file_path(1))?; + File::create(storage.file_path(2))?; + File::create(storage.file_path(3))?; + + // Create non-WAL files that should be ignored + File::create(temp_dir.path().join("0.tmp"))?; + File::create(temp_dir.path().join("4.tmp"))?; + + // Check files range + assert_eq!(storage.files_range()?, Some(1..=3)); + + Ok(()) + } } From b1cc16809b9246f632d9cd8736a283af247b98fb Mon Sep 17 00:00:00 2001 From: Kien Trinh <51135161+kien6034@users.noreply.github.com> Date: Thu, 17 Oct 2024 03:13:16 +0700 Subject: [PATCH 037/113] feat(cli): make pruning block interval an option (#11810) --- book/cli/reth/node.md | 2 -- crates/node/builder/src/launch/common.rs | 2 +- crates/node/core/src/args/pruning.rs | 4 ++-- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/book/cli/reth/node.md b/book/cli/reth/node.md index ea10d9522161..34d32209ada9 100644 --- a/book/cli/reth/node.md +++ b/book/cli/reth/node.md @@ -616,8 +616,6 @@ Pruning: --block-interval Minimum pruning interval measured in blocks - [default: 0] - --prune.senderrecovery.full Prunes all sender recovery data diff --git a/crates/node/builder/src/launch/common.rs b/crates/node/builder/src/launch/common.rs index 3e8f92e707c0..ac2339fa6cfc 100644 --- a/crates/node/builder/src/launch/common.rs +++ b/crates/node/builder/src/launch/common.rs @@ -1072,7 +1072,7 @@ mod tests { let node_config = NodeConfig { pruning: PruningArgs { full: true, - block_interval: 0, + block_interval: None, sender_recovery_full: false, sender_recovery_distance: None, sender_recovery_before: None, diff --git a/crates/node/core/src/args/pruning.rs b/crates/node/core/src/args/pruning.rs index 2bee5ec164fe..c0a3ae375c0a 100644 --- a/crates/node/core/src/args/pruning.rs +++ b/crates/node/core/src/args/pruning.rs @@ -17,8 +17,8 @@ pub struct PruningArgs { pub full: bool, /// Minimum pruning interval measured in blocks. - #[arg(long, default_value_t = 0)] - pub block_interval: u64, + #[arg(long, default_value = None)] + pub block_interval: Option, // Sender Recovery /// Prunes all sender recovery data. From 82862fabd762f2a2b00dd77d140c2c6f5b63cadf Mon Sep 17 00:00:00 2001 From: Thomas Coratger <60488569+tcoratger@users.noreply.github.com> Date: Wed, 16 Oct 2024 22:33:57 +0200 Subject: [PATCH 038/113] primitives: rm redundant functions for `Transaction` (#11747) --- Cargo.lock | 3 + crates/chain-state/src/test_utils.rs | 2 +- crates/engine/util/Cargo.toml | 1 + crates/engine/util/src/reorg.rs | 1 + crates/ethereum/evm/Cargo.toml | 2 +- crates/ethereum/evm/src/execute.rs | 1 + crates/ethereum/evm/src/strategy.rs | 1 + crates/optimism/evm/Cargo.toml | 1 + crates/optimism/evm/src/execute.rs | 1 + crates/optimism/evm/src/strategy.rs | 1 + crates/optimism/rpc/Cargo.toml | 1 + crates/optimism/rpc/src/eth/transaction.rs | 1 + crates/primitives/src/transaction/mod.rs | 107 +----------------- crates/rpc/rpc-eth-api/Cargo.toml | 1 + .../rpc-eth-api/src/helpers/transaction.rs | 1 + crates/rpc/rpc-eth-types/src/receipt.rs | 1 + crates/rpc/rpc-eth-types/src/simulate.rs | 2 +- crates/rpc/rpc/src/txpool.rs | 1 + .../provider/src/providers/static_file/mod.rs | 1 + 19 files changed, 21 insertions(+), 109 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a1e11216b3f9..aa7c704b462e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7158,6 +7158,7 @@ dependencies = [ name = "reth-engine-util" version = "1.1.0" dependencies = [ + "alloy-consensus", "alloy-primitives", "alloy-rpc-types-engine", "eyre", @@ -8235,6 +8236,7 @@ dependencies = [ name = "reth-optimism-rpc" version = "1.1.0" dependencies = [ + "alloy-consensus", "alloy-eips", "alloy-primitives", "alloy-rpc-types", @@ -8726,6 +8728,7 @@ dependencies = [ name = "reth-rpc-eth-api" version = "1.1.0" dependencies = [ + "alloy-consensus", "alloy-dyn-abi", "alloy-eips", "alloy-json-rpc", diff --git a/crates/chain-state/src/test_utils.rs b/crates/chain-state/src/test_utils.rs index 4b0bfcdd996a..ad5f2dbdbcc2 100644 --- a/crates/chain-state/src/test_utils.rs +++ b/crates/chain-state/src/test_utils.rs @@ -2,7 +2,7 @@ use crate::{ in_memory::ExecutedBlock, CanonStateNotification, CanonStateNotifications, CanonStateSubscriptions, }; -use alloy_consensus::TxEip1559; +use alloy_consensus::{Transaction as _, TxEip1559}; use alloy_primitives::{Address, BlockNumber, Sealable, B256, U256}; use alloy_signer::SignerSync; use alloy_signer_local::PrivateKeySigner; diff --git a/crates/engine/util/Cargo.toml b/crates/engine/util/Cargo.toml index 20a0acb8d428..c11948b9405f 100644 --- a/crates/engine/util/Cargo.toml +++ b/crates/engine/util/Cargo.toml @@ -29,6 +29,7 @@ reth-trie.workspace = true # alloy alloy-primitives.workspace = true alloy-rpc-types-engine.workspace = true +alloy-consensus.workspace = true # async tokio = { workspace = true, default-features = false } diff --git a/crates/engine/util/src/reorg.rs b/crates/engine/util/src/reorg.rs index 611095101ff3..abfa23a57b32 100644 --- a/crates/engine/util/src/reorg.rs +++ b/crates/engine/util/src/reorg.rs @@ -1,5 +1,6 @@ //! Stream wrapper that simulates reorgs. +use alloy_consensus::Transaction; use alloy_primitives::U256; use alloy_rpc_types_engine::{ CancunPayloadFields, ExecutionPayload, ForkchoiceState, PayloadStatus, diff --git a/crates/ethereum/evm/Cargo.toml b/crates/ethereum/evm/Cargo.toml index a19cbc018c72..7215efa68c60 100644 --- a/crates/ethereum/evm/Cargo.toml +++ b/crates/ethereum/evm/Cargo.toml @@ -29,6 +29,7 @@ revm-primitives.workspace = true alloy-primitives.workspace = true alloy-eips.workspace = true alloy-sol-types.workspace = true +alloy-consensus.workspace = true [dev-dependencies] reth-testing-utils.workspace = true @@ -38,7 +39,6 @@ reth-primitives = { workspace = true, features = ["secp256k1"] } secp256k1.workspace = true serde_json.workspace = true alloy-genesis.workspace = true -alloy-consensus.workspace = true [features] default = ["std"] diff --git a/crates/ethereum/evm/src/execute.rs b/crates/ethereum/evm/src/execute.rs index 108e1f87c455..f712389fe121 100644 --- a/crates/ethereum/evm/src/execute.rs +++ b/crates/ethereum/evm/src/execute.rs @@ -5,6 +5,7 @@ use crate::{ EthEvmConfig, }; use alloc::{boxed::Box, sync::Arc, vec, vec::Vec}; +use alloy_consensus::Transaction as _; use alloy_primitives::{BlockNumber, U256}; use core::fmt::Display; use reth_chainspec::{ChainSpec, EthereumHardforks, MAINNET}; diff --git a/crates/ethereum/evm/src/strategy.rs b/crates/ethereum/evm/src/strategy.rs index 1c284e068d03..7a297be498a3 100644 --- a/crates/ethereum/evm/src/strategy.rs +++ b/crates/ethereum/evm/src/strategy.rs @@ -5,6 +5,7 @@ use crate::{ EthEvmConfig, }; use alloc::sync::Arc; +use alloy_consensus::Transaction as _; use core::fmt::Display; use reth_chainspec::{ChainSpec, EthereumHardfork, EthereumHardforks, MAINNET}; use reth_consensus::ConsensusError; diff --git a/crates/optimism/evm/Cargo.toml b/crates/optimism/evm/Cargo.toml index 53f9ae033dd3..0a22dcfddb44 100644 --- a/crates/optimism/evm/Cargo.toml +++ b/crates/optimism/evm/Cargo.toml @@ -25,6 +25,7 @@ reth-consensus.workspace = true # ethereum alloy-primitives.workspace = true op-alloy-consensus.workspace = true +alloy-consensus.workspace = true # Optimism reth-optimism-consensus.workspace = true diff --git a/crates/optimism/evm/src/execute.rs b/crates/optimism/evm/src/execute.rs index ee0d028e4251..f7da1c250d9b 100644 --- a/crates/optimism/evm/src/execute.rs +++ b/crates/optimism/evm/src/execute.rs @@ -3,6 +3,7 @@ use crate::{ l1::ensure_create2_deployer, OpChainSpec, OptimismBlockExecutionError, OptimismEvmConfig, }; +use alloy_consensus::Transaction as _; use alloy_primitives::{BlockNumber, U256}; use reth_chainspec::{ChainSpec, EthereumHardforks}; use reth_evm::{ diff --git a/crates/optimism/evm/src/strategy.rs b/crates/optimism/evm/src/strategy.rs index 33770714c4cb..fe8164cc7cf3 100644 --- a/crates/optimism/evm/src/strategy.rs +++ b/crates/optimism/evm/src/strategy.rs @@ -1,6 +1,7 @@ //! Optimism block execution strategy, use crate::{l1::ensure_create2_deployer, OptimismBlockExecutionError, OptimismEvmConfig}; +use alloy_consensus::Transaction as _; use reth_chainspec::EthereumHardforks; use reth_consensus::ConsensusError; use reth_evm::{ diff --git a/crates/optimism/rpc/Cargo.toml b/crates/optimism/rpc/Cargo.toml index 65dce7510b0e..90984998ac7e 100644 --- a/crates/optimism/rpc/Cargo.toml +++ b/crates/optimism/rpc/Cargo.toml @@ -38,6 +38,7 @@ alloy-eips.workspace = true alloy-primitives.workspace = true alloy-rpc-types-eth.workspace = true alloy-rpc-types.workspace = true +alloy-consensus.workspace = true op-alloy-network.workspace = true op-alloy-rpc-types.workspace = true op-alloy-consensus.workspace = true diff --git a/crates/optimism/rpc/src/eth/transaction.rs b/crates/optimism/rpc/src/eth/transaction.rs index e161504f8405..b7575c24416a 100644 --- a/crates/optimism/rpc/src/eth/transaction.rs +++ b/crates/optimism/rpc/src/eth/transaction.rs @@ -1,5 +1,6 @@ //! Loads and formats OP transaction RPC response. +use alloy_consensus::Transaction as _; use alloy_primitives::{Bytes, B256}; use alloy_rpc_types::TransactionInfo; use op_alloy_rpc_types::Transaction; diff --git a/crates/primitives/src/transaction/mod.rs b/crates/primitives/src/transaction/mod.rs index 0463cd9ea7e1..aeee4232e05d 100644 --- a/crates/primitives/src/transaction/mod.rs +++ b/crates/primitives/src/transaction/mod.rs @@ -249,33 +249,6 @@ impl Transaction { } } - /// Gets the transaction's value field. - pub const fn value(&self) -> U256 { - *match self { - Self::Legacy(TxLegacy { value, .. }) | - Self::Eip2930(TxEip2930 { value, .. }) | - Self::Eip1559(TxEip1559 { value, .. }) | - Self::Eip4844(TxEip4844 { value, .. }) | - Self::Eip7702(TxEip7702 { value, .. }) => value, - #[cfg(feature = "optimism")] - Self::Deposit(TxDeposit { value, .. }) => value, - } - } - - /// Get the transaction's nonce. - pub const fn nonce(&self) -> u64 { - match self { - Self::Legacy(TxLegacy { nonce, .. }) | - Self::Eip2930(TxEip2930 { nonce, .. }) | - Self::Eip1559(TxEip1559 { nonce, .. }) | - Self::Eip4844(TxEip4844 { nonce, .. }) | - Self::Eip7702(TxEip7702 { nonce, .. }) => *nonce, - // Deposit transactions do not have nonces. - #[cfg(feature = "optimism")] - Self::Deposit(_) => 0, - } - } - /// Returns the [`AccessList`] of the transaction. /// /// Returns `None` for legacy transactions. @@ -301,19 +274,6 @@ impl Transaction { } } - /// Get the gas limit of the transaction. - pub const fn gas_limit(&self) -> u64 { - match self { - Self::Legacy(TxLegacy { gas_limit, .. }) | - Self::Eip1559(TxEip1559 { gas_limit, .. }) | - Self::Eip4844(TxEip4844 { gas_limit, .. }) | - Self::Eip7702(TxEip7702 { gas_limit, .. }) | - Self::Eip2930(TxEip2930 { gas_limit, .. }) => *gas_limit, - #[cfg(feature = "optimism")] - Self::Deposit(TxDeposit { gas_limit, .. }) => *gas_limit, - } - } - /// Returns true if the tx supports dynamic fees pub const fn is_dynamic_fee(&self) -> bool { match self { @@ -324,40 +284,6 @@ impl Transaction { } } - /// Max fee per gas for eip1559 transaction, for legacy transactions this is `gas_price`. - /// - /// This is also commonly referred to as the "Gas Fee Cap" (`GasFeeCap`). - pub const fn max_fee_per_gas(&self) -> u128 { - match self { - Self::Legacy(TxLegacy { gas_price, .. }) | - Self::Eip2930(TxEip2930 { gas_price, .. }) => *gas_price, - Self::Eip1559(TxEip1559 { max_fee_per_gas, .. }) | - Self::Eip4844(TxEip4844 { max_fee_per_gas, .. }) | - Self::Eip7702(TxEip7702 { max_fee_per_gas, .. }) => *max_fee_per_gas, - // Deposit transactions buy their L2 gas on L1 and, as such, the L2 gas is not - // refundable. - #[cfg(feature = "optimism")] - Self::Deposit(_) => 0, - } - } - - /// Max priority fee per gas for eip1559 transaction, for legacy and eip2930 transactions this - /// is `None` - /// - /// This is also commonly referred to as the "Gas Tip Cap" (`GasTipCap`). - pub const fn max_priority_fee_per_gas(&self) -> Option { - match self { - Self::Legacy(_) | Self::Eip2930(_) => None, - Self::Eip1559(TxEip1559 { max_priority_fee_per_gas, .. }) | - Self::Eip4844(TxEip4844 { max_priority_fee_per_gas, .. }) | - Self::Eip7702(TxEip7702 { max_priority_fee_per_gas, .. }) => { - Some(*max_priority_fee_per_gas) - } - #[cfg(feature = "optimism")] - Self::Deposit(_) => None, - } - } - /// Blob versioned hashes for eip4844 transaction, for legacy, eip1559, eip2930 and eip7702 /// transactions this is `None` /// @@ -373,18 +299,6 @@ impl Transaction { } } - /// Max fee per blob gas for eip4844 transaction [`TxEip4844`]. - /// - /// Returns `None` for non-eip4844 transactions. - /// - /// This is also commonly referred to as the "Blob Gas Fee Cap" (`BlobGasFeeCap`). - pub const fn max_fee_per_blob_gas(&self) -> Option { - match self { - Self::Eip4844(TxEip4844 { max_fee_per_blob_gas, .. }) => Some(*max_fee_per_blob_gas), - _ => None, - } - } - /// Returns the blob gas used for all blobs of the EIP-4844 transaction if it is an EIP-4844 /// transaction. /// @@ -394,25 +308,6 @@ impl Transaction { self.as_eip4844().map(TxEip4844::blob_gas) } - /// Return the max priority fee per gas if the transaction is an EIP-1559 transaction, and - /// otherwise return the gas price. - /// - /// # Warning - /// - /// This is different than the `max_priority_fee_per_gas` method, which returns `None` for - /// non-EIP-1559 transactions. - pub const fn priority_fee_or_price(&self) -> u128 { - match self { - Self::Legacy(TxLegacy { gas_price, .. }) | - Self::Eip2930(TxEip2930 { gas_price, .. }) => *gas_price, - Self::Eip1559(TxEip1559 { max_priority_fee_per_gas, .. }) | - Self::Eip4844(TxEip4844 { max_priority_fee_per_gas, .. }) | - Self::Eip7702(TxEip7702 { max_priority_fee_per_gas, .. }) => *max_priority_fee_per_gas, - #[cfg(feature = "optimism")] - Self::Deposit(_) => 0, - } - } - /// Returns the effective gas price for the given base fee. /// /// If the transaction is a legacy or EIP2930 transaction, the gas price is returned. @@ -923,7 +818,7 @@ impl AlloyTransaction for Transaction { } } - fn value(&self) -> alloy_primitives::U256 { + fn value(&self) -> U256 { match self { Self::Legacy(tx) => tx.value(), Self::Eip2930(tx) => tx.value(), diff --git a/crates/rpc/rpc-eth-api/Cargo.toml b/crates/rpc/rpc-eth-api/Cargo.toml index e59ee39a694b..9d0f6cfd83d6 100644 --- a/crates/rpc/rpc-eth-api/Cargo.toml +++ b/crates/rpc/rpc-eth-api/Cargo.toml @@ -40,6 +40,7 @@ alloy-primitives.workspace = true alloy-rpc-types-eth.workspace = true alloy-rpc-types.workspace = true alloy-rpc-types-mev.workspace = true +alloy-consensus.workspace = true # rpc jsonrpsee = { workspace = true, features = ["server", "macros"] } diff --git a/crates/rpc/rpc-eth-api/src/helpers/transaction.rs b/crates/rpc/rpc-eth-api/src/helpers/transaction.rs index 4c2493717a04..54d60cb7abdf 100644 --- a/crates/rpc/rpc-eth-api/src/helpers/transaction.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/transaction.rs @@ -1,6 +1,7 @@ //! Database access for `eth_` transaction RPC methods. Loads transaction and receipt data w.r.t. //! network. +use alloy_consensus::Transaction; use alloy_dyn_abi::TypedData; use alloy_eips::eip2718::Encodable2718; use alloy_network::TransactionBuilder; diff --git a/crates/rpc/rpc-eth-types/src/receipt.rs b/crates/rpc/rpc-eth-types/src/receipt.rs index e95c92f24ae6..2668291e2c8c 100644 --- a/crates/rpc/rpc-eth-types/src/receipt.rs +++ b/crates/rpc/rpc-eth-types/src/receipt.rs @@ -1,5 +1,6 @@ //! RPC receipt response builder, extends a layer one receipt with layer two data. +use alloy_consensus::Transaction; use alloy_primitives::{Address, TxKind}; use alloy_rpc_types::{ AnyReceiptEnvelope, AnyTransactionReceipt, Log, ReceiptWithBloom, TransactionReceipt, diff --git a/crates/rpc/rpc-eth-types/src/simulate.rs b/crates/rpc/rpc-eth-types/src/simulate.rs index 561aa360d86f..a673da967202 100644 --- a/crates/rpc/rpc-eth-types/src/simulate.rs +++ b/crates/rpc/rpc-eth-types/src/simulate.rs @@ -1,6 +1,6 @@ //! Utilities for serving `eth_simulateV1` -use alloy_consensus::{TxEip4844Variant, TxType, TypedTransaction}; +use alloy_consensus::{Transaction as _, TxEip4844Variant, TxType, TypedTransaction}; use alloy_primitives::Parity; use alloy_rpc_types::{ simulate::{SimCallResult, SimulateError, SimulatedBlock}, diff --git a/crates/rpc/rpc/src/txpool.rs b/crates/rpc/rpc/src/txpool.rs index 5e26935ca1ba..47aaac0bbfd5 100644 --- a/crates/rpc/rpc/src/txpool.rs +++ b/crates/rpc/rpc/src/txpool.rs @@ -1,5 +1,6 @@ use std::{collections::BTreeMap, marker::PhantomData}; +use alloy_consensus::Transaction; use alloy_primitives::Address; use alloy_rpc_types_txpool::{ TxpoolContent, TxpoolContentFrom, TxpoolInspect, TxpoolInspectSummary, TxpoolStatus, diff --git a/crates/storage/provider/src/providers/static_file/mod.rs b/crates/storage/provider/src/providers/static_file/mod.rs index 45b7816af02a..52eb6ed666ea 100644 --- a/crates/storage/provider/src/providers/static_file/mod.rs +++ b/crates/storage/provider/src/providers/static_file/mod.rs @@ -56,6 +56,7 @@ impl Deref for LoadedJar { mod tests { use super::*; use crate::{test_utils::create_test_provider_factory, HeaderProvider}; + use alloy_consensus::Transaction; use alloy_primitives::{BlockHash, TxNumber, B256, U256}; use rand::seq::SliceRandom; use reth_db::{ From d2ca8f3a2b4139617fcafb05318447653a2a68af Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Wed, 16 Oct 2024 23:59:58 +0200 Subject: [PATCH 039/113] fix: update block interval properly (#11546) --- crates/config/src/config.rs | 49 ++++++++++++++++------------ crates/node/core/src/args/pruning.rs | 9 +++-- 2 files changed, 35 insertions(+), 23 deletions(-) diff --git a/crates/config/src/config.rs b/crates/config/src/config.rs index e4a7fc9677aa..4c4b6066a3e9 100644 --- a/crates/config/src/config.rs +++ b/crates/config/src/config.rs @@ -14,6 +14,9 @@ use std::{ const EXTENSION: &str = "toml"; +/// The default prune block interval +pub const DEFAULT_BLOCK_INTERVAL: usize = 5; + /// Configuration for the reth node. #[derive(Debug, Clone, Default, Deserialize, PartialEq, Eq, Serialize)] #[serde(default)] @@ -383,7 +386,7 @@ pub struct PruneConfig { impl Default for PruneConfig { fn default() -> Self { - Self { block_interval: 5, segments: PruneModes::none() } + Self { block_interval: DEFAULT_BLOCK_INTERVAL, segments: PruneModes::none() } } } @@ -397,27 +400,33 @@ impl PruneConfig { /// if the corresponding value in this config is not set. pub fn merge(&mut self, other: Option) { let Some(other) = other else { return }; - - // Merge block_interval - if self.block_interval == 0 { - self.block_interval = other.block_interval; + let Self { + block_interval, + segments: + PruneModes { + sender_recovery, + transaction_lookup, + receipts, + account_history, + storage_history, + receipts_log_filter, + }, + } = other; + + // Merge block_interval, only update if it's the default interval + if self.block_interval == DEFAULT_BLOCK_INTERVAL { + self.block_interval = block_interval; } // Merge the various segment prune modes - self.segments.sender_recovery = - self.segments.sender_recovery.or(other.segments.sender_recovery); - self.segments.transaction_lookup = - self.segments.transaction_lookup.or(other.segments.transaction_lookup); - self.segments.receipts = self.segments.receipts.or(other.segments.receipts); - self.segments.account_history = - self.segments.account_history.or(other.segments.account_history); - self.segments.storage_history = - self.segments.storage_history.or(other.segments.storage_history); - - if self.segments.receipts_log_filter.0.is_empty() && - !other.segments.receipts_log_filter.0.is_empty() - { - self.segments.receipts_log_filter = other.segments.receipts_log_filter; + self.segments.sender_recovery = self.segments.sender_recovery.or(sender_recovery); + self.segments.transaction_lookup = self.segments.transaction_lookup.or(transaction_lookup); + self.segments.receipts = self.segments.receipts.or(receipts); + self.segments.account_history = self.segments.account_history.or(account_history); + self.segments.storage_history = self.segments.storage_history.or(storage_history); + + if self.segments.receipts_log_filter.0.is_empty() && !receipts_log_filter.0.is_empty() { + self.segments.receipts_log_filter = receipts_log_filter; } } } @@ -961,7 +970,7 @@ receipts = 'full' // Check that the configuration has been merged. Any configuration present in config1 // should not be overwritten by config2 - assert_eq!(config1.block_interval, 5); + assert_eq!(config1.block_interval, 10); assert_eq!(config1.segments.sender_recovery, Some(PruneMode::Full)); assert_eq!(config1.segments.transaction_lookup, Some(PruneMode::Full)); assert_eq!(config1.segments.receipts, Some(PruneMode::Distance(1000))); diff --git a/crates/node/core/src/args/pruning.rs b/crates/node/core/src/args/pruning.rs index c0a3ae375c0a..cd852b9e1685 100644 --- a/crates/node/core/src/args/pruning.rs +++ b/crates/node/core/src/args/pruning.rs @@ -2,7 +2,7 @@ use crate::args::error::ReceiptsLogError; use alloy_primitives::{Address, BlockNumber}; -use clap::Args; +use clap::{builder::RangedU64ValueParser, Args}; use reth_chainspec::EthChainSpec; use reth_config::config::PruneConfig; use reth_prune_types::{PruneMode, PruneModes, ReceiptsLogPruneConfig, MINIMUM_PRUNING_DISTANCE}; @@ -17,7 +17,7 @@ pub struct PruningArgs { pub full: bool, /// Minimum pruning interval measured in blocks. - #[arg(long, default_value = None)] + #[arg(long, value_parser = RangedU64ValueParser::::new().range(1..),)] pub block_interval: Option, // Sender Recovery @@ -99,7 +99,7 @@ impl PruningArgs { // If --full is set, use full node defaults. if self.full { config = PruneConfig { - block_interval: 5, + block_interval: config.block_interval, segments: PruneModes { sender_recovery: Some(PruneMode::Full), transaction_lookup: None, @@ -123,6 +123,9 @@ impl PruningArgs { } // Override with any explicitly set prune.* flags. + if let Some(block_interval) = self.block_interval { + config.block_interval = block_interval as usize; + } if let Some(mode) = self.sender_recovery_prune_mode() { config.segments.sender_recovery = Some(mode); } From 5a82f20a294c817d7070ad8fa0118a18400f7b63 Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Thu, 17 Oct 2024 00:03:33 +0200 Subject: [PATCH 040/113] chore: rm 1 usage of optimism feature (#11813) --- crates/storage/codecs/src/alloy/transaction/mod.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/crates/storage/codecs/src/alloy/transaction/mod.rs b/crates/storage/codecs/src/alloy/transaction/mod.rs index 86edfee5bcca..5b1d173a528e 100644 --- a/crates/storage/codecs/src/alloy/transaction/mod.rs +++ b/crates/storage/codecs/src/alloy/transaction/mod.rs @@ -15,8 +15,6 @@ mod tests { // this check is to ensure we do not inadvertently add too many fields to a struct which would // expand the flags field and break backwards compatibility - #[cfg(feature = "optimism")] - use crate::alloy::transaction::optimism::TxDeposit; use crate::alloy::transaction::{ eip1559::TxEip1559, eip2930::TxEip2930, eip4844::TxEip4844, eip7702::TxEip7702, legacy::TxLegacy, @@ -34,6 +32,6 @@ mod tests { #[cfg(feature = "optimism")] #[test] fn test_ensure_backwards_compatibility_optimism() { - assert_eq!(TxDeposit::bitflag_encoded_bytes(), 2); + assert_eq!(crate::alloy::transaction::optimism::TxDeposit::bitflag_encoded_bytes(), 2); } } From 025cb3b70e02ee99295a5f98a117906d2938c42d Mon Sep 17 00:00:00 2001 From: Thomas Coratger <60488569+tcoratger@users.noreply.github.com> Date: Thu, 17 Oct 2024 00:07:27 +0200 Subject: [PATCH 041/113] primitive-traits: rm redundant `EMPTY_ROOT_HASH` definition (#11811) Co-authored-by: Matthias Seitz --- Cargo.lock | 2 ++ crates/blockchain-tree/src/blockchain_tree.rs | 4 ++-- crates/chain-state/src/test_utils.rs | 4 ++-- crates/ethereum/evm/src/execute.rs | 5 ++--- crates/primitives-traits/src/constants/mod.rs | 5 +---- crates/primitives/src/proofs.rs | 3 ++- crates/rpc/rpc-eth-api/src/helpers/pending_block.rs | 3 ++- crates/trie/db/Cargo.toml | 2 ++ crates/trie/db/tests/proof.rs | 3 ++- crates/trie/db/tests/trie.rs | 3 ++- crates/trie/db/tests/witness.rs | 3 ++- crates/trie/trie/Cargo.toml | 1 + crates/trie/trie/src/trie.rs | 2 +- crates/trie/trie/src/witness.rs | 2 +- 14 files changed, 24 insertions(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index aa7c704b462e..bb2577577f83 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9119,6 +9119,7 @@ dependencies = [ name = "reth-trie" version = "1.1.0" dependencies = [ + "alloy-consensus", "alloy-primitives", "alloy-rlp", "auto_impl", @@ -9174,6 +9175,7 @@ dependencies = [ name = "reth-trie-db" version = "1.1.0" dependencies = [ + "alloy-consensus", "alloy-primitives", "alloy-rlp", "auto_impl", diff --git a/crates/blockchain-tree/src/blockchain_tree.rs b/crates/blockchain-tree/src/blockchain_tree.rs index 4bed718aa0a6..71a58aa56288 100644 --- a/crates/blockchain-tree/src/blockchain_tree.rs +++ b/crates/blockchain-tree/src/blockchain_tree.rs @@ -1376,7 +1376,7 @@ where #[cfg(test)] mod tests { use super::*; - use alloy_consensus::TxEip1559; + use alloy_consensus::{TxEip1559, EMPTY_ROOT_HASH}; use alloy_genesis::{Genesis, GenesisAccount}; use alloy_primitives::{keccak256, Address, Sealable, B256}; use assert_matches::assert_matches; @@ -1388,7 +1388,7 @@ mod tests { use reth_evm::test_utils::MockExecutorProvider; use reth_evm_ethereum::execute::EthExecutorProvider; use reth_primitives::{ - constants::{EIP1559_INITIAL_BASE_FEE, EMPTY_ROOT_HASH}, + constants::EIP1559_INITIAL_BASE_FEE, proofs::{calculate_receipt_root, calculate_transaction_root}, revm_primitives::AccountInfo, Account, BlockBody, Header, Signature, Transaction, TransactionSigned, diff --git a/crates/chain-state/src/test_utils.rs b/crates/chain-state/src/test_utils.rs index ad5f2dbdbcc2..a820bb5cf018 100644 --- a/crates/chain-state/src/test_utils.rs +++ b/crates/chain-state/src/test_utils.rs @@ -2,7 +2,7 @@ use crate::{ in_memory::ExecutedBlock, CanonStateNotification, CanonStateNotifications, CanonStateSubscriptions, }; -use alloy_consensus::{Transaction as _, TxEip1559}; +use alloy_consensus::{Transaction as _, TxEip1559, EMPTY_ROOT_HASH}; use alloy_primitives::{Address, BlockNumber, Sealable, B256, U256}; use alloy_signer::SignerSync; use alloy_signer_local::PrivateKeySigner; @@ -10,7 +10,7 @@ use rand::{thread_rng, Rng}; use reth_chainspec::{ChainSpec, EthereumHardfork, MIN_TRANSACTION_GAS}; use reth_execution_types::{Chain, ExecutionOutcome}; use reth_primitives::{ - constants::{EIP1559_INITIAL_BASE_FEE, EMPTY_ROOT_HASH}, + constants::EIP1559_INITIAL_BASE_FEE, proofs::{calculate_receipt_root, calculate_transaction_root, calculate_withdrawals_root}, BlockBody, Header, Receipt, Receipts, Requests, SealedBlock, SealedBlockWithSenders, SealedHeader, Transaction, TransactionSigned, TransactionSignedEcRecovered, diff --git a/crates/ethereum/evm/src/execute.rs b/crates/ethereum/evm/src/execute.rs index f712389fe121..9c7748a561f0 100644 --- a/crates/ethereum/evm/src/execute.rs +++ b/crates/ethereum/evm/src/execute.rs @@ -494,7 +494,7 @@ where #[cfg(test)] mod tests { use super::*; - use alloy_consensus::TxLegacy; + use alloy_consensus::{TxLegacy, EMPTY_ROOT_HASH}; use alloy_eips::{ eip2935::{HISTORY_STORAGE_ADDRESS, HISTORY_STORAGE_CODE}, eip4788::{BEACON_ROOTS_ADDRESS, BEACON_ROOTS_CODE, SYSTEM_ADDRESS}, @@ -503,8 +503,7 @@ mod tests { use alloy_primitives::{b256, fixed_bytes, keccak256, Bytes, TxKind, B256}; use reth_chainspec::{ChainSpecBuilder, ForkCondition}; use reth_primitives::{ - constants::{EMPTY_ROOT_HASH, ETH_TO_WEI}, - public_key_to_address, Account, Block, BlockBody, Transaction, + constants::ETH_TO_WEI, public_key_to_address, Account, Block, BlockBody, Transaction, }; use reth_revm::{ database::StateProviderDatabase, test_utils::StateProviderTest, TransitionState, diff --git a/crates/primitives-traits/src/constants/mod.rs b/crates/primitives-traits/src/constants/mod.rs index ed5c893dd6c2..d40abdd64ba7 100644 --- a/crates/primitives-traits/src/constants/mod.rs +++ b/crates/primitives-traits/src/constants/mod.rs @@ -1,5 +1,6 @@ //! Ethereum protocol-related constants +use alloy_consensus::EMPTY_ROOT_HASH; use alloy_primitives::{address, b256, Address, B256, U256}; use core::time::Duration; @@ -122,10 +123,6 @@ pub const KECCAK_EMPTY: B256 = pub const EMPTY_OMMER_ROOT_HASH: B256 = b256!("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"); -/// Root hash of an empty trie: `0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421` -pub const EMPTY_ROOT_HASH: B256 = - b256!("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"); - /// From address from Optimism system txs: `0xdeaddeaddeaddeaddeaddeaddeaddeaddead0001` pub const OP_SYSTEM_TX_FROM_ADDR: Address = address!("deaddeaddeaddeaddeaddeaddeaddeaddead0001"); diff --git a/crates/primitives/src/proofs.rs b/crates/primitives/src/proofs.rs index a12a5d6be89f..dc814804ec81 100644 --- a/crates/primitives/src/proofs.rs +++ b/crates/primitives/src/proofs.rs @@ -65,7 +65,8 @@ pub fn calculate_ommers_root(ommers: &[Header]) -> B256 { #[cfg(test)] mod tests { use super::*; - use crate::{constants::EMPTY_ROOT_HASH, Block}; + use crate::Block; + use alloy_consensus::EMPTY_ROOT_HASH; use alloy_genesis::GenesisAccount; use alloy_primitives::{b256, hex_literal::hex, Address, U256}; use alloy_rlp::Decodable; diff --git a/crates/rpc/rpc-eth-api/src/helpers/pending_block.rs b/crates/rpc/rpc-eth-api/src/helpers/pending_block.rs index 26e0ffc7412a..81c6a567846b 100644 --- a/crates/rpc/rpc-eth-api/src/helpers/pending_block.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/pending_block.rs @@ -5,6 +5,7 @@ use std::time::{Duration, Instant}; use crate::{EthApiTypes, FromEthApiError, FromEvmError}; +use alloy_consensus::EMPTY_ROOT_HASH; use alloy_primitives::{BlockNumber, B256, U256}; use alloy_rpc_types::BlockNumberOrTag; use futures::Future; @@ -12,7 +13,7 @@ use reth_chainspec::{EthChainSpec, EthereumHardforks}; use reth_evm::{system_calls::SystemCaller, ConfigureEvm, ConfigureEvmEnv}; use reth_execution_types::ExecutionOutcome; use reth_primitives::{ - constants::{eip4844::MAX_DATA_GAS_PER_BLOCK, BEACON_NONCE, EMPTY_ROOT_HASH}, + constants::{eip4844::MAX_DATA_GAS_PER_BLOCK, BEACON_NONCE}, proofs::calculate_transaction_root, revm_primitives::{ BlockEnv, CfgEnv, CfgEnvWithHandlerCfg, EVMError, Env, ExecutionResult, InvalidTransaction, diff --git a/crates/trie/db/Cargo.toml b/crates/trie/db/Cargo.toml index 6d322ba3ff67..a0e1acbce352 100644 --- a/crates/trie/db/Cargo.toml +++ b/crates/trie/db/Cargo.toml @@ -58,6 +58,8 @@ reth-trie-common = { workspace = true, features = ["test-utils", "arbitrary"] } reth-trie = { workspace = true, features = ["test-utils"] } reth-node-types.workspace = true +alloy-consensus.workspace = true + # trie triehash = "0.8" diff --git a/crates/trie/db/tests/proof.rs b/crates/trie/db/tests/proof.rs index 5ffa6729b49a..79a2ce96fced 100644 --- a/crates/trie/db/tests/proof.rs +++ b/crates/trie/db/tests/proof.rs @@ -1,9 +1,10 @@ #![allow(missing_docs)] +use alloy_consensus::EMPTY_ROOT_HASH; use alloy_primitives::{keccak256, Address, Bytes, B256, U256}; use alloy_rlp::EMPTY_STRING_CODE; use reth_chainspec::{Chain, ChainSpec, HOLESKY, MAINNET}; -use reth_primitives::{constants::EMPTY_ROOT_HASH, Account}; +use reth_primitives::Account; use reth_provider::test_utils::{create_test_provider_factory, insert_genesis}; use reth_trie::{proof::Proof, Nibbles}; use reth_trie_common::{AccountProof, StorageProof}; diff --git a/crates/trie/db/tests/trie.rs b/crates/trie/db/tests/trie.rs index 59fffec58d06..f5823404c899 100644 --- a/crates/trie/db/tests/trie.rs +++ b/crates/trie/db/tests/trie.rs @@ -1,5 +1,6 @@ #![allow(missing_docs)] +use alloy_consensus::EMPTY_ROOT_HASH; use alloy_primitives::{hex_literal::hex, keccak256, Address, B256, U256}; use proptest::{prelude::ProptestConfig, proptest}; use proptest_arbitrary_interop::arb; @@ -8,7 +9,7 @@ use reth_db_api::{ cursor::{DbCursorRO, DbCursorRW, DbDupCursorRO}, transaction::DbTxMut, }; -use reth_primitives::{constants::EMPTY_ROOT_HASH, Account, StorageEntry}; +use reth_primitives::{Account, StorageEntry}; use reth_provider::{ test_utils::create_test_provider_factory, DatabaseProviderRW, StorageTrieWriter, TrieWriter, }; diff --git a/crates/trie/db/tests/witness.rs b/crates/trie/db/tests/witness.rs index 20f8cfbb9081..8e00472b4738 100644 --- a/crates/trie/db/tests/witness.rs +++ b/crates/trie/db/tests/witness.rs @@ -1,5 +1,6 @@ #![allow(missing_docs)] +use alloy_consensus::EMPTY_ROOT_HASH; use alloy_primitives::{ keccak256, map::{HashMap, HashSet}, @@ -8,7 +9,7 @@ use alloy_primitives::{ use alloy_rlp::EMPTY_STRING_CODE; use reth_db::{cursor::DbCursorRW, tables}; use reth_db_api::transaction::DbTxMut; -use reth_primitives::{constants::EMPTY_ROOT_HASH, Account, StorageEntry}; +use reth_primitives::{Account, StorageEntry}; use reth_provider::{test_utils::create_test_provider_factory, HashingWriter}; use reth_trie::{proof::Proof, witness::TrieWitness, HashedPostState, HashedStorage, StateRoot}; use reth_trie_db::{DatabaseProof, DatabaseStateRoot, DatabaseTrieWitness}; diff --git a/crates/trie/trie/Cargo.toml b/crates/trie/trie/Cargo.toml index d0f0fa092a77..31b5ac3e25cd 100644 --- a/crates/trie/trie/Cargo.toml +++ b/crates/trie/trie/Cargo.toml @@ -24,6 +24,7 @@ revm.workspace = true # alloy alloy-rlp.workspace = true alloy-primitives.workspace = true +alloy-consensus.workspace = true # tracing tracing.workspace = true diff --git a/crates/trie/trie/src/trie.rs b/crates/trie/trie/src/trie.rs index b8aa133d6fa3..1bf8cf1ce797 100644 --- a/crates/trie/trie/src/trie.rs +++ b/crates/trie/trie/src/trie.rs @@ -9,10 +9,10 @@ use crate::{ walker::TrieWalker, HashBuilder, Nibbles, TrieAccount, }; +use alloy_consensus::EMPTY_ROOT_HASH; use alloy_primitives::{keccak256, Address, B256}; use alloy_rlp::{BufMut, Encodable}; use reth_execution_errors::{StateRootError, StorageRootError}; -use reth_primitives::constants::EMPTY_ROOT_HASH; use tracing::trace; #[cfg(feature = "metrics")] diff --git a/crates/trie/trie/src/witness.rs b/crates/trie/trie/src/witness.rs index f3b70e85ad6f..39d82a7bda7a 100644 --- a/crates/trie/trie/src/witness.rs +++ b/crates/trie/trie/src/witness.rs @@ -5,6 +5,7 @@ use crate::{ trie_cursor::TrieCursorFactory, HashedPostState, }; +use alloy_consensus::EMPTY_ROOT_HASH; use alloy_primitives::{ keccak256, map::{HashMap, HashSet}, @@ -13,7 +14,6 @@ use alloy_primitives::{ use alloy_rlp::{BufMut, Decodable, Encodable}; use itertools::{Either, Itertools}; use reth_execution_errors::{StateProofError, TrieWitnessError}; -use reth_primitives::constants::EMPTY_ROOT_HASH; use reth_trie_common::{ BranchNode, HashBuilder, Nibbles, StorageMultiProof, TrieAccount, TrieNode, CHILD_INDEX_RANGE, }; From 24287e8562ab5e70d473e0c0b87f800277a84d8a Mon Sep 17 00:00:00 2001 From: Thomas Coratger <60488569+tcoratger@users.noreply.github.com> Date: Thu, 17 Oct 2024 01:02:44 +0200 Subject: [PATCH 042/113] primitives: use `EMPTY_ROOT_HASH` when possible (#11822) --- Cargo.lock | 1 + crates/chainspec/src/spec.rs | 4 +--- crates/consensus/common/src/validation.rs | 6 ++--- crates/net/eth-wire-types/src/header.rs | 28 ++++++----------------- crates/optimism/primitives/Cargo.toml | 1 + crates/optimism/primitives/src/bedrock.rs | 5 ++-- 6 files changed, 16 insertions(+), 29 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bb2577577f83..740810d1b1b8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8227,6 +8227,7 @@ dependencies = [ name = "reth-optimism-primitives" version = "1.1.0" dependencies = [ + "alloy-consensus", "alloy-primitives", "reth-primitives", "reth-primitives-traits", diff --git a/crates/chainspec/src/spec.rs b/crates/chainspec/src/spec.rs index e6e8a67d75d3..a8bae966b58e 100644 --- a/crates/chainspec/src/spec.rs +++ b/crates/chainspec/src/spec.rs @@ -1814,9 +1814,7 @@ Post-merge hard forks (timestamp based): hex!("078dc6061b1d8eaa8493384b59c9c65ceb917201221d08b80c4de6770b6ec7e7").into(); assert_eq!(chainspec.genesis_header().state_root, expected_state_root); - let expected_withdrawals_hash: B256 = - hex!("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421").into(); - assert_eq!(chainspec.genesis_header().withdrawals_root, Some(expected_withdrawals_hash)); + assert_eq!(chainspec.genesis_header().withdrawals_root, Some(EMPTY_ROOT_HASH)); let expected_hash: B256 = hex!("1fc027d65f820d3eef441ebeec139ebe09e471cf98516dce7b5643ccb27f418c").into(); diff --git a/crates/consensus/common/src/validation.rs b/crates/consensus/common/src/validation.rs index 88a4cabe96c5..df66a00d1dfe 100644 --- a/crates/consensus/common/src/validation.rs +++ b/crates/consensus/common/src/validation.rs @@ -300,7 +300,7 @@ pub fn validate_against_parent_4844( #[cfg(test)] mod tests { use super::*; - use alloy_consensus::TxEip4844; + use alloy_consensus::{TxEip4844, EMPTY_ROOT_HASH}; use alloy_primitives::{ hex_literal::hex, Address, BlockHash, BlockNumber, Bytes, Parity, Sealable, U256, }; @@ -444,8 +444,8 @@ mod tests { ommers_hash: hex!("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347").into(), beneficiary: hex!("4675c7e5baafbffbca748158becba61ef3b0a263").into(), state_root: hex!("8337403406e368b3e40411138f4868f79f6d835825d55fd0c2f6e17b1a3948e9").into(), - transactions_root: hex!("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421").into(), - receipts_root: hex!("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421").into(), + transactions_root: EMPTY_ROOT_HASH, + receipts_root: EMPTY_ROOT_HASH, logs_bloom: hex!("002400000000004000220000800002000000000000000000000000000000100000000000000000100000000000000021020000000800000006000000002100040000000c0004000000000008000008200000000000000000000000008000000001040000020000020000002000000800000002000020000000022010000000000000010002001000000000020200000000000001000200880000004000000900020000000000020000000040000000000000000000000000000080000000000001000002000000000000012000200020000000000000001000000000000020000010321400000000100000000000000000000000000000400000000000000000").into(), difficulty: U256::ZERO, // total difficulty: 0xc70d815d562d3cfa955).into(), number: 0xf21d20, diff --git a/crates/net/eth-wire-types/src/header.rs b/crates/net/eth-wire-types/src/header.rs index 4075a4a92fb7..7ecfc802d8a8 100644 --- a/crates/net/eth-wire-types/src/header.rs +++ b/crates/net/eth-wire-types/src/header.rs @@ -87,6 +87,7 @@ impl From for bool { #[cfg(test)] mod tests { use super::*; + use alloy_consensus::EMPTY_ROOT_HASH; use alloy_primitives::{address, b256, bloom, bytes, hex, Address, Bytes, B256, U256}; use alloy_rlp::{Decodable, Encodable}; use reth_primitives::Header; @@ -201,10 +202,7 @@ mod tests { gas_used: 0x0125b8, timestamp: 0x079e, extra_data: Bytes::from_str("42").unwrap(), - mix_hash: B256::from_str( - "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - ) - .unwrap(), + mix_hash: EMPTY_ROOT_HASH, base_fee_per_gas: Some(0x09), withdrawals_root: Some( B256::from_str("27f166f1d7c789251299535cb176ba34116e44894476a7886fe5d73d9be5c973") @@ -254,16 +252,10 @@ mod tests { gas_used: 0x02a865, timestamp: 0x079e, extra_data: Bytes::from(vec![0x42]), - mix_hash: B256::from_str( - "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - ) - .unwrap(), + mix_hash: EMPTY_ROOT_HASH, nonce: 0u64.into(), base_fee_per_gas: Some(9), - withdrawals_root: Some( - B256::from_str("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421") - .unwrap(), - ), + withdrawals_root: Some(EMPTY_ROOT_HASH), blob_gas_used: Some(0x020000), excess_blob_gas: Some(0), parent_beacon_block_root: None, @@ -291,12 +283,8 @@ mod tests { ommers_hash: b256!("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"), beneficiary: address!("f97e180c050e5ab072211ad2c213eb5aee4df134"), state_root: b256!("ec229dbe85b0d3643ad0f471e6ec1a36bbc87deffbbd970762d22a53b35d068a"), - transactions_root: b256!( - "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421" - ), - receipts_root: b256!( - "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421" - ), + transactions_root: EMPTY_ROOT_HASH, + receipts_root: EMPTY_ROOT_HASH, logs_bloom: Default::default(), difficulty: U256::from(0), number: 0x30598, @@ -307,9 +295,7 @@ mod tests { mix_hash: b256!("70ccadc40b16e2094954b1064749cc6fbac783c1712f1b271a8aac3eda2f2325"), nonce: 0u64.into(), base_fee_per_gas: Some(7), - withdrawals_root: Some(b256!( - "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421" - )), + withdrawals_root: Some(EMPTY_ROOT_HASH), parent_beacon_block_root: None, blob_gas_used: Some(0), excess_blob_gas: Some(0x1600000), diff --git a/crates/optimism/primitives/Cargo.toml b/crates/optimism/primitives/Cargo.toml index 73a3bab1e445..2054de7305ba 100644 --- a/crates/optimism/primitives/Cargo.toml +++ b/crates/optimism/primitives/Cargo.toml @@ -15,3 +15,4 @@ workspace = true reth-primitives.workspace = true reth-primitives-traits.workspace = true alloy-primitives.workspace = true +alloy-consensus.workspace = true diff --git a/crates/optimism/primitives/src/bedrock.rs b/crates/optimism/primitives/src/bedrock.rs index 4ece12ad679e..1a347aecafe9 100644 --- a/crates/optimism/primitives/src/bedrock.rs +++ b/crates/optimism/primitives/src/bedrock.rs @@ -1,5 +1,6 @@ //! OP mainnet bedrock related data. +use alloy_consensus::EMPTY_ROOT_HASH; use alloy_primitives::{address, b256, bloom, bytes, B256, B64, U256}; use reth_primitives::Header; use reth_primitives_traits::constants::EMPTY_OMMER_ROOT_HASH; @@ -73,10 +74,10 @@ pub const BEDROCK_HEADER: Header = Header { nonce: B64::ZERO, number: 105235063, parent_hash: b256!("21a168dfa5e727926063a28ba16fd5ee84c814e847c81a699c7a0ea551e4ca50"), - receipts_root: b256!("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"), + receipts_root: EMPTY_ROOT_HASH, state_root: b256!("920314c198da844a041d63bf6cbe8b59583165fd2229d1b3f599da812fd424cb"), timestamp: 1686068903, - transactions_root: b256!("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"), + transactions_root: EMPTY_ROOT_HASH, ommers_hash: EMPTY_OMMER_ROOT_HASH, beneficiary: address!("4200000000000000000000000000000000000011"), withdrawals_root: None, From 1b97b1d942c671831bb81c0ccc53a9018c9febc5 Mon Sep 17 00:00:00 2001 From: joshieDo <93316087+joshieDo@users.noreply.github.com> Date: Thu, 17 Oct 2024 12:00:25 +0900 Subject: [PATCH 043/113] fix(staged-sync): prevent `StaticFileProducer` from running with an unwinded target on legacy engine (#11717) --- .../beacon/src/engine/hooks/static_file.rs | 18 +++++++++++++----- crates/stages/api/src/pipeline/mod.rs | 4 ++++ .../static-file/src/static_file_producer.rs | 14 ++++++++++++-- 3 files changed, 29 insertions(+), 7 deletions(-) diff --git a/crates/consensus/beacon/src/engine/hooks/static_file.rs b/crates/consensus/beacon/src/engine/hooks/static_file.rs index 8a5a28f95741..89231ed55825 100644 --- a/crates/consensus/beacon/src/engine/hooks/static_file.rs +++ b/crates/consensus/beacon/src/engine/hooks/static_file.rs @@ -9,7 +9,8 @@ use futures::FutureExt; use reth_errors::RethResult; use reth_primitives::static_file::HighestStaticFiles; use reth_provider::{ - BlockReader, DatabaseProviderFactory, StageCheckpointReader, StaticFileProviderFactory, + BlockReader, ChainStateBlockReader, DatabaseProviderFactory, StageCheckpointReader, + StaticFileProviderFactory, }; use reth_static_file::{StaticFileProducer, StaticFileProducerWithResult}; use reth_tasks::TaskSpawner; @@ -31,8 +32,9 @@ pub struct StaticFileHook { impl StaticFileHook where Provider: StaticFileProviderFactory - + DatabaseProviderFactory - + 'static, + + DatabaseProviderFactory< + Provider: StageCheckpointReader + BlockReader + ChainStateBlockReader, + > + 'static, { /// Create a new instance pub fn new( @@ -104,6 +106,11 @@ where return Ok(None) }; + let finalized_block_number = locked_static_file_producer + .last_finalized_block()? + .map(|on_disk| finalized_block_number.min(on_disk)) + .unwrap_or(finalized_block_number); + let targets = locked_static_file_producer.get_static_file_targets(HighestStaticFiles { headers: Some(finalized_block_number), @@ -137,8 +144,9 @@ where impl EngineHook for StaticFileHook where Provider: StaticFileProviderFactory - + DatabaseProviderFactory - + 'static, + + DatabaseProviderFactory< + Provider: StageCheckpointReader + BlockReader + ChainStateBlockReader, + > + 'static, { fn name(&self) -> &'static str { "StaticFile" diff --git a/crates/stages/api/src/pipeline/mod.rs b/crates/stages/api/src/pipeline/mod.rs index 1f6d9341ad6d..14225a595285 100644 --- a/crates/stages/api/src/pipeline/mod.rs +++ b/crates/stages/api/src/pipeline/mod.rs @@ -276,6 +276,10 @@ impl Pipeline { // Unwind stages in reverse order of execution let unwind_pipeline = self.stages.iter_mut().rev(); + // Legacy Engine: This prevents a race condition in which the `StaticFileProducer` could + // attempt to proceed with a finalized block which has been unwinded + let _locked_sf_producer = self.static_file_producer.lock(); + let mut provider_rw = self.provider_factory.database_provider_rw()?; for stage in unwind_pipeline { diff --git a/crates/static-file/static-file/src/static_file_producer.rs b/crates/static-file/static-file/src/static_file_producer.rs index 32565fd6dfa6..2c442aedfa34 100644 --- a/crates/static-file/static-file/src/static_file_producer.rs +++ b/crates/static-file/static-file/src/static_file_producer.rs @@ -5,8 +5,8 @@ use alloy_primitives::BlockNumber; use parking_lot::Mutex; use rayon::prelude::*; use reth_provider::{ - providers::StaticFileWriter, BlockReader, DBProvider, DatabaseProviderFactory, - StageCheckpointReader, StaticFileProviderFactory, + providers::StaticFileWriter, BlockReader, ChainStateBlockReader, DBProvider, + DatabaseProviderFactory, StageCheckpointReader, StaticFileProviderFactory, }; use reth_prune_types::PruneModes; use reth_stages_types::StageId; @@ -106,6 +106,16 @@ impl StaticFileProducerInner { } } +impl StaticFileProducerInner +where + Provider: StaticFileProviderFactory + DatabaseProviderFactory, +{ + /// Returns the last finalized block number on disk. + pub fn last_finalized_block(&self) -> ProviderResult> { + self.provider.database_provider_ro()?.last_finalized_block_number() + } +} + impl StaticFileProducerInner where Provider: StaticFileProviderFactory From b57a5607cbc47f4995fa567c27351f342e08147e Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Thu, 17 Oct 2024 05:05:26 +0200 Subject: [PATCH 044/113] test: make provider compile with cargo t (#11817) --- crates/storage/provider/Cargo.toml | 2 ++ .../provider/src/providers/blockchain_provider.rs | 9 ++------- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/crates/storage/provider/Cargo.toml b/crates/storage/provider/Cargo.toml index 7ef827a37042..00e1c9f098df 100644 --- a/crates/storage/provider/Cargo.toml +++ b/crates/storage/provider/Cargo.toml @@ -73,8 +73,10 @@ rayon.workspace = true [dev-dependencies] reth-db = { workspace = true, features = ["test-utils"] } reth-primitives = { workspace = true, features = ["arbitrary", "test-utils"] } +reth-chain-state = { workspace = true, features = ["test-utils"] } reth-trie = { workspace = true, features = ["test-utils"] } reth-testing-utils.workspace = true +reth-ethereum-engine-primitives.workspace = true parking_lot.workspace = true tempfile.workspace = true diff --git a/crates/storage/provider/src/providers/blockchain_provider.rs b/crates/storage/provider/src/providers/blockchain_provider.rs index 3013be0603c8..9e6f32b33a3b 100644 --- a/crates/storage/provider/src/providers/blockchain_provider.rs +++ b/crates/storage/provider/src/providers/blockchain_provider.rs @@ -1933,7 +1933,7 @@ mod tests { /// This simulates a RPC method having a different view than when its database transaction was /// created. fn persist_block_after_db_tx_creation( - provider: Arc>, + provider: BlockchainProvider2, block_number: BlockNumber, ) { let hook_provider = provider.clone(); @@ -3142,7 +3142,6 @@ mod tests { ..Default::default() }, )?; - let provider = Arc::new(provider); $( // Since data moves for each tried method, need to recalculate everything @@ -3257,7 +3256,6 @@ mod tests { ..Default::default() }, )?; - let provider = Arc::new(provider); $( // Since data moves for each tried method, need to recalculate everything @@ -3383,7 +3381,6 @@ mod tests { ..Default::default() }, )?; - let provider = Arc::new(provider); let mut in_memory_blocks: std::collections::VecDeque<_> = in_memory_blocks.into(); @@ -3685,8 +3682,6 @@ mod tests { }, )?; - let provider = Arc::new(provider); - // Old implementation was querying the database first. This is problematic, if there are // changes AFTER the database transaction is created. let old_transaction_hash_fn = @@ -3739,7 +3734,7 @@ mod tests { correct_transaction_hash_fn( to_be_persisted_tx.hash(), provider.canonical_in_memory_state(), - provider.database.clone() + provider.database ), Ok(Some(to_be_persisted_tx)) ); From e828b34ed1332832bcebb421a98684a894c49993 Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Thu, 17 Oct 2024 05:06:23 +0200 Subject: [PATCH 045/113] chore: rm features from test utils (#11816) --- .../storage/provider/src/test_utils/blocks.rs | 140 +++++++++--------- 1 file changed, 70 insertions(+), 70 deletions(-) diff --git a/crates/storage/provider/src/test_utils/blocks.rs b/crates/storage/provider/src/test_utils/blocks.rs index e6a88618792d..57e111d674ba 100644 --- a/crates/storage/provider/src/test_utils/blocks.rs +++ b/crates/storage/provider/src/test_utils/blocks.rs @@ -201,20 +201,20 @@ fn block1(number: BlockNumber) -> (SealedBlockWithSenders, ExecutionOutcome) { .revert_account_info(number, account2, Some(None)) .state_storage(account1, HashMap::from_iter([(slot, (U256::ZERO, U256::from(10)))])) .build(), - vec![vec![Some(Receipt { - tx_type: TxType::Eip2930, - success: true, - cumulative_gas_used: 300, - logs: vec![Log::new_unchecked( - Address::new([0x60; 20]), - vec![B256::with_last_byte(1), B256::with_last_byte(2)], - Bytes::default(), - )], - #[cfg(feature = "optimism")] - deposit_nonce: None, - #[cfg(feature = "optimism")] - deposit_receipt_version: None, - })]] + vec![vec![Some( + #[allow(clippy::needless_update)] // side-effect of optimism fields + Receipt { + tx_type: TxType::Eip2930, + success: true, + cumulative_gas_used: 300, + logs: vec![Log::new_unchecked( + Address::new([0x60; 20]), + vec![B256::with_last_byte(1), B256::with_last_byte(2)], + Bytes::default(), + )], + ..Default::default() + }, + )]] .into(), number, Vec::new(), @@ -263,20 +263,20 @@ fn block2( ) .revert_storage(number, account, Vec::from([(slot, U256::from(10))])) .build(), - vec![vec![Some(Receipt { - tx_type: TxType::Eip1559, - success: false, - cumulative_gas_used: 400, - logs: vec![Log::new_unchecked( - Address::new([0x61; 20]), - vec![B256::with_last_byte(3), B256::with_last_byte(4)], - Bytes::default(), - )], - #[cfg(feature = "optimism")] - deposit_nonce: None, - #[cfg(feature = "optimism")] - deposit_receipt_version: None, - })]] + vec![vec![Some( + #[allow(clippy::needless_update)] // side-effect of optimism fields + Receipt { + tx_type: TxType::Eip1559, + success: false, + cumulative_gas_used: 400, + logs: vec![Log::new_unchecked( + Address::new([0x61; 20]), + vec![B256::with_last_byte(3), B256::with_last_byte(4)], + Bytes::default(), + )], + ..Default::default() + }, + )]] .into(), number, Vec::new(), @@ -334,20 +334,20 @@ fn block3( } let execution_outcome = ExecutionOutcome::new( bundle_state_builder.build(), - vec![vec![Some(Receipt { - tx_type: TxType::Eip1559, - success: true, - cumulative_gas_used: 400, - logs: vec![Log::new_unchecked( - Address::new([0x61; 20]), - vec![B256::with_last_byte(3), B256::with_last_byte(4)], - Bytes::default(), - )], - #[cfg(feature = "optimism")] - deposit_nonce: None, - #[cfg(feature = "optimism")] - deposit_receipt_version: None, - })]] + vec![vec![Some( + #[allow(clippy::needless_update)] // side-effect of optimism fields + Receipt { + tx_type: TxType::Eip1559, + success: true, + cumulative_gas_used: 400, + logs: vec![Log::new_unchecked( + Address::new([0x61; 20]), + vec![B256::with_last_byte(3), B256::with_last_byte(4)], + Bytes::default(), + )], + ..Default::default() + }, + )]] .into(), number, Vec::new(), @@ -425,20 +425,20 @@ fn block4( } let execution_outcome = ExecutionOutcome::new( bundle_state_builder.build(), - vec![vec![Some(Receipt { - tx_type: TxType::Eip1559, - success: true, - cumulative_gas_used: 400, - logs: vec![Log::new_unchecked( - Address::new([0x61; 20]), - vec![B256::with_last_byte(3), B256::with_last_byte(4)], - Bytes::default(), - )], - #[cfg(feature = "optimism")] - deposit_nonce: None, - #[cfg(feature = "optimism")] - deposit_receipt_version: None, - })]] + vec![vec![Some( + #[allow(clippy::needless_update)] // side-effect of optimism fields + Receipt { + tx_type: TxType::Eip1559, + success: true, + cumulative_gas_used: 400, + logs: vec![Log::new_unchecked( + Address::new([0x61; 20]), + vec![B256::with_last_byte(3), B256::with_last_byte(4)], + Bytes::default(), + )], + ..Default::default() + }, + )]] .into(), number, Vec::new(), @@ -513,20 +513,20 @@ fn block5( } let execution_outcome = ExecutionOutcome::new( bundle_state_builder.build(), - vec![vec![Some(Receipt { - tx_type: TxType::Eip1559, - success: true, - cumulative_gas_used: 400, - logs: vec![Log::new_unchecked( - Address::new([0x61; 20]), - vec![B256::with_last_byte(3), B256::with_last_byte(4)], - Bytes::default(), - )], - #[cfg(feature = "optimism")] - deposit_nonce: None, - #[cfg(feature = "optimism")] - deposit_receipt_version: None, - })]] + vec![vec![Some( + #[allow(clippy::needless_update)] // side-effect of optimism fields + Receipt { + tx_type: TxType::Eip1559, + success: true, + cumulative_gas_used: 400, + logs: vec![Log::new_unchecked( + Address::new([0x61; 20]), + vec![B256::with_last_byte(3), B256::with_last_byte(4)], + Bytes::default(), + )], + ..Default::default() + }, + )]] .into(), number, Vec::new(), From e3e83b7e71c7d9f6a34b9d7b407b72ca3eda9b4e Mon Sep 17 00:00:00 2001 From: Roman Krasiuk Date: Thu, 17 Oct 2024 10:03:25 +0200 Subject: [PATCH 046/113] docs(trie): revealed sparse trie invariants (#11825) --- crates/trie/sparse/src/trie.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/crates/trie/sparse/src/trie.rs b/crates/trie/sparse/src/trie.rs index 2edaaf76b274..d8f4280e875a 100644 --- a/crates/trie/sparse/src/trie.rs +++ b/crates/trie/sparse/src/trie.rs @@ -69,6 +69,13 @@ impl SparseTrie { } /// The representation of revealed sparse trie. +/// +/// ## Invariants +/// +/// - The root node is always present in `nodes` collection. +/// - Each leaf entry in `nodes` collection must have a corresponding entry in `values` collection. +/// The opposite is also true. +/// - All keys in `values` collection are full leaf paths. #[derive(PartialEq, Eq)] pub struct RevealedSparseTrie { /// All trie nodes. From 63a75fdd95ea71028d9d65c277a514f7e518676e Mon Sep 17 00:00:00 2001 From: Roman Krasiuk Date: Thu, 17 Oct 2024 10:07:45 +0200 Subject: [PATCH 047/113] fix(trie): intermediate trie node hashes (#11826) --- crates/trie/sparse/src/trie.rs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/crates/trie/sparse/src/trie.rs b/crates/trie/sparse/src/trie.rs index d8f4280e875a..e83522ca8904 100644 --- a/crates/trie/sparse/src/trie.rs +++ b/crates/trie/sparse/src/trie.rs @@ -345,9 +345,7 @@ impl RevealedSparseTrie { } else { let value = self.values.get(&path).unwrap(); let rlp_node = LeafNodeRef { key, value }.rlp(&mut self.rlp_buf); - if let Some(node_hash) = rlp_node.as_hash() { - *hash = Some(node_hash); - } + *hash = rlp_node.as_hash(); rlp_node } } @@ -360,9 +358,7 @@ impl RevealedSparseTrie { let (_, child) = rlp_node_stack.pop().unwrap(); self.rlp_buf.clear(); let rlp_node = ExtensionNodeRef::new(key, &child).rlp(&mut self.rlp_buf); - if let Some(node_hash) = rlp_node.as_hash() { - *hash = Some(node_hash); - } + *hash = rlp_node.as_hash(); rlp_node } else { path_stack.extend([path, child_path]); // need to get rlp node for child first @@ -400,9 +396,7 @@ impl RevealedSparseTrie { self.rlp_buf.clear(); let rlp_node = BranchNodeRef::new(&branch_value_stack_buf, *state_mask) .rlp(&mut self.rlp_buf); - if let Some(node_hash) = rlp_node.as_hash() { - *hash = Some(node_hash); - } + *hash = rlp_node.as_hash(); rlp_node } }; From 491f154c3437d36d3a8add91f76efce8eea28a63 Mon Sep 17 00:00:00 2001 From: Thomas Coratger <60488569+tcoratger@users.noreply.github.com> Date: Thu, 17 Oct 2024 11:30:26 +0200 Subject: [PATCH 048/113] primitives-traits: rm redundant definitions of `EMPTY_OMMER_ROOT_HASH` (#11820) --- Cargo.lock | 4 ++++ crates/ethereum/consensus/Cargo.toml | 1 + crates/ethereum/consensus/src/lib.rs | 2 +- crates/ethereum/payload/Cargo.toml | 1 + crates/ethereum/payload/src/lib.rs | 3 ++- crates/optimism/consensus/Cargo.toml | 1 + crates/optimism/consensus/src/lib.rs | 5 ++--- crates/optimism/payload/Cargo.toml | 1 + crates/optimism/payload/src/builder.rs | 3 ++- crates/optimism/primitives/src/bedrock.rs | 3 +-- crates/primitives-traits/src/constants/mod.rs | 4 ---- crates/primitives/src/lib.rs | 4 ++-- crates/primitives/src/proofs.rs | 4 ++-- crates/rpc/rpc-eth-api/src/helpers/pending_block.rs | 4 ++-- crates/rpc/rpc-types-compat/src/engine/payload.rs | 3 ++- 15 files changed, 24 insertions(+), 19 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 740810d1b1b8..e434e80cfde2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7270,6 +7270,7 @@ dependencies = [ name = "reth-ethereum-consensus" version = "1.1.0" dependencies = [ + "alloy-consensus", "alloy-primitives", "reth-chainspec", "reth-consensus", @@ -7320,6 +7321,7 @@ dependencies = [ name = "reth-ethereum-payload-builder" version = "1.1.0" dependencies = [ + "alloy-consensus", "alloy-primitives", "reth-basic-payload-builder", "reth-chain-state", @@ -8086,6 +8088,7 @@ dependencies = [ name = "reth-optimism-consensus" version = "1.1.0" dependencies = [ + "alloy-consensus", "alloy-primitives", "reth-chainspec", "reth-consensus", @@ -8194,6 +8197,7 @@ dependencies = [ name = "reth-optimism-payload-builder" version = "1.1.0" dependencies = [ + "alloy-consensus", "alloy-eips", "alloy-primitives", "alloy-rlp", diff --git a/crates/ethereum/consensus/Cargo.toml b/crates/ethereum/consensus/Cargo.toml index 02d217b63b27..af934d3e2b62 100644 --- a/crates/ethereum/consensus/Cargo.toml +++ b/crates/ethereum/consensus/Cargo.toml @@ -19,5 +19,6 @@ reth-consensus.workspace = true # alloy alloy-primitives.workspace = true +alloy-consensus.workspace = true tracing.workspace = true diff --git a/crates/ethereum/consensus/src/lib.rs b/crates/ethereum/consensus/src/lib.rs index e74f3498fa5f..8f2a8a720427 100644 --- a/crates/ethereum/consensus/src/lib.rs +++ b/crates/ethereum/consensus/src/lib.rs @@ -8,6 +8,7 @@ #![cfg_attr(not(test), warn(unused_crate_dependencies))] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] +use alloy_consensus::EMPTY_OMMER_ROOT_HASH; use alloy_primitives::U256; use reth_chainspec::{EthChainSpec, EthereumHardfork, EthereumHardforks}; use reth_consensus::{Consensus, ConsensusError, PostExecutionInput}; @@ -19,7 +20,6 @@ use reth_consensus_common::validation::{ }; use reth_primitives::{ constants::MINIMUM_GAS_LIMIT, BlockWithSenders, Header, SealedBlock, SealedHeader, - EMPTY_OMMER_ROOT_HASH, }; use std::{fmt::Debug, sync::Arc, time::SystemTime}; diff --git a/crates/ethereum/payload/Cargo.toml b/crates/ethereum/payload/Cargo.toml index f169d58f7e8d..ce37a4f8ea4f 100644 --- a/crates/ethereum/payload/Cargo.toml +++ b/crates/ethereum/payload/Cargo.toml @@ -34,6 +34,7 @@ revm-primitives.workspace = true # alloy alloy-primitives.workspace = true +alloy-consensus.workspace = true # misc tracing.workspace = true diff --git a/crates/ethereum/payload/src/lib.rs b/crates/ethereum/payload/src/lib.rs index 248aa3486de4..dcf54fc02489 100644 --- a/crates/ethereum/payload/src/lib.rs +++ b/crates/ethereum/payload/src/lib.rs @@ -9,6 +9,7 @@ #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] #![allow(clippy::useless_let_if_seq)] +use alloy_consensus::EMPTY_OMMER_ROOT_HASH; use alloy_primitives::U256; use reth_basic_payload_builder::{ commit_withdrawals, is_better_payload, BuildArguments, BuildOutcome, PayloadBuilder, @@ -26,7 +27,7 @@ use reth_primitives::{ constants::{eip4844::MAX_DATA_GAS_PER_BLOCK, BEACON_NONCE}, proofs::{self, calculate_requests_root}, revm_primitives::{BlockEnv, CfgEnvWithHandlerCfg}, - Block, BlockBody, EthereumHardforks, Header, Receipt, EMPTY_OMMER_ROOT_HASH, + Block, BlockBody, EthereumHardforks, Header, Receipt, }; use reth_provider::{ChainSpecProvider, StateProviderFactory}; use reth_revm::database::StateProviderDatabase; diff --git a/crates/optimism/consensus/Cargo.toml b/crates/optimism/consensus/Cargo.toml index f5f061c59929..e2520c89340d 100644 --- a/crates/optimism/consensus/Cargo.toml +++ b/crates/optimism/consensus/Cargo.toml @@ -25,6 +25,7 @@ reth-optimism-chainspec.workspace = true # ethereum alloy-primitives.workspace = true +alloy-consensus.workspace = true tracing.workspace = true diff --git a/crates/optimism/consensus/src/lib.rs b/crates/optimism/consensus/src/lib.rs index fe67ff1bcd9e..16c1d5d37d7c 100644 --- a/crates/optimism/consensus/src/lib.rs +++ b/crates/optimism/consensus/src/lib.rs @@ -9,6 +9,7 @@ // The `optimism` feature must be enabled to use this crate. #![cfg(feature = "optimism")] +use alloy_consensus::EMPTY_OMMER_ROOT_HASH; use alloy_primitives::{B64, U256}; use reth_chainspec::EthereumHardforks; use reth_consensus::{Consensus, ConsensusError, PostExecutionInput}; @@ -20,9 +21,7 @@ use reth_consensus_common::validation::{ }; use reth_optimism_chainspec::OpChainSpec; use reth_optimism_forks::OptimismHardforks; -use reth_primitives::{ - BlockWithSenders, GotExpected, Header, SealedBlock, SealedHeader, EMPTY_OMMER_ROOT_HASH, -}; +use reth_primitives::{BlockWithSenders, GotExpected, Header, SealedBlock, SealedHeader}; use std::{sync::Arc, time::SystemTime}; mod proof; diff --git a/crates/optimism/payload/Cargo.toml b/crates/optimism/payload/Cargo.toml index e1d6fe47d291..46cc82edb6ce 100644 --- a/crates/optimism/payload/Cargo.toml +++ b/crates/optimism/payload/Cargo.toml @@ -41,6 +41,7 @@ alloy-rlp.workspace = true op-alloy-rpc-types-engine.workspace = true revm-primitives.workspace = true alloy-rpc-types-engine.workspace = true +alloy-consensus.workspace = true # misc tracing.workspace = true diff --git a/crates/optimism/payload/src/builder.rs b/crates/optimism/payload/src/builder.rs index 0a8dcdb12449..e590635f524e 100644 --- a/crates/optimism/payload/src/builder.rs +++ b/crates/optimism/payload/src/builder.rs @@ -2,6 +2,7 @@ use std::sync::Arc; +use alloy_consensus::EMPTY_OMMER_ROOT_HASH; use alloy_primitives::U256; use reth_basic_payload_builder::*; use reth_chain_state::ExecutedBlock; @@ -16,7 +17,7 @@ use reth_primitives::{ constants::BEACON_NONCE, proofs, revm_primitives::{BlockEnv, CfgEnvWithHandlerCfg}, - Block, BlockBody, Header, Receipt, TxType, EMPTY_OMMER_ROOT_HASH, + Block, BlockBody, Header, Receipt, TxType, }; use reth_provider::StateProviderFactory; use reth_revm::database::StateProviderDatabase; diff --git a/crates/optimism/primitives/src/bedrock.rs b/crates/optimism/primitives/src/bedrock.rs index 1a347aecafe9..bd42298588fe 100644 --- a/crates/optimism/primitives/src/bedrock.rs +++ b/crates/optimism/primitives/src/bedrock.rs @@ -1,9 +1,8 @@ //! OP mainnet bedrock related data. -use alloy_consensus::EMPTY_ROOT_HASH; +use alloy_consensus::{EMPTY_OMMER_ROOT_HASH, EMPTY_ROOT_HASH}; use alloy_primitives::{address, b256, bloom, bytes, B256, B64, U256}; use reth_primitives::Header; -use reth_primitives_traits::constants::EMPTY_OMMER_ROOT_HASH; /// Transaction 0x9ed8f713b2cc6439657db52dcd2fdb9cc944915428f3c6e2a7703e242b259cb9 in block 985, /// replayed in blocks: diff --git a/crates/primitives-traits/src/constants/mod.rs b/crates/primitives-traits/src/constants/mod.rs index d40abdd64ba7..5d64b911b60a 100644 --- a/crates/primitives-traits/src/constants/mod.rs +++ b/crates/primitives-traits/src/constants/mod.rs @@ -119,10 +119,6 @@ pub const DEV_GENESIS_HASH: B256 = pub const KECCAK_EMPTY: B256 = b256!("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"); -/// Ommer root of empty list: `0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347` -pub const EMPTY_OMMER_ROOT_HASH: B256 = - b256!("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"); - /// From address from Optimism system txs: `0xdeaddeaddeaddeaddeaddeaddeaddeaddead0001` pub const OP_SYSTEM_TX_FROM_ADDR: Address = address!("deaddeaddeaddeaddeaddeaddeaddeaddead0001"); diff --git a/crates/primitives/src/lib.rs b/crates/primitives/src/lib.rs index ec65cbf20e52..a59e72bbd556 100644 --- a/crates/primitives/src/lib.rs +++ b/crates/primitives/src/lib.rs @@ -40,8 +40,8 @@ pub use block::{ #[cfg(feature = "reth-codec")] pub use compression::*; pub use constants::{ - DEV_GENESIS_HASH, EMPTY_OMMER_ROOT_HASH, HOLESKY_GENESIS_HASH, KECCAK_EMPTY, - MAINNET_GENESIS_HASH, SEPOLIA_GENESIS_HASH, + DEV_GENESIS_HASH, HOLESKY_GENESIS_HASH, KECCAK_EMPTY, MAINNET_GENESIS_HASH, + SEPOLIA_GENESIS_HASH, }; pub use receipt::{ gas_spent_by_transactions, Receipt, ReceiptWithBloom, ReceiptWithBloomRef, Receipts, diff --git a/crates/primitives/src/proofs.rs b/crates/primitives/src/proofs.rs index dc814804ec81..4efbb588e10d 100644 --- a/crates/primitives/src/proofs.rs +++ b/crates/primitives/src/proofs.rs @@ -1,10 +1,10 @@ //! Helper function for calculating Merkle proofs and hashes. use crate::{ - constants::EMPTY_OMMER_ROOT_HASH, Header, Receipt, ReceiptWithBloom, ReceiptWithBloomRef, - Request, TransactionSigned, Withdrawal, + Header, Receipt, ReceiptWithBloom, ReceiptWithBloomRef, Request, TransactionSigned, Withdrawal, }; use alloc::vec::Vec; +use alloy_consensus::EMPTY_OMMER_ROOT_HASH; use alloy_eips::{eip2718::Encodable2718, eip7685::Encodable7685}; use alloy_primitives::{keccak256, B256}; use reth_trie_common::root::{ordered_trie_root, ordered_trie_root_with_encoder}; diff --git a/crates/rpc/rpc-eth-api/src/helpers/pending_block.rs b/crates/rpc/rpc-eth-api/src/helpers/pending_block.rs index 81c6a567846b..832cf17055a5 100644 --- a/crates/rpc/rpc-eth-api/src/helpers/pending_block.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/pending_block.rs @@ -5,7 +5,7 @@ use std::time::{Duration, Instant}; use crate::{EthApiTypes, FromEthApiError, FromEvmError}; -use alloy_consensus::EMPTY_ROOT_HASH; +use alloy_consensus::{EMPTY_OMMER_ROOT_HASH, EMPTY_ROOT_HASH}; use alloy_primitives::{BlockNumber, B256, U256}; use alloy_rpc_types::BlockNumberOrTag; use futures::Future; @@ -20,7 +20,7 @@ use reth_primitives::{ ResultAndState, SpecId, }, Block, BlockBody, Header, Receipt, Requests, SealedBlockWithSenders, SealedHeader, - TransactionSignedEcRecovered, EMPTY_OMMER_ROOT_HASH, + TransactionSignedEcRecovered, }; use reth_provider::{ BlockReader, BlockReaderIdExt, ChainSpecProvider, EvmEnvProvider, ProviderError, diff --git a/crates/rpc/rpc-types-compat/src/engine/payload.rs b/crates/rpc/rpc-types-compat/src/engine/payload.rs index 84943b60e208..e6f2f97ca75c 100644 --- a/crates/rpc/rpc-types-compat/src/engine/payload.rs +++ b/crates/rpc/rpc-types-compat/src/engine/payload.rs @@ -1,6 +1,7 @@ //! Standalone Conversion Functions for Handling Different Versions of Execution Payloads in //! Ethereum's Engine +use alloy_consensus::EMPTY_OMMER_ROOT_HASH; use alloy_eips::eip2718::{Decodable2718, Encodable2718}; use alloy_primitives::{B256, U256}; use alloy_rpc_types_engine::{ @@ -9,7 +10,7 @@ use alloy_rpc_types_engine::{ ExecutionPayloadV3, ExecutionPayloadV4, PayloadError, }; use reth_primitives::{ - constants::{EMPTY_OMMER_ROOT_HASH, MAXIMUM_EXTRA_DATA_SIZE}, + constants::MAXIMUM_EXTRA_DATA_SIZE, proofs::{self}, Block, BlockBody, Header, Request, SealedBlock, TransactionSigned, Withdrawals, }; From bac244ae970f201afda63811b7b8d8b901fb94de Mon Sep 17 00:00:00 2001 From: Alexey Shekhirin Date: Thu, 17 Oct 2024 11:20:56 +0100 Subject: [PATCH 049/113] feat(trie): sparse trie leaf removal (#11752) Co-authored-by: Roman Krasiuk --- Cargo.lock | 8 +- crates/trie/sparse/Cargo.toml | 11 +- crates/trie/sparse/src/trie.rs | 708 ++++++++++++++++++++++++++++++--- 3 files changed, 669 insertions(+), 58 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e434e80cfde2..d31239808a2a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4464,7 +4464,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" dependencies = [ "cfg-if", - "windows-targets 0.48.5", + "windows-targets 0.52.6", ] [[package]] @@ -9248,9 +9248,13 @@ dependencies = [ "assert_matches", "criterion", "itertools 0.13.0", + "pretty_assertions", "proptest", + "rand 0.8.5", "rayon", "reth-primitives", + "reth-testing-utils", + "reth-tracing", "reth-trie", "reth-trie-common", "smallvec", @@ -11388,7 +11392,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] diff --git a/crates/trie/sparse/Cargo.toml b/crates/trie/sparse/Cargo.toml index c31bbe2df2fe..4ba6ed0f2ec6 100644 --- a/crates/trie/sparse/Cargo.toml +++ b/crates/trie/sparse/Cargo.toml @@ -15,6 +15,7 @@ workspace = true [dependencies] # reth reth-primitives.workspace = true +reth-tracing.workspace = true reth-trie-common.workspace = true reth-trie.workspace = true @@ -26,18 +27,22 @@ alloy-rlp.workspace = true tracing.workspace = true # misc -thiserror.workspace = true rayon.workspace = true smallvec = { workspace = true, features = ["const_new"] } +thiserror.workspace = true [dev-dependencies] reth-primitives = { workspace = true, features = ["test-utils", "arbitrary"] } -reth-trie-common = { workspace = true, features = ["test-utils", "arbitrary"] } +reth-testing-utils.workspace = true reth-trie = { workspace = true, features = ["test-utils"] } +reth-trie-common = { workspace = true, features = ["test-utils", "arbitrary"] } + assert_matches.workspace = true +criterion.workspace = true itertools.workspace = true +pretty_assertions = "1.4" proptest.workspace = true -criterion.workspace = true +rand.workspace = true [[bench]] name = "root" diff --git a/crates/trie/sparse/src/trie.rs b/crates/trie/sparse/src/trie.rs index e83522ca8904..0b9ffb5c0ed4 100644 --- a/crates/trie/sparse/src/trie.rs +++ b/crates/trie/sparse/src/trie.rs @@ -1,6 +1,7 @@ use crate::{SparseTrieError, SparseTrieResult}; use alloy_primitives::{hex, keccak256, map::HashMap, B256}; use alloy_rlp::Decodable; +use reth_tracing::tracing::debug; use reth_trie::{ prefix_set::{PrefixSet, PrefixSetMut}, RlpNode, @@ -264,8 +265,244 @@ impl RevealedSparseTrie { } /// Remove leaf node from the trie. - pub fn remove_leaf(&mut self, _path: Nibbles) { - unimplemented!() + pub fn remove_leaf(&mut self, path: Nibbles) -> SparseTrieResult<()> { + self.prefix_set.insert(path.clone()); + let existing = self.values.remove(&path); + if existing.is_none() { + // trie structure unchanged, return immediately + return Ok(()) + } + + let mut removed_nodes = self.take_nodes_for_path(&path)?; + debug!(target: "trie::sparse", ?path, ?removed_nodes, "Removed nodes for path"); + // Pop the first node from the stack which is the leaf node we want to remove. + let mut child = removed_nodes.pop().expect("leaf exists"); + #[cfg(debug_assertions)] + { + let mut child_path = child.path.clone(); + let SparseNode::Leaf { key, .. } = &child.node else { panic!("expected leaf node") }; + child_path.extend_from_slice_unchecked(key); + assert_eq!(child_path, path); + } + + // If we don't have any other removed nodes, insert an empty node at the root. + if removed_nodes.is_empty() { + debug_assert!(self.nodes.is_empty()); + self.nodes.insert(Nibbles::default(), SparseNode::Empty); + + return Ok(()) + } + + // Walk the stack of removed nodes from the back and re-insert them back into the trie, + // adjusting the node type as needed. + while let Some(removed_node) = removed_nodes.pop() { + let removed_path = removed_node.path; + + let new_node = match &removed_node.node { + SparseNode::Empty => return Err(SparseTrieError::Blind), + SparseNode::Hash(hash) => { + return Err(SparseTrieError::BlindedNode { path: removed_path, hash: *hash }) + } + SparseNode::Leaf { .. } => { + unreachable!("we already popped the leaf node") + } + SparseNode::Extension { key, .. } => { + // If the node is an extension node, we need to look at its child to see if we + // need to merge them. + match &child.node { + SparseNode::Empty => return Err(SparseTrieError::Blind), + SparseNode::Hash(hash) => { + return Err(SparseTrieError::BlindedNode { + path: child.path, + hash: *hash, + }) + } + // For a leaf node, we collapse the extension node into a leaf node, + // extending the key. While it's impossible to encounter an extension node + // followed by a leaf node in a complete trie, it's possible here because we + // could have downgraded the extension node's child into a leaf node from + // another node type. + SparseNode::Leaf { key: leaf_key, .. } => { + self.nodes.remove(&child.path); + + let mut new_key = key.clone(); + new_key.extend_from_slice_unchecked(leaf_key); + SparseNode::new_leaf(new_key) + } + // For an extension node, we collapse them into one extension node, + // extending the key + SparseNode::Extension { key: extension_key, .. } => { + self.nodes.remove(&child.path); + + let mut new_key = key.clone(); + new_key.extend_from_slice_unchecked(extension_key); + SparseNode::new_ext(new_key) + } + // For a branch node, we just leave the extension node as-is. + SparseNode::Branch { .. } => removed_node.node, + } + } + SparseNode::Branch { mut state_mask, hash: _ } => { + // If the node is a branch node, we need to check the number of children left + // after deleting the child at the given nibble. + + if let Some(removed_nibble) = removed_node.unset_branch_nibble { + state_mask.unset_bit(removed_nibble); + } + + // If only one child is left set in the branch node, we need to collapse it. + if state_mask.count_bits() == 1 { + let child_nibble = + state_mask.first_set_bit_index().expect("state mask is not empty"); + + // Get full path of the only child node left. + let mut child_path = removed_path.clone(); + child_path.push_unchecked(child_nibble); + + // Remove the only child node. + let child = self.nodes.get(&child_path).unwrap(); + + debug!(target: "trie::sparse", ?removed_path, ?child_path, ?child, "Branch node has only one child"); + + let mut delete_child = false; + let new_node = match child { + SparseNode::Empty => return Err(SparseTrieError::Blind), + SparseNode::Hash(hash) => { + return Err(SparseTrieError::BlindedNode { + path: child_path, + hash: *hash, + }) + } + // If the only child is a leaf node, we downgrade the branch node into a + // leaf node, prepending the nibble to the key, and delete the old + // child. + SparseNode::Leaf { key, .. } => { + delete_child = true; + + let mut new_key = Nibbles::from_nibbles_unchecked([child_nibble]); + new_key.extend_from_slice_unchecked(key); + SparseNode::new_leaf(new_key) + } + // If the only child node is an extension node, we downgrade the branch + // node into an even longer extension node, prepending the nibble to the + // key, and delete the old child. + SparseNode::Extension { key, .. } => { + delete_child = true; + + let mut new_key = Nibbles::from_nibbles_unchecked([child_nibble]); + new_key.extend_from_slice_unchecked(key); + SparseNode::new_ext(new_key) + } + // If the only child is a branch node, we downgrade the current branch + // node into a one-nibble extension node. + SparseNode::Branch { .. } => { + SparseNode::new_ext(Nibbles::from_nibbles_unchecked([child_nibble])) + } + }; + + if delete_child { + self.nodes.remove(&child_path); + } + + new_node + } + // If more than one child is left set in the branch, we just re-insert it + // as-is. + else { + SparseNode::new_branch(state_mask) + } + } + }; + + child = RemovedSparseNode { + path: removed_path.clone(), + node: new_node.clone(), + unset_branch_nibble: None, + }; + debug!(target: "trie::sparse", ?removed_path, ?new_node, "Re-inserting the node"); + self.nodes.insert(removed_path, new_node); + } + + Ok(()) + } + + /// Traverse trie nodes down to the leaf node and collect all nodes along the path. + fn take_nodes_for_path(&mut self, path: &Nibbles) -> SparseTrieResult> { + let mut current = Nibbles::default(); // Start traversal from the root + let mut nodes = Vec::new(); // Collect traversed nodes + + while let Some(node) = self.nodes.remove(¤t) { + match &node { + SparseNode::Empty => return Err(SparseTrieError::Blind), + SparseNode::Hash(hash) => { + return Err(SparseTrieError::BlindedNode { path: current, hash: *hash }) + } + SparseNode::Leaf { key: _key, .. } => { + // Leaf node is always the one that we're deleting, and no other leaf nodes can + // be found during traversal. + + #[cfg(debug_assertions)] + { + let mut current = current.clone(); + current.extend_from_slice_unchecked(_key); + assert_eq!(¤t, path); + } + + nodes.push(RemovedSparseNode { + path: current.clone(), + node, + unset_branch_nibble: None, + }); + break + } + SparseNode::Extension { key, .. } => { + #[cfg(debug_assertions)] + { + let mut current = current.clone(); + current.extend_from_slice_unchecked(key); + assert!(path.starts_with(¤t)); + } + + let path = current.clone(); + current.extend_from_slice_unchecked(key); + nodes.push(RemovedSparseNode { path, node, unset_branch_nibble: None }); + } + SparseNode::Branch { state_mask, .. } => { + let nibble = path[current.len()]; + debug_assert!(state_mask.is_bit_set(nibble)); + + // If the branch node has a child that is a leaf node that we're removing, + // we need to unset this nibble. + // Any other branch nodes will not require unsetting the nibble, because + // deleting one leaf node can not remove the whole path + // where the branch node is located. + let mut child_path = + Nibbles::from_nibbles([current.as_slice(), &[nibble]].concat()); + let unset_branch_nibble = self + .nodes + .get(&child_path) + .map_or(false, move |node| match node { + SparseNode::Leaf { key, .. } => { + // Get full path of the leaf node + child_path.extend_from_slice_unchecked(key); + &child_path == path + } + _ => false, + }) + .then_some(nibble); + + nodes.push(RemovedSparseNode { + path: current.clone(), + node, + unset_branch_nibble, + }); + + current.push_unchecked(nibble); + } + } + } + + Ok(nodes) } /// Return the root of the sparse trie. @@ -476,13 +713,87 @@ impl SparseNode { } } +#[derive(Debug)] +struct RemovedSparseNode { + path: Nibbles, + node: SparseNode, + unset_branch_nibble: Option, +} + #[cfg(test)] mod tests { + use std::collections::BTreeMap; + use super::*; use alloy_primitives::U256; use itertools::Itertools; use proptest::prelude::*; - use reth_trie_common::HashBuilder; + use rand::seq::IteratorRandom; + use reth_testing_utils::generators; + use reth_trie::{BranchNode, ExtensionNode, LeafNode}; + use reth_trie_common::{ + proof::{ProofNodes, ProofRetainer}, + HashBuilder, + }; + + /// Calculate the state root by feeding the provided state to the hash builder and retaining the + /// proofs for the provided targets. + /// + /// Returns the state root and the retained proof nodes. + fn hash_builder_root_with_proofs>( + state: impl IntoIterator, + proof_targets: impl IntoIterator, + ) -> (B256, ProofNodes) { + let mut hash_builder = + HashBuilder::default().with_proof_retainer(ProofRetainer::from_iter(proof_targets)); + for (key, value) in state { + hash_builder.add_leaf(key, value.as_ref()); + } + (hash_builder.root(), hash_builder.take_proof_nodes()) + } + + /// Assert that the sparse trie nodes and the proof nodes from the hash builder are equal. + fn assert_eq_sparse_trie_proof_nodes( + sparse_trie: &RevealedSparseTrie, + proof_nodes: ProofNodes, + ) { + let proof_nodes = proof_nodes + .into_nodes_sorted() + .into_iter() + .map(|(path, node)| (path, TrieNode::decode(&mut node.as_ref()).unwrap())); + + let sparse_nodes = sparse_trie.nodes.iter().sorted_by_key(|(path, _)| *path); + + for ((proof_node_path, proof_node), (sparse_node_path, sparse_node)) in + proof_nodes.zip(sparse_nodes) + { + assert_eq!(&proof_node_path, sparse_node_path); + + let equals = match (&proof_node, &sparse_node) { + // Both nodes are empty + (TrieNode::EmptyRoot, SparseNode::Empty) => true, + // Both nodes are branches and have the same state mask + ( + TrieNode::Branch(BranchNode { state_mask: proof_state_mask, .. }), + SparseNode::Branch { state_mask: sparse_state_mask, .. }, + ) => proof_state_mask == sparse_state_mask, + // Both nodes are extensions and have the same key + ( + TrieNode::Extension(ExtensionNode { key: proof_key, .. }), + SparseNode::Extension { key: sparse_key, .. }, + ) | + // Both nodes are leaves and have the same key + ( + TrieNode::Leaf(LeafNode { key: proof_key, .. }), + SparseNode::Leaf { key: sparse_key, .. }, + ) => proof_key == sparse_key, + // Empty and hash nodes are specific to the sparse trie, skip them + (_, SparseNode::Empty | SparseNode::Hash(_)) => continue, + _ => false, + }; + assert!(equals, "proof node: {:?}, sparse node: {:?}", proof_node, sparse_node); + } + } #[test] fn sparse_trie_is_blind() { @@ -495,14 +806,15 @@ mod tests { let path = Nibbles::unpack(B256::with_last_byte(42)); let value = alloy_rlp::encode_fixed_size(&U256::from(1)); - let mut hash_builder = HashBuilder::default(); - hash_builder.add_leaf(path.clone(), &value); - let expected = hash_builder.root(); + let (hash_builder_root, hash_builder_proof_nodes) = + hash_builder_root_with_proofs([(path.clone(), &value)], [path.clone()]); let mut sparse = RevealedSparseTrie::default(); sparse.update_leaf(path, value.to_vec()).unwrap(); - let root = sparse.root(); - assert_eq!(root, expected); + let sparse_root = sparse.root(); + + assert_eq!(sparse_root, hash_builder_root); + assert_eq_sparse_trie_proof_nodes(&sparse, hash_builder_proof_nodes); } #[test] @@ -510,18 +822,19 @@ mod tests { let paths = (0..=16).map(|b| Nibbles::unpack(B256::with_last_byte(b))).collect::>(); let value = alloy_rlp::encode_fixed_size(&U256::from(1)); - let mut hash_builder = HashBuilder::default(); - for path in &paths { - hash_builder.add_leaf(path.clone(), &value); - } - let expected = hash_builder.root(); + let (hash_builder_root, hash_builder_proof_nodes) = hash_builder_root_with_proofs( + paths.iter().cloned().zip(std::iter::repeat_with(|| value.clone())), + paths.clone(), + ); let mut sparse = RevealedSparseTrie::default(); for path in &paths { sparse.update_leaf(path.clone(), value.to_vec()).unwrap(); } - let root = sparse.root(); - assert_eq!(root, expected); + let sparse_root = sparse.root(); + + assert_eq!(sparse_root, hash_builder_root); + assert_eq_sparse_trie_proof_nodes(&sparse, hash_builder_proof_nodes); } #[test] @@ -529,18 +842,19 @@ mod tests { let paths = (239..=255).map(|b| Nibbles::unpack(B256::repeat_byte(b))).collect::>(); let value = alloy_rlp::encode_fixed_size(&U256::from(1)); - let mut hash_builder = HashBuilder::default(); - for path in &paths { - hash_builder.add_leaf(path.clone(), &value); - } - let expected = hash_builder.root(); + let (hash_builder_root, hash_builder_proof_nodes) = hash_builder_root_with_proofs( + paths.iter().cloned().zip(std::iter::repeat_with(|| value.clone())), + paths.clone(), + ); let mut sparse = RevealedSparseTrie::default(); for path in &paths { sparse.update_leaf(path.clone(), value.to_vec()).unwrap(); } - let root = sparse.root(); - assert_eq!(root, expected); + let sparse_root = sparse.root(); + + assert_eq!(sparse_root, hash_builder_root); + assert_eq_sparse_trie_proof_nodes(&sparse, hash_builder_proof_nodes); } #[test] @@ -556,18 +870,19 @@ mod tests { .collect::>(); let value = alloy_rlp::encode_fixed_size(&U256::from(1)); - let mut hash_builder = HashBuilder::default(); - for path in paths.iter().sorted_unstable_by_key(|key| *key) { - hash_builder.add_leaf(path.clone(), &value); - } - let expected = hash_builder.root(); + let (hash_builder_root, hash_builder_proof_nodes) = hash_builder_root_with_proofs( + paths.iter().sorted_unstable().cloned().zip(std::iter::repeat_with(|| value.clone())), + paths.clone(), + ); let mut sparse = RevealedSparseTrie::default(); for path in &paths { sparse.update_leaf(path.clone(), value.to_vec()).unwrap(); } - let root = sparse.root(); - assert_eq!(root, expected); + let sparse_root = sparse.root(); + + assert_eq!(sparse_root, hash_builder_root); + assert_eq_sparse_trie_proof_nodes(&sparse, hash_builder_proof_nodes); } #[test] @@ -576,52 +891,339 @@ mod tests { let old_value = alloy_rlp::encode_fixed_size(&U256::from(1)); let new_value = alloy_rlp::encode_fixed_size(&U256::from(2)); - let mut hash_builder = HashBuilder::default(); - for path in paths.iter().sorted_unstable_by_key(|key| *key) { - hash_builder.add_leaf(path.clone(), &old_value); - } - let expected = hash_builder.root(); + let (hash_builder_root, hash_builder_proof_nodes) = hash_builder_root_with_proofs( + paths.iter().cloned().zip(std::iter::repeat_with(|| old_value.clone())), + paths.clone(), + ); let mut sparse = RevealedSparseTrie::default(); for path in &paths { sparse.update_leaf(path.clone(), old_value.to_vec()).unwrap(); } - let root = sparse.root(); - assert_eq!(root, expected); + let sparse_root = sparse.root(); - let mut hash_builder = HashBuilder::default(); - for path in paths.iter().sorted_unstable_by_key(|key| *key) { - hash_builder.add_leaf(path.clone(), &new_value); - } - let expected = hash_builder.root(); + assert_eq!(sparse_root, hash_builder_root); + assert_eq_sparse_trie_proof_nodes(&sparse, hash_builder_proof_nodes); + + let (hash_builder_root, hash_builder_proof_nodes) = hash_builder_root_with_proofs( + paths.iter().cloned().zip(std::iter::repeat_with(|| new_value.clone())), + paths.clone(), + ); for path in &paths { sparse.update_leaf(path.clone(), new_value.to_vec()).unwrap(); } - let root = sparse.root(); - assert_eq!(root, expected); + let sparse_root = sparse.root(); + + assert_eq!(sparse_root, hash_builder_root); + assert_eq_sparse_trie_proof_nodes(&sparse, hash_builder_proof_nodes); + } + + #[test] + fn sparse_trie_remove_leaf() { + reth_tracing::init_test_tracing(); + + let mut sparse = RevealedSparseTrie::default(); + + let value = alloy_rlp::encode_fixed_size(&U256::ZERO).to_vec(); + + sparse + .update_leaf(Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x1]), value.clone()) + .unwrap(); + sparse + .update_leaf(Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x3]), value.clone()) + .unwrap(); + sparse + .update_leaf(Nibbles::from_nibbles([0x5, 0x2, 0x0, 0x1, 0x3]), value.clone()) + .unwrap(); + sparse + .update_leaf(Nibbles::from_nibbles([0x5, 0x3, 0x1, 0x0, 0x2]), value.clone()) + .unwrap(); + sparse + .update_leaf(Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x0, 0x2]), value.clone()) + .unwrap(); + sparse.update_leaf(Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x2, 0x0]), value).unwrap(); + + // Extension (Key = 5) + // └── Branch (Mask = 1011) + // ├── 0 -> Extension (Key = 23) + // │ └── Branch (Mask = 0101) + // │ ├── 1 -> Leaf (Key = 1, Path = 50231) + // │ └── 3 -> Leaf (Key = 3, Path = 50233) + // ├── 2 -> Leaf (Key = 013, Path = 52013) + // └── 3 -> Branch (Mask = 0101) + // ├── 1 -> Leaf (Key = 3102, Path = 53102) + // └── 3 -> Branch (Mask = 1010) + // ├── 0 -> Leaf (Key = 3302, Path = 53302) + // └── 2 -> Leaf (Key = 3320, Path = 53320) + pretty_assertions::assert_eq!( + sparse.nodes.clone().into_iter().collect::>(), + BTreeMap::from_iter([ + (Nibbles::new(), SparseNode::new_ext(Nibbles::from_nibbles([0x5]))), + (Nibbles::from_nibbles([0x5]), SparseNode::new_branch(0b1101.into())), + ( + Nibbles::from_nibbles([0x5, 0x0]), + SparseNode::new_ext(Nibbles::from_nibbles([0x2, 0x3])) + ), + ( + Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3]), + SparseNode::new_branch(0b1010.into()) + ), + ( + Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x1]), + SparseNode::new_leaf(Nibbles::new()) + ), + ( + Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x3]), + SparseNode::new_leaf(Nibbles::new()) + ), + ( + Nibbles::from_nibbles([0x5, 0x2]), + SparseNode::new_leaf(Nibbles::from_nibbles([0x0, 0x1, 0x3])) + ), + (Nibbles::from_nibbles([0x5, 0x3]), SparseNode::new_branch(0b1010.into())), + ( + Nibbles::from_nibbles([0x5, 0x3, 0x1]), + SparseNode::new_leaf(Nibbles::from_nibbles([0x0, 0x2])) + ), + (Nibbles::from_nibbles([0x5, 0x3, 0x3]), SparseNode::new_branch(0b0101.into())), + ( + Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x0]), + SparseNode::new_leaf(Nibbles::from_nibbles([0x2])) + ), + ( + Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x2]), + SparseNode::new_leaf(Nibbles::from_nibbles([0x0])) + ) + ]) + ); + + sparse.remove_leaf(Nibbles::from_nibbles([0x5, 0x2, 0x0, 0x1, 0x3])).unwrap(); + + // Extension (Key = 5) + // └── Branch (Mask = 1001) + // ├── 0 -> Extension (Key = 23) + // │ └── Branch (Mask = 0101) + // │ ├── 1 -> Leaf (Key = 0231, Path = 50231) + // │ └── 3 -> Leaf (Key = 0233, Path = 50233) + // └── 3 -> Branch (Mask = 0101) + // ├── 1 -> Leaf (Key = 3102, Path = 53102) + // └── 3 -> Branch (Mask = 1010) + // ├── 0 -> Leaf (Key = 3302, Path = 53302) + // └── 2 -> Leaf (Key = 3320, Path = 53320) + pretty_assertions::assert_eq!( + sparse.nodes.clone().into_iter().collect::>(), + BTreeMap::from_iter([ + (Nibbles::new(), SparseNode::new_ext(Nibbles::from_nibbles([0x5]))), + (Nibbles::from_nibbles([0x5]), SparseNode::new_branch(0b1001.into())), + ( + Nibbles::from_nibbles([0x5, 0x0]), + SparseNode::new_ext(Nibbles::from_nibbles([0x2, 0x3])) + ), + ( + Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3]), + SparseNode::new_branch(0b1010.into()) + ), + ( + Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x1]), + SparseNode::new_leaf(Nibbles::new()) + ), + ( + Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x3]), + SparseNode::new_leaf(Nibbles::new()) + ), + (Nibbles::from_nibbles([0x5, 0x3]), SparseNode::new_branch(0b1010.into())), + ( + Nibbles::from_nibbles([0x5, 0x3, 0x1]), + SparseNode::new_leaf(Nibbles::from_nibbles([0x0, 0x2])) + ), + (Nibbles::from_nibbles([0x5, 0x3, 0x3]), SparseNode::new_branch(0b0101.into())), + ( + Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x0]), + SparseNode::new_leaf(Nibbles::from_nibbles([0x2])) + ), + ( + Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x2]), + SparseNode::new_leaf(Nibbles::from_nibbles([0x0])) + ) + ]) + ); + + sparse.remove_leaf(Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x1])).unwrap(); + + // Extension (Key = 5) + // └── Branch (Mask = 1001) + // ├── 0 -> Leaf (Key = 0233, Path = 50233) + // └── 3 -> Branch (Mask = 0101) + // ├── 1 -> Leaf (Key = 3102, Path = 53102) + // └── 3 -> Branch (Mask = 1010) + // ├── 0 -> Leaf (Key = 3302, Path = 53302) + // └── 2 -> Leaf (Key = 3320, Path = 53320) + pretty_assertions::assert_eq!( + sparse.nodes.clone().into_iter().collect::>(), + BTreeMap::from_iter([ + (Nibbles::new(), SparseNode::new_ext(Nibbles::from_nibbles([0x5]))), + (Nibbles::from_nibbles([0x5]), SparseNode::new_branch(0b1001.into())), + ( + Nibbles::from_nibbles([0x5, 0x0]), + SparseNode::new_leaf(Nibbles::from_nibbles([0x2, 0x3, 0x3])) + ), + (Nibbles::from_nibbles([0x5, 0x3]), SparseNode::new_branch(0b1010.into())), + ( + Nibbles::from_nibbles([0x5, 0x3, 0x1]), + SparseNode::new_leaf(Nibbles::from_nibbles([0x0, 0x2])) + ), + (Nibbles::from_nibbles([0x5, 0x3, 0x3]), SparseNode::new_branch(0b0101.into())), + ( + Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x0]), + SparseNode::new_leaf(Nibbles::from_nibbles([0x2])) + ), + ( + Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x2]), + SparseNode::new_leaf(Nibbles::from_nibbles([0x0])) + ) + ]) + ); + + sparse.remove_leaf(Nibbles::from_nibbles([0x5, 0x3, 0x1, 0x0, 0x2])).unwrap(); + + // Extension (Key = 5) + // └── Branch (Mask = 1001) + // ├── 0 -> Leaf (Key = 0233, Path = 50233) + // └── 3 -> Branch (Mask = 1010) + // ├── 0 -> Leaf (Key = 3302, Path = 53302) + // └── 2 -> Leaf (Key = 3320, Path = 53320) + pretty_assertions::assert_eq!( + sparse.nodes.clone().into_iter().collect::>(), + BTreeMap::from_iter([ + (Nibbles::new(), SparseNode::new_ext(Nibbles::from_nibbles([0x5]))), + (Nibbles::from_nibbles([0x5]), SparseNode::new_branch(0b1001.into())), + ( + Nibbles::from_nibbles([0x5, 0x0]), + SparseNode::new_leaf(Nibbles::from_nibbles([0x2, 0x3, 0x3])) + ), + ( + Nibbles::from_nibbles([0x5, 0x3]), + SparseNode::new_ext(Nibbles::from_nibbles([0x3])) + ), + (Nibbles::from_nibbles([0x5, 0x3, 0x3]), SparseNode::new_branch(0b0101.into())), + ( + Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x0]), + SparseNode::new_leaf(Nibbles::from_nibbles([0x2])) + ), + ( + Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x2]), + SparseNode::new_leaf(Nibbles::from_nibbles([0x0])) + ) + ]) + ); + + sparse.remove_leaf(Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x2, 0x0])).unwrap(); + + // Extension (Key = 5) + // └── Branch (Mask = 1001) + // ├── 0 -> Leaf (Key = 0233, Path = 50233) + // └── 3 -> Leaf (Key = 3302, Path = 53302) + pretty_assertions::assert_eq!( + sparse.nodes.clone().into_iter().collect::>(), + BTreeMap::from_iter([ + (Nibbles::new(), SparseNode::new_ext(Nibbles::from_nibbles([0x5]))), + (Nibbles::from_nibbles([0x5]), SparseNode::new_branch(0b1001.into())), + ( + Nibbles::from_nibbles([0x5, 0x0]), + SparseNode::new_leaf(Nibbles::from_nibbles([0x2, 0x3, 0x3])) + ), + ( + Nibbles::from_nibbles([0x5, 0x3]), + SparseNode::new_leaf(Nibbles::from_nibbles([0x3, 0x0, 0x2])) + ), + ]) + ); + + sparse.remove_leaf(Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x3])).unwrap(); + + // Leaf (Key = 53302) + pretty_assertions::assert_eq!( + sparse.nodes.clone().into_iter().collect::>(), + BTreeMap::from_iter([( + Nibbles::new(), + SparseNode::new_leaf(Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x0, 0x2])) + ),]) + ); + + sparse.remove_leaf(Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x0, 0x2])).unwrap(); + + // Empty + pretty_assertions::assert_eq!( + sparse.nodes.clone().into_iter().collect::>(), + BTreeMap::from_iter([(Nibbles::new(), SparseNode::Empty),]) + ); } #[test] - fn sparse_trie_empty_update_fuzz() { + fn sparse_trie_fuzz() { proptest!(ProptestConfig::with_cases(10), |(updates: Vec>)| { - let mut state = std::collections::BTreeMap::default(); + let mut rng = generators::rng(); + + let mut state = BTreeMap::default(); + let mut unpacked_state = BTreeMap::default(); let mut sparse = RevealedSparseTrie::default(); for update in updates { - for (key, value) in &update { - sparse.update_leaf(Nibbles::unpack(key), alloy_rlp::encode_fixed_size(value).to_vec()).unwrap(); + let keys_to_delete_len = update.len() / 2; + + let unpacked_update = update.iter().map(|(key, value)| ( + Nibbles::unpack(key), + alloy_rlp::encode_fixed_size(value).to_vec() + )); + + // Insert state updates into the sparse trie and calculate the root + for (key, value) in unpacked_update.clone() { + sparse.update_leaf(key, value).unwrap(); } - let root = sparse.root(); + let sparse_root = sparse.root(); + // Insert state updates into the hash builder and calculate the root + unpacked_state.extend(unpacked_update); state.extend(update); - let mut hash_builder = HashBuilder::default(); - for (key, value) in &state { - hash_builder.add_leaf(Nibbles::unpack(key), &alloy_rlp::encode_fixed_size(value)); + let keys = state.keys().map(Nibbles::unpack).collect::>(); + let (hash_builder_root, hash_builder_proof_nodes) = hash_builder_root_with_proofs( + unpacked_state.clone(), + keys, + ); + + // Assert that the sparse trie root matches the hash builder root + assert_eq!(sparse_root, hash_builder_root); + // Assert that the sparse trie nodes match the hash builder proof nodes + assert_eq_sparse_trie_proof_nodes(&sparse, hash_builder_proof_nodes); + + // Delete some keys from both the hash builder and the sparse trie and check + // that the sparse trie root still matches the hash builder root + + let keys_to_delete = state + .keys() + .choose_multiple(&mut rng, keys_to_delete_len) + .into_iter() + .copied() + .collect::>(); + for key in keys_to_delete { + state.remove(&key).unwrap(); + unpacked_state.remove(&Nibbles::unpack(key)).unwrap(); + sparse.remove_leaf(Nibbles::unpack(key)).unwrap(); } - let expected = hash_builder.root(); - assert_eq!(root, expected); + let sparse_root = sparse.root(); + + let keys = state.keys().map(Nibbles::unpack).collect::>(); + let (hash_builder_root, hash_builder_proof_nodes) = hash_builder_root_with_proofs( + unpacked_state.clone(), + keys, + ); + + // Assert that the sparse trie root matches the hash builder root + assert_eq!(sparse_root, hash_builder_root); + // Assert that the sparse trie nodes match the hash builder proof nodes + assert_eq_sparse_trie_proof_nodes(&sparse, hash_builder_proof_nodes); } }); } From 4254b80a89630f1cb875d05c4b3c32f39af86b6b Mon Sep 17 00:00:00 2001 From: Roman Krasiuk Date: Thu, 17 Oct 2024 12:27:57 +0200 Subject: [PATCH 050/113] bench(trie): avoid unnecessary clones in hash builder repeated bench (#11827) --- crates/trie/sparse/benches/root.rs | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/crates/trie/sparse/benches/root.rs b/crates/trie/sparse/benches/root.rs index 4078eb7af314..248e3caeeeee 100644 --- a/crates/trie/sparse/benches/root.rs +++ b/crates/trie/sparse/benches/root.rs @@ -90,12 +90,23 @@ pub fn calculate_root_from_leaves_repeated(c: &mut Criterion) { }, |(init_storage, storage_updates, mut trie_updates)| { let mut storage = init_storage; - for update in storage_updates { + let mut storage_updates = storage_updates.into_iter().peekable(); + while let Some(update) = storage_updates.next() { storage.extend(&update); let prefix_set = update.construct_prefix_set().freeze(); - let storage_sorted = storage.clone().into_sorted(); - let trie_updates_sorted = trie_updates.clone().into_sorted(); + let (storage_sorted, trie_updates_sorted) = + if storage_updates.peek().is_some() { + ( + storage.clone().into_sorted(), + trie_updates.clone().into_sorted(), + ) + } else { + ( + std::mem::take(&mut storage).into_sorted(), + std::mem::take(&mut trie_updates).into_sorted(), + ) + }; let walker = TrieWalker::new( InMemoryStorageTrieCursor::new( @@ -133,7 +144,9 @@ pub fn calculate_root_from_leaves_repeated(c: &mut Criterion) { } hb.root(); - trie_updates.finalize(node_iter.walker, hb); + if storage_updates.peek().is_some() { + trie_updates.finalize(node_iter.walker, hb); + } } }, ) From b47ce92d9a049f1069162d7d8e5c63b056d3c36e Mon Sep 17 00:00:00 2001 From: Steven <112043913+stevencartavia@users.noreply.github.com> Date: Thu, 17 Oct 2024 04:36:25 -0600 Subject: [PATCH 051/113] replace ChainSpec to use EthereumHardforks trait (#11824) --- crates/payload/primitives/src/lib.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/crates/payload/primitives/src/lib.rs b/crates/payload/primitives/src/lib.rs index 5d1004051350..8173cae344ae 100644 --- a/crates/payload/primitives/src/lib.rs +++ b/crates/payload/primitives/src/lib.rs @@ -26,7 +26,7 @@ pub use traits::{ mod payload; pub use payload::PayloadOrAttributes; -use reth_chainspec::{ChainSpec, EthereumHardforks}; +use reth_chainspec::EthereumHardforks; /// The types that are used by the engine API. pub trait PayloadTypes: Send + Sync + Unpin + core::fmt::Debug + Clone + 'static { /// The built payload type. @@ -125,8 +125,8 @@ pub fn validate_payload_timestamp( /// Validates the presence of the `withdrawals` field according to the payload timestamp. /// After Shanghai, withdrawals field must be [Some]. /// Before Shanghai, withdrawals field must be [None]; -pub fn validate_withdrawals_presence( - chain_spec: &ChainSpec, +pub fn validate_withdrawals_presence( + chain_spec: &T, version: EngineApiMessageVersion, message_validation_kind: MessageValidationKind, timestamp: u64, @@ -210,8 +210,8 @@ pub fn validate_withdrawals_presence( /// `MessageValidationKind::Payload`, then the error code will be `-32602: Invalid params`. If the /// parameter is `MessageValidationKind::PayloadAttributes`, then the error code will be `-38003: /// Invalid payload attributes`. -pub fn validate_parent_beacon_block_root_presence( - chain_spec: &ChainSpec, +pub fn validate_parent_beacon_block_root_presence( + chain_spec: &T, version: EngineApiMessageVersion, validation_kind: MessageValidationKind, timestamp: u64, @@ -298,13 +298,14 @@ impl MessageValidationKind { /// either an execution payload, or payload attributes. /// /// The version is provided by the [`EngineApiMessageVersion`] argument. -pub fn validate_version_specific_fields( - chain_spec: &ChainSpec, +pub fn validate_version_specific_fields( + chain_spec: &T, version: EngineApiMessageVersion, payload_or_attrs: PayloadOrAttributes<'_, Type>, ) -> Result<(), EngineObjectValidationError> where Type: PayloadAttributes, + T: EthereumHardforks, { validate_withdrawals_presence( chain_spec, From f8902b59f5ccc626469e419c273e724a6bb79bae Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Thu, 17 Oct 2024 12:54:28 +0200 Subject: [PATCH 052/113] chore: pedantic style change (#11832) --- crates/primitives/src/transaction/mod.rs | 35 +++++++++++------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/crates/primitives/src/transaction/mod.rs b/crates/primitives/src/transaction/mod.rs index aeee4232e05d..da1a2d871398 100644 --- a/crates/primitives/src/transaction/mod.rs +++ b/crates/primitives/src/transaction/mod.rs @@ -1,18 +1,15 @@ //! Transaction types. use crate::BlockHashOrNumber; -use alloy_eips::eip7702::SignedAuthorization; -use alloy_primitives::{keccak256, Address, ChainId, TxKind, B256, U256}; - use alloy_consensus::{ - SignableTransaction, Transaction as AlloyTransaction, TxEip1559, TxEip2930, TxEip4844, - TxEip7702, TxLegacy, + SignableTransaction, Transaction as _, TxEip1559, TxEip2930, TxEip4844, TxEip7702, TxLegacy, }; use alloy_eips::{ eip2718::{Decodable2718, Eip2718Error, Eip2718Result, Encodable2718}, eip2930::AccessList, + eip7702::SignedAuthorization, }; -use alloy_primitives::{Bytes, TxHash}; +use alloy_primitives::{keccak256, Address, Bytes, ChainId, TxHash, TxKind, B256, U256}; use alloy_rlp::{Decodable, Encodable, Error as RlpError, Header}; use core::mem; use derive_more::{AsRef, Deref}; @@ -709,7 +706,7 @@ impl Encodable for Transaction { } } -impl AlloyTransaction for Transaction { +impl alloy_consensus::Transaction for Transaction { fn chain_id(&self) -> Option { match self { Self::Legacy(tx) => tx.chain_id(), @@ -782,18 +779,6 @@ impl AlloyTransaction for Transaction { } } - fn priority_fee_or_price(&self) -> u128 { - match self { - Self::Legacy(tx) => tx.priority_fee_or_price(), - Self::Eip2930(tx) => tx.priority_fee_or_price(), - Self::Eip1559(tx) => tx.priority_fee_or_price(), - Self::Eip4844(tx) => tx.priority_fee_or_price(), - Self::Eip7702(tx) => tx.priority_fee_or_price(), - #[cfg(feature = "optimism")] - Self::Deposit(tx) => tx.priority_fee_or_price(), - } - } - fn max_fee_per_blob_gas(&self) -> Option { match self { Self::Legacy(tx) => tx.max_fee_per_blob_gas(), @@ -806,6 +791,18 @@ impl AlloyTransaction for Transaction { } } + fn priority_fee_or_price(&self) -> u128 { + match self { + Self::Legacy(tx) => tx.priority_fee_or_price(), + Self::Eip2930(tx) => tx.priority_fee_or_price(), + Self::Eip1559(tx) => tx.priority_fee_or_price(), + Self::Eip4844(tx) => tx.priority_fee_or_price(), + Self::Eip7702(tx) => tx.priority_fee_or_price(), + #[cfg(feature = "optimism")] + Self::Deposit(tx) => tx.priority_fee_or_price(), + } + } + fn to(&self) -> TxKind { match self { Self::Legacy(tx) => tx.to(), From b77265e61b06cb6402ac210a01396ebf57c55418 Mon Sep 17 00:00:00 2001 From: nk_ysg Date: Thu, 17 Oct 2024 18:59:27 +0800 Subject: [PATCH 053/113] reth-bench: rm redundant clone (#11829) --- bin/reth-bench/src/bench/new_payload_fcu.rs | 3 +-- bin/reth-bench/src/bench/new_payload_only.rs | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/bin/reth-bench/src/bench/new_payload_fcu.rs b/bin/reth-bench/src/bench/new_payload_fcu.rs index a8c18b48a2b7..ca5359fb8c26 100644 --- a/bin/reth-bench/src/bench/new_payload_fcu.rs +++ b/bin/reth-bench/src/bench/new_payload_fcu.rs @@ -37,9 +37,8 @@ pub struct Command { impl Command { /// Execute `benchmark new-payload-fcu` command pub async fn execute(self, _ctx: CliContext) -> eyre::Result<()> { - let cloned_args = self.benchmark.clone(); let BenchContext { benchmark_mode, block_provider, auth_provider, mut next_block } = - BenchContext::new(&cloned_args, self.rpc_url).await?; + BenchContext::new(&self.benchmark, self.rpc_url).await?; let (sender, mut receiver) = tokio::sync::mpsc::channel(1000); tokio::task::spawn(async move { diff --git a/bin/reth-bench/src/bench/new_payload_only.rs b/bin/reth-bench/src/bench/new_payload_only.rs index e6392318a542..85342d1af76c 100644 --- a/bin/reth-bench/src/bench/new_payload_only.rs +++ b/bin/reth-bench/src/bench/new_payload_only.rs @@ -35,11 +35,10 @@ pub struct Command { impl Command { /// Execute `benchmark new-payload-only` command pub async fn execute(self, _ctx: CliContext) -> eyre::Result<()> { - let cloned_args = self.benchmark.clone(); // TODO: this could be just a function I guess, but destructuring makes the code slightly // more readable than a 4 element tuple. let BenchContext { benchmark_mode, block_provider, auth_provider, mut next_block } = - BenchContext::new(&cloned_args, self.rpc_url).await?; + BenchContext::new(&self.benchmark, self.rpc_url).await?; let (sender, mut receiver) = tokio::sync::mpsc::channel(1000); tokio::task::spawn(async move { From 3bc3e7169990b9340e60c394b0e3241728fd841c Mon Sep 17 00:00:00 2001 From: Thomas Coratger <60488569+tcoratger@users.noreply.github.com> Date: Thu, 17 Oct 2024 13:21:40 +0200 Subject: [PATCH 054/113] primitives: use `EMPTY_OMMER_ROOT_HASH` const when possible (#11833) --- crates/consensus/common/src/validation.rs | 4 ++-- crates/net/eth-wire-types/src/header.rs | 11 ++++------- crates/storage/codecs/src/alloy/header.rs | 3 ++- crates/storage/provider/src/test_utils/blocks.rs | 5 ++--- 4 files changed, 10 insertions(+), 13 deletions(-) diff --git a/crates/consensus/common/src/validation.rs b/crates/consensus/common/src/validation.rs index df66a00d1dfe..711e7772b666 100644 --- a/crates/consensus/common/src/validation.rs +++ b/crates/consensus/common/src/validation.rs @@ -300,7 +300,7 @@ pub fn validate_against_parent_4844( #[cfg(test)] mod tests { use super::*; - use alloy_consensus::{TxEip4844, EMPTY_ROOT_HASH}; + use alloy_consensus::{TxEip4844, EMPTY_OMMER_ROOT_HASH, EMPTY_ROOT_HASH}; use alloy_primitives::{ hex_literal::hex, Address, BlockHash, BlockNumber, Bytes, Parity, Sealable, U256, }; @@ -441,7 +441,7 @@ mod tests { let header = Header { parent_hash: hex!("859fad46e75d9be177c2584843501f2270c7e5231711e90848290d12d7c6dcdd").into(), - ommers_hash: hex!("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347").into(), + ommers_hash: EMPTY_OMMER_ROOT_HASH, beneficiary: hex!("4675c7e5baafbffbca748158becba61ef3b0a263").into(), state_root: hex!("8337403406e368b3e40411138f4868f79f6d835825d55fd0c2f6e17b1a3948e9").into(), transactions_root: EMPTY_ROOT_HASH, diff --git a/crates/net/eth-wire-types/src/header.rs b/crates/net/eth-wire-types/src/header.rs index 7ecfc802d8a8..b25a7568b222 100644 --- a/crates/net/eth-wire-types/src/header.rs +++ b/crates/net/eth-wire-types/src/header.rs @@ -87,7 +87,7 @@ impl From for bool { #[cfg(test)] mod tests { use super::*; - use alloy_consensus::EMPTY_ROOT_HASH; + use alloy_consensus::{EMPTY_OMMER_ROOT_HASH, EMPTY_ROOT_HASH}; use alloy_primitives::{address, b256, bloom, bytes, hex, Address, Bytes, B256, U256}; use alloy_rlp::{Decodable, Encodable}; use reth_primitives::Header; @@ -124,7 +124,7 @@ mod tests { .unwrap(); let header = Header { parent_hash: b256!("e0a94a7a3c9617401586b1a27025d2d9671332d22d540e0af72b069170380f2a"), - ommers_hash: b256!("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"), + ommers_hash: EMPTY_OMMER_ROOT_HASH, beneficiary: address!("ba5e000000000000000000000000000000000000"), state_root: b256!("ec3c94b18b8a1cff7d60f8d258ec723312932928626b4c9355eb4ab3568ec7f7"), transactions_root: b256!("50f738580ed699f0469702c7ccc63ed2e51bc034be9479b7bff4e68dee84accf"), @@ -228,10 +228,7 @@ mod tests { "3a9b485972e7353edd9152712492f0c58d89ef80623686b6bf947a4a6dce6cb6", ) .unwrap(), - ommers_hash: B256::from_str( - "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", - ) - .unwrap(), + ommers_hash: EMPTY_OMMER_ROOT_HASH, beneficiary: Address::from_str("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba").unwrap(), state_root: B256::from_str( "3c837fc158e3e93eafcaf2e658a02f5d8f99abc9f1c4c66cdea96c0ca26406ae", @@ -280,7 +277,7 @@ mod tests { "13a7ec98912f917b3e804654e37c9866092043c13eb8eab94eb64818e886cff5", ) .unwrap(), - ommers_hash: b256!("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"), + ommers_hash: EMPTY_OMMER_ROOT_HASH, beneficiary: address!("f97e180c050e5ab072211ad2c213eb5aee4df134"), state_root: b256!("ec229dbe85b0d3643ad0f471e6ec1a36bbc87deffbbd970762d22a53b35d068a"), transactions_root: EMPTY_ROOT_HASH, diff --git a/crates/storage/codecs/src/alloy/header.rs b/crates/storage/codecs/src/alloy/header.rs index 3a17ed1fdcd2..623eded9ee99 100644 --- a/crates/storage/codecs/src/alloy/header.rs +++ b/crates/storage/codecs/src/alloy/header.rs @@ -126,12 +126,13 @@ impl Compact for AlloyHeader { #[cfg(test)] mod tests { use super::*; + use alloy_consensus::EMPTY_OMMER_ROOT_HASH; use alloy_primitives::{address, b256, bloom, bytes, hex}; /// Holesky block #1947953 const HOLESKY_BLOCK: Header = Header { parent_hash: b256!("8605e0c46689f66b3deed82598e43d5002b71a929023b665228728f0c6e62a95"), - ommers_hash: b256!("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"), + ommers_hash: EMPTY_OMMER_ROOT_HASH, beneficiary: address!("c6e2459991bfe27cca6d86722f35da23a1e4cb97"), state_root: b256!("edad188ca5647d62f4cca417c11a1afbadebce30d23260767f6f587e9b3b9993"), transactions_root: b256!("4daf25dc08a841aa22aa0d3cb3e1f159d4dcaf6a6063d4d36bfac11d3fdb63ee"), diff --git a/crates/storage/provider/src/test_utils/blocks.rs b/crates/storage/provider/src/test_utils/blocks.rs index 57e111d674ba..2a70664b1b3a 100644 --- a/crates/storage/provider/src/test_utils/blocks.rs +++ b/crates/storage/provider/src/test_utils/blocks.rs @@ -1,6 +1,6 @@ //! Dummy blocks and data for tests use crate::{DatabaseProviderRW, ExecutionOutcome}; -use alloy_consensus::TxLegacy; +use alloy_consensus::{TxLegacy, EMPTY_OMMER_ROOT_HASH}; use alloy_primitives::{ b256, hex_literal::hex, map::HashMap, Address, BlockNumber, Bytes, Log, Parity, Sealable, TxKind, B256, U256, @@ -66,8 +66,7 @@ pub(crate) static TEST_BLOCK: LazyLock = LazyLock::new(|| SealedBlo Header { parent_hash: hex!("c86e8cc0310ae7c531c758678ddbfd16fc51c8cef8cec650b032de9869e8b94f") .into(), - ommers_hash: hex!("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347") - .into(), + ommers_hash: EMPTY_OMMER_ROOT_HASH, beneficiary: hex!("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba").into(), state_root: hex!("50554882fbbda2c2fd93fdc466db9946ea262a67f7a76cc169e714f105ab583d") .into(), From 52407b18de50a07efde4d441d9107ab78f1c19ae Mon Sep 17 00:00:00 2001 From: Emilia Hane Date: Thu, 17 Oct 2024 15:14:48 +0200 Subject: [PATCH 055/113] chore(sdk): incorporate block module into `reth-primitives-traits` (#11835) --- crates/primitives-traits/src/block.rs | 99 ---------------------- crates/primitives-traits/src/block/body.rs | 72 ++-------------- crates/primitives-traits/src/block/mod.rs | 47 +++++----- crates/primitives-traits/src/lib.rs | 3 + 4 files changed, 39 insertions(+), 182 deletions(-) delete mode 100644 crates/primitives-traits/src/block.rs diff --git a/crates/primitives-traits/src/block.rs b/crates/primitives-traits/src/block.rs deleted file mode 100644 index 02f581801c93..000000000000 --- a/crates/primitives-traits/src/block.rs +++ /dev/null @@ -1,99 +0,0 @@ -//! Block abstraction. - -pub mod body; - -use alloc::fmt; -use core::ops; - -use alloy_consensus::BlockHeader; -use alloy_primitives::{Address, Sealable, B256}; - -use crate::{traits::BlockBody, BlockWithSenders, SealedBlock, SealedHeader}; - -/// Abstraction of block data type. -pub trait Block: - fmt::Debug - + Clone - + PartialEq - + Eq - + Default - + serde::Serialize - + for<'a> serde::Deserialize<'a> - + From<(Self::Header, Self::Body)> - + Into<(Self::Header, Self::Body)> -{ - /// Header part of the block. - type Header: BlockHeader + Sealable; - - /// The block's body contains the transactions in the block. - type Body: BlockBody; - - /// A block and block hash. - type SealedBlock; - - /// A block and addresses of senders of transactions in it. - type BlockWithSenders; - - /// Returns reference to [`BlockHeader`] type. - fn header(&self) -> &Self::Header; - - /// Returns reference to [`BlockBody`] type. - fn body(&self) -> &Self::Body; - - /// Calculate the header hash and seal the block so that it can't be changed. - // todo: can be default impl if sealed block type is made generic over header and body and - // migrated to alloy - fn seal_slow(self) -> Self::SealedBlock; - - /// Seal the block with a known hash. - /// - /// WARNING: This method does not perform validation whether the hash is correct. - // todo: can be default impl if sealed block type is made generic over header and body and - // migrated to alloy - fn seal(self, hash: B256) -> Self::SealedBlock; - - /// Expensive operation that recovers transaction signer. See - /// [`SealedBlockWithSenders`](reth_primitives::SealedBlockWithSenders). - fn senders(&self) -> Option> { - self.body().recover_signers() - } - - /// Transform into a [`BlockWithSenders`]. - /// - /// # Panics - /// - /// If the number of senders does not match the number of transactions in the block - /// and the signer recovery for one of the transactions fails. - /// - /// Note: this is expected to be called with blocks read from disk. - #[track_caller] - fn with_senders_unchecked(self, senders: Vec
) -> Self::BlockWithSenders { - self.try_with_senders_unchecked(senders).expect("stored block is valid") - } - - /// Transform into a [`BlockWithSenders`] using the given senders. - /// - /// If the number of senders does not match the number of transactions in the block, this falls - /// back to manually recovery, but _without ensuring that the signature has a low `s` value_. - /// See also [`TransactionSigned::recover_signer_unchecked`] - /// - /// Returns an error if a signature is invalid. - // todo: can be default impl if block with senders type is made generic over block and migrated - // to alloy - #[track_caller] - fn try_with_senders_unchecked( - self, - senders: Vec
, - ) -> Result; - - /// **Expensive**. Transform into a [`BlockWithSenders`] by recovering senders in the contained - /// transactions. - /// - /// Returns `None` if a transaction is invalid. - // todo: can be default impl if sealed block type is made generic over header and body and - // migrated to alloy - fn with_recovered_senders(self) -> Option; - - /// Calculates a heuristic for the in-memory size of the [`Block`]. - fn size(&self) -> usize; -} diff --git a/crates/primitives-traits/src/block/body.rs b/crates/primitives-traits/src/block/body.rs index 03246c68b454..85eeda166c43 100644 --- a/crates/primitives-traits/src/block/body.rs +++ b/crates/primitives-traits/src/block/body.rs @@ -1,11 +1,10 @@ //! Block body abstraction. -use alloc::fmt; -use core::ops; +use alloc::{fmt, vec::Vec}; -use alloy_consensus::{BlockHeader,Request, Transaction, TxType}; +use alloy_consensus::{BlockHeader, Request, Transaction, TxType}; +use alloy_eips::eip4895::Withdrawal; use alloy_primitives::{Address, B256}; -use alloy_eips::eip1559::Withdrawal; use crate::Block; @@ -37,7 +36,7 @@ pub trait BlockBody: /// Returns reference to transactions in block. fn transactions(&self) -> &[Self::SignedTransaction]; - /// Returns [`Withdrawals`] in the block, if any. + /// Returns `Withdrawals` in the block, if any. // todo: branch out into extension trait fn withdrawals(&self) -> Option<&Self::Withdrawals>; @@ -60,13 +59,13 @@ pub trait BlockBody: /// Calculate the withdrawals root for the block body, if withdrawals exist. If there are no /// withdrawals, this will return `None`. - // todo: can be default impl if `calculate_withdrawals_root` made into a method on + // todo: can be default impl if `calculate_withdrawals_root` made into a method on // `Withdrawals` and `Withdrawals` moved to alloy fn calculate_withdrawals_root(&self) -> Option; /// Calculate the requests root for the block body, if requests exist. If there are no /// requests, this will return `None`. - // todo: can be default impl if `calculate_requests_root` made into a method on + // todo: can be default impl if `calculate_requests_root` made into a method on // `Requests` and `Requests` moved to alloy fn calculate_requests_root(&self) -> Option; @@ -75,17 +74,17 @@ pub trait BlockBody: /// Returns whether or not the block body contains any blob transactions. fn has_blob_transactions(&self) -> bool { - self.transactions().iter().any(|tx| tx.ty() as u8 == TxType::Eip4844 as u8) + self.transactions().iter().any(|tx| tx.ty() == TxType::Eip4844 as u8) } /// Returns whether or not the block body contains any EIP-7702 transactions. fn has_eip7702_transactions(&self) -> bool { - self.transactions().iter().any(|tx| tx.ty() as u8 == TxType::Eip7702 as u8) + self.transactions().iter().any(|tx| tx.ty() == TxType::Eip7702 as u8) } /// Returns an iterator over all blob transactions of the block fn blob_transactions_iter(&self) -> impl Iterator + '_ { - self.transactions().iter().filter(|tx| tx.ty() as u8 == TxType::Eip4844 as u8) + self.transactions().iter().filter(|tx| tx.ty() == TxType::Eip4844 as u8) } /// Returns only the blob transactions, if any, from the block body. @@ -104,56 +103,3 @@ pub trait BlockBody: /// Calculates a heuristic for the in-memory size of the [`BlockBody`]. fn size(&self) -> usize; } - -impl BlockBody for T -where - T: ops::Deref - + Clone - + fmt::Debug - + PartialEq - + Eq - + Default - + serde::Serialize - + for<'de> serde::Deserialize<'de> - + alloy_rlp::Encodable - + alloy_rlp::Decodable, -{ - type Header = ::Header; - type SignedTransaction = ::SignedTransaction; - - fn transactions(&self) -> &Vec { - self.deref().transactions() - } - - fn withdrawals(&self) -> Option<&Withdrawals> { - self.deref().withdrawals() - } - - fn ommers(&self) -> &Vec { - self.deref().ommers() - } - - fn requests(&self) -> Option<&Requests> { - self.deref().requests() - } - - fn calculate_tx_root(&self) -> B256 { - self.deref().calculate_tx_root() - } - - fn calculate_ommers_root(&self) -> B256 { - self.deref().calculate_ommers_root() - } - - fn recover_signers(&self) -> Option> { - self.deref().recover_signers() - } - - fn blob_versioned_hashes_iter(&self) -> impl Iterator + '_ { - self.deref().blob_versioned_hashes_iter() - } - - fn size(&self) -> usize { - self.deref().size() - } -} diff --git a/crates/primitives-traits/src/block/mod.rs b/crates/primitives-traits/src/block/mod.rs index 02f581801c93..395cf61df145 100644 --- a/crates/primitives-traits/src/block/mod.rs +++ b/crates/primitives-traits/src/block/mod.rs @@ -2,15 +2,22 @@ pub mod body; -use alloc::fmt; -use core::ops; +use alloc::{fmt, vec::Vec}; use alloy_consensus::BlockHeader; use alloy_primitives::{Address, Sealable, B256}; -use crate::{traits::BlockBody, BlockWithSenders, SealedBlock, SealedHeader}; +use crate::BlockBody; + +/// Helper trait, unifies behaviour required of a block header. +pub trait Header: BlockHeader + Sealable {} + +impl Header for T where T: BlockHeader + Sealable {} /// Abstraction of block data type. +// todo: make sealable super-trait, depends on +// todo: make with senders extension trait, so block can be impl by block type already containing +// senders pub trait Block: fmt::Debug + Clone @@ -23,16 +30,16 @@ pub trait Block: + Into<(Self::Header, Self::Body)> { /// Header part of the block. - type Header: BlockHeader + Sealable; + type Header: Header; /// The block's body contains the transactions in the block. type Body: BlockBody; /// A block and block hash. - type SealedBlock; + type SealedBlock; /// A block and addresses of senders of transactions in it. - type BlockWithSenders; + type BlockWithSenders; /// Returns reference to [`BlockHeader`] type. fn header(&self) -> &Self::Header; @@ -41,24 +48,24 @@ pub trait Block: fn body(&self) -> &Self::Body; /// Calculate the header hash and seal the block so that it can't be changed. - // todo: can be default impl if sealed block type is made generic over header and body and + // todo: can be default impl if sealed block type is made generic over header and body and // migrated to alloy - fn seal_slow(self) -> Self::SealedBlock; + fn seal_slow(self) -> Self::SealedBlock; /// Seal the block with a known hash. /// /// WARNING: This method does not perform validation whether the hash is correct. - // todo: can be default impl if sealed block type is made generic over header and body and + // todo: can be default impl if sealed block type is made generic over header and body and // migrated to alloy - fn seal(self, hash: B256) -> Self::SealedBlock; + fn seal(self, hash: B256) -> Self::SealedBlock; /// Expensive operation that recovers transaction signer. See - /// [`SealedBlockWithSenders`](reth_primitives::SealedBlockWithSenders). + /// `SealedBlockWithSenders`. fn senders(&self) -> Option> { self.body().recover_signers() } - /// Transform into a [`BlockWithSenders`]. + /// Transform into a `BlockWithSenders`. /// /// # Panics /// @@ -67,32 +74,32 @@ pub trait Block: /// /// Note: this is expected to be called with blocks read from disk. #[track_caller] - fn with_senders_unchecked(self, senders: Vec
) -> Self::BlockWithSenders { + fn with_senders_unchecked(self, senders: Vec
) -> Self::BlockWithSenders { self.try_with_senders_unchecked(senders).expect("stored block is valid") } - /// Transform into a [`BlockWithSenders`] using the given senders. + /// Transform into a `BlockWithSenders` using the given senders. /// /// If the number of senders does not match the number of transactions in the block, this falls /// back to manually recovery, but _without ensuring that the signature has a low `s` value_. - /// See also [`TransactionSigned::recover_signer_unchecked`] + /// See also `SignedTransaction::recover_signer_unchecked`. /// /// Returns an error if a signature is invalid. - // todo: can be default impl if block with senders type is made generic over block and migrated + // todo: can be default impl if block with senders type is made generic over block and migrated // to alloy #[track_caller] fn try_with_senders_unchecked( self, senders: Vec
, - ) -> Result; + ) -> Result, Self>; - /// **Expensive**. Transform into a [`BlockWithSenders`] by recovering senders in the contained + /// **Expensive**. Transform into a `BlockWithSenders` by recovering senders in the contained /// transactions. /// /// Returns `None` if a transaction is invalid. - // todo: can be default impl if sealed block type is made generic over header and body and + // todo: can be default impl if sealed block type is made generic over header and body and // migrated to alloy - fn with_recovered_senders(self) -> Option; + fn with_recovered_senders(self) -> Option>; /// Calculates a heuristic for the in-memory size of the [`Block`]. fn size(&self) -> usize; diff --git a/crates/primitives-traits/src/lib.rs b/crates/primitives-traits/src/lib.rs index dd68607f5911..8c54bd68c966 100644 --- a/crates/primitives-traits/src/lib.rs +++ b/crates/primitives-traits/src/lib.rs @@ -32,6 +32,9 @@ pub use integer_list::{IntegerList, IntegerListError}; pub mod request; pub use request::{Request, Requests}; +pub mod block; +pub use block::{body::BlockBody, Block}; + mod withdrawal; pub use withdrawal::{Withdrawal, Withdrawals}; From 6ba4bbe4aad49e483b0670903bdb0328d9ca1b57 Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Thu, 17 Oct 2024 15:54:32 +0200 Subject: [PATCH 056/113] chore: make op-evm compile with no-std (#11834) --- Cargo.lock | 2 +- crates/optimism/evm/Cargo.toml | 4 +++- crates/optimism/evm/src/error.rs | 13 ++++++++----- crates/optimism/evm/src/execute.rs | 3 ++- crates/optimism/evm/src/l1.rs | 2 +- crates/optimism/evm/src/lib.rs | 6 +++++- crates/optimism/evm/src/strategy.rs | 3 ++- 7 files changed, 22 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d31239808a2a..855e3de5e1c3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8108,6 +8108,7 @@ dependencies = [ "alloy-eips", "alloy-genesis", "alloy-primitives", + "derive_more 1.0.0", "op-alloy-consensus", "reth-chainspec", "reth-consensus", @@ -8123,7 +8124,6 @@ dependencies = [ "reth-revm", "revm", "revm-primitives", - "thiserror", "tracing", ] diff --git a/crates/optimism/evm/Cargo.toml b/crates/optimism/evm/Cargo.toml index 0a22dcfddb44..a1e2021a4ad7 100644 --- a/crates/optimism/evm/Cargo.toml +++ b/crates/optimism/evm/Cargo.toml @@ -37,7 +37,7 @@ revm.workspace = true revm-primitives.workspace = true # misc -thiserror.workspace = true +derive_more.workspace = true tracing.workspace = true [dev-dependencies] @@ -51,6 +51,8 @@ alloy-genesis.workspace = true alloy-consensus.workspace = true [features] +default = ["std"] +std = [] optimism = [ "reth-primitives/optimism", "reth-execution-types/optimism", diff --git a/crates/optimism/evm/src/error.rs b/crates/optimism/evm/src/error.rs index c5c6a0a4a3d3..71f8709e1ade 100644 --- a/crates/optimism/evm/src/error.rs +++ b/crates/optimism/evm/src/error.rs @@ -1,27 +1,30 @@ //! Error types for the Optimism EVM module. +use alloc::string::String; use reth_evm::execute::BlockExecutionError; /// Optimism Block Executor Errors -#[derive(thiserror::Error, Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, derive_more::Display)] pub enum OptimismBlockExecutionError { /// Error when trying to parse L1 block info - #[error("could not get L1 block info from L2 block: {message:?}")] + #[display("could not get L1 block info from L2 block: {message}")] L1BlockInfoError { /// The inner error message message: String, }, /// Thrown when force deploy of create2deployer code fails. - #[error("failed to force create2deployer account code")] + #[display("failed to force create2deployer account code")] ForceCreate2DeployerFail, /// Thrown when a blob transaction is included in a sequencer's block. - #[error("blob transaction included in sequencer block")] + #[display("blob transaction included in sequencer block")] BlobTransactionRejected, /// Thrown when a database account could not be loaded. - #[error("failed to load account {0}")] + #[display("failed to load account {_0}")] AccountLoadFailed(alloy_primitives::Address), } +impl core::error::Error for OptimismBlockExecutionError {} + impl From for BlockExecutionError { fn from(err: OptimismBlockExecutionError) -> Self { Self::other(err) diff --git a/crates/optimism/evm/src/execute.rs b/crates/optimism/evm/src/execute.rs index f7da1c250d9b..263420623212 100644 --- a/crates/optimism/evm/src/execute.rs +++ b/crates/optimism/evm/src/execute.rs @@ -3,8 +3,10 @@ use crate::{ l1::ensure_create2_deployer, OpChainSpec, OptimismBlockExecutionError, OptimismEvmConfig, }; +use alloc::{boxed::Box, sync::Arc, vec::Vec}; use alloy_consensus::Transaction as _; use alloy_primitives::{BlockNumber, U256}; +use core::fmt::Display; use reth_chainspec::{ChainSpec, EthereumHardforks}; use reth_evm::{ execute::{ @@ -27,7 +29,6 @@ use revm_primitives::{ db::{Database, DatabaseCommit}, BlockEnv, CfgEnvWithHandlerCfg, EnvWithHandlerCfg, ResultAndState, }; -use std::{fmt::Display, sync::Arc}; use tracing::trace; /// Provides executors to execute regular optimism blocks diff --git a/crates/optimism/evm/src/l1.rs b/crates/optimism/evm/src/l1.rs index 3412501eb99b..e0668ab02042 100644 --- a/crates/optimism/evm/src/l1.rs +++ b/crates/optimism/evm/src/l1.rs @@ -1,6 +1,7 @@ //! Optimism-specific implementation and utilities for the executor use crate::OptimismBlockExecutionError; +use alloc::{string::ToString, sync::Arc}; use alloy_primitives::{address, b256, hex, Address, Bytes, B256, U256}; use reth_chainspec::ChainSpec; use reth_execution_errors::BlockExecutionError; @@ -11,7 +12,6 @@ use revm::{ primitives::{Bytecode, HashMap, SpecId}, DatabaseCommit, L1BlockInfo, }; -use std::sync::Arc; use tracing::trace; /// The address of the create2 deployer diff --git a/crates/optimism/evm/src/lib.rs b/crates/optimism/evm/src/lib.rs index 4d0f9d89ff41..eb067da32566 100644 --- a/crates/optimism/evm/src/lib.rs +++ b/crates/optimism/evm/src/lib.rs @@ -6,9 +6,14 @@ issue_tracker_base_url = "https://github.com/paradigmxyz/reth/issues/" )] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] +#![cfg_attr(not(feature = "std"), no_std)] // The `optimism` feature must be enabled to use this crate. #![cfg(feature = "optimism")] +#[macro_use] +extern crate alloc; + +use alloc::{sync::Arc, vec::Vec}; use alloy_primitives::{Address, U256}; use reth_evm::{ConfigureEvm, ConfigureEvmEnv, NextBlockEnvAttributes}; use reth_optimism_chainspec::OpChainSpec; @@ -18,7 +23,6 @@ use reth_primitives::{ Head, Header, TransactionSigned, }; use reth_revm::{inspector_handle_register, Database, Evm, EvmBuilder, GetInspector}; -use std::sync::Arc; mod config; pub use config::{revm_spec, revm_spec_by_timestamp_after_bedrock}; diff --git a/crates/optimism/evm/src/strategy.rs b/crates/optimism/evm/src/strategy.rs index fe8164cc7cf3..9ba43604ea0b 100644 --- a/crates/optimism/evm/src/strategy.rs +++ b/crates/optimism/evm/src/strategy.rs @@ -1,7 +1,9 @@ //! Optimism block execution strategy, use crate::{l1::ensure_create2_deployer, OptimismBlockExecutionError, OptimismEvmConfig}; +use alloc::{boxed::Box, sync::Arc, vec::Vec}; use alloy_consensus::Transaction as _; +use core::fmt::Display; use reth_chainspec::EthereumHardforks; use reth_consensus::ConsensusError; use reth_evm::{ @@ -24,7 +26,6 @@ use reth_revm::{ use revm_primitives::{ db::DatabaseCommit, BlockEnv, CfgEnvWithHandlerCfg, EnvWithHandlerCfg, ResultAndState, U256, }; -use std::{fmt::Display, sync::Arc}; use tracing::trace; /// Factory for [`OpExecutionStrategy`]. From 2131c87edb8f3c7459a73c19de9034fd1e28a77c Mon Sep 17 00:00:00 2001 From: nk_ysg Date: Thu, 17 Oct 2024 22:40:10 +0800 Subject: [PATCH 057/113] refactor: rm redundant clones in tests (#11840) --- crates/prune/prune/src/segments/receipts.rs | 6 ++++-- crates/prune/prune/src/segments/user/receipts_by_logs.rs | 1 + crates/prune/prune/src/segments/user/sender_recovery.rs | 7 ++++--- crates/prune/prune/src/segments/user/transaction_lookup.rs | 6 ++++-- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/crates/prune/prune/src/segments/receipts.rs b/crates/prune/prune/src/segments/receipts.rs index 05482d65953d..c081bf88c7d2 100644 --- a/crates/prune/prune/src/segments/receipts.rs +++ b/crates/prune/prune/src/segments/receipts.rs @@ -109,12 +109,14 @@ mod tests { let mut receipts = Vec::new(); for block in &blocks { + receipts.reserve_exact(block.body.transactions.len()); for transaction in &block.body.transactions { receipts .push((receipts.len() as u64, random_receipt(&mut rng, transaction, Some(0)))); } } - db.insert_receipts(receipts.clone()).expect("insert receipts"); + let receipts_len = receipts.len(); + db.insert_receipts(receipts).expect("insert receipts"); assert_eq!( db.table::().unwrap().len(), @@ -194,7 +196,7 @@ mod tests { assert_eq!( db.table::().unwrap().len(), - receipts.len() - (last_pruned_tx_number + 1) + receipts_len - (last_pruned_tx_number + 1) ); assert_eq!( db.factory diff --git a/crates/prune/prune/src/segments/user/receipts_by_logs.rs b/crates/prune/prune/src/segments/user/receipts_by_logs.rs index 05bc40b6c7b0..ee2accee1b34 100644 --- a/crates/prune/prune/src/segments/user/receipts_by_logs.rs +++ b/crates/prune/prune/src/segments/user/receipts_by_logs.rs @@ -263,6 +263,7 @@ mod tests { let (deposit_contract_addr, _) = random_eoa_account(&mut rng); for block in &blocks { + receipts.reserve_exact(block.body.size()); for (txi, transaction) in block.body.transactions.iter().enumerate() { let mut receipt = random_receipt(&mut rng, transaction, Some(1)); receipt.logs.push(random_log( diff --git a/crates/prune/prune/src/segments/user/sender_recovery.rs b/crates/prune/prune/src/segments/user/sender_recovery.rs index bd86f3e65213..f189e6c36af4 100644 --- a/crates/prune/prune/src/segments/user/sender_recovery.rs +++ b/crates/prune/prune/src/segments/user/sender_recovery.rs @@ -110,6 +110,7 @@ mod tests { let mut transaction_senders = Vec::new(); for block in &blocks { + transaction_senders.reserve_exact(block.body.transactions.len()); for transaction in &block.body.transactions { transaction_senders.push(( transaction_senders.len() as u64, @@ -117,8 +118,8 @@ mod tests { )); } } - db.insert_transaction_senders(transaction_senders.clone()) - .expect("insert transaction senders"); + let transaction_senders_len = transaction_senders.len(); + db.insert_transaction_senders(transaction_senders).expect("insert transaction senders"); assert_eq!( db.table::().unwrap().len(), @@ -202,7 +203,7 @@ mod tests { assert_eq!( db.table::().unwrap().len(), - transaction_senders.len() - (last_pruned_tx_number + 1) + transaction_senders_len - (last_pruned_tx_number + 1) ); assert_eq!( db.factory diff --git a/crates/prune/prune/src/segments/user/transaction_lookup.rs b/crates/prune/prune/src/segments/user/transaction_lookup.rs index bb8196cdb03b..2df8cccf3056 100644 --- a/crates/prune/prune/src/segments/user/transaction_lookup.rs +++ b/crates/prune/prune/src/segments/user/transaction_lookup.rs @@ -140,11 +140,13 @@ mod tests { let mut tx_hash_numbers = Vec::new(); for block in &blocks { + tx_hash_numbers.reserve_exact(block.body.transactions.len()); for transaction in &block.body.transactions { tx_hash_numbers.push((transaction.hash, tx_hash_numbers.len() as u64)); } } - db.insert_tx_hash_numbers(tx_hash_numbers.clone()).expect("insert tx hash numbers"); + let tx_hash_numbers_len = tx_hash_numbers.len(); + db.insert_tx_hash_numbers(tx_hash_numbers).expect("insert tx hash numbers"); assert_eq!( db.table::().unwrap().len(), @@ -228,7 +230,7 @@ mod tests { assert_eq!( db.table::().unwrap().len(), - tx_hash_numbers.len() - (last_pruned_tx_number + 1) + tx_hash_numbers_len - (last_pruned_tx_number + 1) ); assert_eq!( db.factory From 9db28d91a47e309960f554479a5fbfa61a56dc4e Mon Sep 17 00:00:00 2001 From: Emilia Hane Date: Thu, 17 Oct 2024 18:29:17 +0200 Subject: [PATCH 058/113] chore(sdk): Impl `alloy_consensus::Transaction` for `TransactionSigned` (#11843) --- crates/primitives/src/transaction/mod.rs | 66 ++++++++++++++++++- .../rpc-types-compat/src/transaction/mod.rs | 4 +- crates/rpc/rpc/src/eth/helpers/types.rs | 5 +- crates/rpc/rpc/src/txpool.rs | 2 +- crates/transaction-pool/src/traits.rs | 4 +- 5 files changed, 71 insertions(+), 10 deletions(-) diff --git a/crates/primitives/src/transaction/mod.rs b/crates/primitives/src/transaction/mod.rs index da1a2d871398..10fddcb4c375 100644 --- a/crates/primitives/src/transaction/mod.rs +++ b/crates/primitives/src/transaction/mod.rs @@ -1351,6 +1351,68 @@ impl TransactionSigned { } } +impl alloy_consensus::Transaction for TransactionSigned { + fn chain_id(&self) -> Option { + self.deref().chain_id() + } + + fn nonce(&self) -> u64 { + self.deref().nonce() + } + + fn gas_limit(&self) -> u64 { + self.deref().gas_limit() + } + + fn gas_price(&self) -> Option { + self.deref().gas_price() + } + + fn max_fee_per_gas(&self) -> u128 { + self.deref().max_fee_per_gas() + } + + fn max_priority_fee_per_gas(&self) -> Option { + self.deref().max_priority_fee_per_gas() + } + + fn max_fee_per_blob_gas(&self) -> Option { + self.deref().max_fee_per_blob_gas() + } + + fn priority_fee_or_price(&self) -> u128 { + self.deref().priority_fee_or_price() + } + + fn to(&self) -> TxKind { + alloy_consensus::Transaction::to(self.deref()) + } + + fn value(&self) -> U256 { + self.deref().value() + } + + fn input(&self) -> &[u8] { + self.deref().input() + } + + fn ty(&self) -> u8 { + self.deref().ty() + } + + fn access_list(&self) -> Option<&AccessList> { + self.deref().access_list() + } + + fn blob_versioned_hashes(&self) -> Option<&[B256]> { + alloy_consensus::Transaction::blob_versioned_hashes(self.deref()) + } + + fn authorization_list(&self) -> Option<&[SignedAuthorization]> { + self.deref().authorization_list() + } +} + impl From for TransactionSigned { fn from(recovered: TransactionSignedEcRecovered) -> Self { recovered.signed_transaction @@ -2181,8 +2243,8 @@ mod tests { let tx = TransactionSigned::decode_2718(&mut data.as_slice()).unwrap(); let sender = tx.recover_signer().unwrap(); assert_eq!(sender, address!("001e2b7dE757bA469a57bF6b23d982458a07eFcE")); - assert_eq!(tx.to(), Some(address!("D9e1459A7A482635700cBc20BBAF52D495Ab9C96"))); - assert_eq!(tx.input().as_ref(), hex!("1b55ba3a")); + assert_eq!(tx.to(), Some(address!("D9e1459A7A482635700cBc20BBAF52D495Ab9C96")).into()); + assert_eq!(tx.input(), hex!("1b55ba3a")); let encoded = tx.encoded_2718(); assert_eq!(encoded.as_ref(), data.to_vec()); } diff --git a/crates/rpc/rpc-types-compat/src/transaction/mod.rs b/crates/rpc/rpc-types-compat/src/transaction/mod.rs index a489a588617a..7ffd48cb1f72 100644 --- a/crates/rpc/rpc-types-compat/src/transaction/mod.rs +++ b/crates/rpc/rpc-types-compat/src/transaction/mod.rs @@ -48,9 +48,7 @@ pub trait TransactionCompat: Send + Sync + Unpin + Clone + fmt::Debug { // baseFee` let gas_price = base_fee .and_then(|base_fee| { - signed_tx - .effective_tip_per_gas(Some(base_fee)) - .map(|tip| tip + base_fee as u128) + signed_tx.effective_tip_per_gas(base_fee).map(|tip| tip + base_fee as u128) }) .unwrap_or_else(|| signed_tx.max_fee_per_gas()); diff --git a/crates/rpc/rpc/src/eth/helpers/types.rs b/crates/rpc/rpc/src/eth/helpers/types.rs index 982afdcac0ad..ab7b1a268e06 100644 --- a/crates/rpc/rpc/src/eth/helpers/types.rs +++ b/crates/rpc/rpc/src/eth/helpers/types.rs @@ -37,8 +37,9 @@ where let GasPrice { gas_price, max_fee_per_gas } = Self::gas_price(&signed_tx, base_fee.map(|fee| fee as u64)); + let input = signed_tx.input().to_vec().into(); let chain_id = signed_tx.chain_id(); - let blob_versioned_hashes = signed_tx.blob_versioned_hashes(); + let blob_versioned_hashes = signed_tx.blob_versioned_hashes().map(|hs| hs.to_vec()); let access_list = signed_tx.access_list().cloned(); let authorization_list = signed_tx.authorization_list().map(|l| l.to_vec()); @@ -60,7 +61,7 @@ where max_priority_fee_per_gas: signed_tx.max_priority_fee_per_gas(), signature: Some(signature), gas: signed_tx.gas_limit(), - input: signed_tx.input().clone(), + input, chain_id, access_list, transaction_type: Some(signed_tx.tx_type() as u8), diff --git a/crates/rpc/rpc/src/txpool.rs b/crates/rpc/rpc/src/txpool.rs index 47aaac0bbfd5..d40cdc5cdbbf 100644 --- a/crates/rpc/rpc/src/txpool.rs +++ b/crates/rpc/rpc/src/txpool.rs @@ -101,7 +101,7 @@ where entry.insert( tx.nonce().to_string(), TxpoolInspectSummary { - to: tx.to(), + to: tx.to().into(), value: tx.value(), gas: tx.gas_limit() as u128, gas_price: tx.transaction.max_fee_per_gas(), diff --git a/crates/transaction-pool/src/traits.rs b/crates/transaction-pool/src/traits.rs index d19381935ec4..ee4a5ada3d8d 100644 --- a/crates/transaction-pool/src/traits.rs +++ b/crates/transaction-pool/src/traits.rs @@ -1183,7 +1183,7 @@ impl PoolTransaction for EthPooledTransaction { /// For EIP-1559 transactions: `min(max_fee_per_gas - base_fee, max_priority_fee_per_gas)`. /// For legacy transactions: `gas_price - base_fee`. fn effective_tip_per_gas(&self, base_fee: u64) -> Option { - self.transaction.effective_tip_per_gas(Some(base_fee)) + self.transaction.effective_tip_per_gas(base_fee) } /// Returns the max priority fee per gas if the transaction is an EIP-1559 transaction, and @@ -1199,7 +1199,7 @@ impl PoolTransaction for EthPooledTransaction { } fn input(&self) -> &[u8] { - self.transaction.input().as_ref() + self.transaction.input() } /// Returns a measurement of the heap usage of this type and all its internals. From 1aa3ce1a5a99d9ffd050d18b8a2fc621c22e80b2 Mon Sep 17 00:00:00 2001 From: Kunal Arora <55632507+aroralanuk@users.noreply.github.com> Date: Thu, 17 Oct 2024 22:02:29 +0530 Subject: [PATCH 059/113] feat(cli): add ChainSpecParser type to rethCli (#11772) --- crates/cli/cli/src/lib.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crates/cli/cli/src/lib.rs b/crates/cli/cli/src/lib.rs index f7bf716ea379..e2c55057a48b 100644 --- a/crates/cli/cli/src/lib.rs +++ b/crates/cli/cli/src/lib.rs @@ -15,6 +15,7 @@ use std::{borrow::Cow, ffi::OsString}; /// The chainspec module defines the different chainspecs that can be used by the node. pub mod chainspec; +use crate::chainspec::ChainSpecParser; /// Reth based node cli. /// @@ -23,6 +24,9 @@ pub mod chainspec; /// It provides commonly used functionality for running commands and information about the CL, such /// as the name and version. pub trait RethCli: Sized { + /// The associated `ChainSpecParser` type + type ChainSpecParser: ChainSpecParser; + /// The name of the implementation, eg. `reth`, `op-reth`, etc. fn name(&self) -> Cow<'static, str>; From 0a1473b6e7949875f480043fa6874bdc583786d2 Mon Sep 17 00:00:00 2001 From: nk_ysg Date: Fri, 18 Oct 2024 00:40:59 +0800 Subject: [PATCH 060/113] perf(blockchain-tree:) use `Vec::reserve_exact` (#11839) --- crates/blockchain-tree/src/blockchain_tree.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/blockchain-tree/src/blockchain_tree.rs b/crates/blockchain-tree/src/blockchain_tree.rs index 71a58aa56288..db43dffcd36a 100644 --- a/crates/blockchain-tree/src/blockchain_tree.rs +++ b/crates/blockchain-tree/src/blockchain_tree.rs @@ -902,6 +902,7 @@ where // check unconnected block buffer for children of the chains let mut all_chain_blocks = Vec::new(); for chain in self.state.chains.values() { + all_chain_blocks.reserve_exact(chain.blocks().len()); for (&number, block) in chain.blocks() { all_chain_blocks.push(BlockNumHash { number, hash: block.hash() }) } From 76edc388237c18a586038924bc39dcbc6c72eaac Mon Sep 17 00:00:00 2001 From: Dan Cline <6798349+Rjected@users.noreply.github.com> Date: Thu, 17 Oct 2024 13:48:05 -0400 Subject: [PATCH 061/113] fix(rpc): apply beacon root contract call in debug_traceTransaction (#11845) --- crates/rpc/rpc/src/debug.rs | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/crates/rpc/rpc/src/debug.rs b/crates/rpc/rpc/src/debug.rs index acf215b3b2cc..164f402e44cc 100644 --- a/crates/rpc/rpc/src/debug.rs +++ b/crates/rpc/rpc/src/debug.rs @@ -16,6 +16,7 @@ use jsonrpsee::core::RpcResult; use reth_chainspec::EthereumHardforks; use reth_evm::{ execute::{BlockExecutorProvider, Executor}, + system_calls::SystemCaller, ConfigureEvmEnv, }; use reth_primitives::{Block, BlockId, BlockNumberOrTag, TransactionSignedEcRecovered}; @@ -26,7 +27,7 @@ use reth_provider::{ use reth_revm::database::StateProviderDatabase; use reth_rpc_api::DebugApiServer; use reth_rpc_eth_api::{ - helpers::{Call, EthApiSpec, EthTransactions, TraceExt}, + helpers::{Call, EthApiSpec, EthTransactions, LoadState, TraceExt}, EthApiTypes, FromEthApiError, }; use reth_rpc_eth_types::{EthApiError, StateCacheDb}; @@ -245,6 +246,7 @@ where // block the transaction is included in let state_at: BlockId = block.parent_hash.into(); let block_hash = block.hash(); + let parent_beacon_block_root = block.parent_beacon_block_root; let this = self.clone(); self.eth_api() @@ -255,6 +257,26 @@ where let tx = transaction.into_recovered(); let mut db = CacheDB::new(StateProviderDatabase::new(state)); + + // apply relevant system calls + let mut system_caller = SystemCaller::new( + Call::evm_config(this.eth_api()).clone(), + LoadState::provider(this.eth_api()).chain_spec(), + ); + + system_caller + .pre_block_beacon_root_contract_call( + &mut db, + &cfg, + &block_env, + parent_beacon_block_root, + ) + .map_err(|_| { + EthApiError::EvmCustom( + "failed to apply 4788 beacon root system call".to_string(), + ) + })?; + // replay all transactions prior to the targeted transaction let index = this.eth_api().replay_transactions_until( &mut db, From 52848a352a241cb1d16ef5040ef2c4b16b0cac15 Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Thu, 17 Oct 2024 20:13:05 +0200 Subject: [PATCH 062/113] fix: check for prague timestmap on pool init (#11847) --- crates/transaction-pool/src/validate/eth.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/transaction-pool/src/validate/eth.rs b/crates/transaction-pool/src/validate/eth.rs index 49165f189a05..2594e569aa0b 100644 --- a/crates/transaction-pool/src/validate/eth.rs +++ b/crates/transaction-pool/src/validate/eth.rs @@ -639,6 +639,7 @@ impl EthTransactionValidatorBuilder { pub fn with_head_timestamp(mut self, timestamp: u64) -> Self { self.cancun = self.chain_spec.is_cancun_active_at_timestamp(timestamp); self.shanghai = self.chain_spec.is_shanghai_active_at_timestamp(timestamp); + self.prague = self.chain_spec.is_prague_active_at_timestamp(timestamp); self } From a6c8bda029eb32703ae77a8eea4e69aa0ec00a10 Mon Sep 17 00:00:00 2001 From: Thomas Coratger <60488569+tcoratger@users.noreply.github.com> Date: Thu, 17 Oct 2024 21:44:04 +0200 Subject: [PATCH 063/113] primitives: use alloy `MAINNET_GENESIS_HASH` constant (#11848) --- Cargo.lock | 5 +++++ crates/chainspec/Cargo.toml | 1 + crates/chainspec/src/spec.rs | 3 ++- crates/ethereum-forks/Cargo.toml | 1 + crates/ethereum-forks/src/forkid.rs | 11 ++++------- crates/ethereum/node/Cargo.toml | 1 + crates/ethereum/node/tests/e2e/blobs.rs | 8 +++----- crates/net/eth-wire-types/src/status.rs | 13 ++++--------- crates/primitives-traits/src/constants/mod.rs | 5 ----- crates/primitives/src/lib.rs | 5 +---- crates/storage/db-common/Cargo.toml | 1 + crates/storage/db-common/src/init.rs | 3 ++- examples/manual-p2p/Cargo.toml | 2 ++ examples/manual-p2p/src/main.rs | 3 ++- 14 files changed, 29 insertions(+), 33 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 855e3de5e1c3..600d61e97e27 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2857,6 +2857,7 @@ dependencies = [ name = "example-manual-p2p" version = "0.0.0" dependencies = [ + "alloy-consensus", "eyre", "futures", "reth-chainspec", @@ -6528,6 +6529,7 @@ name = "reth-chainspec" version = "1.1.0" dependencies = [ "alloy-chains", + "alloy-consensus", "alloy-eips", "alloy-genesis", "alloy-primitives", @@ -6813,6 +6815,7 @@ dependencies = [ name = "reth-db-common" version = "1.1.0" dependencies = [ + "alloy-consensus", "alloy-genesis", "alloy-primitives", "boyer-moore-magiclen", @@ -7303,6 +7306,7 @@ name = "reth-ethereum-forks" version = "1.1.0" dependencies = [ "alloy-chains", + "alloy-consensus", "alloy-primitives", "alloy-rlp", "arbitrary", @@ -7931,6 +7935,7 @@ dependencies = [ name = "reth-node-ethereum" version = "1.1.0" dependencies = [ + "alloy-consensus", "alloy-genesis", "alloy-primitives", "eyre", diff --git a/crates/chainspec/Cargo.toml b/crates/chainspec/Cargo.toml index b44a606b65b7..2864427c2af6 100644 --- a/crates/chainspec/Cargo.toml +++ b/crates/chainspec/Cargo.toml @@ -23,6 +23,7 @@ alloy-eips = { workspace = true, features = ["serde"] } alloy-genesis.workspace = true alloy-primitives = { workspace = true, features = ["rand", "rlp"] } alloy-trie.workspace = true +alloy-consensus.workspace = true # misc auto_impl.workspace = true diff --git a/crates/chainspec/src/spec.rs b/crates/chainspec/src/spec.rs index a8bae966b58e..deaca188a21a 100644 --- a/crates/chainspec/src/spec.rs +++ b/crates/chainspec/src/spec.rs @@ -7,6 +7,7 @@ use alloy_primitives::{address, b256, Address, BlockNumber, B256, U256}; use alloy_trie::EMPTY_ROOT_HASH; use derive_more::From; +use alloy_consensus::constants::MAINNET_GENESIS_HASH; use reth_ethereum_forks::{ ChainHardforks, DisplayHardforks, EthereumHardfork, EthereumHardforks, ForkCondition, ForkFilter, ForkFilterKey, ForkHash, ForkId, Hardfork, Hardforks, Head, DEV_HARDFORKS, @@ -18,7 +19,7 @@ use reth_network_peers::{ use reth_primitives_traits::{ constants::{ DEV_GENESIS_HASH, EIP1559_INITIAL_BASE_FEE, EMPTY_WITHDRAWALS, ETHEREUM_BLOCK_GAS_LIMIT, - HOLESKY_GENESIS_HASH, MAINNET_GENESIS_HASH, SEPOLIA_GENESIS_HASH, + HOLESKY_GENESIS_HASH, SEPOLIA_GENESIS_HASH, }, Header, SealedHeader, }; diff --git a/crates/ethereum-forks/Cargo.toml b/crates/ethereum-forks/Cargo.toml index 08a0bc98dbcf..62ea234cd5bb 100644 --- a/crates/ethereum-forks/Cargo.toml +++ b/crates/ethereum-forks/Cargo.toml @@ -36,6 +36,7 @@ auto_impl.workspace = true [dev-dependencies] arbitrary = { workspace = true, features = ["derive"] } proptest.workspace = true +alloy-consensus.workspace = true [features] default = ["std", "serde", "rustc-hash"] diff --git a/crates/ethereum-forks/src/forkid.rs b/crates/ethereum-forks/src/forkid.rs index 6876d0eb926d..b612f3b0b1ae 100644 --- a/crates/ethereum-forks/src/forkid.rs +++ b/crates/ethereum-forks/src/forkid.rs @@ -446,15 +446,12 @@ impl Cache { #[cfg(test)] mod tests { use super::*; - use alloy_primitives::b256; - - const GENESIS_HASH: B256 = - b256!("d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3"); + use alloy_consensus::constants::MAINNET_GENESIS_HASH; // EIP test vectors. #[test] fn forkhash() { - let mut fork_hash = ForkHash::from(GENESIS_HASH); + let mut fork_hash = ForkHash::from(MAINNET_GENESIS_HASH); assert_eq!(fork_hash.0, hex!("fc64ec04")); fork_hash += 1_150_000u64; @@ -468,7 +465,7 @@ mod tests { fn compatibility_check() { let mut filter = ForkFilter::new( Head { number: 0, ..Default::default() }, - GENESIS_HASH, + MAINNET_GENESIS_HASH, 0, vec![ ForkFilterKey::Block(1_150_000), @@ -727,7 +724,7 @@ mod tests { let mut fork_filter = ForkFilter::new( Head { number: 0, ..Default::default() }, - GENESIS_HASH, + MAINNET_GENESIS_HASH, 0, vec![ForkFilterKey::Block(b1), ForkFilterKey::Block(b2)], ); diff --git a/crates/ethereum/node/Cargo.toml b/crates/ethereum/node/Cargo.toml index 7a323f91d877..213071cbfb50 100644 --- a/crates/ethereum/node/Cargo.toml +++ b/crates/ethereum/node/Cargo.toml @@ -52,6 +52,7 @@ alloy-genesis.workspace = true tokio.workspace = true futures-util.workspace = true serde_json.workspace = true +alloy-consensus.workspace = true [features] default = [] diff --git a/crates/ethereum/node/tests/e2e/blobs.rs b/crates/ethereum/node/tests/e2e/blobs.rs index 9390b34f444a..b4d9a532aebe 100644 --- a/crates/ethereum/node/tests/e2e/blobs.rs +++ b/crates/ethereum/node/tests/e2e/blobs.rs @@ -1,7 +1,7 @@ use std::sync::Arc; +use alloy_consensus::constants::MAINNET_GENESIS_HASH; use alloy_genesis::Genesis; -use alloy_primitives::b256; use reth::{ args::RpcServerArgs, builder::{NodeBuilder, NodeConfig, NodeHandle}, @@ -75,13 +75,11 @@ async fn can_handle_blobs() -> eyre::Result<()> { .submit_payload(blob_payload, blob_attr, PayloadStatusEnum::Valid, versioned_hashes.clone()) .await?; - let genesis_hash = b256!("d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3"); - let (_, _) = tokio::join!( // send fcu with blob hash - node.engine_api.update_forkchoice(genesis_hash, blob_block_hash), + node.engine_api.update_forkchoice(MAINNET_GENESIS_HASH, blob_block_hash), // send fcu with normal hash - node.engine_api.update_forkchoice(genesis_hash, payload.block().hash()) + node.engine_api.update_forkchoice(MAINNET_GENESIS_HASH, payload.block().hash()) ); // submit normal payload diff --git a/crates/net/eth-wire-types/src/status.rs b/crates/net/eth-wire-types/src/status.rs index a5e7530ec09a..90e1731c90ab 100644 --- a/crates/net/eth-wire-types/src/status.rs +++ b/crates/net/eth-wire-types/src/status.rs @@ -138,10 +138,10 @@ impl Default for Status { /// /// # Example /// ``` +/// use alloy_consensus::constants::MAINNET_GENESIS_HASH; /// use alloy_primitives::{B256, U256}; /// use reth_chainspec::{Chain, EthereumHardfork, MAINNET}; /// use reth_eth_wire_types::{EthVersion, Status}; -/// use reth_primitives::MAINNET_GENESIS_HASH; /// /// // this is just an example status message! /// let status = Status::builder() @@ -216,6 +216,7 @@ impl StatusBuilder { #[cfg(test)] mod tests { use crate::{EthVersion, Status}; + use alloy_consensus::constants::MAINNET_GENESIS_HASH; use alloy_genesis::Genesis; use alloy_primitives::{hex, B256, U256}; use alloy_rlp::{Decodable, Encodable}; @@ -235,10 +236,7 @@ mod tests { "feb27336ca7923f8fab3bd617fcb6e75841538f71c1bcfc267d7838489d9e13d", ) .unwrap(), - genesis: B256::from_str( - "d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3", - ) - .unwrap(), + genesis: MAINNET_GENESIS_HASH, forkid: ForkId { hash: ForkHash([0xb7, 0x15, 0x07, 0x7d]), next: 0 }, }; @@ -258,10 +256,7 @@ mod tests { "feb27336ca7923f8fab3bd617fcb6e75841538f71c1bcfc267d7838489d9e13d", ) .unwrap(), - genesis: B256::from_str( - "d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3", - ) - .unwrap(), + genesis: MAINNET_GENESIS_HASH, forkid: ForkId { hash: ForkHash([0xb7, 0x15, 0x07, 0x7d]), next: 0 }, }; let status = Status::decode(&mut &data[..]).unwrap(); diff --git a/crates/primitives-traits/src/constants/mod.rs b/crates/primitives-traits/src/constants/mod.rs index 5d64b911b60a..890287f8bc19 100644 --- a/crates/primitives-traits/src/constants/mod.rs +++ b/crates/primitives-traits/src/constants/mod.rs @@ -98,11 +98,6 @@ pub const FINNEY_TO_WEI: u128 = (GWEI_TO_WEI as u128) * 1_000_000; /// Multiplier for converting ether to wei. pub const ETH_TO_WEI: u128 = FINNEY_TO_WEI * 1000; -/// The Ethereum mainnet genesis hash: -/// `0x0d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3` -pub const MAINNET_GENESIS_HASH: B256 = - b256!("d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3"); - /// Sepolia genesis hash: `0x25a5cc106eea7138acab33231d7160d69cb777ee0c2c553fcddf5138993e6dd9` pub const SEPOLIA_GENESIS_HASH: B256 = b256!("25a5cc106eea7138acab33231d7160d69cb777ee0c2c553fcddf5138993e6dd9"); diff --git a/crates/primitives/src/lib.rs b/crates/primitives/src/lib.rs index a59e72bbd556..4a8d812ef834 100644 --- a/crates/primitives/src/lib.rs +++ b/crates/primitives/src/lib.rs @@ -39,10 +39,7 @@ pub use block::{ }; #[cfg(feature = "reth-codec")] pub use compression::*; -pub use constants::{ - DEV_GENESIS_HASH, HOLESKY_GENESIS_HASH, KECCAK_EMPTY, MAINNET_GENESIS_HASH, - SEPOLIA_GENESIS_HASH, -}; +pub use constants::{DEV_GENESIS_HASH, HOLESKY_GENESIS_HASH, KECCAK_EMPTY, SEPOLIA_GENESIS_HASH}; pub use receipt::{ gas_spent_by_transactions, Receipt, ReceiptWithBloom, ReceiptWithBloomRef, Receipts, }; diff --git a/crates/storage/db-common/Cargo.toml b/crates/storage/db-common/Cargo.toml index 7fc487969861..9e4954357f84 100644 --- a/crates/storage/db-common/Cargo.toml +++ b/crates/storage/db-common/Cargo.toml @@ -42,6 +42,7 @@ tracing.workspace = true [dev-dependencies] reth-primitives-traits.workspace = true reth-provider = { workspace = true, features = ["test-utils"] } +alloy-consensus.workspace = true [lints] workspace = true diff --git a/crates/storage/db-common/src/init.rs b/crates/storage/db-common/src/init.rs index 3962dfd69809..f0695421ec5c 100644 --- a/crates/storage/db-common/src/init.rs +++ b/crates/storage/db-common/src/init.rs @@ -581,6 +581,7 @@ struct GenesisAccountWithAddress { #[cfg(test)] mod tests { use super::*; + use alloy_consensus::constants::MAINNET_GENESIS_HASH; use alloy_genesis::Genesis; use reth_chainspec::{Chain, ChainSpec, HOLESKY, MAINNET, SEPOLIA}; use reth_db::DatabaseEnv; @@ -591,7 +592,7 @@ mod tests { transaction::DbTx, Database, }; - use reth_primitives::{HOLESKY_GENESIS_HASH, MAINNET_GENESIS_HASH, SEPOLIA_GENESIS_HASH}; + use reth_primitives::{HOLESKY_GENESIS_HASH, SEPOLIA_GENESIS_HASH}; use reth_primitives_traits::IntegerList; use reth_provider::{ test_utils::{create_test_provider_factory_with_chain_spec, MockNodeTypesWithDB}, diff --git a/examples/manual-p2p/Cargo.toml b/examples/manual-p2p/Cargo.toml index 2303bfbfeac6..b1642f66ca04 100644 --- a/examples/manual-p2p/Cargo.toml +++ b/examples/manual-p2p/Cargo.toml @@ -14,6 +14,8 @@ reth-eth-wire.workspace = true reth-ecies.workspace = true reth-network-peers.workspace = true +alloy-consensus.workspace = true + secp256k1 = { workspace = true, features = ["global-context", "rand-std", "recovery"] } futures.workspace = true diff --git a/examples/manual-p2p/src/main.rs b/examples/manual-p2p/src/main.rs index edaaf8584897..857a8a1c1269 100644 --- a/examples/manual-p2p/src/main.rs +++ b/examples/manual-p2p/src/main.rs @@ -8,6 +8,7 @@ use std::time::Duration; +use alloy_consensus::constants::MAINNET_GENESIS_HASH; use futures::StreamExt; use reth_chainspec::{Chain, MAINNET}; use reth_discv4::{DiscoveryUpdate, Discv4, Discv4ConfigBuilder, DEFAULT_DISCOVERY_ADDRESS}; @@ -17,7 +18,7 @@ use reth_eth_wire::{ }; use reth_network::config::rng_secret_key; use reth_network_peers::{mainnet_nodes, pk2id, NodeRecord}; -use reth_primitives::{EthereumHardfork, Head, MAINNET_GENESIS_HASH}; +use reth_primitives::{EthereumHardfork, Head}; use secp256k1::{SecretKey, SECP256K1}; use std::sync::LazyLock; use tokio::net::TcpStream; From 8eb5d4f04782ae6d22bc242fc0ec7db63115b315 Mon Sep 17 00:00:00 2001 From: "0xriazaka.eth" <168359025+0xriazaka@users.noreply.github.com> Date: Thu, 17 Oct 2024 21:28:13 +0100 Subject: [PATCH 064/113] Remove unsafe from impl Compact for ClientVersion (#11318) Co-authored-by: Emilia Hane Co-authored-by: DaniPopes <57450786+DaniPopes@users.noreply.github.com> --- crates/storage/codecs/src/lib.rs | 15 +++++++++++++++ crates/storage/db-models/src/client_version.rs | 18 +++++++----------- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/crates/storage/codecs/src/lib.rs b/crates/storage/codecs/src/lib.rs index 8608c5eb8c19..54ca046cb71a 100644 --- a/crates/storage/codecs/src/lib.rs +++ b/crates/storage/codecs/src/lib.rs @@ -78,6 +78,21 @@ pub trait Compact: Sized { } } +impl Compact for alloc::string::String { + fn to_compact(&self, buf: &mut B) -> usize + where + B: bytes::BufMut + AsMut<[u8]>, + { + self.as_bytes().to_compact(buf) + } + + fn from_compact(buf: &[u8], len: usize) -> (Self, &[u8]) { + let (vec, buf) = Vec::::from_compact(buf, len); + let string = Self::from_utf8(vec).unwrap(); // Safe conversion + (string, buf) + } +} + impl Compact for &T { fn to_compact(&self, buf: &mut B) -> usize where diff --git a/crates/storage/db-models/src/client_version.rs b/crates/storage/db-models/src/client_version.rs index de074ac88c6e..a28e7385f658 100644 --- a/crates/storage/db-models/src/client_version.rs +++ b/crates/storage/db-models/src/client_version.rs @@ -28,20 +28,16 @@ impl Compact for ClientVersion { where B: bytes::BufMut + AsMut<[u8]>, { - self.version.as_bytes().to_compact(buf); - self.git_sha.as_bytes().to_compact(buf); - self.build_timestamp.as_bytes().to_compact(buf) + self.version.to_compact(buf); + self.git_sha.to_compact(buf); + self.build_timestamp.to_compact(buf) } fn from_compact(buf: &[u8], len: usize) -> (Self, &[u8]) { - let (version, buf) = Vec::::from_compact(buf, len); - let (git_sha, buf) = Vec::::from_compact(buf, len); - let (build_timestamp, buf) = Vec::::from_compact(buf, len); - let client_version = Self { - version: unsafe { String::from_utf8_unchecked(version) }, - git_sha: unsafe { String::from_utf8_unchecked(git_sha) }, - build_timestamp: unsafe { String::from_utf8_unchecked(build_timestamp) }, - }; + let (version, buf) = String::from_compact(buf, len); + let (git_sha, buf) = String::from_compact(buf, len); + let (build_timestamp, buf) = String::from_compact(buf, len); + let client_version = Self { version, git_sha, build_timestamp }; (client_version, buf) } } From b57cbfd21ba4a39d31c64cf4c7bbc5449a86afb5 Mon Sep 17 00:00:00 2001 From: Thomas Coratger <60488569+tcoratger@users.noreply.github.com> Date: Thu, 17 Oct 2024 22:29:31 +0200 Subject: [PATCH 065/113] primitives: use alloy `DEV_GENESIS_HASH` constant (#11849) --- Cargo.lock | 1 + crates/chainspec/src/spec.rs | 4 ++-- crates/optimism/chainspec/Cargo.toml | 1 + crates/optimism/chainspec/src/dev.rs | 2 +- crates/primitives-traits/src/constants/mod.rs | 4 ---- crates/primitives/src/lib.rs | 2 +- 6 files changed, 6 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 600d61e97e27..1d9f74a207d5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8032,6 +8032,7 @@ name = "reth-optimism-chainspec" version = "1.1.0" dependencies = [ "alloy-chains", + "alloy-consensus", "alloy-genesis", "alloy-primitives", "derive_more 1.0.0", diff --git a/crates/chainspec/src/spec.rs b/crates/chainspec/src/spec.rs index deaca188a21a..adfee564d749 100644 --- a/crates/chainspec/src/spec.rs +++ b/crates/chainspec/src/spec.rs @@ -7,7 +7,7 @@ use alloy_primitives::{address, b256, Address, BlockNumber, B256, U256}; use alloy_trie::EMPTY_ROOT_HASH; use derive_more::From; -use alloy_consensus::constants::MAINNET_GENESIS_HASH; +use alloy_consensus::constants::{DEV_GENESIS_HASH, MAINNET_GENESIS_HASH}; use reth_ethereum_forks::{ ChainHardforks, DisplayHardforks, EthereumHardfork, EthereumHardforks, ForkCondition, ForkFilter, ForkFilterKey, ForkHash, ForkId, Hardfork, Hardforks, Head, DEV_HARDFORKS, @@ -18,7 +18,7 @@ use reth_network_peers::{ }; use reth_primitives_traits::{ constants::{ - DEV_GENESIS_HASH, EIP1559_INITIAL_BASE_FEE, EMPTY_WITHDRAWALS, ETHEREUM_BLOCK_GAS_LIMIT, + EIP1559_INITIAL_BASE_FEE, EMPTY_WITHDRAWALS, ETHEREUM_BLOCK_GAS_LIMIT, HOLESKY_GENESIS_HASH, SEPOLIA_GENESIS_HASH, }, Header, SealedHeader, diff --git a/crates/optimism/chainspec/Cargo.toml b/crates/optimism/chainspec/Cargo.toml index c9f951c8d20d..efc9bf0b0126 100644 --- a/crates/optimism/chainspec/Cargo.toml +++ b/crates/optimism/chainspec/Cargo.toml @@ -25,6 +25,7 @@ reth-optimism-forks.workspace = true alloy-chains.workspace = true alloy-genesis.workspace = true alloy-primitives.workspace = true +alloy-consensus.workspace = true # op op-alloy-rpc-types.workspace = true diff --git a/crates/optimism/chainspec/src/dev.rs b/crates/optimism/chainspec/src/dev.rs index cb8163dfc521..eae25f73e01e 100644 --- a/crates/optimism/chainspec/src/dev.rs +++ b/crates/optimism/chainspec/src/dev.rs @@ -3,10 +3,10 @@ use alloc::sync::Arc; use alloy_chains::Chain; +use alloy_consensus::constants::DEV_GENESIS_HASH; use alloy_primitives::U256; use reth_chainspec::{once_cell_set, BaseFeeParams, BaseFeeParamsKind, ChainSpec}; use reth_optimism_forks::DEV_HARDFORKS; -use reth_primitives_traits::constants::DEV_GENESIS_HASH; use crate::{LazyLock, OpChainSpec}; diff --git a/crates/primitives-traits/src/constants/mod.rs b/crates/primitives-traits/src/constants/mod.rs index 890287f8bc19..eade399897bb 100644 --- a/crates/primitives-traits/src/constants/mod.rs +++ b/crates/primitives-traits/src/constants/mod.rs @@ -106,10 +106,6 @@ pub const SEPOLIA_GENESIS_HASH: B256 = pub const HOLESKY_GENESIS_HASH: B256 = b256!("b5f7f912443c940f21fd611f12828d75b534364ed9e95ca4e307729a4661bde4"); -/// Testnet genesis hash: `0x2f980576711e3617a5e4d83dd539548ec0f7792007d505a3d2e9674833af2d7c` -pub const DEV_GENESIS_HASH: B256 = - b256!("2f980576711e3617a5e4d83dd539548ec0f7792007d505a3d2e9674833af2d7c"); - /// Keccak256 over empty array: `0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470` pub const KECCAK_EMPTY: B256 = b256!("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"); diff --git a/crates/primitives/src/lib.rs b/crates/primitives/src/lib.rs index 4a8d812ef834..a39139349ab5 100644 --- a/crates/primitives/src/lib.rs +++ b/crates/primitives/src/lib.rs @@ -39,7 +39,7 @@ pub use block::{ }; #[cfg(feature = "reth-codec")] pub use compression::*; -pub use constants::{DEV_GENESIS_HASH, HOLESKY_GENESIS_HASH, KECCAK_EMPTY, SEPOLIA_GENESIS_HASH}; +pub use constants::{HOLESKY_GENESIS_HASH, KECCAK_EMPTY, SEPOLIA_GENESIS_HASH}; pub use receipt::{ gas_spent_by_transactions, Receipt, ReceiptWithBloom, ReceiptWithBloomRef, Receipts, }; From bc43613be35f316304f7ce4a2225855ac26b5923 Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Thu, 17 Oct 2024 22:33:37 +0200 Subject: [PATCH 066/113] chore: disable SC2034 in check_wasm.sh (#11854) --- .github/assets/check_wasm.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/assets/check_wasm.sh b/.github/assets/check_wasm.sh index 1b1c0641fc0a..52d7009412c5 100755 --- a/.github/assets/check_wasm.sh +++ b/.github/assets/check_wasm.sh @@ -3,7 +3,10 @@ set +e # Disable immediate exit on error # Array of crates to compile crates=($(cargo metadata --format-version=1 --no-deps | jq -r '.packages[].name' | grep '^reth' | sort)) + # Array of crates to exclude +# Used with the `contains` function. +# shellcheck disable=SC2034 exclude_crates=( # The following are not working yet, but known to be fixable reth-exex-types # https://github.com/paradigmxyz/reth/issues/9946 From 96ad6d5bd525c821ea95122290c76cf133f5d36d Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Fri, 18 Oct 2024 00:40:15 +0200 Subject: [PATCH 067/113] chore: rm unused reth-revm c-kzg feature (#11860) --- crates/revm/Cargo.toml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crates/revm/Cargo.toml b/crates/revm/Cargo.toml index 7ffb06ce960c..b2d3bccde6bc 100644 --- a/crates/revm/Cargo.toml +++ b/crates/revm/Cargo.toml @@ -32,8 +32,7 @@ reth-ethereum-forks.workspace = true alloy-primitives.workspace = true [features] -default = ["std", "c-kzg"] +default = ["std"] std = [] -c-kzg = ["revm/c-kzg"] test-utils = ["dep:reth-trie"] serde = ["revm/serde"] From f3c0dda0d34960b6c28e27b41bdc2c86b712c09e Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Fri, 18 Oct 2024 00:40:33 +0200 Subject: [PATCH 068/113] perf: use existing block hash functions (#11858) --- crates/storage/storage-api/src/block_id.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/crates/storage/storage-api/src/block_id.rs b/crates/storage/storage-api/src/block_id.rs index 3d9df2e329f0..55cd6ab1c763 100644 --- a/crates/storage/storage-api/src/block_id.rs +++ b/crates/storage/storage-api/src/block_id.rs @@ -82,11 +82,10 @@ pub trait BlockIdReader: BlockNumReader + Send + Sync { BlockNumberOrTag::Pending => self .pending_block_num_hash() .map(|res_opt| res_opt.map(|num_hash| num_hash.hash)), - _ => self - .convert_block_number(num)? - .map(|num| self.block_hash(num)) - .transpose() - .map(|maybe_hash| maybe_hash.flatten()), + BlockNumberOrTag::Finalized => self.finalized_block_hash(), + BlockNumberOrTag::Safe => self.safe_block_hash(), + BlockNumberOrTag::Earliest => self.block_hash(0), + BlockNumberOrTag::Number(num) => self.block_hash(num), }, } } From 62e7625b16549530beafef1e0c6a6d9ed2bde649 Mon Sep 17 00:00:00 2001 From: Thomas Coratger <60488569+tcoratger@users.noreply.github.com> Date: Fri, 18 Oct 2024 00:41:59 +0200 Subject: [PATCH 069/113] primitives: use alloy `*_TX_TYPE_ID` constants (#11853) --- crates/primitives/src/lib.rs | 2 -- crates/primitives/src/receipt.rs | 8 ++++---- crates/primitives/src/transaction/mod.rs | 7 +++---- crates/primitives/src/transaction/pooled.rs | 3 ++- crates/primitives/src/transaction/sidecar.rs | 6 ++++-- crates/primitives/src/transaction/tx_type.rs | 20 ++++--------------- crates/transaction-pool/src/config.rs | 6 ++---- crates/transaction-pool/src/pool/txpool.rs | 10 +++++----- .../transaction-pool/src/test_utils/mock.rs | 6 ++++-- crates/transaction-pool/src/traits.rs | 6 ++++-- crates/transaction-pool/src/validate/eth.rs | 6 ++++-- 11 files changed, 36 insertions(+), 44 deletions(-) diff --git a/crates/primitives/src/lib.rs b/crates/primitives/src/lib.rs index a39139349ab5..796090d79e5f 100644 --- a/crates/primitives/src/lib.rs +++ b/crates/primitives/src/lib.rs @@ -61,8 +61,6 @@ pub use transaction::{ util::secp256k1::{public_key_to_address, recover_signer_unchecked, sign_message}, InvalidTransactionError, Signature, Transaction, TransactionMeta, TransactionSigned, TransactionSignedEcRecovered, TransactionSignedNoHash, TxHashOrNumber, TxType, - EIP1559_TX_TYPE_ID, EIP2930_TX_TYPE_ID, EIP4844_TX_TYPE_ID, EIP7702_TX_TYPE_ID, - LEGACY_TX_TYPE_ID, }; // Re-exports diff --git a/crates/primitives/src/receipt.rs b/crates/primitives/src/receipt.rs index cfd831ed0f74..9006a067e9cc 100644 --- a/crates/primitives/src/receipt.rs +++ b/crates/primitives/src/receipt.rs @@ -1,10 +1,10 @@ #[cfg(feature = "reth-codec")] use crate::compression::{RECEIPT_COMPRESSOR, RECEIPT_DECOMPRESSOR}; -use crate::{ - logs_bloom, TxType, EIP1559_TX_TYPE_ID, EIP2930_TX_TYPE_ID, EIP4844_TX_TYPE_ID, - EIP7702_TX_TYPE_ID, -}; +use crate::{logs_bloom, TxType}; use alloc::{vec, vec::Vec}; +use alloy_consensus::constants::{ + EIP1559_TX_TYPE_ID, EIP2930_TX_TYPE_ID, EIP4844_TX_TYPE_ID, EIP7702_TX_TYPE_ID, +}; use alloy_primitives::{Bloom, Bytes, Log, B256}; use alloy_rlp::{length_of_length, Decodable, Encodable, RlpDecodable, RlpEncodable}; use bytes::{Buf, BufMut}; diff --git a/crates/primitives/src/transaction/mod.rs b/crates/primitives/src/transaction/mod.rs index 10fddcb4c375..b7eeeadc8970 100644 --- a/crates/primitives/src/transaction/mod.rs +++ b/crates/primitives/src/transaction/mod.rs @@ -1,6 +1,8 @@ //! Transaction types. use crate::BlockHashOrNumber; +#[cfg(any(test, feature = "reth-codec"))] +use alloy_consensus::constants::{EIP4844_TX_TYPE_ID, EIP7702_TX_TYPE_ID}; use alloy_consensus::{ SignableTransaction, Transaction as _, TxEip1559, TxEip2930, TxEip4844, TxEip7702, TxLegacy, }; @@ -37,10 +39,7 @@ pub use compat::FillTxEnv; pub use signature::{ extract_chain_id, legacy_parity, recover_signer, recover_signer_unchecked, Signature, }; -pub use tx_type::{ - TxType, EIP1559_TX_TYPE_ID, EIP2930_TX_TYPE_ID, EIP4844_TX_TYPE_ID, EIP7702_TX_TYPE_ID, - LEGACY_TX_TYPE_ID, -}; +pub use tx_type::TxType; pub use variant::TransactionSignedVariant; pub(crate) mod access_list; diff --git a/crates/primitives/src/transaction/pooled.rs b/crates/primitives/src/transaction/pooled.rs index ec49f44a680b..32d4da65980e 100644 --- a/crates/primitives/src/transaction/pooled.rs +++ b/crates/primitives/src/transaction/pooled.rs @@ -8,9 +8,10 @@ use super::{ }; use crate::{ BlobTransaction, BlobTransactionSidecar, Signature, Transaction, TransactionSigned, - TransactionSignedEcRecovered, EIP4844_TX_TYPE_ID, + TransactionSignedEcRecovered, }; use alloy_consensus::{ + constants::EIP4844_TX_TYPE_ID, transaction::{TxEip1559, TxEip2930, TxEip4844, TxLegacy}, SignableTransaction, TxEip4844WithSidecar, }; diff --git a/crates/primitives/src/transaction/sidecar.rs b/crates/primitives/src/transaction/sidecar.rs index 87b8c1fbf3e8..edc1427d1fe8 100644 --- a/crates/primitives/src/transaction/sidecar.rs +++ b/crates/primitives/src/transaction/sidecar.rs @@ -1,7 +1,9 @@ #![cfg_attr(docsrs, doc(cfg(feature = "c-kzg")))] -use crate::{Signature, Transaction, TransactionSigned, EIP4844_TX_TYPE_ID}; -use alloy_consensus::{transaction::TxEip4844, TxEip4844WithSidecar}; +use crate::{Signature, Transaction, TransactionSigned}; +use alloy_consensus::{ + constants::EIP4844_TX_TYPE_ID, transaction::TxEip4844, TxEip4844WithSidecar, +}; use alloy_primitives::{keccak256, TxHash}; use alloy_rlp::{Decodable, Error as RlpError, Header}; use serde::{Deserialize, Serialize}; diff --git a/crates/primitives/src/transaction/tx_type.rs b/crates/primitives/src/transaction/tx_type.rs index c55e0d3c6193..b6e1ecbf226a 100644 --- a/crates/primitives/src/transaction/tx_type.rs +++ b/crates/primitives/src/transaction/tx_type.rs @@ -1,3 +1,7 @@ +use alloy_consensus::constants::{ + EIP1559_TX_TYPE_ID, EIP2930_TX_TYPE_ID, EIP4844_TX_TYPE_ID, EIP7702_TX_TYPE_ID, + LEGACY_TX_TYPE_ID, +}; use alloy_primitives::{U64, U8}; use alloy_rlp::{Decodable, Encodable}; use serde::{Deserialize, Serialize}; @@ -23,22 +27,6 @@ pub(crate) const COMPACT_IDENTIFIER_EIP1559: usize = 2; #[cfg(any(test, feature = "reth-codec"))] pub(crate) const COMPACT_EXTENDED_IDENTIFIER_FLAG: usize = 3; -/// Identifier for legacy transaction, however [`TxLegacy`](alloy_consensus::TxLegacy) this is -/// technically not typed. -pub const LEGACY_TX_TYPE_ID: u8 = 0; - -/// Identifier for [`TxEip2930`](alloy_consensus::TxEip2930) transaction. -pub const EIP2930_TX_TYPE_ID: u8 = 1; - -/// Identifier for [`TxEip1559`](alloy_consensus::TxEip1559) transaction. -pub const EIP1559_TX_TYPE_ID: u8 = 2; - -/// Identifier for [`TxEip4844`](alloy_consensus::TxEip4844) transaction. -pub const EIP4844_TX_TYPE_ID: u8 = 3; - -/// Identifier for [`TxEip7702`](alloy_consensus::TxEip7702) transaction. -pub const EIP7702_TX_TYPE_ID: u8 = 4; - /// Identifier for [`TxDeposit`](op_alloy_consensus::TxDeposit) transaction. #[cfg(feature = "optimism")] pub const DEPOSIT_TX_TYPE_ID: u8 = 126; diff --git a/crates/transaction-pool/src/config.rs b/crates/transaction-pool/src/config.rs index 1b4b010a8e14..30703f888c38 100644 --- a/crates/transaction-pool/src/config.rs +++ b/crates/transaction-pool/src/config.rs @@ -2,11 +2,9 @@ use crate::{ pool::{NEW_TX_LISTENER_BUFFER_SIZE, PENDING_TX_LISTENER_BUFFER_SIZE}, PoolSize, TransactionOrigin, }; +use alloy_consensus::constants::EIP4844_TX_TYPE_ID; use alloy_primitives::Address; -use reth_primitives::{ - constants::{ETHEREUM_BLOCK_GAS_LIMIT, MIN_PROTOCOL_BASE_FEE}, - EIP4844_TX_TYPE_ID, -}; +use reth_primitives::constants::{ETHEREUM_BLOCK_GAS_LIMIT, MIN_PROTOCOL_BASE_FEE}; use std::{collections::HashSet, ops::Mul}; /// Guarantees max transactions for one sender, compatible with geth/erigon diff --git a/crates/transaction-pool/src/pool/txpool.rs b/crates/transaction-pool/src/pool/txpool.rs index 9d284392db55..a85a9a1856b9 100644 --- a/crates/transaction-pool/src/pool/txpool.rs +++ b/crates/transaction-pool/src/pool/txpool.rs @@ -18,14 +18,14 @@ use crate::{ PoolConfig, PoolResult, PoolTransaction, PriceBumpConfig, TransactionOrdering, ValidPoolTransaction, U256, }; -use alloy_primitives::{Address, TxHash, B256}; -use reth_primitives::{ - constants::{ - eip4844::BLOB_TX_MIN_BLOB_GASPRICE, ETHEREUM_BLOCK_GAS_LIMIT, MIN_PROTOCOL_BASE_FEE, - }, +use alloy_consensus::constants::{ EIP1559_TX_TYPE_ID, EIP2930_TX_TYPE_ID, EIP4844_TX_TYPE_ID, EIP7702_TX_TYPE_ID, LEGACY_TX_TYPE_ID, }; +use alloy_primitives::{Address, TxHash, B256}; +use reth_primitives::constants::{ + eip4844::BLOB_TX_MIN_BLOB_GASPRICE, ETHEREUM_BLOCK_GAS_LIMIT, MIN_PROTOCOL_BASE_FEE, +}; use rustc_hash::FxHashMap; use smallvec::SmallVec; use std::{ diff --git a/crates/transaction-pool/src/test_utils/mock.rs b/crates/transaction-pool/src/test_utils/mock.rs index e2b5f373e446..474cf5cc8f83 100644 --- a/crates/transaction-pool/src/test_utils/mock.rs +++ b/crates/transaction-pool/src/test_utils/mock.rs @@ -7,7 +7,10 @@ use crate::{ CoinbaseTipOrdering, EthBlobTransactionSidecar, EthPoolTransaction, PoolTransaction, ValidPoolTransaction, }; -use alloy_consensus::{TxEip1559, TxEip2930, TxEip4844, TxLegacy}; +use alloy_consensus::{ + constants::{EIP1559_TX_TYPE_ID, EIP2930_TX_TYPE_ID, EIP4844_TX_TYPE_ID, LEGACY_TX_TYPE_ID}, + TxEip1559, TxEip2930, TxEip4844, TxLegacy, +}; use alloy_eips::eip2930::AccessList; use alloy_primitives::{Address, Bytes, ChainId, TxHash, TxKind, B256, U256}; use paste::paste; @@ -20,7 +23,6 @@ use reth_primitives::{ transaction::TryFromRecoveredTransactionError, BlobTransactionSidecar, BlobTransactionValidationError, PooledTransactionsElementEcRecovered, Signature, Transaction, TransactionSigned, TransactionSignedEcRecovered, TxType, - EIP1559_TX_TYPE_ID, EIP2930_TX_TYPE_ID, EIP4844_TX_TYPE_ID, LEGACY_TX_TYPE_ID, }; use std::{ops::Range, sync::Arc, time::Instant, vec::IntoIter}; diff --git a/crates/transaction-pool/src/traits.rs b/crates/transaction-pool/src/traits.rs index ee4a5ada3d8d..fcfdae4ed1b3 100644 --- a/crates/transaction-pool/src/traits.rs +++ b/crates/transaction-pool/src/traits.rs @@ -7,7 +7,10 @@ use crate::{ validate::ValidPoolTransaction, AllTransactionsEvents, }; -use alloy_consensus::Transaction as _; +use alloy_consensus::{ + constants::{EIP1559_TX_TYPE_ID, EIP4844_TX_TYPE_ID, EIP7702_TX_TYPE_ID}, + Transaction as _, +}; use alloy_eips::{eip2718::Encodable2718, eip2930::AccessList, eip4844::BlobAndProofV1}; use alloy_primitives::{Address, TxHash, TxKind, B256, U256}; use futures_util::{ready, Stream}; @@ -17,7 +20,6 @@ use reth_primitives::{ kzg::KzgSettings, transaction::TryFromRecoveredTransactionError, BlobTransactionSidecar, BlobTransactionValidationError, PooledTransactionsElement, PooledTransactionsElementEcRecovered, SealedBlock, Transaction, TransactionSignedEcRecovered, - EIP1559_TX_TYPE_ID, EIP4844_TX_TYPE_ID, EIP7702_TX_TYPE_ID, }; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; diff --git a/crates/transaction-pool/src/validate/eth.rs b/crates/transaction-pool/src/validate/eth.rs index 2594e569aa0b..22744c58a798 100644 --- a/crates/transaction-pool/src/validate/eth.rs +++ b/crates/transaction-pool/src/validate/eth.rs @@ -11,11 +11,13 @@ use crate::{ EthBlobTransactionSidecar, EthPoolTransaction, LocalTransactionConfig, PoolTransaction, TransactionValidationOutcome, TransactionValidationTaskExecutor, TransactionValidator, }; +use alloy_consensus::constants::{ + EIP1559_TX_TYPE_ID, EIP2930_TX_TYPE_ID, EIP4844_TX_TYPE_ID, EIP7702_TX_TYPE_ID, + LEGACY_TX_TYPE_ID, +}; use reth_chainspec::{ChainSpec, EthereumHardforks}; use reth_primitives::{ constants::eip4844::MAX_BLOBS_PER_BLOCK, GotExpected, InvalidTransactionError, SealedBlock, - EIP1559_TX_TYPE_ID, EIP2930_TX_TYPE_ID, EIP4844_TX_TYPE_ID, EIP7702_TX_TYPE_ID, - LEGACY_TX_TYPE_ID, }; use reth_storage_api::{AccountReader, StateProviderFactory}; use reth_tasks::TaskSpawner; From dfcaad4608797ed05a8b896fcfad83a83a6292af Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Fri, 18 Oct 2024 00:42:24 +0200 Subject: [PATCH 070/113] chore: remove some cfg imports (#11864) --- crates/primitives/src/block.rs | 4 +--- crates/primitives/src/receipt.rs | 6 +++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/crates/primitives/src/block.rs b/crates/primitives/src/block.rs index de0817fb025d..b7e11f7b92ea 100644 --- a/crates/primitives/src/block.rs +++ b/crates/primitives/src/block.rs @@ -10,8 +10,6 @@ use alloy_primitives::{Address, Bytes, Sealable, B256}; use alloy_rlp::{Decodable, Encodable, RlpDecodable, RlpEncodable}; use derive_more::{Deref, DerefMut}; #[cfg(any(test, feature = "arbitrary"))] -use proptest::prelude::prop_compose; -#[cfg(any(test, feature = "arbitrary"))] pub use reth_primitives_traits::test_utils::{generate_valid_header, valid_header_strategy}; use reth_primitives_traits::Requests; use serde::{Deserialize, Serialize}; @@ -20,7 +18,7 @@ use serde::{Deserialize, Serialize}; // a block with `None` withdrawals and `Some` requests, in which case we end up trying to decode the // requests as withdrawals #[cfg(any(feature = "arbitrary", test))] -prop_compose! { +proptest::prelude::prop_compose! { pub fn empty_requests_strategy()(_ in 0..1) -> Option { None } diff --git a/crates/primitives/src/receipt.rs b/crates/primitives/src/receipt.rs index 9006a067e9cc..b117f8d96156 100644 --- a/crates/primitives/src/receipt.rs +++ b/crates/primitives/src/receipt.rs @@ -11,14 +11,14 @@ use bytes::{Buf, BufMut}; use core::{cmp::Ordering, ops::Deref}; use derive_more::{DerefMut, From, IntoIterator}; #[cfg(feature = "reth-codec")] -use reth_codecs::{Compact, CompactZstd}; +use reth_codecs::Compact; use serde::{Deserialize, Serialize}; /// Receipt containing result of transaction execution. #[derive( Clone, Debug, PartialEq, Eq, Default, RlpEncodable, RlpDecodable, Serialize, Deserialize, )] -#[cfg_attr(any(test, feature = "reth-codec"), derive(CompactZstd))] +#[cfg_attr(any(test, feature = "reth-codec"), derive(reth_codecs::CompactZstd))] #[cfg_attr(any(test, feature = "reth-codec"), reth_codecs::add_arbitrary_tests)] #[rlp(trailing)] pub struct Receipt { @@ -130,7 +130,7 @@ impl From for ReceiptWithBloom { /// [`Receipt`] with calculated bloom filter. #[derive(Clone, Debug, PartialEq, Eq, Default, Serialize, Deserialize)] #[cfg_attr(any(test, feature = "arbitrary"), derive(arbitrary::Arbitrary))] -#[cfg_attr(any(test, feature = "reth-codec"), derive(Compact))] +#[cfg_attr(any(test, feature = "reth-codec"), derive(reth_codecs::Compact))] #[cfg_attr(any(test, feature = "reth-codec"), reth_codecs::add_arbitrary_tests(compact))] pub struct ReceiptWithBloom { /// Bloom filter build from logs. From 0c70f6bd3519d5c5bce85481bea728df89fdabf3 Mon Sep 17 00:00:00 2001 From: Thomas Coratger <60488569+tcoratger@users.noreply.github.com> Date: Fri, 18 Oct 2024 10:25:22 +0200 Subject: [PATCH 071/113] primitives: use alloy `KECCAK_EMPTY` constant (#11851) --- Cargo.lock | 1 + crates/ethereum/evm/src/lib.rs | 3 ++- crates/optimism/evm/src/lib.rs | 3 ++- crates/primitives-traits/src/constants/mod.rs | 4 ---- crates/primitives/src/lib.rs | 2 +- crates/rpc/rpc-eth-api/src/helpers/state.rs | 3 ++- crates/storage/storage-api/Cargo.toml | 1 + crates/storage/storage-api/src/state.rs | 3 ++- crates/trie/common/src/proofs.rs | 5 +++-- 9 files changed, 14 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1d9f74a207d5..2aa5675cd872 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9002,6 +9002,7 @@ dependencies = [ name = "reth-storage-api" version = "1.1.0" dependencies = [ + "alloy-consensus", "alloy-eips", "alloy-primitives", "auto_impl", diff --git a/crates/ethereum/evm/src/lib.rs b/crates/ethereum/evm/src/lib.rs index ed18a24fb191..ac9bb5a0bbb5 100644 --- a/crates/ethereum/evm/src/lib.rs +++ b/crates/ethereum/evm/src/lib.rs @@ -194,13 +194,14 @@ impl ConfigureEvm for EthEvmConfig { #[cfg(test)] mod tests { use super::*; + use alloy_consensus::constants::KECCAK_EMPTY; use alloy_genesis::Genesis; use alloy_primitives::{B256, U256}; use reth_chainspec::{Chain, ChainSpec, MAINNET}; use reth_evm::execute::ProviderError; use reth_primitives::{ revm_primitives::{BlockEnv, CfgEnv, SpecId}, - Header, KECCAK_EMPTY, + Header, }; use reth_revm::{ db::{CacheDB, EmptyDBTyped}, diff --git a/crates/optimism/evm/src/lib.rs b/crates/optimism/evm/src/lib.rs index eb067da32566..3eda2878cae4 100644 --- a/crates/optimism/evm/src/lib.rs +++ b/crates/optimism/evm/src/lib.rs @@ -208,6 +208,7 @@ impl ConfigureEvm for OptimismEvmConfig { #[cfg(test)] mod tests { use super::*; + use alloy_consensus::constants::KECCAK_EMPTY; use alloy_genesis::Genesis; use alloy_primitives::{B256, U256}; use reth_chainspec::ChainSpec; @@ -216,7 +217,7 @@ mod tests { use reth_optimism_chainspec::BASE_MAINNET; use reth_primitives::{ revm_primitives::{BlockEnv, CfgEnv, SpecId}, - Header, Receipt, Receipts, SealedBlockWithSenders, TxType, KECCAK_EMPTY, + Header, Receipt, Receipts, SealedBlockWithSenders, TxType, }; use reth_revm::{ db::{CacheDB, EmptyDBTyped}, diff --git a/crates/primitives-traits/src/constants/mod.rs b/crates/primitives-traits/src/constants/mod.rs index eade399897bb..33101b2c053b 100644 --- a/crates/primitives-traits/src/constants/mod.rs +++ b/crates/primitives-traits/src/constants/mod.rs @@ -106,10 +106,6 @@ pub const SEPOLIA_GENESIS_HASH: B256 = pub const HOLESKY_GENESIS_HASH: B256 = b256!("b5f7f912443c940f21fd611f12828d75b534364ed9e95ca4e307729a4661bde4"); -/// Keccak256 over empty array: `0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470` -pub const KECCAK_EMPTY: B256 = - b256!("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"); - /// From address from Optimism system txs: `0xdeaddeaddeaddeaddeaddeaddeaddeaddead0001` pub const OP_SYSTEM_TX_FROM_ADDR: Address = address!("deaddeaddeaddeaddeaddeaddeaddeaddead0001"); diff --git a/crates/primitives/src/lib.rs b/crates/primitives/src/lib.rs index 796090d79e5f..a9e8c08203d0 100644 --- a/crates/primitives/src/lib.rs +++ b/crates/primitives/src/lib.rs @@ -39,7 +39,7 @@ pub use block::{ }; #[cfg(feature = "reth-codec")] pub use compression::*; -pub use constants::{HOLESKY_GENESIS_HASH, KECCAK_EMPTY, SEPOLIA_GENESIS_HASH}; +pub use constants::{HOLESKY_GENESIS_HASH, SEPOLIA_GENESIS_HASH}; pub use receipt::{ gas_spent_by_transactions, Receipt, ReceiptWithBloom, ReceiptWithBloomRef, Receipts, }; diff --git a/crates/rpc/rpc-eth-api/src/helpers/state.rs b/crates/rpc/rpc-eth-api/src/helpers/state.rs index 7b11ce6afe63..f2fc13f5d03e 100644 --- a/crates/rpc/rpc-eth-api/src/helpers/state.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/state.rs @@ -1,13 +1,14 @@ //! Loads a pending block from database. Helper trait for `eth_` block, transaction, call and trace //! RPC methods. +use alloy_consensus::constants::KECCAK_EMPTY; use alloy_primitives::{Address, Bytes, B256, U256}; use alloy_rpc_types::{serde_helpers::JsonStorageKey, Account, EIP1186AccountProofResponse}; use futures::Future; use reth_chainspec::{EthChainSpec, EthereumHardforks}; use reth_errors::RethError; use reth_evm::ConfigureEvmEnv; -use reth_primitives::{BlockId, Header, KECCAK_EMPTY}; +use reth_primitives::{BlockId, Header}; use reth_provider::{ BlockIdReader, BlockNumReader, ChainSpecProvider, StateProvider, StateProviderBox, StateProviderFactory, diff --git a/crates/storage/storage-api/Cargo.toml b/crates/storage/storage-api/Cargo.toml index 51d8eabfc40f..0ae8b284588e 100644 --- a/crates/storage/storage-api/Cargo.toml +++ b/crates/storage/storage-api/Cargo.toml @@ -26,5 +26,6 @@ reth-trie.workspace = true # ethereum alloy-eips.workspace = true alloy-primitives.workspace = true +alloy-consensus.workspace = true auto_impl.workspace = true diff --git a/crates/storage/storage-api/src/state.rs b/crates/storage/storage-api/src/state.rs index 9a3b855ff14d..d37940f04787 100644 --- a/crates/storage/storage-api/src/state.rs +++ b/crates/storage/storage-api/src/state.rs @@ -2,11 +2,12 @@ use super::{ AccountReader, BlockHashReader, BlockIdReader, StateProofProvider, StateRootProvider, StorageRootProvider, }; +use alloy_consensus::constants::KECCAK_EMPTY; use alloy_eips::{BlockId, BlockNumHash, BlockNumberOrTag}; use alloy_primitives::{Address, BlockHash, BlockNumber, StorageKey, StorageValue, B256, U256}; use auto_impl::auto_impl; use reth_execution_types::ExecutionOutcome; -use reth_primitives::{Bytecode, KECCAK_EMPTY}; +use reth_primitives::Bytecode; use reth_storage_errors::provider::{ProviderError, ProviderResult}; /// Type alias of boxed [`StateProvider`]. diff --git a/crates/trie/common/src/proofs.rs b/crates/trie/common/src/proofs.rs index 8aca67f8d1ad..a94b2b96fbdf 100644 --- a/crates/trie/common/src/proofs.rs +++ b/crates/trie/common/src/proofs.rs @@ -1,6 +1,7 @@ //! Merkle trie proofs. use crate::{Nibbles, TrieAccount}; +use alloy_consensus::constants::KECCAK_EMPTY; use alloy_primitives::{keccak256, Address, Bytes, B256, U256}; use alloy_rlp::{encode_fixed_size, Decodable, EMPTY_STRING_CODE}; use alloy_trie::{ @@ -9,13 +10,13 @@ use alloy_trie::{ EMPTY_ROOT_HASH, }; use itertools::Itertools; -use reth_primitives_traits::{constants::KECCAK_EMPTY, Account}; +use reth_primitives_traits::Account; use serde::{Deserialize, Serialize}; use std::collections::HashMap; /// The state multiproof of target accounts and multiproofs of their storage tries. /// Multiproof is effectively a state subtrie that only contains the nodes -/// in the paths of target accounts. +/// in the paths of target accounts. #[derive(Clone, Default, Debug)] pub struct MultiProof { /// State trie multiproof for requested accounts. From 5859f93c56352a619aaae6598ee91dfcc11cd38d Mon Sep 17 00:00:00 2001 From: Thomas Coratger <60488569+tcoratger@users.noreply.github.com> Date: Fri, 18 Oct 2024 10:53:21 +0200 Subject: [PATCH 072/113] primitives: use alloy `EMPTY_` constants (#11852) --- Cargo.lock | 1 + crates/chainspec/src/spec.rs | 5 +++-- crates/payload/basic/Cargo.toml | 1 + crates/payload/basic/src/lib.rs | 3 ++- crates/primitives-traits/src/constants/mod.rs | 10 ---------- crates/primitives/src/alloy_compat.rs | 8 +++++--- 6 files changed, 12 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2aa5675cd872..2f8a1057124b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6340,6 +6340,7 @@ dependencies = [ name = "reth-basic-payload-builder" version = "1.1.0" dependencies = [ + "alloy-consensus", "alloy-primitives", "alloy-rlp", "futures-core", diff --git a/crates/chainspec/src/spec.rs b/crates/chainspec/src/spec.rs index adfee564d749..59e1a5ce1e15 100644 --- a/crates/chainspec/src/spec.rs +++ b/crates/chainspec/src/spec.rs @@ -2,6 +2,7 @@ pub use alloy_eips::eip1559::BaseFeeParams; use alloc::{boxed::Box, sync::Arc, vec::Vec}; use alloy_chains::{Chain, NamedChain}; +use alloy_consensus::constants::EMPTY_WITHDRAWALS; use alloy_genesis::Genesis; use alloy_primitives::{address, b256, Address, BlockNumber, B256, U256}; use alloy_trie::EMPTY_ROOT_HASH; @@ -18,8 +19,8 @@ use reth_network_peers::{ }; use reth_primitives_traits::{ constants::{ - EIP1559_INITIAL_BASE_FEE, EMPTY_WITHDRAWALS, ETHEREUM_BLOCK_GAS_LIMIT, - HOLESKY_GENESIS_HASH, SEPOLIA_GENESIS_HASH, + EIP1559_INITIAL_BASE_FEE, ETHEREUM_BLOCK_GAS_LIMIT, HOLESKY_GENESIS_HASH, + SEPOLIA_GENESIS_HASH, }, Header, SealedHeader, }; diff --git a/crates/payload/basic/Cargo.toml b/crates/payload/basic/Cargo.toml index 939eb5b54b73..f201df0c1bd5 100644 --- a/crates/payload/basic/Cargo.toml +++ b/crates/payload/basic/Cargo.toml @@ -26,6 +26,7 @@ reth-tasks.workspace = true alloy-rlp.workspace = true alloy-primitives.workspace = true revm.workspace = true +alloy-consensus.workspace = true # async tokio = { workspace = true, features = ["sync", "time"] } diff --git a/crates/payload/basic/src/lib.rs b/crates/payload/basic/src/lib.rs index f9487ec784ca..835f20f3ef84 100644 --- a/crates/payload/basic/src/lib.rs +++ b/crates/payload/basic/src/lib.rs @@ -9,6 +9,7 @@ #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] use crate::metrics::PayloadBuilderMetrics; +use alloy_consensus::constants::EMPTY_WITHDRAWALS; use alloy_primitives::{Bytes, B256, U256}; use futures_core::ready; use futures_util::FutureExt; @@ -18,7 +19,7 @@ use reth_payload_builder::{ }; use reth_payload_primitives::{BuiltPayload, PayloadBuilderAttributes, PayloadBuilderError}; use reth_primitives::{ - constants::{EMPTY_WITHDRAWALS, RETH_CLIENT_VERSION, SLOT_DURATION}, + constants::{RETH_CLIENT_VERSION, SLOT_DURATION}, proofs, BlockNumberOrTag, SealedBlock, Withdrawals, }; use reth_provider::{ diff --git a/crates/primitives-traits/src/constants/mod.rs b/crates/primitives-traits/src/constants/mod.rs index 33101b2c053b..a4918137e7cd 100644 --- a/crates/primitives-traits/src/constants/mod.rs +++ b/crates/primitives-traits/src/constants/mod.rs @@ -1,6 +1,5 @@ //! Ethereum protocol-related constants -use alloy_consensus::EMPTY_ROOT_HASH; use alloy_primitives::{address, b256, Address, B256, U256}; use core::time::Duration; @@ -112,15 +111,6 @@ pub const OP_SYSTEM_TX_FROM_ADDR: Address = address!("deaddeaddeaddeaddeaddeadde /// To address from Optimism system txs: `0x4200000000000000000000000000000000000015` pub const OP_SYSTEM_TX_TO_ADDR: Address = address!("4200000000000000000000000000000000000015"); -/// Transactions root of empty receipts set. -pub const EMPTY_RECEIPTS: B256 = EMPTY_ROOT_HASH; - -/// Transactions root of empty transactions set. -pub const EMPTY_TRANSACTIONS: B256 = EMPTY_ROOT_HASH; - -/// Withdrawals root of empty withdrawals set. -pub const EMPTY_WITHDRAWALS: B256 = EMPTY_ROOT_HASH; - /// The number of blocks to unwind during a reorg that already became a part of canonical chain. /// /// In reality, the node can end up in this particular situation very rarely. It would happen only diff --git a/crates/primitives/src/alloy_compat.rs b/crates/primitives/src/alloy_compat.rs index c9bdfad89f57..0ac1458c5ac2 100644 --- a/crates/primitives/src/alloy_compat.rs +++ b/crates/primitives/src/alloy_compat.rs @@ -1,11 +1,13 @@ //! Common conversions from alloy types. use crate::{ - constants::EMPTY_TRANSACTIONS, transaction::extract_chain_id, Block, BlockBody, Signature, - Transaction, TransactionSigned, TransactionSignedEcRecovered, TransactionSignedNoHash, TxType, + transaction::extract_chain_id, Block, BlockBody, Signature, Transaction, TransactionSigned, + TransactionSignedEcRecovered, TransactionSignedNoHash, TxType, }; use alloc::{string::ToString, vec::Vec}; -use alloy_consensus::{Transaction as _, TxEip1559, TxEip2930, TxEip4844, TxLegacy}; +use alloy_consensus::{ + constants::EMPTY_TRANSACTIONS, Transaction as _, TxEip1559, TxEip2930, TxEip4844, TxLegacy, +}; use alloy_primitives::{Parity, TxKind}; use alloy_rlp::Error as RlpError; use alloy_serde::WithOtherFields; From cb604826b74859c41e2b39d5bfdcc1d4a12046e2 Mon Sep 17 00:00:00 2001 From: Emilia Hane Date: Fri, 18 Oct 2024 11:23:25 +0200 Subject: [PATCH 073/113] chore(sdk): Define `NodePrimitives::Block` (#11399) --- Cargo.lock | 2 ++ crates/ethereum/node/src/node.rs | 16 +++++++++++++--- crates/node/types/Cargo.toml | 4 +++- crates/node/types/src/lib.rs | 13 +++++++++---- crates/optimism/node/src/node.rs | 14 +++++++++++--- 5 files changed, 38 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2f8a1057124b..c8b4f76329ef 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8026,6 +8026,8 @@ dependencies = [ "reth-chainspec", "reth-db-api", "reth-engine-primitives", + "reth-primitives", + "reth-primitives-traits", ] [[package]] diff --git a/crates/ethereum/node/src/node.rs b/crates/ethereum/node/src/node.rs index 82f313fbb0b2..a890810b00e7 100644 --- a/crates/ethereum/node/src/node.rs +++ b/crates/ethereum/node/src/node.rs @@ -11,7 +11,9 @@ use reth_ethereum_engine_primitives::{ }; use reth_evm_ethereum::execute::EthExecutorProvider; use reth_network::NetworkHandle; -use reth_node_api::{ConfigureEvm, EngineValidator, FullNodeComponents, NodeTypesWithDB}; +use reth_node_api::{ + ConfigureEvm, EngineValidator, FullNodeComponents, NodePrimitives, NodeTypesWithDB, +}; use reth_node_builder::{ components::{ ComponentsBuilder, ConsensusBuilder, EngineValidatorBuilder, ExecutorBuilder, @@ -22,7 +24,7 @@ use reth_node_builder::{ BuilderContext, Node, NodeAdapter, NodeComponentsBuilder, PayloadBuilderConfig, PayloadTypes, }; use reth_payload_builder::{PayloadBuilderHandle, PayloadBuilderService}; -use reth_primitives::Header; +use reth_primitives::{Block, Header}; use reth_provider::CanonStateSubscriptions; use reth_rpc::EthApi; use reth_tracing::tracing::{debug, info}; @@ -33,6 +35,14 @@ use reth_transaction_pool::{ use crate::{EthEngineTypes, EthEvmConfig}; +/// Ethereum primitive types. +#[derive(Debug)] +pub struct EthPrimitives; + +impl NodePrimitives for EthPrimitives { + type Block = Block; +} + /// Type configuration for a regular Ethereum node. #[derive(Debug, Default, Clone, Copy)] #[non_exhaustive] @@ -69,7 +79,7 @@ impl EthereumNode { } impl NodeTypes for EthereumNode { - type Primitives = (); + type Primitives = EthPrimitives; type ChainSpec = ChainSpec; } diff --git a/crates/node/types/Cargo.toml b/crates/node/types/Cargo.toml index f04925d9cd41..b28dcfba5911 100644 --- a/crates/node/types/Cargo.toml +++ b/crates/node/types/Cargo.toml @@ -14,4 +14,6 @@ workspace = true # reth reth-chainspec.workspace = true reth-db-api.workspace = true -reth-engine-primitives.workspace = true \ No newline at end of file +reth-engine-primitives.workspace = true +reth-primitives.workspace = true +reth-primitives-traits.workspace = true \ No newline at end of file diff --git a/crates/node/types/src/lib.rs b/crates/node/types/src/lib.rs index 2c72e02d3edc..5ba03e6795ab 100644 --- a/crates/node/types/src/lib.rs +++ b/crates/node/types/src/lib.rs @@ -8,6 +8,8 @@ #![cfg_attr(not(test), warn(unused_crate_dependencies))] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] +pub use reth_primitives_traits::{Block, BlockBody}; + use std::marker::PhantomData; use reth_chainspec::EthChainSpec; @@ -18,11 +20,14 @@ use reth_db_api::{ use reth_engine_primitives::EngineTypes; /// Configures all the primitive types of the node. -// TODO(mattsse): this is currently a placeholder -pub trait NodePrimitives {} +pub trait NodePrimitives { + /// Block primitive. + type Block; +} -// TODO(mattsse): Placeholder -impl NodePrimitives for () {} +impl NodePrimitives for () { + type Block = reth_primitives::Block; +} /// The type that configures the essential types of an Ethereum-like node. /// diff --git a/crates/optimism/node/src/node.rs b/crates/optimism/node/src/node.rs index 648da85d0bb4..c2576d318dd1 100644 --- a/crates/optimism/node/src/node.rs +++ b/crates/optimism/node/src/node.rs @@ -6,7 +6,7 @@ use reth_basic_payload_builder::{BasicPayloadJobGenerator, BasicPayloadJobGenera use reth_chainspec::{EthChainSpec, Hardforks}; use reth_evm::ConfigureEvm; use reth_network::{NetworkConfig, NetworkHandle, NetworkManager}; -use reth_node_api::{EngineValidator, FullNodeComponents, NodeAddOns}; +use reth_node_api::{EngineValidator, FullNodeComponents, NodeAddOns, NodePrimitives}; use reth_node_builder::{ components::{ ComponentsBuilder, ConsensusBuilder, EngineValidatorBuilder, ExecutorBuilder, @@ -21,7 +21,7 @@ use reth_optimism_consensus::OptimismBeaconConsensus; use reth_optimism_evm::{OpExecutorProvider, OptimismEvmConfig}; use reth_optimism_rpc::OpEthApi; use reth_payload_builder::{PayloadBuilderHandle, PayloadBuilderService}; -use reth_primitives::Header; +use reth_primitives::{Block, Header}; use reth_provider::CanonStateSubscriptions; use reth_tracing::tracing::{debug, info}; use reth_transaction_pool::{ @@ -36,6 +36,14 @@ use crate::{ OptimismEngineTypes, }; +/// Optimism primitive types. +#[derive(Debug)] +pub struct OpPrimitives; + +impl NodePrimitives for OpPrimitives { + type Block = Block; +} + /// Type configuration for a regular Optimism node. #[derive(Debug, Default, Clone)] #[non_exhaustive] @@ -113,7 +121,7 @@ where } impl NodeTypes for OptimismNode { - type Primitives = (); + type Primitives = OpPrimitives; type ChainSpec = OpChainSpec; } From cfd066c0714e7b8375e667995a9acc812f7dfd15 Mon Sep 17 00:00:00 2001 From: Emilia Hane Date: Fri, 18 Oct 2024 11:43:23 +0200 Subject: [PATCH 074/113] chore(sdk): `SignedTransaction` abstraction (#11432) Co-authored-by: Matthias Seitz --- crates/primitives-traits/src/lib.rs | 2 +- crates/primitives-traits/src/mod.rs | 0 .../{transaction.rs => transaction/mod.rs} | 2 + .../src/transaction/signed.rs | 72 +++++++++++++++++++ crates/primitives/src/traits/mod.rs | 9 +++ 5 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 crates/primitives-traits/src/mod.rs rename crates/primitives-traits/src/{transaction.rs => transaction/mod.rs} (97%) create mode 100644 crates/primitives-traits/src/transaction/signed.rs create mode 100644 crates/primitives/src/traits/mod.rs diff --git a/crates/primitives-traits/src/lib.rs b/crates/primitives-traits/src/lib.rs index 8c54bd68c966..dd10ac9c5f1e 100644 --- a/crates/primitives-traits/src/lib.rs +++ b/crates/primitives-traits/src/lib.rs @@ -24,7 +24,7 @@ pub mod receipt; pub use receipt::Receipt; pub mod transaction; -pub use transaction::Transaction; +pub use transaction::{signed::SignedTransaction, Transaction}; mod integer_list; pub use integer_list::{IntegerList, IntegerListError}; diff --git a/crates/primitives-traits/src/mod.rs b/crates/primitives-traits/src/mod.rs new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/crates/primitives-traits/src/transaction.rs b/crates/primitives-traits/src/transaction/mod.rs similarity index 97% rename from crates/primitives-traits/src/transaction.rs rename to crates/primitives-traits/src/transaction/mod.rs index 93645ead82e8..a306c5f76ed5 100644 --- a/crates/primitives-traits/src/transaction.rs +++ b/crates/primitives-traits/src/transaction/mod.rs @@ -1,5 +1,7 @@ //! Transaction abstraction +pub mod signed; + use alloc::fmt; use reth_codecs::Compact; diff --git a/crates/primitives-traits/src/transaction/signed.rs b/crates/primitives-traits/src/transaction/signed.rs new file mode 100644 index 000000000000..1bc8308b13f0 --- /dev/null +++ b/crates/primitives-traits/src/transaction/signed.rs @@ -0,0 +1,72 @@ +//! API of a signed transaction. + +use alloc::fmt; +use core::hash::Hash; + +use alloy_consensus::Transaction; +use alloy_eips::eip2718::{Decodable2718, Encodable2718}; +use alloy_primitives::{keccak256, Address, TxHash, B256}; + +/// A signed transaction. +pub trait SignedTransaction: + fmt::Debug + + Clone + + PartialEq + + Eq + + Hash + + Send + + Sync + + serde::Serialize + + for<'a> serde::Deserialize<'a> + + alloy_rlp::Encodable + + alloy_rlp::Decodable + + Encodable2718 + + Decodable2718 +{ + /// Transaction type that is signed. + type Transaction: Transaction; + + /// Signature type that results from signing transaction. + type Signature; + + /// Returns reference to transaction hash. + fn tx_hash(&self) -> &TxHash; + + /// Returns reference to transaction. + fn transaction(&self) -> &Self::Transaction; + + /// Returns reference to signature. + fn signature(&self) -> &Self::Signature; + + /// Recover signer from signature and hash. + /// + /// Returns `None` if the transaction's signature is invalid following [EIP-2](https://eips.ethereum.org/EIPS/eip-2), see also `reth_primitives::transaction::recover_signer`. + /// + /// Note: + /// + /// This can fail for some early ethereum mainnet transactions pre EIP-2, use + /// [`Self::recover_signer_unchecked`] if you want to recover the signer without ensuring that + /// the signature has a low `s` value. + fn recover_signer(&self) -> Option
; + + /// Recover signer from signature and hash _without ensuring that the signature has a low `s` + /// value_. + /// + /// Returns `None` if the transaction's signature is invalid, see also + /// `reth_primitives::transaction::recover_signer_unchecked`. + fn recover_signer_unchecked(&self) -> Option
; + + /// Create a new signed transaction from a transaction and its signature. + /// + /// This will also calculate the transaction hash using its encoding. + fn from_transaction_and_signature( + transaction: Self::Transaction, + signature: Self::Signature, + ) -> Self; + + /// Calculate transaction hash, eip2728 transaction does not contain rlp header and start with + /// tx type. + fn recalculate_hash(&self) -> B256 { + keccak256(self.encoded_2718()) + } +} diff --git a/crates/primitives/src/traits/mod.rs b/crates/primitives/src/traits/mod.rs new file mode 100644 index 000000000000..49fb73ea5555 --- /dev/null +++ b/crates/primitives/src/traits/mod.rs @@ -0,0 +1,9 @@ +//! Abstractions of primitive data types + +pub mod block; +pub mod transaction; + +pub use block::{body::BlockBody, Block}; +pub use transaction::signed::SignedTransaction; + +pub use alloy_consensus::BlockHeader; From 8d32fd788bfa8c2e041bd1b93ecca37093a09c5a Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Fri, 18 Oct 2024 14:45:51 +0400 Subject: [PATCH 075/113] feat: allow awaiting payload in progress (#11823) Co-authored-by: Matthias Seitz --- crates/e2e-test-utils/src/payload.rs | 2 +- crates/engine/local/src/miner.rs | 9 ++- crates/payload/basic/src/lib.rs | 15 +++- crates/payload/builder/src/lib.rs | 6 +- crates/payload/builder/src/noop.rs | 2 +- crates/payload/builder/src/service.rs | 79 +++++++++++----------- crates/payload/builder/src/test_utils.rs | 7 +- crates/payload/builder/src/traits.rs | 20 +++++- crates/payload/primitives/src/lib.rs | 22 ++++++ crates/payload/primitives/src/traits.rs | 40 +++++------ examples/custom-payload-builder/src/job.rs | 6 +- 11 files changed, 127 insertions(+), 81 deletions(-) diff --git a/crates/e2e-test-utils/src/payload.rs b/crates/e2e-test-utils/src/payload.rs index 1f9a89307b66..946d9af57536 100644 --- a/crates/e2e-test-utils/src/payload.rs +++ b/crates/e2e-test-utils/src/payload.rs @@ -28,7 +28,7 @@ impl PayloadTestContext { ) -> eyre::Result { self.timestamp += 1; let attributes: E::PayloadBuilderAttributes = attributes_generator(self.timestamp); - self.payload_builder.new_payload(attributes.clone()).await.unwrap(); + self.payload_builder.send_new_payload(attributes.clone()).await.unwrap()?; Ok(attributes) } diff --git a/crates/engine/local/src/miner.rs b/crates/engine/local/src/miner.rs index f20d70b14893..8bcb7083aab0 100644 --- a/crates/engine/local/src/miner.rs +++ b/crates/engine/local/src/miner.rs @@ -9,7 +9,7 @@ use reth_chainspec::EthereumHardforks; use reth_engine_primitives::EngineTypes; use reth_payload_builder::PayloadBuilderHandle; use reth_payload_primitives::{ - BuiltPayload, PayloadAttributesBuilder, PayloadBuilder, PayloadTypes, + BuiltPayload, PayloadAttributesBuilder, PayloadBuilder, PayloadKind, PayloadTypes, }; use reth_provider::{BlockReader, ChainSpecProvider}; use reth_rpc_types_compat::engine::payload::block_to_payload; @@ -202,10 +202,9 @@ where let payload_id = res.payload_id.ok_or_eyre("No payload id")?; - // wait for some time to let the payload be built - tokio::time::sleep(Duration::from_millis(200)).await; - - let Some(Ok(payload)) = self.payload_builder.best_payload(payload_id).await else { + let Some(Ok(payload)) = + self.payload_builder.resolve_kind(payload_id, PayloadKind::WaitForPending).await + else { eyre::bail!("No payload") }; diff --git a/crates/payload/basic/src/lib.rs b/crates/payload/basic/src/lib.rs index 835f20f3ef84..7416283c1f5d 100644 --- a/crates/payload/basic/src/lib.rs +++ b/crates/payload/basic/src/lib.rs @@ -17,7 +17,9 @@ use reth_chainspec::{ChainSpec, EthereumHardforks}; use reth_payload_builder::{ database::CachedReads, KeepPayloadJobAlive, PayloadId, PayloadJob, PayloadJobGenerator, }; -use reth_payload_primitives::{BuiltPayload, PayloadBuilderAttributes, PayloadBuilderError}; +use reth_payload_primitives::{ + BuiltPayload, PayloadBuilderAttributes, PayloadBuilderError, PayloadKind, +}; use reth_primitives::{ constants::{RETH_CLIENT_VERSION, SLOT_DURATION}, proofs, BlockNumberOrTag, SealedBlock, Withdrawals, @@ -474,7 +476,10 @@ where Ok(self.config.attributes.clone()) } - fn resolve(&mut self) -> (Self::ResolvePayloadFuture, KeepPayloadJobAlive) { + fn resolve_kind( + &mut self, + kind: PayloadKind, + ) -> (Self::ResolvePayloadFuture, KeepPayloadJobAlive) { let best_payload = self.best_payload.take(); if best_payload.is_none() && self.pending_block.is_none() { @@ -530,7 +535,11 @@ where }; } - let fut = ResolveBestPayload { best_payload, maybe_better, empty_payload }; + let fut = ResolveBestPayload { + best_payload, + maybe_better, + empty_payload: empty_payload.filter(|_| kind != PayloadKind::WaitForPending), + }; (fut, KeepPayloadJobAlive::No) } diff --git a/crates/payload/builder/src/lib.rs b/crates/payload/builder/src/lib.rs index 70b4296da4e6..0df15f5b0de0 100644 --- a/crates/payload/builder/src/lib.rs +++ b/crates/payload/builder/src/lib.rs @@ -28,7 +28,7 @@ //! use std::pin::Pin; //! use std::task::{Context, Poll}; //! use alloy_primitives::U256; -//! use reth_payload_builder::{EthBuiltPayload, PayloadBuilderError, KeepPayloadJobAlive, EthPayloadBuilderAttributes, PayloadJob, PayloadJobGenerator}; +//! use reth_payload_builder::{EthBuiltPayload, PayloadBuilderError, KeepPayloadJobAlive, EthPayloadBuilderAttributes, PayloadJob, PayloadJobGenerator, PayloadKind}; //! use reth_primitives::{Block, Header}; //! //! /// The generator type that creates new jobs that builds empty blocks. @@ -73,7 +73,7 @@ //! Ok(self.attributes.clone()) //! } //! -//! fn resolve(&mut self) -> (Self::ResolvePayloadFuture, KeepPayloadJobAlive) { +//! fn resolve_kind(&mut self, _kind: PayloadKind) -> (Self::ResolvePayloadFuture, KeepPayloadJobAlive) { //! let payload = self.best_payload(); //! (futures_util::future::ready(payload), KeepPayloadJobAlive::No) //! } @@ -112,7 +112,7 @@ pub mod noop; pub mod test_utils; pub use alloy_rpc_types::engine::PayloadId; -pub use reth_payload_primitives::PayloadBuilderError; +pub use reth_payload_primitives::{PayloadBuilderError, PayloadKind}; pub use service::{ PayloadBuilderHandle, PayloadBuilderService, PayloadServiceCommand, PayloadStore, }; diff --git a/crates/payload/builder/src/noop.rs b/crates/payload/builder/src/noop.rs index 06da7dcfada1..cbf21f1cebf2 100644 --- a/crates/payload/builder/src/noop.rs +++ b/crates/payload/builder/src/noop.rs @@ -51,7 +51,7 @@ where } PayloadServiceCommand::BestPayload(_, tx) => tx.send(None).ok(), PayloadServiceCommand::PayloadAttributes(_, tx) => tx.send(None).ok(), - PayloadServiceCommand::Resolve(_, tx) => tx.send(None).ok(), + PayloadServiceCommand::Resolve(_, _, tx) => tx.send(None).ok(), PayloadServiceCommand::Subscribe(_) => None, }; } diff --git a/crates/payload/builder/src/service.rs b/crates/payload/builder/src/service.rs index 1ebf6770c991..853c69e90d83 100644 --- a/crates/payload/builder/src/service.rs +++ b/crates/payload/builder/src/service.rs @@ -11,7 +11,7 @@ use alloy_rpc_types::engine::PayloadId; use futures_util::{future::FutureExt, Stream, StreamExt}; use reth_payload_primitives::{ BuiltPayload, Events, PayloadBuilder, PayloadBuilderAttributes, PayloadBuilderError, - PayloadEvents, PayloadTypes, + PayloadEvents, PayloadKind, PayloadTypes, }; use reth_provider::CanonStateNotification; use std::{ @@ -45,11 +45,20 @@ where /// /// Note: depending on the installed [`PayloadJobGenerator`], this may or may not terminate the /// job, See [`PayloadJob::resolve`]. + pub async fn resolve_kind( + &self, + id: PayloadId, + kind: PayloadKind, + ) -> Option> { + self.inner.resolve_kind(id, kind).await + } + + /// Resolves the payload job and returns the best payload that has been built so far. pub async fn resolve( &self, id: PayloadId, ) -> Option> { - self.inner.resolve(id).await + self.resolve_kind(id, PayloadKind::Earliest).await } /// Returns the best payload for the given identifier. @@ -110,16 +119,13 @@ where type PayloadType = T; type Error = PayloadBuilderError; - async fn send_and_resolve_payload( + fn send_new_payload( &self, attr: ::PayloadBuilderAttributes, - ) -> Result::BuiltPayload>, Self::Error> { - let rx = self.send_new_payload(attr); - let id = rx.await??; - + ) -> Receiver> { let (tx, rx) = oneshot::channel(); - let _ = self.to_service.send(PayloadServiceCommand::Resolve(id, tx)); - rx.await?.ok_or(PayloadBuilderError::MissingPayload) + let _ = self.to_service.send(PayloadServiceCommand::BuildNewPayload(attr, tx)); + rx } /// Note: this does not resolve the job if it's still in progress. @@ -132,21 +138,17 @@ where rx.await.ok()? } - fn send_new_payload( + async fn resolve_kind( &self, - attr: ::PayloadBuilderAttributes, - ) -> Receiver> { + id: PayloadId, + kind: PayloadKind, + ) -> Option> { let (tx, rx) = oneshot::channel(); - let _ = self.to_service.send(PayloadServiceCommand::BuildNewPayload(attr, tx)); - rx - } - - /// Note: if there's already payload in progress with same identifier, it will be returned. - async fn new_payload( - &self, - attr: ::PayloadBuilderAttributes, - ) -> Result { - self.send_new_payload(attr).await? + self.to_service.send(PayloadServiceCommand::Resolve(id, kind, tx)).ok()?; + match rx.await.transpose()? { + Ok(fut) => Some(fut.await), + Err(e) => Some(Err(e.into())), + } } async fn subscribe(&self) -> Result, Self::Error> { @@ -168,19 +170,6 @@ where Self { to_service } } - /// Resolves the payload job and returns the best payload that has been built so far. - /// - /// Note: depending on the installed [`PayloadJobGenerator`], this may or may not terminate the - /// job, See [`PayloadJob::resolve`]. - async fn resolve(&self, id: PayloadId) -> Option> { - let (tx, rx) = oneshot::channel(); - self.to_service.send(PayloadServiceCommand::Resolve(id, tx)).ok()?; - match rx.await.transpose()? { - Ok(fut) => Some(fut.await), - Err(e) => Some(Err(e.into())), - } - } - /// Returns the payload attributes associated with the given identifier. /// /// Note: this returns the attributes of the payload and does not resolve the job. @@ -296,11 +285,15 @@ where /// Returns the best payload for the given identifier that has been built so far and terminates /// the job if requested. - fn resolve(&mut self, id: PayloadId) -> Option> { + fn resolve( + &mut self, + id: PayloadId, + kind: PayloadKind, + ) -> Option> { trace!(%id, "resolving payload job"); let job = self.payload_jobs.iter().position(|(_, job_id)| *job_id == id)?; - let (fut, keep_alive) = self.payload_jobs[job].0.resolve(); + let (fut, keep_alive) = self.payload_jobs[job].0.resolve_kind(kind); if keep_alive == KeepPayloadJobAlive::No { let (_, id) = self.payload_jobs.swap_remove(job); @@ -437,8 +430,8 @@ where let attributes = this.payload_attributes(id); let _ = tx.send(attributes); } - PayloadServiceCommand::Resolve(id, tx) => { - let _ = tx.send(this.resolve(id)); + PayloadServiceCommand::Resolve(id, strategy, tx) => { + let _ = tx.send(this.resolve(id, strategy)); } PayloadServiceCommand::Subscribe(tx) => { let new_rx = this.payload_events.subscribe(); @@ -469,7 +462,11 @@ pub enum PayloadServiceCommand { oneshot::Sender>>, ), /// Resolve the payload and return the payload - Resolve(PayloadId, oneshot::Sender>>), + Resolve( + PayloadId, + /* kind: */ PayloadKind, + oneshot::Sender>>, + ), /// Payload service events Subscribe(oneshot::Sender>>), } @@ -489,7 +486,7 @@ where Self::PayloadAttributes(f0, f1) => { f.debug_tuple("PayloadAttributes").field(&f0).field(&f1).finish() } - Self::Resolve(f0, _f1) => f.debug_tuple("Resolve").field(&f0).finish(), + Self::Resolve(f0, f1, _f2) => f.debug_tuple("Resolve").field(&f0).field(&f1).finish(), Self::Subscribe(f0) => f.debug_tuple("Subscribe").field(&f0).finish(), } } diff --git a/crates/payload/builder/src/test_utils.rs b/crates/payload/builder/src/test_utils.rs index 55b9b84f45ea..6990dc9b1744 100644 --- a/crates/payload/builder/src/test_utils.rs +++ b/crates/payload/builder/src/test_utils.rs @@ -7,7 +7,7 @@ use crate::{ use alloy_primitives::U256; use reth_chain_state::ExecutedBlock; -use reth_payload_primitives::{PayloadBuilderError, PayloadTypes}; +use reth_payload_primitives::{PayloadBuilderError, PayloadKind, PayloadTypes}; use reth_primitives::Block; use reth_provider::CanonStateNotification; use std::{ @@ -96,7 +96,10 @@ impl PayloadJob for TestPayloadJob { Ok(self.attr.clone()) } - fn resolve(&mut self) -> (Self::ResolvePayloadFuture, KeepPayloadJobAlive) { + fn resolve_kind( + &mut self, + _kind: PayloadKind, + ) -> (Self::ResolvePayloadFuture, KeepPayloadJobAlive) { let fut = futures_util::future::ready(self.best_payload()); (fut, KeepPayloadJobAlive::No) } diff --git a/crates/payload/builder/src/traits.rs b/crates/payload/builder/src/traits.rs index 8d448eeff5ad..62dadeb45d7c 100644 --- a/crates/payload/builder/src/traits.rs +++ b/crates/payload/builder/src/traits.rs @@ -1,6 +1,8 @@ //! Trait abstractions used by the payload crate. -use reth_payload_primitives::{BuiltPayload, PayloadBuilderAttributes, PayloadBuilderError}; +use reth_payload_primitives::{ + BuiltPayload, PayloadBuilderAttributes, PayloadBuilderError, PayloadKind, +}; use reth_provider::CanonStateNotification; use std::future::Future; @@ -53,7 +55,21 @@ pub trait PayloadJob: Future> + Send + /// If this returns [`KeepPayloadJobAlive::Yes`], then the [`PayloadJob`] will be polled /// once more. If this returns [`KeepPayloadJobAlive::No`] then the [`PayloadJob`] will be /// dropped after this call. - fn resolve(&mut self) -> (Self::ResolvePayloadFuture, KeepPayloadJobAlive); + /// + /// The [`PayloadKind`] determines how the payload should be resolved in the + /// `ResolvePayloadFuture`. [`PayloadKind::Earliest`] should return the earliest available + /// payload (as fast as possible), e.g. racing an empty payload job against a pending job if + /// there's no payload available yet. [`PayloadKind::WaitForPending`] is allowed to wait + /// until a built payload is available. + fn resolve_kind( + &mut self, + kind: PayloadKind, + ) -> (Self::ResolvePayloadFuture, KeepPayloadJobAlive); + + /// Resolves the payload as fast as possible. + fn resolve(&mut self) -> (Self::ResolvePayloadFuture, KeepPayloadJobAlive) { + self.resolve_kind(PayloadKind::Earliest) + } } /// Whether the payload job should be kept alive or terminated after the payload was requested by diff --git a/crates/payload/primitives/src/lib.rs b/crates/payload/primitives/src/lib.rs index 8173cae344ae..08aa428000ed 100644 --- a/crates/payload/primitives/src/lib.rs +++ b/crates/payload/primitives/src/lib.rs @@ -342,6 +342,28 @@ pub enum EngineApiMessageVersion { V4, } +/// Determines how we should choose the payload to return. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] +pub enum PayloadKind { + /// Returns the next best available payload (the earliest available payload). + /// This does not wait for a real for pending job to finish if there's no best payload yet and + /// is allowed to race various payload jobs (empty, pending best) against each other and + /// returns whichever job finishes faster. + /// + /// This should be used when it's more important to return a valid payload as fast as possible. + /// For example, the engine API timeout for `engine_getPayload` is 1s and clients should rather + /// return an empty payload than indefinitely waiting for the pending payload job to finish and + /// risk missing the deadline. + #[default] + Earliest, + /// Only returns once we have at least one built payload. + /// + /// Compared to [`PayloadKind::Earliest`] this does not race an empty payload job against the + /// already in progress one, and returns the best available built payload or awaits the job in + /// progress. + WaitForPending, +} + #[cfg(test)] mod tests { use super::*; diff --git a/crates/payload/primitives/src/traits.rs b/crates/payload/primitives/src/traits.rs index 494ed68aa4ee..ce98fcad32ea 100644 --- a/crates/payload/primitives/src/traits.rs +++ b/crates/payload/primitives/src/traits.rs @@ -1,4 +1,4 @@ -use crate::{PayloadBuilderError, PayloadEvents, PayloadTypes}; +use crate::{PayloadEvents, PayloadKind, PayloadTypes}; use alloy_primitives::{Address, B256, U256}; use alloy_rpc_types::{ engine::{PayloadAttributes as EthPayloadAttributes, PayloadId}, @@ -7,12 +7,8 @@ use alloy_rpc_types::{ use op_alloy_rpc_types_engine::OpPayloadAttributes; use reth_chain_state::ExecutedBlock; use reth_primitives::{SealedBlock, Withdrawals}; -use std::{future::Future, pin::Pin}; use tokio::sync::oneshot; -pub(crate) type PayloadFuture

= - Pin> + Send + Sync>>; - /// A type that can request, subscribe to and resolve payloads. #[async_trait::async_trait] pub trait PayloadBuilder: Send + Unpin { @@ -21,12 +17,13 @@ pub trait PayloadBuilder: Send + Unpin { /// The error type returned by the builder. type Error; - /// Sends a message to the service to start building a new payload for the given payload - /// attributes and returns a future that resolves to the payload. - async fn send_and_resolve_payload( + /// Sends a message to the service to start building a new payload for the given payload. + /// + /// Returns a receiver that will receive the payload id. + fn send_new_payload( &self, attr: ::PayloadBuilderAttributes, - ) -> Result::BuiltPayload>, Self::Error>; + ) -> oneshot::Receiver>; /// Returns the best payload for the given identifier. async fn best_payload( @@ -34,22 +31,21 @@ pub trait PayloadBuilder: Send + Unpin { id: PayloadId, ) -> Option::BuiltPayload, Self::Error>>; - /// Sends a message to the service to start building a new payload for the given payload. - /// - /// This is the same as [`PayloadBuilder::new_payload`] but does not wait for the result - /// and returns the receiver instead - fn send_new_payload( + /// Resolves the payload job and returns the best payload that has been built so far. + async fn resolve_kind( &self, - attr: ::PayloadBuilderAttributes, - ) -> oneshot::Receiver>; + id: PayloadId, + kind: PayloadKind, + ) -> Option::BuiltPayload, Self::Error>>; - /// Starts building a new payload for the given payload attributes. - /// - /// Returns the identifier of the payload. - async fn new_payload( + /// Resolves the payload job as fast and possible and returns the best payload that has been + /// built so far. + async fn resolve( &self, - attr: ::PayloadBuilderAttributes, - ) -> Result; + id: PayloadId, + ) -> Option::BuiltPayload, Self::Error>> { + self.resolve_kind(id, PayloadKind::Earliest).await + } /// Sends a message to the service to subscribe to payload events. /// Returns a receiver that will receive them. diff --git a/examples/custom-payload-builder/src/job.rs b/examples/custom-payload-builder/src/job.rs index 26b594be94b8..014198259596 100644 --- a/examples/custom-payload-builder/src/job.rs +++ b/examples/custom-payload-builder/src/job.rs @@ -3,6 +3,7 @@ use reth::{ providers::StateProviderFactory, tasks::TaskSpawner, transaction_pool::TransactionPool, }; use reth_basic_payload_builder::{PayloadBuilder, PayloadConfig}; +use reth_node_api::PayloadKind; use reth_payload_builder::{KeepPayloadJobAlive, PayloadBuilderError, PayloadJob}; use std::{ @@ -52,7 +53,10 @@ where Ok(self.config.attributes.clone()) } - fn resolve(&mut self) -> (Self::ResolvePayloadFuture, KeepPayloadJobAlive) { + fn resolve_kind( + &mut self, + _kind: PayloadKind, + ) -> (Self::ResolvePayloadFuture, KeepPayloadJobAlive) { let payload = self.best_payload(); (futures_util::future::ready(payload), KeepPayloadJobAlive::No) } From 9c8f5d89d884e3a4c0b2e8120b5f4c6121e626f1 Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Fri, 18 Oct 2024 13:47:56 +0200 Subject: [PATCH 076/113] chore: rm v2 get bodies functions (#11870) --- crates/rpc/rpc-api/src/engine.rs | 23 ++------ crates/rpc/rpc-engine-api/src/capabilities.rs | 2 - crates/rpc/rpc-engine-api/src/engine_api.rs | 52 ++----------------- crates/rpc/rpc-engine-api/src/metrics.rs | 4 -- .../rpc-types-compat/src/engine/payload.rs | 50 +----------------- 5 files changed, 8 insertions(+), 123 deletions(-) diff --git a/crates/rpc/rpc-api/src/engine.rs b/crates/rpc/rpc-api/src/engine.rs index 50181d23a75c..eedada8ffa7a 100644 --- a/crates/rpc/rpc-api/src/engine.rs +++ b/crates/rpc/rpc-api/src/engine.rs @@ -10,9 +10,9 @@ use alloy_rpc_types::{ state::StateOverride, BlockOverrides, EIP1186AccountProofResponse, Filter, Log, SyncStatus, }; use alloy_rpc_types_engine::{ - ClientVersionV1, ExecutionPayloadBodiesV1, ExecutionPayloadBodiesV2, ExecutionPayloadInputV2, - ExecutionPayloadV1, ExecutionPayloadV3, ExecutionPayloadV4, ForkchoiceState, ForkchoiceUpdated, - PayloadId, PayloadStatus, TransitionConfiguration, + ClientVersionV1, ExecutionPayloadBodiesV1, ExecutionPayloadInputV2, ExecutionPayloadV1, + ExecutionPayloadV3, ExecutionPayloadV4, ForkchoiceState, ForkchoiceUpdated, PayloadId, + PayloadStatus, TransitionConfiguration, }; use alloy_rpc_types_eth::transaction::TransactionRequest; use alloy_serde::JsonStorageKey; @@ -146,13 +146,6 @@ pub trait EngineApi { block_hashes: Vec, ) -> RpcResult; - /// See also - #[method(name = "getPayloadBodiesByHashV2")] - async fn get_payload_bodies_by_hash_v2( - &self, - block_hashes: Vec, - ) -> RpcResult; - /// See also /// /// Returns the execution payload bodies by the range starting at `start`, containing `count` @@ -172,16 +165,6 @@ pub trait EngineApi { count: U64, ) -> RpcResult; - /// See also - /// - /// Similar to `getPayloadBodiesByRangeV1`, but returns [`ExecutionPayloadBodiesV2`] - #[method(name = "getPayloadBodiesByRangeV2")] - async fn get_payload_bodies_by_range_v2( - &self, - start: U64, - count: U64, - ) -> RpcResult; - /// See also /// /// Note: This method will be deprecated after the cancun hardfork: diff --git a/crates/rpc/rpc-engine-api/src/capabilities.rs b/crates/rpc/rpc-engine-api/src/capabilities.rs index de4d96231538..af0609b0d1f0 100644 --- a/crates/rpc/rpc-engine-api/src/capabilities.rs +++ b/crates/rpc/rpc-engine-api/src/capabilities.rs @@ -17,8 +17,6 @@ pub const CAPABILITIES: &[&str] = &[ "engine_newPayloadV4", "engine_getPayloadBodiesByHashV1", "engine_getPayloadBodiesByRangeV1", - "engine_getPayloadBodiesByHashV2", - "engine_getPayloadBodiesByRangeV2", "engine_getBlobsV1", ]; diff --git a/crates/rpc/rpc-engine-api/src/engine_api.rs b/crates/rpc/rpc-engine-api/src/engine_api.rs index 252808c14a77..fb7f98ed203e 100644 --- a/crates/rpc/rpc-engine-api/src/engine_api.rs +++ b/crates/rpc/rpc-engine-api/src/engine_api.rs @@ -5,9 +5,8 @@ use alloy_eips::eip4844::BlobAndProofV1; use alloy_primitives::{BlockHash, BlockNumber, B256, U64}; use alloy_rpc_types_engine::{ CancunPayloadFields, ClientVersionV1, ExecutionPayload, ExecutionPayloadBodiesV1, - ExecutionPayloadBodiesV2, ExecutionPayloadInputV2, ExecutionPayloadV1, ExecutionPayloadV3, - ExecutionPayloadV4, ForkchoiceState, ForkchoiceUpdated, PayloadId, PayloadStatus, - TransitionConfiguration, + ExecutionPayloadInputV2, ExecutionPayloadV1, ExecutionPayloadV3, ExecutionPayloadV4, + ForkchoiceState, ForkchoiceUpdated, PayloadId, PayloadStatus, TransitionConfiguration, }; use async_trait::async_trait; use jsonrpsee_core::RpcResult; @@ -23,7 +22,7 @@ use reth_payload_primitives::{ use reth_primitives::{Block, BlockHashOrNumber, EthereumHardfork}; use reth_rpc_api::EngineApiServer; use reth_rpc_types_compat::engine::payload::{ - convert_payload_input_v2_to_payload, convert_to_payload_body_v1, convert_to_payload_body_v2, + convert_payload_input_v2_to_payload, convert_to_payload_body_v1, }; use reth_storage_api::{BlockReader, HeaderProvider, StateProviderFactory}; use reth_tasks::TaskSpawner; @@ -451,18 +450,6 @@ where self.get_payload_bodies_by_range_with(start, count, convert_to_payload_body_v1).await } - /// Returns the execution payload bodies by the range starting at `start`, containing `count` - /// blocks. - /// - /// Same as [`Self::get_payload_bodies_by_range_v1`] but as [`ExecutionPayloadBodiesV2`]. - pub async fn get_payload_bodies_by_range_v2( - &self, - start: BlockNumber, - count: u64, - ) -> EngineApiResult { - self.get_payload_bodies_by_range_with(start, count, convert_to_payload_body_v2).await - } - /// Called to retrieve execution payload bodies by hashes. async fn get_payload_bodies_by_hash_with( &self, @@ -509,16 +496,6 @@ where self.get_payload_bodies_by_hash_with(hashes, convert_to_payload_body_v1).await } - /// Called to retrieve execution payload bodies by hashes. - /// - /// Same as [`Self::get_payload_bodies_by_hash_v1`] but as [`ExecutionPayloadBodiesV2`]. - pub async fn get_payload_bodies_by_hash_v2( - &self, - hashes: Vec, - ) -> EngineApiResult { - self.get_payload_bodies_by_hash_with(hashes, convert_to_payload_body_v2).await - } - /// Called to verify network configuration parameters and ensure that Consensus and Execution /// layers are using the latest configuration. pub fn exchange_transition_configuration( @@ -846,17 +823,6 @@ where Ok(res.await?) } - async fn get_payload_bodies_by_hash_v2( - &self, - block_hashes: Vec, - ) -> RpcResult { - trace!(target: "rpc::engine", "Serving engine_getPayloadBodiesByHashV2"); - let start = Instant::now(); - let res = Self::get_payload_bodies_by_hash_v2(self, block_hashes); - self.inner.metrics.latency.get_payload_bodies_by_hash_v2.record(start.elapsed()); - Ok(res.await?) - } - /// Handler for `engine_getPayloadBodiesByRangeV1` /// /// See also @@ -885,18 +851,6 @@ where Ok(res?) } - async fn get_payload_bodies_by_range_v2( - &self, - start: U64, - count: U64, - ) -> RpcResult { - trace!(target: "rpc::engine", "Serving engine_getPayloadBodiesByRangeV2"); - let start_time = Instant::now(); - let res = Self::get_payload_bodies_by_range_v2(self, start.to(), count.to()).await; - self.inner.metrics.latency.get_payload_bodies_by_range_v2.record(start_time.elapsed()); - Ok(res?) - } - /// Handler for `engine_exchangeTransitionConfigurationV1` /// See also async fn exchange_transition_configuration( diff --git a/crates/rpc/rpc-engine-api/src/metrics.rs b/crates/rpc/rpc-engine-api/src/metrics.rs index 2c4216664ae2..8d0106f9dd93 100644 --- a/crates/rpc/rpc-engine-api/src/metrics.rs +++ b/crates/rpc/rpc-engine-api/src/metrics.rs @@ -44,12 +44,8 @@ pub(crate) struct EngineApiLatencyMetrics { pub(crate) get_payload_v4: Histogram, /// Latency for `engine_getPayloadBodiesByRangeV1` pub(crate) get_payload_bodies_by_range_v1: Histogram, - /// Latency for `engine_getPayloadBodiesByRangeV2` - pub(crate) get_payload_bodies_by_range_v2: Histogram, /// Latency for `engine_getPayloadBodiesByHashV1` pub(crate) get_payload_bodies_by_hash_v1: Histogram, - /// Latency for `engine_getPayloadBodiesByHashV2` - pub(crate) get_payload_bodies_by_hash_v2: Histogram, /// Latency for `engine_exchangeTransitionConfigurationV1` pub(crate) exchange_transition_configuration: Histogram, } diff --git a/crates/rpc/rpc-types-compat/src/engine/payload.rs b/crates/rpc/rpc-types-compat/src/engine/payload.rs index e6f2f97ca75c..cd9ce1cbf7d7 100644 --- a/crates/rpc/rpc-types-compat/src/engine/payload.rs +++ b/crates/rpc/rpc-types-compat/src/engine/payload.rs @@ -6,8 +6,8 @@ use alloy_eips::eip2718::{Decodable2718, Encodable2718}; use alloy_primitives::{B256, U256}; use alloy_rpc_types_engine::{ payload::{ExecutionPayloadBodyV1, ExecutionPayloadFieldV2, ExecutionPayloadInputV2}, - ExecutionPayload, ExecutionPayloadBodyV2, ExecutionPayloadV1, ExecutionPayloadV2, - ExecutionPayloadV3, ExecutionPayloadV4, PayloadError, + ExecutionPayload, ExecutionPayloadV1, ExecutionPayloadV2, ExecutionPayloadV3, + ExecutionPayloadV4, PayloadError, }; use reth_primitives::{ constants::MAXIMUM_EXTRA_DATA_SIZE, @@ -381,52 +381,6 @@ pub fn convert_to_payload_body_v1(value: Block) -> ExecutionPayloadBodyV1 { } } -/// Converts [`Block`] to [`ExecutionPayloadBodyV2`] -pub fn convert_to_payload_body_v2(value: Block) -> ExecutionPayloadBodyV2 { - let transactions = value.body.transactions.into_iter().map(|tx| { - let mut out = Vec::new(); - tx.encode_2718(&mut out); - out.into() - }); - - let mut payload = ExecutionPayloadBodyV2 { - transactions: transactions.collect(), - withdrawals: value.body.withdrawals.map(Withdrawals::into_inner), - deposit_requests: None, - withdrawal_requests: None, - consolidation_requests: None, - }; - - if let Some(requests) = value.body.requests { - let (deposit_requests, withdrawal_requests, consolidation_requests) = - requests.into_iter().fold( - (Vec::new(), Vec::new(), Vec::new()), - |(mut deposits, mut withdrawals, mut consolidation_requests), request| { - match request { - Request::DepositRequest(r) => { - deposits.push(r); - } - Request::WithdrawalRequest(r) => { - withdrawals.push(r); - } - Request::ConsolidationRequest(r) => { - consolidation_requests.push(r); - } - _ => {} - }; - - (deposits, withdrawals, consolidation_requests) - }, - ); - - payload.deposit_requests = Some(deposit_requests); - payload.withdrawal_requests = Some(withdrawal_requests); - payload.consolidation_requests = Some(consolidation_requests); - } - - payload -} - /// Transforms a [`SealedBlock`] into a [`ExecutionPayloadV1`] pub fn execution_payload_from_sealed_block(value: SealedBlock) -> ExecutionPayloadV1 { let transactions = value.raw_transactions(); From 587c91f1cf988cf9f99bb251bf5da7f86ff5600d Mon Sep 17 00:00:00 2001 From: Ayodeji Akinola Date: Fri, 18 Oct 2024 16:17:11 +0100 Subject: [PATCH 077/113] Optimize Sender Recovery Process (#11385) --- .../stages/src/stages/sender_recovery.rs | 146 +++++++++++------- 1 file changed, 86 insertions(+), 60 deletions(-) diff --git a/crates/stages/stages/src/stages/sender_recovery.rs b/crates/stages/stages/src/stages/sender_recovery.rs index a85b0bc60ccb..a4eda6394c07 100644 --- a/crates/stages/stages/src/stages/sender_recovery.rs +++ b/crates/stages/stages/src/stages/sender_recovery.rs @@ -29,6 +29,9 @@ const BATCH_SIZE: usize = 100_000; /// Maximum number of senders to recover per rayon worker job. const WORKER_CHUNK_SIZE: usize = 100; +/// Type alias for a sender that transmits the result of sender recovery. +type RecoveryResultSender = mpsc::Sender>>; + /// The sender recovery stage iterates over existing transactions, /// recovers the transaction signer and stores them /// in [`TransactionSenders`][reth_db::tables::TransactionSenders] table. @@ -100,8 +103,10 @@ where .map(|start| start..std::cmp::min(start + BATCH_SIZE as u64, tx_range.end)) .collect::>>(); + let tx_batch_sender = setup_range_recovery(provider); + for range in batch { - recover_range(range, provider, &mut senders_cursor)?; + recover_range(range, provider, tx_batch_sender.clone(), &mut senders_cursor)?; } Ok(ExecOutput { @@ -136,15 +141,16 @@ where fn recover_range( tx_range: Range, provider: &Provider, + tx_batch_sender: mpsc::Sender, RecoveryResultSender)>>, senders_cursor: &mut CURSOR, ) -> Result<(), StageError> where Provider: DBProvider + HeaderProvider + StaticFileProviderFactory, CURSOR: DbCursorRW, { - debug!(target: "sync::stages::sender_recovery", ?tx_range, "Recovering senders batch"); + debug!(target: "sync::stages::sender_recovery", ?tx_range, "Sending batch for processing"); - // Preallocate channels + // Preallocate channels for each chunks in the batch let (chunks, receivers): (Vec<_>, Vec<_>) = tx_range .clone() .step_by(WORKER_CHUNK_SIZE) @@ -156,62 +162,9 @@ where }) .unzip(); - let static_file_provider = provider.static_file_provider(); - - // We do not use `tokio::task::spawn_blocking` because, during a shutdown, - // there will be a timeout grace period in which Tokio does not allow spawning - // additional blocking tasks. This would cause this function to return - // `SenderRecoveryStageError::RecoveredSendersMismatch` at the end. - // - // However, using `std::thread::spawn` allows us to utilize the timeout grace - // period to complete some work without throwing errors during the shutdown. - std::thread::spawn(move || { - for (chunk_range, recovered_senders_tx) in chunks { - // Read the raw value, and let the rayon worker to decompress & decode. - let chunk = match static_file_provider.fetch_range_with_predicate( - StaticFileSegment::Transactions, - chunk_range.clone(), - |cursor, number| { - Ok(cursor - .get_one::>>( - number.into(), - )? - .map(|tx| (number, tx))) - }, - |_| true, - ) { - Ok(chunk) => chunk, - Err(err) => { - // We exit early since we could not process this chunk. - let _ = recovered_senders_tx - .send(Err(Box::new(SenderRecoveryStageError::StageError(err.into())))); - break - } - }; - - // Spawn the task onto the global rayon pool - // This task will send the results through the channel after it has read the transaction - // and calculated the sender. - rayon::spawn(move || { - let mut rlp_buf = Vec::with_capacity(128); - for (number, tx) in chunk { - let res = tx - .value() - .map_err(|err| Box::new(SenderRecoveryStageError::StageError(err.into()))) - .and_then(|tx| recover_sender((number, tx), &mut rlp_buf)); - - let is_err = res.is_err(); - - let _ = recovered_senders_tx.send(res); - - // Finish early - if is_err { - break - } - } - }); - } - }); + if let Some(err) = tx_batch_sender.send(chunks).err() { + return Err(StageError::Fatal(err.into())); + } debug!(target: "sync::stages::sender_recovery", ?tx_range, "Appending recovered senders to the database"); @@ -235,6 +188,7 @@ where provider.sealed_header(block_number)?.ok_or_else(|| { ProviderError::HeaderNotFound(block_number.into()) })?; + Err(StageError::Block { block: Box::new(sealed_header), error: BlockErrorKind::Validation( @@ -269,10 +223,82 @@ where .into(), )); } - Ok(()) } +/// Spawns a thread to handle the recovery of transaction senders for +/// specified chunks of a given batch. It processes incoming ranges, fetching and recovering +/// transactions in parallel using global rayon pool +fn setup_range_recovery( + provider: &Provider, +) -> mpsc::Sender, RecoveryResultSender)>> +where + Provider: DBProvider + HeaderProvider + StaticFileProviderFactory, +{ + let (tx_sender, tx_receiver) = mpsc::channel::, RecoveryResultSender)>>(); + let static_file_provider = provider.static_file_provider(); + + // We do not use `tokio::task::spawn_blocking` because, during a shutdown, + // there will be a timeout grace period in which Tokio does not allow spawning + // additional blocking tasks. This would cause this function to return + // `SenderRecoveryStageError::RecoveredSendersMismatch` at the end. + // + // However, using `std::thread::spawn` allows us to utilize the timeout grace + // period to complete some work without throwing errors during the shutdown. + std::thread::spawn(move || { + while let Ok(chunks) = tx_receiver.recv() { + for (chunk_range, recovered_senders_tx) in chunks { + // Read the raw value, and let the rayon worker to decompress & decode. + let chunk = match static_file_provider.fetch_range_with_predicate( + StaticFileSegment::Transactions, + chunk_range.clone(), + |cursor, number| { + Ok(cursor + .get_one::>>( + number.into(), + )? + .map(|tx| (number, tx))) + }, + |_| true, + ) { + Ok(chunk) => chunk, + Err(err) => { + // We exit early since we could not process this chunk. + let _ = recovered_senders_tx + .send(Err(Box::new(SenderRecoveryStageError::StageError(err.into())))); + break + } + }; + + // Spawn the task onto the global rayon pool + // This task will send the results through the channel after it has read the + // transaction and calculated the sender. + rayon::spawn(move || { + let mut rlp_buf = Vec::with_capacity(128); + for (number, tx) in chunk { + let res = tx + .value() + .map_err(|err| { + Box::new(SenderRecoveryStageError::StageError(err.into())) + }) + .and_then(|tx| recover_sender((number, tx), &mut rlp_buf)); + + let is_err = res.is_err(); + + let _ = recovered_senders_tx.send(res); + + // Finish early + if is_err { + break + } + } + }); + } + } + }); + tx_sender +} + #[inline] fn recover_sender( (tx_id, tx): (TxNumber, TransactionSignedNoHash), From a908f977736ebd0d609fc3d2f4a6904a14f0bd73 Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Fri, 18 Oct 2024 20:21:55 +0200 Subject: [PATCH 078/113] chore: simplify update fn (#11880) --- crates/transaction-pool/src/pool/pending.rs | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/crates/transaction-pool/src/pool/pending.rs b/crates/transaction-pool/src/pool/pending.rs index ff3ecf65a494..ff5269014c4c 100644 --- a/crates/transaction-pool/src/pool/pending.rs +++ b/crates/transaction-pool/src/pool/pending.rs @@ -197,7 +197,7 @@ impl PendingPool { } } else { self.size_of += tx.transaction.size(); - self.update_independents_and_highest_nonces(&tx, &id); + self.update_independents_and_highest_nonces(&tx); self.all.insert(tx.clone()); self.by_id.insert(id, tx); } @@ -243,7 +243,7 @@ impl PendingPool { tx.priority = self.ordering.priority(&tx.transaction.transaction, base_fee); self.size_of += tx.transaction.size(); - self.update_independents_and_highest_nonces(&tx, &id); + self.update_independents_and_highest_nonces(&tx); self.all.insert(tx.clone()); self.by_id.insert(id, tx); } @@ -254,12 +254,8 @@ impl PendingPool { /// Updates the independent transaction and highest nonces set, assuming the given transaction /// is being _added_ to the pool. - fn update_independents_and_highest_nonces( - &mut self, - tx: &PendingTransaction, - tx_id: &TransactionId, - ) { - let ancestor_id = tx_id.unchecked_ancestor(); + fn update_independents_and_highest_nonces(&mut self, tx: &PendingTransaction) { + let ancestor_id = tx.transaction.id().unchecked_ancestor(); if let Some(ancestor) = ancestor_id.and_then(|id| self.by_id.get(&id)) { // the transaction already has an ancestor, so we only need to ensure that the // highest nonces set actually contains the highest nonce for that sender @@ -305,7 +301,7 @@ impl PendingPool { let priority = self.ordering.priority(&tx.transaction, base_fee); let tx = PendingTransaction { submission_id, transaction: tx, priority }; - self.update_independents_and_highest_nonces(&tx, &tx_id); + self.update_independents_and_highest_nonces(&tx); self.all.insert(tx.clone()); // send the new transaction to any existing pendingpool static file iterators From eee5e0d41f601dca62339b09b666432377717bd0 Mon Sep 17 00:00:00 2001 From: Thomas Coratger <60488569+tcoratger@users.noreply.github.com> Date: Fri, 18 Oct 2024 22:08:09 +0200 Subject: [PATCH 079/113] bump rust to 1.82 (#11876) --- .github/workflows/lint.yml | 4 ++-- Cargo.toml | 6 ++---- README.md | 2 +- clippy.toml | 18 ++++++++++++++++-- .../src/providers/static_file/manager.rs | 1 + 5 files changed, 22 insertions(+), 9 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index efa38857e06b..65c01c3a4912 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -103,7 +103,7 @@ jobs: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@master with: - toolchain: "1.81" # MSRV + toolchain: "1.82" # MSRV - uses: Swatinem/rust-cache@v2 with: cache-on-failure: true @@ -163,7 +163,7 @@ jobs: - uses: dtolnay/rust-toolchain@nightly - uses: dtolnay/rust-toolchain@master with: - toolchain: "1.81" # MSRV + toolchain: "1.82" # MSRV - uses: Swatinem/rust-cache@v2 with: cache-on-failure: true diff --git a/Cargo.toml b/Cargo.toml index e3ec1c1fb4a6..54111096902c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [workspace.package] version = "1.1.0" edition = "2021" -rust-version = "1.81" +rust-version = "1.82" license = "MIT OR Apache-2.0" homepage = "https://paradigmxyz.github.io/reth" repository = "https://github.com/paradigmxyz/reth" @@ -410,9 +410,7 @@ reth-trie-db = { path = "crates/trie/db" } reth-trie-parallel = { path = "crates/trie/parallel" } # revm -revm = { version = "14.0.3", features = [ - "std", -], default-features = false } +revm = { version = "14.0.3", features = ["std"], default-features = false } revm-inspectors = "0.8.1" revm-primitives = { version = "10.0.0", features = [ "std", diff --git a/README.md b/README.md index 7fae4d0b62c0..8a6b8ddb42fb 100644 --- a/README.md +++ b/README.md @@ -87,7 +87,7 @@ When updating this, also update: - .github/workflows/lint.yml --> -The Minimum Supported Rust Version (MSRV) of this project is [1.81.0](https://blog.rust-lang.org/2024/09/05/Rust-1.81.0.html). +The Minimum Supported Rust Version (MSRV) of this project is [1.82.0](https://blog.rust-lang.org/2024/10/17/Rust-1.82.0.html). See the book for detailed instructions on how to [build from source](https://paradigmxyz.github.io/reth/installation/source.html). diff --git a/clippy.toml b/clippy.toml index cdfa4bc93a21..862c568634e5 100644 --- a/clippy.toml +++ b/clippy.toml @@ -1,3 +1,17 @@ -msrv = "1.81" +msrv = "1.82" too-large-for-stack = 128 -doc-valid-idents = ["P2P", "ExEx", "ExExes", "IPv4", "IPv6", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "WAL", "MessagePack"] +doc-valid-idents = [ + "P2P", + "ExEx", + "ExExes", + "IPv4", + "IPv6", + "KiB", + "MiB", + "GiB", + "TiB", + "PiB", + "EiB", + "WAL", + "MessagePack", +] diff --git a/crates/storage/provider/src/providers/static_file/manager.rs b/crates/storage/provider/src/providers/static_file/manager.rs index e233332a0e95..6f5cf07c95c5 100644 --- a/crates/storage/provider/src/providers/static_file/manager.rs +++ b/crates/storage/provider/src/providers/static_file/manager.rs @@ -143,6 +143,7 @@ impl StaticFileProvider { // appending/truncating rows for segment in event.paths { // Ensure it's a file with the .conf extension + #[allow(clippy::nonminimal_bool)] if !segment .extension() .is_some_and(|s| s.to_str() == Some(CONFIG_FILE_EXTENSION)) From 655fc1a55a6dae5dfd522f1981142524c0ef6924 Mon Sep 17 00:00:00 2001 From: Thomas Coratger <60488569+tcoratger@users.noreply.github.com> Date: Sat, 19 Oct 2024 00:13:02 +0200 Subject: [PATCH 080/113] rpc: add unit tests for `RpcModuleSelection` (#11883) --- crates/rpc/rpc-server-types/src/module.rs | 235 +++++++++++++++++++++- 1 file changed, 232 insertions(+), 3 deletions(-) diff --git a/crates/rpc/rpc-server-types/src/module.rs b/crates/rpc/rpc-server-types/src/module.rs index 72a5e7c85833..56417dda701c 100644 --- a/crates/rpc/rpc-server-types/src/module.rs +++ b/crates/rpc/rpc-server-types/src/module.rs @@ -199,9 +199,12 @@ impl FromStr for RpcModuleSelection { } let mut modules = s.split(',').map(str::trim).peekable(); let first = modules.peek().copied().ok_or(ParseError::VariantNotFound)?; - match first { - "all" | "All" => Ok(Self::All), - "none" | "None" => Ok(Self::Selection(Default::default())), + // We convert to lowercase to make the comparison case-insensitive + // + // This is a way to allow typing "all" and "ALL" and "All" and "aLl" etc. + match first.to_lowercase().as_str() { + "all" => Ok(Self::All), + "none" => Ok(Self::Selection(Default::default())), _ => Self::try_from_selection(modules), } } @@ -329,3 +332,229 @@ impl Serialize for RethRpcModule { s.serialize_str(self.as_ref()) } } + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_all_modules() { + let all_modules = RpcModuleSelection::all_modules(); + assert_eq!(all_modules.len(), RethRpcModule::variant_count()); + } + + #[test] + fn test_standard_modules() { + let standard_modules = RpcModuleSelection::standard_modules(); + let expected_modules: HashSet = + HashSet::from([RethRpcModule::Eth, RethRpcModule::Net, RethRpcModule::Web3]); + assert_eq!(standard_modules, expected_modules); + } + + #[test] + fn test_default_ipc_modules() { + let default_ipc_modules = RpcModuleSelection::default_ipc_modules(); + assert_eq!(default_ipc_modules, RpcModuleSelection::all_modules()); + } + + #[test] + fn test_try_from_selection_success() { + let selection = vec!["eth", "admin"]; + let config = RpcModuleSelection::try_from_selection(selection).unwrap(); + assert_eq!(config, RpcModuleSelection::from([RethRpcModule::Eth, RethRpcModule::Admin])); + } + + #[test] + fn test_rpc_module_selection_len() { + let all_modules = RpcModuleSelection::All; + let standard = RpcModuleSelection::Standard; + let selection = RpcModuleSelection::from([RethRpcModule::Eth, RethRpcModule::Admin]); + + assert_eq!(all_modules.len(), RethRpcModule::variant_count()); + assert_eq!(standard.len(), 3); + assert_eq!(selection.len(), 2); + } + + #[test] + fn test_rpc_module_selection_is_empty() { + let empty_selection = RpcModuleSelection::from(HashSet::new()); + assert!(empty_selection.is_empty()); + + let non_empty_selection = RpcModuleSelection::from([RethRpcModule::Eth]); + assert!(!non_empty_selection.is_empty()); + } + + #[test] + fn test_rpc_module_selection_iter_selection() { + let all_modules = RpcModuleSelection::All; + let standard = RpcModuleSelection::Standard; + let selection = RpcModuleSelection::from([RethRpcModule::Eth, RethRpcModule::Admin]); + + assert_eq!(all_modules.iter_selection().count(), RethRpcModule::variant_count()); + assert_eq!(standard.iter_selection().count(), 3); + assert_eq!(selection.iter_selection().count(), 2); + } + + #[test] + fn test_rpc_module_selection_to_selection() { + let all_modules = RpcModuleSelection::All; + let standard = RpcModuleSelection::Standard; + let selection = RpcModuleSelection::from([RethRpcModule::Eth, RethRpcModule::Admin]); + + assert_eq!(all_modules.to_selection(), RpcModuleSelection::all_modules()); + assert_eq!(standard.to_selection(), RpcModuleSelection::standard_modules()); + assert_eq!( + selection.to_selection(), + HashSet::from([RethRpcModule::Eth, RethRpcModule::Admin]) + ); + } + + #[test] + fn test_rpc_module_selection_are_identical() { + // Test scenario: both selections are `All` + // + // Since both selections include all possible RPC modules, they should be considered + // identical. + let all_modules = RpcModuleSelection::All; + assert!(RpcModuleSelection::are_identical(Some(&all_modules), Some(&all_modules))); + + // Test scenario: both `http` and `ws` are `None` + // + // When both arguments are `None`, the function should return `true` because no modules are + // selected. + assert!(RpcModuleSelection::are_identical(None, None)); + + // Test scenario: both selections contain identical sets of specific modules + // + // In this case, both selections contain the same modules (`Eth` and `Admin`), + // so they should be considered identical. + let selection1 = RpcModuleSelection::from([RethRpcModule::Eth, RethRpcModule::Admin]); + let selection2 = RpcModuleSelection::from([RethRpcModule::Eth, RethRpcModule::Admin]); + assert!(RpcModuleSelection::are_identical(Some(&selection1), Some(&selection2))); + + // Test scenario: one selection is `All`, the other is `Standard` + // + // `All` includes all possible modules, while `Standard` includes a specific set of modules. + // Since `Standard` does not cover all modules, these two selections should not be + // considered identical. + let standard = RpcModuleSelection::Standard; + assert!(!RpcModuleSelection::are_identical(Some(&all_modules), Some(&standard))); + + // Test scenario: one is `None`, the other is an empty selection + // + // When one selection is `None` and the other is an empty selection (no modules), + // they should be considered identical because neither selects any modules. + let empty_selection = RpcModuleSelection::Selection(HashSet::new()); + assert!(RpcModuleSelection::are_identical(None, Some(&empty_selection))); + assert!(RpcModuleSelection::are_identical(Some(&empty_selection), None)); + + // Test scenario: one is `None`, the other is a non-empty selection + // + // If one selection is `None` and the other contains modules, they should not be considered + // identical because `None` represents no selection, while the other explicitly + // selects modules. + let non_empty_selection = RpcModuleSelection::from([RethRpcModule::Eth]); + assert!(!RpcModuleSelection::are_identical(None, Some(&non_empty_selection))); + assert!(!RpcModuleSelection::are_identical(Some(&non_empty_selection), None)); + + // Test scenario: `All` vs. non-full selection + // + // If one selection is `All` (which includes all modules) and the other contains only a + // subset of modules, they should not be considered identical. + let partial_selection = RpcModuleSelection::from([RethRpcModule::Eth, RethRpcModule::Net]); + assert!(!RpcModuleSelection::are_identical(Some(&all_modules), Some(&partial_selection))); + + // Test scenario: full selection vs `All` + // + // If the other selection explicitly selects all available modules, it should be identical + // to `All`. + let full_selection = + RpcModuleSelection::from(RethRpcModule::modules().into_iter().collect::>()); + assert!(RpcModuleSelection::are_identical(Some(&all_modules), Some(&full_selection))); + + // Test scenario: different non-empty selections + // + // If the two selections contain different sets of modules, they should not be considered + // identical. + let selection3 = RpcModuleSelection::from([RethRpcModule::Eth, RethRpcModule::Net]); + let selection4 = RpcModuleSelection::from([RethRpcModule::Eth, RethRpcModule::Web3]); + assert!(!RpcModuleSelection::are_identical(Some(&selection3), Some(&selection4))); + + // Test scenario: `Standard` vs an equivalent selection + // The `Standard` selection includes a predefined set of modules. If we explicitly create + // a selection with the same set of modules, they should be considered identical. + let matching_standard = + RpcModuleSelection::from([RethRpcModule::Eth, RethRpcModule::Net, RethRpcModule::Web3]); + assert!(RpcModuleSelection::are_identical(Some(&standard), Some(&matching_standard))); + + // Test scenario: `Standard` vs non-matching selection + // + // If the selection does not match the modules included in `Standard`, they should not be + // considered identical. + let non_matching_standard = + RpcModuleSelection::from([RethRpcModule::Eth, RethRpcModule::Net]); + assert!(!RpcModuleSelection::are_identical(Some(&standard), Some(&non_matching_standard))); + } + + #[test] + fn test_rpc_module_selection_from_str() { + // Test empty string returns default selection + let result = RpcModuleSelection::from_str(""); + assert!(result.is_ok()); + assert_eq!(result.unwrap(), RpcModuleSelection::Selection(Default::default())); + + // Test "all" (case insensitive) returns All variant + let result = RpcModuleSelection::from_str("all"); + assert!(result.is_ok()); + assert_eq!(result.unwrap(), RpcModuleSelection::All); + + let result = RpcModuleSelection::from_str("All"); + assert!(result.is_ok()); + assert_eq!(result.unwrap(), RpcModuleSelection::All); + + let result = RpcModuleSelection::from_str("ALL"); + assert!(result.is_ok()); + assert_eq!(result.unwrap(), RpcModuleSelection::All); + + // Test "none" (case insensitive) returns empty selection + let result = RpcModuleSelection::from_str("none"); + assert!(result.is_ok()); + assert_eq!(result.unwrap(), RpcModuleSelection::Selection(Default::default())); + + let result = RpcModuleSelection::from_str("None"); + assert!(result.is_ok()); + assert_eq!(result.unwrap(), RpcModuleSelection::Selection(Default::default())); + + let result = RpcModuleSelection::from_str("NONE"); + assert!(result.is_ok()); + assert_eq!(result.unwrap(), RpcModuleSelection::Selection(Default::default())); + + // Test valid selections: "eth,admin" + let result = RpcModuleSelection::from_str("eth,admin"); + assert!(result.is_ok()); + let expected_selection = + RpcModuleSelection::from([RethRpcModule::Eth, RethRpcModule::Admin]); + assert_eq!(result.unwrap(), expected_selection); + + // Test valid selection with extra spaces: " eth , admin " + let result = RpcModuleSelection::from_str(" eth , admin "); + assert!(result.is_ok()); + assert_eq!(result.unwrap(), expected_selection); + + // Test invalid selection should return error + let result = RpcModuleSelection::from_str("invalid,unknown"); + assert!(result.is_err()); + assert_eq!(result.unwrap_err(), ParseError::VariantNotFound); + + // Test single valid selection: "eth" + let result = RpcModuleSelection::from_str("eth"); + assert!(result.is_ok()); + let expected_selection = RpcModuleSelection::from([RethRpcModule::Eth]); + assert_eq!(result.unwrap(), expected_selection); + + // Test single invalid selection: "unknown" + let result = RpcModuleSelection::from_str("unknown"); + assert!(result.is_err()); + assert_eq!(result.unwrap_err(), ParseError::VariantNotFound); + } +} From a4126b3a53f900483fe8946c8067aade68cf5cad Mon Sep 17 00:00:00 2001 From: greged93 <82421016+greged93@users.noreply.github.com> Date: Sat, 19 Oct 2024 00:15:08 +0200 Subject: [PATCH 081/113] feat: tasks executor metrics in grafana (#11815) Co-authored-by: Dan Cline <6798349+Rjected@users.noreply.github.com> --- etc/docker-compose.yml | 2 +- etc/grafana/dashboards/overview.json | 399 +++++++++++++++++++++------ 2 files changed, 315 insertions(+), 86 deletions(-) diff --git a/etc/docker-compose.yml b/etc/docker-compose.yml index 618aa6f5ae63..cd7dd6dd263b 100644 --- a/etc/docker-compose.yml +++ b/etc/docker-compose.yml @@ -65,7 +65,7 @@ services: sh -c "cp -r /etc/grafana/provisioning_temp/dashboards/. /etc/grafana/provisioning/dashboards && find /etc/grafana/provisioning/dashboards/ -name '*.json' -exec sed -i 's/$${DS_PROMETHEUS}/Prometheus/g' {} \+ && /run.sh" - + volumes: mainnet_data: driver: local diff --git a/etc/grafana/dashboards/overview.json b/etc/grafana/dashboards/overview.json index 15786764f429..8c77f5979fe9 100644 --- a/etc/grafana/dashboards/overview.json +++ b/etc/grafana/dashboards/overview.json @@ -1007,13 +1007,242 @@ "title": "Sync progress (stage progress as highest block number reached)", "type": "timeseries" }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "Tracks the number of critical tasks currently ran by the executor.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "semi-dark-red", + "value": 0 + } + ] + }, + "unit": "tasks" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 20 + }, + "id": 248, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "reth_executor_spawn_critical_tasks_total{instance=\"$instance\"}- reth_executor_spawn_finished_critical_tasks_total{instance=\"$instance\"}", + "hide": false, + "instant": false, + "legendFormat": "Tasks running", + "range": true, + "refId": "C" + } + ], + "title": "Task Executor critical tasks", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "Tracks the number of regular tasks currently ran by the executor.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "semi-dark-red", + "value": 80 + } + ] + }, + "unit": "tasks/s" + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "C" + }, + "properties": [ + { + "id": "unit", + "value": "tasks" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 20 + }, + "id": 247, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "disableTextWrap": false, + "editorMode": "builder", + "exemplar": false, + "expr": "rate(reth_executor_spawn_regular_tasks_total{instance=\"$instance\"}[$__rate_interval])", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": false, + "instant": false, + "legendFormat": "Tasks started", + "range": true, + "refId": "A", + "useBackend": false + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "reth_executor_spawn_regular_tasks_total{instance=\"$instance\"}- reth_executor_spawn_finished_regular_tasks_total{instance=\"$instance\"}", + "hide": false, + "instant": false, + "legendFormat": "Tasks running", + "range": true, + "refId": "C" + } + ], + "title": "Task Executor regular tasks", + "type": "timeseries" + }, { "collapsed": false, "gridPos": { "h": 1, "w": 24, "x": 0, - "y": 20 + "y": 28 }, "id": 38, "panels": [], @@ -1085,7 +1314,7 @@ "h": 8, "w": 12, "x": 0, - "y": 21 + "y": 29 }, "id": 40, "options": { @@ -1145,7 +1374,7 @@ "h": 8, "w": 12, "x": 12, - "y": 21 + "y": 29 }, "id": 42, "maxDataPoints": 25, @@ -1273,7 +1502,7 @@ "h": 8, "w": 12, "x": 0, - "y": 29 + "y": 37 }, "id": 117, "options": { @@ -1370,7 +1599,7 @@ "h": 8, "w": 12, "x": 12, - "y": 29 + "y": 37 }, "id": 116, "options": { @@ -1471,7 +1700,7 @@ "h": 8, "w": 12, "x": 0, - "y": 37 + "y": 45 }, "id": 119, "options": { @@ -1572,7 +1801,7 @@ "h": 8, "w": 12, "x": 12, - "y": 37 + "y": 45 }, "id": 118, "options": { @@ -1634,7 +1863,7 @@ "h": 8, "w": 12, "x": 0, - "y": 45 + "y": 53 }, "id": 48, "options": { @@ -1746,7 +1975,7 @@ "h": 8, "w": 12, "x": 12, - "y": 45 + "y": 53 }, "id": 52, "options": { @@ -1804,7 +2033,7 @@ "h": 8, "w": 12, "x": 0, - "y": 53 + "y": 61 }, "id": 50, "options": { @@ -1972,7 +2201,7 @@ "h": 8, "w": 12, "x": 12, - "y": 53 + "y": 61 }, "id": 58, "options": { @@ -2073,7 +2302,7 @@ "h": 8, "w": 12, "x": 0, - "y": 61 + "y": 69 }, "id": 113, "options": { @@ -2110,7 +2339,7 @@ "h": 1, "w": 24, "x": 0, - "y": 69 + "y": 77 }, "id": 203, "panels": [], @@ -2144,7 +2373,7 @@ "h": 8, "w": 8, "x": 0, - "y": 70 + "y": 78 }, "id": 202, "options": { @@ -2305,7 +2534,7 @@ "h": 8, "w": 8, "x": 8, - "y": 70 + "y": 78 }, "id": 204, "options": { @@ -2455,7 +2684,7 @@ "h": 8, "w": 8, "x": 16, - "y": 70 + "y": 78 }, "id": 205, "options": { @@ -2556,7 +2785,7 @@ "h": 8, "w": 12, "x": 0, - "y": 78 + "y": 86 }, "id": 206, "options": { @@ -2653,7 +2882,7 @@ "h": 8, "w": 12, "x": 12, - "y": 78 + "y": 86 }, "id": 207, "options": { @@ -2690,7 +2919,7 @@ "h": 1, "w": 24, "x": 0, - "y": 86 + "y": 94 }, "id": 46, "panels": [], @@ -2761,7 +2990,7 @@ "h": 8, "w": 24, "x": 0, - "y": 87 + "y": 95 }, "id": 56, "options": { @@ -2857,7 +3086,7 @@ "h": 11, "w": 24, "x": 0, - "y": 95 + "y": 103 }, "id": 240, "options": { @@ -2916,7 +3145,7 @@ "h": 1, "w": 24, "x": 0, - "y": 106 + "y": 114 }, "id": 24, "panels": [], @@ -3014,7 +3243,7 @@ "h": 8, "w": 12, "x": 0, - "y": 107 + "y": 115 }, "id": 26, "options": { @@ -3148,7 +3377,7 @@ "h": 8, "w": 12, "x": 12, - "y": 107 + "y": 115 }, "id": 33, "options": { @@ -3268,7 +3497,7 @@ "h": 8, "w": 12, "x": 0, - "y": 115 + "y": 123 }, "id": 36, "options": { @@ -3317,7 +3546,7 @@ "h": 1, "w": 24, "x": 0, - "y": 123 + "y": 131 }, "id": 32, "panels": [], @@ -3425,7 +3654,7 @@ "h": 8, "w": 12, "x": 0, - "y": 124 + "y": 132 }, "id": 30, "options": { @@ -3591,7 +3820,7 @@ "h": 8, "w": 12, "x": 12, - "y": 124 + "y": 132 }, "id": 28, "options": { @@ -3711,7 +3940,7 @@ "h": 8, "w": 12, "x": 0, - "y": 132 + "y": 140 }, "id": 35, "options": { @@ -3837,7 +4066,7 @@ "h": 8, "w": 12, "x": 12, - "y": 132 + "y": 140 }, "id": 73, "options": { @@ -3964,7 +4193,7 @@ "h": 8, "w": 12, "x": 0, - "y": 140 + "y": 148 }, "id": 102, "options": { @@ -4027,7 +4256,7 @@ "h": 1, "w": 24, "x": 0, - "y": 148 + "y": 156 }, "id": 79, "panels": [], @@ -4101,7 +4330,7 @@ "h": 8, "w": 12, "x": 0, - "y": 149 + "y": 157 }, "id": 74, "options": { @@ -4198,7 +4427,7 @@ "h": 8, "w": 12, "x": 12, - "y": 149 + "y": 157 }, "id": 80, "options": { @@ -4295,7 +4524,7 @@ "h": 8, "w": 12, "x": 0, - "y": 157 + "y": 165 }, "id": 81, "options": { @@ -4392,7 +4621,7 @@ "h": 8, "w": 12, "x": 12, - "y": 157 + "y": 165 }, "id": 114, "options": { @@ -4489,7 +4718,7 @@ "h": 8, "w": 12, "x": 12, - "y": 165 + "y": 173 }, "id": 190, "options": { @@ -4527,7 +4756,7 @@ "h": 1, "w": 24, "x": 0, - "y": 173 + "y": 181 }, "id": 87, "panels": [], @@ -4601,7 +4830,7 @@ "h": 8, "w": 12, "x": 0, - "y": 174 + "y": 182 }, "id": 83, "options": { @@ -4697,7 +4926,7 @@ "h": 8, "w": 12, "x": 12, - "y": 174 + "y": 182 }, "id": 84, "options": { @@ -4805,7 +5034,7 @@ "h": 8, "w": 12, "x": 0, - "y": 182 + "y": 190 }, "id": 85, "options": { @@ -4902,7 +5131,7 @@ "h": 8, "w": 12, "x": 12, - "y": 182 + "y": 190 }, "id": 210, "options": { @@ -5227,7 +5456,7 @@ "h": 8, "w": 12, "x": 0, - "y": 190 + "y": 198 }, "id": 211, "options": { @@ -5552,7 +5781,7 @@ "h": 8, "w": 12, "x": 12, - "y": 190 + "y": 198 }, "id": 212, "options": { @@ -5775,9 +6004,9 @@ "h": 8, "w": 24, "x": 0, - "y": 198 + "y": 206 }, - "id": 213, + "id": 213, "options": { "legend": { "calcs": [], @@ -5811,7 +6040,7 @@ "h": 1, "w": 24, "x": 0, - "y": 198 + "y": 214 }, "id": 214, "panels": [], @@ -5883,7 +6112,7 @@ "h": 8, "w": 12, "x": 0, - "y": 199 + "y": 215 }, "id": 215, "options": { @@ -5979,7 +6208,7 @@ "h": 8, "w": 12, "x": 12, - "y": 199 + "y": 215 }, "id": 216, "options": { @@ -6030,7 +6259,7 @@ "h": 1, "w": 24, "x": 0, - "y": 207 + "y": 223 }, "id": 68, "panels": [], @@ -6104,7 +6333,7 @@ "h": 8, "w": 12, "x": 0, - "y": 208 + "y": 224 }, "id": 60, "options": { @@ -6200,7 +6429,7 @@ "h": 8, "w": 12, "x": 12, - "y": 208 + "y": 224 }, "id": 62, "options": { @@ -6296,7 +6525,7 @@ "h": 8, "w": 12, "x": 0, - "y": 216 + "y": 232 }, "id": 64, "options": { @@ -6333,7 +6562,7 @@ "h": 1, "w": 24, "x": 0, - "y": 224 + "y": 240 }, "id": 97, "panels": [], @@ -6418,7 +6647,7 @@ "h": 8, "w": 12, "x": 0, - "y": 225 + "y": 241 }, "id": 98, "options": { @@ -6581,7 +6810,7 @@ "h": 8, "w": 12, "x": 12, - "y": 225 + "y": 241 }, "id": 101, "options": { @@ -6679,7 +6908,7 @@ "h": 8, "w": 12, "x": 0, - "y": 233 + "y": 249 }, "id": 99, "options": { @@ -6777,7 +7006,7 @@ "h": 8, "w": 12, "x": 12, - "y": 233 + "y": 249 }, "id": 100, "options": { @@ -6815,7 +7044,7 @@ "h": 1, "w": 24, "x": 0, - "y": 241 + "y": 257 }, "id": 105, "panels": [], @@ -6888,7 +7117,7 @@ "h": 8, "w": 12, "x": 0, - "y": 242 + "y": 258 }, "id": 106, "options": { @@ -6986,7 +7215,7 @@ "h": 8, "w": 12, "x": 12, - "y": 242 + "y": 258 }, "id": 107, "options": { @@ -7083,7 +7312,7 @@ "h": 8, "w": 12, "x": 0, - "y": 250 + "y": 266 }, "id": 217, "options": { @@ -7121,7 +7350,7 @@ "h": 1, "w": 24, "x": 0, - "y": 258 + "y": 274 }, "id": 108, "panels": [], @@ -7219,7 +7448,7 @@ "h": 8, "w": 12, "x": 0, - "y": 259 + "y": 275 }, "id": 109, "options": { @@ -7281,7 +7510,7 @@ "h": 8, "w": 12, "x": 12, - "y": 259 + "y": 275 }, "id": 111, "maxDataPoints": 25, @@ -7411,7 +7640,7 @@ "h": 8, "w": 12, "x": 0, - "y": 267 + "y": 283 }, "id": 120, "options": { @@ -7469,7 +7698,7 @@ "h": 8, "w": 12, "x": 12, - "y": 267 + "y": 283 }, "id": 112, "maxDataPoints": 25, @@ -7623,7 +7852,7 @@ "h": 8, "w": 12, "x": 0, - "y": 275 + "y": 291 }, "id": 198, "options": { @@ -7809,9 +8038,9 @@ "h": 8, "w": 12, "x": 12, - "y": 275 + "y": 291 }, - "id": 213, + "id": 246, "options": { "legend": { "calcs": [], @@ -7848,7 +8077,7 @@ "h": 1, "w": 24, "x": 0, - "y": 283 + "y": 299 }, "id": 236, "panels": [], @@ -7920,7 +8149,7 @@ "h": 8, "w": 12, "x": 0, - "y": 284 + "y": 300 }, "id": 237, "options": { @@ -8017,7 +8246,7 @@ "h": 8, "w": 12, "x": 12, - "y": 284 + "y": 300 }, "id": 238, "options": { @@ -8114,7 +8343,7 @@ "h": 8, "w": 12, "x": 0, - "y": 292 + "y": 308 }, "id": 239, "options": { @@ -8223,7 +8452,7 @@ "h": 8, "w": 12, "x": 12, - "y": 292 + "y": 308 }, "id": 219, "options": { @@ -8288,7 +8517,7 @@ "h": 8, "w": 12, "x": 0, - "y": 300 + "y": 316 }, "id": 220, "options": { @@ -8332,7 +8561,7 @@ "h": 1, "w": 24, "x": 0, - "y": 308 + "y": 324 }, "id": 241, "panels": [], @@ -8405,7 +8634,7 @@ "h": 8, "w": 12, "x": 0, - "y": 309 + "y": 325 }, "id": 243, "options": { @@ -8517,7 +8746,7 @@ "h": 8, "w": 12, "x": 12, - "y": 309 + "y": 325 }, "id": 244, "options": { @@ -8630,7 +8859,7 @@ "h": 8, "w": 12, "x": 0, - "y": 317 + "y": 333 }, "id": 245, "options": { @@ -8669,7 +8898,7 @@ "h": 1, "w": 24, "x": 0, - "y": 325 + "y": 341 }, "id": 226, "panels": [], @@ -8767,7 +8996,7 @@ "h": 8, "w": 12, "x": 0, - "y": 326 + "y": 342 }, "id": 225, "options": { @@ -8896,7 +9125,7 @@ "h": 8, "w": 12, "x": 12, - "y": 326 + "y": 342 }, "id": 227, "options": { @@ -9025,7 +9254,7 @@ "h": 8, "w": 12, "x": 0, - "y": 334 + "y": 350 }, "id": 235, "options": { @@ -9154,7 +9383,7 @@ "h": 8, "w": 12, "x": 12, - "y": 334 + "y": 350 }, "id": 234, "options": { From a6daafc6a4f087101a849a28a334df34275ffcb6 Mon Sep 17 00:00:00 2001 From: Thomas Coratger <60488569+tcoratger@users.noreply.github.com> Date: Sat, 19 Oct 2024 10:27:29 +0200 Subject: [PATCH 082/113] refactor(txpool): small refactor for `InMemoryBlobStore` impl (#11886) --- crates/transaction-pool/src/blobstore/mem.rs | 28 +++++--------------- 1 file changed, 6 insertions(+), 22 deletions(-) diff --git a/crates/transaction-pool/src/blobstore/mem.rs b/crates/transaction-pool/src/blobstore/mem.rs index 15160c2c3fad..c98a01b88c18 100644 --- a/crates/transaction-pool/src/blobstore/mem.rs +++ b/crates/transaction-pool/src/blobstore/mem.rs @@ -76,42 +76,26 @@ impl BlobStore for InMemoryBlobStore { // Retrieves the decoded blob data for the given transaction hash. fn get(&self, tx: B256) -> Result, BlobStoreError> { - let store = self.inner.store.read(); - Ok(store.get(&tx).cloned()) + Ok(self.inner.store.read().get(&tx).cloned()) } fn contains(&self, tx: B256) -> Result { - let store = self.inner.store.read(); - Ok(store.contains_key(&tx)) + Ok(self.inner.store.read().contains_key(&tx)) } fn get_all( &self, txs: Vec, ) -> Result, BlobStoreError> { - let mut items = Vec::with_capacity(txs.len()); let store = self.inner.store.read(); - for tx in txs { - if let Some(item) = store.get(&tx) { - items.push((tx, item.clone())); - } - } - - Ok(items) + Ok(txs.into_iter().filter_map(|tx| store.get(&tx).map(|item| (tx, item.clone()))).collect()) } fn get_exact(&self, txs: Vec) -> Result, BlobStoreError> { - let mut items = Vec::with_capacity(txs.len()); let store = self.inner.store.read(); - for tx in txs { - if let Some(item) = store.get(&tx) { - items.push(item.clone()); - } else { - return Err(BlobStoreError::MissingSidecar(tx)) - } - } - - Ok(items) + txs.into_iter() + .map(|tx| store.get(&tx).cloned().ok_or_else(|| BlobStoreError::MissingSidecar(tx))) + .collect() } fn get_by_versioned_hashes( From 2f559c62bf94e0fed23e500336ceed1e941e0ed5 Mon Sep 17 00:00:00 2001 From: Thomas Coratger <60488569+tcoratger@users.noreply.github.com> Date: Sat, 19 Oct 2024 10:28:10 +0200 Subject: [PATCH 083/113] primitives: use alloy `MAXIMUM_EXTRA_DATA_SIZE` constant (#11881) --- Cargo.lock | 1 + crates/consensus/common/Cargo.toml | 1 + crates/consensus/common/src/validation.rs | 6 ++---- crates/node/core/Cargo.toml | 5 ++--- crates/node/core/src/args/payload_builder.rs | 5 ++--- crates/primitives-traits/src/constants/mod.rs | 3 --- crates/rpc/rpc-types-compat/src/engine/payload.rs | 3 +-- 7 files changed, 9 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c8b4f76329ef..a97c01e01bc5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7886,6 +7886,7 @@ dependencies = [ name = "reth-node-core" version = "1.1.0" dependencies = [ + "alloy-consensus", "alloy-primitives", "alloy-rpc-types-engine", "clap", diff --git a/crates/consensus/common/Cargo.toml b/crates/consensus/common/Cargo.toml index 66a92270dba8..eaae1301b46a 100644 --- a/crates/consensus/common/Cargo.toml +++ b/crates/consensus/common/Cargo.toml @@ -19,6 +19,7 @@ reth-consensus.workspace = true # ethereum alloy-primitives.workspace = true revm-primitives.workspace = true +alloy-consensus.workspace = true [dev-dependencies] reth-storage-api.workspace = true diff --git a/crates/consensus/common/src/validation.rs b/crates/consensus/common/src/validation.rs index 711e7772b666..4c2e6b192e72 100644 --- a/crates/consensus/common/src/validation.rs +++ b/crates/consensus/common/src/validation.rs @@ -1,12 +1,10 @@ //! Collection of methods for block validation. +use alloy_consensus::constants::MAXIMUM_EXTRA_DATA_SIZE; use reth_chainspec::{EthChainSpec, EthereumHardforks}; use reth_consensus::ConsensusError; use reth_primitives::{ - constants::{ - eip4844::{DATA_GAS_PER_BLOB, MAX_DATA_GAS_PER_BLOCK}, - MAXIMUM_EXTRA_DATA_SIZE, - }, + constants::eip4844::{DATA_GAS_PER_BLOB, MAX_DATA_GAS_PER_BLOCK}, EthereumHardfork, GotExpected, Header, SealedBlock, SealedHeader, }; use revm_primitives::calc_excess_blob_gas; diff --git a/crates/node/core/Cargo.toml b/crates/node/core/Cargo.toml index 3ac90a888705..d7d95751cc5c 100644 --- a/crates/node/core/Cargo.toml +++ b/crates/node/core/Cargo.toml @@ -39,6 +39,7 @@ reth-stages-types.workspace = true # ethereum alloy-primitives.workspace = true alloy-rpc-types-engine = { workspace = true, features = ["jwt"] } +alloy-consensus.workspace = true # misc eyre.workspace = true @@ -76,9 +77,7 @@ tokio.workspace = true tempfile.workspace = true [features] -optimism = [ - "reth-primitives/optimism" -] +optimism = ["reth-primitives/optimism"] # Features for vergen to generate correct env vars jemalloc = [] asm-keccak = [] diff --git a/crates/node/core/src/args/payload_builder.rs b/crates/node/core/src/args/payload_builder.rs index aec35253af26..4a18fd5b0b7d 100644 --- a/crates/node/core/src/args/payload_builder.rs +++ b/crates/node/core/src/args/payload_builder.rs @@ -1,12 +1,11 @@ use crate::{cli::config::PayloadBuilderConfig, version::default_extradata}; +use alloy_consensus::constants::MAXIMUM_EXTRA_DATA_SIZE; use clap::{ builder::{RangedU64ValueParser, TypedValueParser}, Arg, Args, Command, }; use reth_cli_util::{parse_duration_from_secs, parse_duration_from_secs_or_ms}; -use reth_primitives::constants::{ - ETHEREUM_BLOCK_GAS_LIMIT, MAXIMUM_EXTRA_DATA_SIZE, SLOT_DURATION, -}; +use reth_primitives::constants::{ETHEREUM_BLOCK_GAS_LIMIT, SLOT_DURATION}; use std::{borrow::Cow, ffi::OsStr, time::Duration}; /// Parameters for configuring the Payload Builder diff --git a/crates/primitives-traits/src/constants/mod.rs b/crates/primitives-traits/src/constants/mod.rs index a4918137e7cd..482852bdccd4 100644 --- a/crates/primitives-traits/src/constants/mod.rs +++ b/crates/primitives-traits/src/constants/mod.rs @@ -13,9 +13,6 @@ pub const RETH_CLIENT_VERSION: &str = concat!("reth/v", env!("CARGO_PKG_VERSION" /// The first four bytes of the call data for a function call specifies the function to be called. pub const SELECTOR_LEN: usize = 4; -/// Maximum extra data size in a block after genesis -pub const MAXIMUM_EXTRA_DATA_SIZE: usize = 32; - /// An EPOCH is a series of 32 slots. pub const EPOCH_SLOTS: u64 = 32; diff --git a/crates/rpc/rpc-types-compat/src/engine/payload.rs b/crates/rpc/rpc-types-compat/src/engine/payload.rs index cd9ce1cbf7d7..3bbee2b00eaa 100644 --- a/crates/rpc/rpc-types-compat/src/engine/payload.rs +++ b/crates/rpc/rpc-types-compat/src/engine/payload.rs @@ -1,7 +1,7 @@ //! Standalone Conversion Functions for Handling Different Versions of Execution Payloads in //! Ethereum's Engine -use alloy_consensus::EMPTY_OMMER_ROOT_HASH; +use alloy_consensus::{constants::MAXIMUM_EXTRA_DATA_SIZE, EMPTY_OMMER_ROOT_HASH}; use alloy_eips::eip2718::{Decodable2718, Encodable2718}; use alloy_primitives::{B256, U256}; use alloy_rpc_types_engine::{ @@ -10,7 +10,6 @@ use alloy_rpc_types_engine::{ ExecutionPayloadV4, PayloadError, }; use reth_primitives::{ - constants::MAXIMUM_EXTRA_DATA_SIZE, proofs::{self}, Block, BlockBody, Header, Request, SealedBlock, TransactionSigned, Withdrawals, }; From da5079d11fa7f1595323b5636b928fb61f1e61cf Mon Sep 17 00:00:00 2001 From: Thomas Coratger <60488569+tcoratger@users.noreply.github.com> Date: Sat, 19 Oct 2024 10:28:42 +0200 Subject: [PATCH 084/113] test(txpool): add unit test for `BlobStoreCanonTracker` (#11885) --- crates/transaction-pool/Cargo.toml | 6 +- .../transaction-pool/src/blobstore/tracker.rs | 88 +++++++++++++++++++ 2 files changed, 93 insertions(+), 1 deletion(-) diff --git a/crates/transaction-pool/Cargo.toml b/crates/transaction-pool/Cargo.toml index 887543b521aa..cdac6a1aae6d 100644 --- a/crates/transaction-pool/Cargo.toml +++ b/crates/transaction-pool/Cargo.toml @@ -74,7 +74,11 @@ serde_json.workspace = true default = ["serde"] serde = ["dep:serde"] test-utils = ["rand", "paste", "serde"] -arbitrary = ["proptest", "reth-primitives/arbitrary", "proptest-arbitrary-interop"] +arbitrary = [ + "proptest", + "reth-primitives/arbitrary", + "proptest-arbitrary-interop", +] [[bench]] name = "truncate" diff --git a/crates/transaction-pool/src/blobstore/tracker.rs b/crates/transaction-pool/src/blobstore/tracker.rs index e6041fa12e19..f22dcf5706e5 100644 --- a/crates/transaction-pool/src/blobstore/tracker.rs +++ b/crates/transaction-pool/src/blobstore/tracker.rs @@ -81,6 +81,13 @@ pub enum BlobStoreUpdates { #[cfg(test)] mod tests { + use alloy_consensus::Header; + use reth_execution_types::Chain; + use reth_primitives::{ + BlockBody, SealedBlock, SealedBlockWithSenders, SealedHeader, Transaction, + TransactionSigned, + }; + use super::*; #[test] @@ -101,4 +108,85 @@ mod tests { BlobStoreUpdates::Finalized(block2.into_iter().chain(block3).collect::>()) ); } + + #[test] + fn test_add_new_chain_blocks() { + let mut tracker = BlobStoreCanonTracker::default(); + + // Create sample transactions + let tx1_hash = B256::random(); // EIP-4844 transaction + let tx2_hash = B256::random(); // EIP-4844 transaction + let tx3_hash = B256::random(); // Non-EIP-4844 transaction + + // Creating a first block with EIP-4844 transactions + let block1 = SealedBlockWithSenders { + block: SealedBlock { + header: SealedHeader::new( + Header { number: 10, ..Default::default() }, + B256::random(), + ), + body: BlockBody { + transactions: vec![ + TransactionSigned { + hash: tx1_hash, + transaction: Transaction::Eip4844(Default::default()), + ..Default::default() + }, + TransactionSigned { + hash: tx2_hash, + transaction: Transaction::Eip4844(Default::default()), + ..Default::default() + }, + // Another transaction that is not EIP-4844 + TransactionSigned { + hash: B256::random(), + transaction: Transaction::Eip7702(Default::default()), + ..Default::default() + }, + ], + ..Default::default() + }, + }, + ..Default::default() + }; + + // Creating a second block with EIP-1559 and EIP-2930 transactions + // Note: This block does not contain any EIP-4844 transactions + let block2 = SealedBlockWithSenders { + block: SealedBlock { + header: SealedHeader::new( + Header { number: 11, ..Default::default() }, + B256::random(), + ), + body: BlockBody { + transactions: vec![ + TransactionSigned { + hash: tx3_hash, + transaction: Transaction::Eip1559(Default::default()), + ..Default::default() + }, + TransactionSigned { + hash: tx2_hash, + transaction: Transaction::Eip2930(Default::default()), + ..Default::default() + }, + ], + ..Default::default() + }, + }, + ..Default::default() + }; + + // Extract blocks from the chain + let chain = Chain::new(vec![block1, block2], Default::default(), None); + let blocks = chain.into_inner().0; + + // Add new chain blocks to the tracker + tracker.add_new_chain_blocks(&blocks); + + // Tx1 and tx2 should be in the block containing EIP-4844 transactions + assert_eq!(tracker.blob_txs_in_blocks.get(&10).unwrap(), &vec![tx1_hash, tx2_hash]); + // No transactions should be in the block containing non-EIP-4844 transactions + assert!(tracker.blob_txs_in_blocks.get(&11).unwrap().is_empty()); + } } From 2ae93682b4978bf80bf27c777334ead30d3e04f5 Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Sat, 19 Oct 2024 14:08:34 +0400 Subject: [PATCH 085/113] refactor: move `EngineValidator` setup to `RpcAddOns` (#11850) --- Cargo.lock | 1 - crates/ethereum/node/src/node.rs | 19 ++-- crates/exex/test-utils/Cargo.toml | 1 - crates/exex/test-utils/src/lib.rs | 11 +- crates/node/api/src/node.rs | 7 -- crates/node/builder/src/builder/states.rs | 5 - crates/node/builder/src/components/builder.rs | 104 ++++-------------- crates/node/builder/src/components/engine.rs | 38 ------- crates/node/builder/src/components/mod.rs | 29 +---- crates/node/builder/src/rpc.rs | 70 ++++++++++-- crates/optimism/node/src/node.rs | 37 ++++--- examples/custom-engine-types/src/main.rs | 37 +++++-- 12 files changed, 140 insertions(+), 219 deletions(-) delete mode 100644 crates/node/builder/src/components/engine.rs diff --git a/Cargo.lock b/Cargo.lock index a97c01e01bc5..98bfe1f8e002 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7495,7 +7495,6 @@ dependencies = [ "reth-consensus", "reth-db", "reth-db-common", - "reth-ethereum-engine-primitives", "reth-evm", "reth-execution-types", "reth-exex", diff --git a/crates/ethereum/node/src/node.rs b/crates/ethereum/node/src/node.rs index a890810b00e7..d3301b2082e9 100644 --- a/crates/ethereum/node/src/node.rs +++ b/crates/ethereum/node/src/node.rs @@ -12,15 +12,16 @@ use reth_ethereum_engine_primitives::{ use reth_evm_ethereum::execute::EthExecutorProvider; use reth_network::NetworkHandle; use reth_node_api::{ - ConfigureEvm, EngineValidator, FullNodeComponents, NodePrimitives, NodeTypesWithDB, + AddOnsContext, ConfigureEvm, EngineValidator, FullNodeComponents, NodePrimitives, + NodeTypesWithDB, }; use reth_node_builder::{ components::{ - ComponentsBuilder, ConsensusBuilder, EngineValidatorBuilder, ExecutorBuilder, - NetworkBuilder, PayloadServiceBuilder, PoolBuilder, + ComponentsBuilder, ConsensusBuilder, ExecutorBuilder, NetworkBuilder, + PayloadServiceBuilder, PoolBuilder, }, node::{FullNodeTypes, NodeTypes, NodeTypesWithEngine}, - rpc::RpcAddOns, + rpc::{EngineValidatorBuilder, RpcAddOns}, BuilderContext, Node, NodeAdapter, NodeComponentsBuilder, PayloadBuilderConfig, PayloadTypes, }; use reth_payload_builder::{PayloadBuilderHandle, PayloadBuilderService}; @@ -57,7 +58,6 @@ impl EthereumNode { EthereumNetworkBuilder, EthereumExecutorBuilder, EthereumConsensusBuilder, - EthereumEngineValidatorBuilder, > where Node: FullNodeTypes>, @@ -74,7 +74,6 @@ impl EthereumNode { .network(EthereumNetworkBuilder::default()) .executor(EthereumExecutorBuilder::default()) .consensus(EthereumConsensusBuilder::default()) - .engine_validator(EthereumEngineValidatorBuilder::default()) } } @@ -96,6 +95,7 @@ pub type EthereumAddOns = RpcAddOns< NetworkHandle, ::Evm, >, + EthereumEngineValidatorBuilder, >; impl Node for EthereumNode @@ -110,7 +110,6 @@ where EthereumNetworkBuilder, EthereumExecutorBuilder, EthereumConsensusBuilder, - EthereumEngineValidatorBuilder, >; type AddOns = EthereumAddOns< @@ -347,12 +346,12 @@ pub struct EthereumEngineValidatorBuilder; impl EngineValidatorBuilder for EthereumEngineValidatorBuilder where Types: NodeTypesWithEngine, - Node: FullNodeTypes, + Node: FullNodeComponents, EthereumEngineValidator: EngineValidator, { type Validator = EthereumEngineValidator; - async fn build_validator(self, ctx: &BuilderContext) -> eyre::Result { - Ok(EthereumEngineValidator::new(ctx.chain_spec())) + async fn build(self, ctx: &AddOnsContext<'_, Node>) -> eyre::Result { + Ok(EthereumEngineValidator::new(ctx.config.chain.clone())) } } diff --git a/crates/exex/test-utils/Cargo.toml b/crates/exex/test-utils/Cargo.toml index 8488cdb8b731..b850295a332b 100644 --- a/crates/exex/test-utils/Cargo.toml +++ b/crates/exex/test-utils/Cargo.toml @@ -31,7 +31,6 @@ reth-primitives.workspace = true reth-provider = { workspace = true, features = ["test-utils"] } reth-tasks.workspace = true reth-transaction-pool = { workspace = true, features = ["test-utils"] } -reth-ethereum-engine-primitives.workspace = true ## async futures-util.workspace = true diff --git a/crates/exex/test-utils/src/lib.rs b/crates/exex/test-utils/src/lib.rs index 9e17013c4a5e..9b86da7c77a5 100644 --- a/crates/exex/test-utils/src/lib.rs +++ b/crates/exex/test-utils/src/lib.rs @@ -24,7 +24,6 @@ use reth_db::{ DatabaseEnv, }; use reth_db_common::init::init_genesis; -use reth_ethereum_engine_primitives::EthereumEngineValidator; use reth_evm::test_utils::MockExecutorProvider; use reth_execution_types::Chain; use reth_exex::{ExExContext, ExExEvent, ExExNotification, ExExNotifications, Wal}; @@ -41,10 +40,7 @@ use reth_node_builder::{ }; use reth_node_core::node_config::NodeConfig; use reth_node_ethereum::{ - node::{ - EthereumAddOns, EthereumEngineValidatorBuilder, EthereumNetworkBuilder, - EthereumPayloadBuilder, - }, + node::{EthereumAddOns, EthereumNetworkBuilder, EthereumPayloadBuilder}, EthEngineTypes, EthEvmConfig, }; use reth_payload_builder::noop::NoopPayloadBuilderService; @@ -140,7 +136,6 @@ where EthereumNetworkBuilder, TestExecutorBuilder, TestConsensusBuilder, - EthereumEngineValidatorBuilder, >; type AddOns = EthereumAddOns< NodeAdapter>::Components>, @@ -154,7 +149,6 @@ where .network(EthereumNetworkBuilder::default()) .executor(TestExecutorBuilder::default()) .consensus(TestConsensusBuilder::default()) - .engine_validator(EthereumEngineValidatorBuilder::default()) } fn add_ons(&self) -> Self::AddOns { @@ -284,8 +278,6 @@ pub async fn test_exex_context_with_chain_spec( let tasks = TaskManager::current(); let task_executor = tasks.executor(); - let engine_validator = EthereumEngineValidator::new(chain_spec.clone()); - let components = NodeAdapter::, _>, _> { components: Components { transaction_pool, @@ -294,7 +286,6 @@ pub async fn test_exex_context_with_chain_spec( consensus, network, payload_builder, - engine_validator, }, task_executor, provider, diff --git a/crates/node/api/src/node.rs b/crates/node/api/src/node.rs index 40c2a3a60b08..3173fd2b3985 100644 --- a/crates/node/api/src/node.rs +++ b/crates/node/api/src/node.rs @@ -5,7 +5,6 @@ use std::{future::Future, marker::PhantomData}; use alloy_rpc_types_engine::JwtSecret; use reth_beacon_consensus::BeaconConsensusEngineHandle; use reth_consensus::Consensus; -use reth_engine_primitives::EngineValidator; use reth_evm::execute::BlockExecutorProvider; use reth_network_api::FullNetwork; use reth_node_core::node_config::NodeConfig; @@ -64,9 +63,6 @@ pub trait FullNodeComponents: FullNodeTypes + Clone + 'static { /// Network API. type Network: FullNetwork; - /// Validator for the engine API. - type EngineValidator: EngineValidator<::Engine>; - /// Returns the transaction pool of the node. fn pool(&self) -> &Self::Pool; @@ -87,9 +83,6 @@ pub trait FullNodeComponents: FullNodeTypes + Clone + 'static { &self, ) -> &PayloadBuilderHandle<::Engine>; - /// Returns the engine validator. - fn engine_validator(&self) -> &Self::EngineValidator; - /// Returns the provider of the node. fn provider(&self) -> &Self::Provider; diff --git a/crates/node/builder/src/builder/states.rs b/crates/node/builder/src/builder/states.rs index c4da466f23e9..e75a07802a6e 100644 --- a/crates/node/builder/src/builder/states.rs +++ b/crates/node/builder/src/builder/states.rs @@ -97,7 +97,6 @@ impl> FullNodeComponents for NodeAdapter< type Executor = C::Executor; type Network = C::Network; type Consensus = C::Consensus; - type EngineValidator = C::EngineValidator; fn pool(&self) -> &Self::Pool { self.components.pool() @@ -130,10 +129,6 @@ impl> FullNodeComponents for NodeAdapter< fn consensus(&self) -> &Self::Consensus { self.components.consensus() } - - fn engine_validator(&self) -> &Self::EngineValidator { - self.components.engine_validator() - } } impl> Clone for NodeAdapter { diff --git a/crates/node/builder/src/components/builder.rs b/crates/node/builder/src/components/builder.rs index ab8e29929a92..48a0ba9b5fdf 100644 --- a/crates/node/builder/src/components/builder.rs +++ b/crates/node/builder/src/components/builder.rs @@ -4,7 +4,6 @@ use std::{future::Future, marker::PhantomData}; use reth_consensus::Consensus; use reth_evm::execute::BlockExecutorProvider; -use reth_node_api::{EngineValidator, NodeTypesWithEngine}; use reth_primitives::Header; use reth_transaction_pool::TransactionPool; @@ -16,8 +15,6 @@ use crate::{ BuilderContext, ConfigureEvm, FullNodeTypes, }; -use super::EngineValidatorBuilder; - /// A generic, general purpose and customizable [`NodeComponentsBuilder`] implementation. /// /// This type is stateful and captures the configuration of the node's components. @@ -38,23 +35,22 @@ use super::EngineValidatorBuilder; /// All component builders are captured in the builder state and will be consumed once the node is /// launched. #[derive(Debug)] -pub struct ComponentsBuilder { +pub struct ComponentsBuilder { pool_builder: PoolB, payload_builder: PayloadB, network_builder: NetworkB, executor_builder: ExecB, consensus_builder: ConsB, - engine_validator_builder: EVB, _marker: PhantomData, } -impl - ComponentsBuilder +impl + ComponentsBuilder { /// Configures the node types. pub fn node_types( self, - ) -> ComponentsBuilder + ) -> ComponentsBuilder where Types: FullNodeTypes, { @@ -64,7 +60,6 @@ impl network_builder, executor_builder: evm_builder, consensus_builder, - engine_validator_builder, _marker, } = self; ComponentsBuilder { @@ -73,7 +68,6 @@ impl payload_builder, network_builder, consensus_builder, - engine_validator_builder, _marker: Default::default(), } } @@ -86,7 +80,6 @@ impl network_builder: self.network_builder, executor_builder: self.executor_builder, consensus_builder: self.consensus_builder, - engine_validator_builder: self.engine_validator_builder, _marker: self._marker, } } @@ -99,7 +92,6 @@ impl network_builder: self.network_builder, executor_builder: self.executor_builder, consensus_builder: self.consensus_builder, - engine_validator_builder: self.engine_validator_builder, _marker: self._marker, } } @@ -112,7 +104,6 @@ impl network_builder: f(self.network_builder), executor_builder: self.executor_builder, consensus_builder: self.consensus_builder, - engine_validator_builder: self.engine_validator_builder, _marker: self._marker, } } @@ -125,7 +116,6 @@ impl network_builder: self.network_builder, executor_builder: f(self.executor_builder), consensus_builder: self.consensus_builder, - engine_validator_builder: self.engine_validator_builder, _marker: self._marker, } } @@ -138,14 +128,13 @@ impl network_builder: self.network_builder, executor_builder: self.executor_builder, consensus_builder: f(self.consensus_builder), - engine_validator_builder: self.engine_validator_builder, _marker: self._marker, } } } -impl - ComponentsBuilder +impl + ComponentsBuilder where Node: FullNodeTypes, { @@ -156,7 +145,7 @@ where pub fn pool( self, pool_builder: PB, - ) -> ComponentsBuilder + ) -> ComponentsBuilder where PB: PoolBuilder, { @@ -166,7 +155,6 @@ where network_builder, executor_builder: evm_builder, consensus_builder, - engine_validator_builder, _marker, } = self; ComponentsBuilder { @@ -175,14 +163,13 @@ where network_builder, executor_builder: evm_builder, consensus_builder, - engine_validator_builder, _marker, } } } -impl - ComponentsBuilder +impl + ComponentsBuilder where Node: FullNodeTypes, PoolB: PoolBuilder, @@ -194,7 +181,7 @@ where pub fn network( self, network_builder: NB, - ) -> ComponentsBuilder + ) -> ComponentsBuilder where NB: NetworkBuilder, { @@ -204,7 +191,6 @@ where network_builder: _, executor_builder: evm_builder, consensus_builder, - engine_validator_builder, _marker, } = self; ComponentsBuilder { @@ -213,7 +199,6 @@ where network_builder, executor_builder: evm_builder, consensus_builder, - engine_validator_builder, _marker, } } @@ -225,7 +210,7 @@ where pub fn payload( self, payload_builder: PB, - ) -> ComponentsBuilder + ) -> ComponentsBuilder where PB: PayloadServiceBuilder, { @@ -235,7 +220,6 @@ where network_builder, executor_builder: evm_builder, consensus_builder, - engine_validator_builder, _marker, } = self; ComponentsBuilder { @@ -244,7 +228,6 @@ where network_builder, executor_builder: evm_builder, consensus_builder, - engine_validator_builder, _marker, } } @@ -256,7 +239,7 @@ where pub fn executor( self, executor_builder: EB, - ) -> ComponentsBuilder + ) -> ComponentsBuilder where EB: ExecutorBuilder, { @@ -266,7 +249,6 @@ where network_builder, executor_builder: _, consensus_builder, - engine_validator_builder, _marker, } = self; ComponentsBuilder { @@ -275,7 +257,6 @@ where network_builder, executor_builder, consensus_builder, - engine_validator_builder, _marker, } } @@ -287,7 +268,7 @@ where pub fn consensus( self, consensus_builder: CB, - ) -> ComponentsBuilder + ) -> ComponentsBuilder where CB: ConsensusBuilder, { @@ -297,38 +278,7 @@ where network_builder, executor_builder, consensus_builder: _, - engine_validator_builder, - _marker, - } = self; - ComponentsBuilder { - pool_builder, - payload_builder, - network_builder, - executor_builder, - consensus_builder, - engine_validator_builder, - _marker, - } - } - /// Configures the consensus builder. - /// - /// This accepts a [`ConsensusBuilder`] instance that will be used to create the node's - /// components for consensus. - pub fn engine_validator( - self, - engine_validator_builder: EngineVB, - ) -> ComponentsBuilder - where - EngineVB: EngineValidatorBuilder, - { - let Self { - pool_builder, - payload_builder, - network_builder, - executor_builder, - consensus_builder, - engine_validator_builder: _, _marker, } = self; ComponentsBuilder { @@ -337,14 +287,13 @@ where network_builder, executor_builder, consensus_builder, - engine_validator_builder, _marker, } } } -impl NodeComponentsBuilder - for ComponentsBuilder +impl NodeComponentsBuilder + for ComponentsBuilder where Node: FullNodeTypes, PoolB: PoolBuilder, @@ -352,16 +301,8 @@ where PayloadB: PayloadServiceBuilder, ExecB: ExecutorBuilder, ConsB: ConsensusBuilder, - EVB: EngineValidatorBuilder, { - type Components = Components< - Node, - PoolB::Pool, - ExecB::EVM, - ExecB::Executor, - ConsB::Consensus, - EVB::Validator, - >; + type Components = Components; async fn build_components( self, @@ -373,7 +314,6 @@ where network_builder, executor_builder: evm_builder, consensus_builder, - engine_validator_builder, _marker, } = self; @@ -382,7 +322,6 @@ where let network = network_builder.build_network(context, pool.clone()).await?; let payload_builder = payload_builder.spawn_payload_service(context, pool.clone()).await?; let consensus = consensus_builder.build_consensus(context).await?; - let engine_validator = engine_validator_builder.build_validator(context).await?; Ok(Components { transaction_pool: pool, @@ -391,12 +330,11 @@ where payload_builder, executor, consensus, - engine_validator, }) } } -impl Default for ComponentsBuilder<(), (), (), (), (), (), ()> { +impl Default for ComponentsBuilder<(), (), (), (), (), ()> { fn default() -> Self { Self { pool_builder: (), @@ -404,7 +342,6 @@ impl Default for ComponentsBuilder<(), (), (), (), (), (), ()> { network_builder: (), executor_builder: (), consensus_builder: (), - engine_validator_builder: (), _marker: Default::default(), } } @@ -430,18 +367,17 @@ pub trait NodeComponentsBuilder: Send { ) -> impl Future> + Send; } -impl NodeComponentsBuilder for F +impl NodeComponentsBuilder for F where Node: FullNodeTypes, F: FnOnce(&BuilderContext) -> Fut + Send, - Fut: Future>> + Send, + Fut: Future>> + Send, Pool: TransactionPool + Unpin + 'static, EVM: ConfigureEvm

, Executor: BlockExecutorProvider, Cons: Consensus + Clone + Unpin + 'static, - Val: EngineValidator<::Engine> + Clone + Unpin + 'static, { - type Components = Components; + type Components = Components; fn build_components( self, diff --git a/crates/node/builder/src/components/engine.rs b/crates/node/builder/src/components/engine.rs deleted file mode 100644 index b3ee7cbbbf2f..000000000000 --- a/crates/node/builder/src/components/engine.rs +++ /dev/null @@ -1,38 +0,0 @@ -//! Consensus component for the node builder. -use reth_node_api::{EngineValidator, NodeTypesWithEngine}; - -use crate::{BuilderContext, FullNodeTypes}; -use std::future::Future; - -/// A type that knows how to build the engine validator. -pub trait EngineValidatorBuilder: Send { - /// The consensus implementation to build. - type Validator: EngineValidator<::Engine> - + Clone - + Unpin - + 'static; - - /// Creates the engine validator. - fn build_validator( - self, - ctx: &BuilderContext, - ) -> impl Future> + Send; -} - -impl EngineValidatorBuilder for F -where - Node: FullNodeTypes, - Validator: - EngineValidator<::Engine> + Clone + Unpin + 'static, - F: FnOnce(&BuilderContext) -> Fut + Send, - Fut: Future> + Send, -{ - type Validator = Validator; - - fn build_validator( - self, - ctx: &BuilderContext, - ) -> impl Future> { - self(ctx) - } -} diff --git a/crates/node/builder/src/components/mod.rs b/crates/node/builder/src/components/mod.rs index ff1646593edf..42001fc10056 100644 --- a/crates/node/builder/src/components/mod.rs +++ b/crates/node/builder/src/components/mod.rs @@ -9,7 +9,6 @@ mod builder; mod consensus; -mod engine; mod execute; mod network; mod payload; @@ -17,7 +16,6 @@ mod pool; pub use builder::*; pub use consensus::*; -pub use engine::*; pub use execute::*; pub use network::*; pub use payload::*; @@ -27,7 +25,7 @@ use reth_consensus::Consensus; use reth_evm::execute::BlockExecutorProvider; use reth_network::NetworkHandle; use reth_network_api::FullNetwork; -use reth_node_api::{EngineValidator, NodeTypesWithEngine}; +use reth_node_api::NodeTypesWithEngine; use reth_payload_builder::PayloadBuilderHandle; use reth_primitives::Header; use reth_transaction_pool::TransactionPool; @@ -55,9 +53,6 @@ pub trait NodeComponents: Clone + Unpin + Send + Sync + 'stati /// Network API. type Network: FullNetwork; - /// Validator for the engine API. - type EngineValidator: EngineValidator<::Engine>; - /// Returns the transaction pool of the node. fn pool(&self) -> &Self::Pool; @@ -75,16 +70,13 @@ pub trait NodeComponents: Clone + Unpin + Send + Sync + 'stati /// Returns the handle to the payload builder service. fn payload_builder(&self) -> &PayloadBuilderHandle<::Engine>; - - /// Returns the engine validator. - fn engine_validator(&self) -> &Self::EngineValidator; } /// All the components of the node. /// /// This provides access to all the components of the node. #[derive(Debug)] -pub struct Components { +pub struct Components { /// The transaction pool of the node. pub transaction_pool: Pool, /// The node's EVM configuration, defining settings for the Ethereum Virtual Machine. @@ -97,26 +89,22 @@ pub struct Components::Engine>, - /// The validator for the engine API. - pub engine_validator: Validator, } -impl NodeComponents - for Components +impl NodeComponents + for Components where Node: FullNodeTypes, Pool: TransactionPool + Unpin + 'static, EVM: ConfigureEvm
, Executor: BlockExecutorProvider, Cons: Consensus + Clone + Unpin + 'static, - Val: EngineValidator<::Engine> + Clone + Unpin + 'static, { type Pool = Pool; type Evm = EVM; type Executor = Executor; type Consensus = Cons; type Network = NetworkHandle; - type EngineValidator = Val; fn pool(&self) -> &Self::Pool { &self.transaction_pool @@ -143,21 +131,15 @@ where ) -> &PayloadBuilderHandle<::Engine> { &self.payload_builder } - - fn engine_validator(&self) -> &Self::EngineValidator { - &self.engine_validator - } } -impl Clone - for Components +impl Clone for Components where Node: FullNodeTypes, Pool: TransactionPool, EVM: ConfigureEvm
, Executor: BlockExecutorProvider, Cons: Consensus + Clone, - Val: EngineValidator<::Engine>, { fn clone(&self) -> Self { Self { @@ -167,7 +149,6 @@ where consensus: self.consensus.clone(), network: self.network.clone(), payload_builder: self.payload_builder.clone(), - engine_validator: self.engine_validator.clone(), } } } diff --git a/crates/node/builder/src/rpc.rs b/crates/node/builder/src/rpc.rs index d8cce9217efc..18293118dc66 100644 --- a/crates/node/builder/src/rpc.rs +++ b/crates/node/builder/src/rpc.rs @@ -2,6 +2,7 @@ use std::{ fmt::{self, Debug}, + future::Future, marker::PhantomData, ops::{Deref, DerefMut}, }; @@ -9,7 +10,7 @@ use std::{ use alloy_rpc_types::engine::ClientVersionV1; use futures::TryFutureExt; use reth_node_api::{ - AddOnsContext, FullNodeComponents, NodeAddOns, NodeTypes, NodeTypesWithEngine, + AddOnsContext, EngineValidator, FullNodeComponents, NodeAddOns, NodeTypes, NodeTypesWithEngine, }; use reth_node_core::{ node_config::NodeConfig, @@ -327,31 +328,38 @@ where /// Node add-ons containing RPC server configuration, with customizable eth API handler. #[allow(clippy::type_complexity)] -pub struct RpcAddOns { +pub struct RpcAddOns { /// Additional RPC add-ons. pub hooks: RpcHooks, /// Builder for `EthApi` eth_api_builder: Box) -> EthApi + Send + Sync>, + /// Engine validator + engine_validator_builder: EV, _pd: PhantomData<(Node, EthApi)>, } -impl Debug for RpcAddOns { +impl Debug + for RpcAddOns +{ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("RpcAddOns") .field("hooks", &self.hooks) .field("eth_api_builder", &"...") + .field("engine_validator_builder", &self.engine_validator_builder) .finish() } } -impl RpcAddOns { +impl RpcAddOns { /// Creates a new instance of the RPC add-ons. pub fn new( eth_api_builder: impl FnOnce(&EthApiBuilderCtx) -> EthApi + Send + Sync + 'static, + engine_validator_builder: EV, ) -> Self { Self { hooks: RpcHooks::default(), eth_api_builder: Box::new(eth_api_builder), + engine_validator_builder, _pd: PhantomData, } } @@ -377,23 +385,28 @@ impl RpcAddOns { } } -impl> Default - for RpcAddOns +impl Default for RpcAddOns +where + Node: FullNodeComponents, + EthApi: EthApiTypes + EthApiBuilder, + EV: Default, { fn default() -> Self { - Self::new(EthApi::build) + Self::new(EthApi::build, EV::default()) } } -impl NodeAddOns for RpcAddOns +impl NodeAddOns for RpcAddOns where N: FullNodeComponents, EthApi: EthApiTypes + FullEthApiServer + AddDevSigners + Unpin + 'static, + EV: EngineValidatorBuilder, { type Handle = RpcHandle; async fn launch_add_ons(self, ctx: AddOnsContext<'_, N>) -> eyre::Result { let AddOnsContext { node, config, beacon_engine_handle, jwt_secret } = ctx; + let Self { eth_api_builder, engine_validator_builder, hooks, _pd: _ } = self; let client = ClientVersionV1 { code: CLIENT_CODE, @@ -411,7 +424,7 @@ where Box::new(node.task_executor().clone()), client, EngineCapabilities::default(), - node.engine_validator().clone(), + engine_validator_builder.build(&ctx).await?, ); info!(target: "reth::cli", "Engine API handler initialized"); @@ -427,7 +440,7 @@ where .with_executor(node.task_executor().clone()) .with_evm_config(node.evm_config().clone()) .with_block_executor(node.block_executor().clone()) - .build_with_auth_server(module_config, engine_api, self.eth_api_builder); + .build_with_auth_server(module_config, engine_api, eth_api_builder); // in dev mode we generate 20 random dev-signer accounts if config.dev.dev { @@ -443,7 +456,7 @@ where auth_module: &mut auth_module, }; - let RpcHooks { on_rpc_started, extend_rpc_modules } = self.hooks; + let RpcHooks { on_rpc_started, extend_rpc_modules } = hooks; extend_rpc_modules.extend_rpc_modules(ctx)?; @@ -503,7 +516,7 @@ pub trait RethRpcAddOns: fn hooks_mut(&mut self) -> &mut RpcHooks; } -impl RethRpcAddOns for RpcAddOns +impl RethRpcAddOns for RpcAddOns where Self: NodeAddOns>, { @@ -525,3 +538,36 @@ impl EthApiBuilder for EthApi: Send { + /// The consensus implementation to build. + type Validator: EngineValidator<::Engine> + + Clone + + Unpin + + 'static; + + /// Creates the engine validator. + fn build( + self, + ctx: &AddOnsContext<'_, Node>, + ) -> impl Future> + Send; +} + +impl EngineValidatorBuilder for F +where + Node: FullNodeComponents, + Validator: + EngineValidator<::Engine> + Clone + Unpin + 'static, + F: FnOnce(&AddOnsContext<'_, Node>) -> Fut + Send, + Fut: Future> + Send, +{ + type Validator = Validator; + + fn build( + self, + ctx: &AddOnsContext<'_, Node>, + ) -> impl Future> { + self(ctx) + } +} diff --git a/crates/optimism/node/src/node.rs b/crates/optimism/node/src/node.rs index c2576d318dd1..175b2d4bf413 100644 --- a/crates/optimism/node/src/node.rs +++ b/crates/optimism/node/src/node.rs @@ -6,14 +6,16 @@ use reth_basic_payload_builder::{BasicPayloadJobGenerator, BasicPayloadJobGenera use reth_chainspec::{EthChainSpec, Hardforks}; use reth_evm::ConfigureEvm; use reth_network::{NetworkConfig, NetworkHandle, NetworkManager}; -use reth_node_api::{EngineValidator, FullNodeComponents, NodeAddOns, NodePrimitives}; +use reth_node_api::{ + AddOnsContext, EngineValidator, FullNodeComponents, NodeAddOns, NodePrimitives, +}; use reth_node_builder::{ components::{ - ComponentsBuilder, ConsensusBuilder, EngineValidatorBuilder, ExecutorBuilder, - NetworkBuilder, PayloadServiceBuilder, PoolBuilder, PoolBuilderConfigOverrides, + ComponentsBuilder, ConsensusBuilder, ExecutorBuilder, NetworkBuilder, + PayloadServiceBuilder, PoolBuilder, PoolBuilderConfigOverrides, }, node::{FullNodeTypes, NodeTypes, NodeTypesWithEngine}, - rpc::{RethRpcAddOns, RpcAddOns, RpcHandle}, + rpc::{EngineValidatorBuilder, RethRpcAddOns, RpcAddOns, RpcHandle}, BuilderContext, Node, NodeAdapter, NodeComponentsBuilder, PayloadBuilderConfig, }; use reth_optimism_chainspec::OpChainSpec; @@ -68,7 +70,6 @@ impl OptimismNode { OptimismNetworkBuilder, OptimismExecutorBuilder, OptimismConsensusBuilder, - OptimismEngineValidatorBuilder, > where Node: FullNodeTypes< @@ -86,7 +87,6 @@ impl OptimismNode { }) .executor(OptimismExecutorBuilder::default()) .consensus(OptimismConsensusBuilder::default()) - .engine_validator(OptimismEngineValidatorBuilder::default()) } } @@ -103,7 +103,6 @@ where OptimismNetworkBuilder, OptimismExecutorBuilder, OptimismConsensusBuilder, - OptimismEngineValidatorBuilder, >; type AddOns = OptimismAddOns< @@ -131,7 +130,9 @@ impl NodeTypesWithEngine for OptimismNode { /// Add-ons w.r.t. optimism. #[derive(Debug)] -pub struct OptimismAddOns(pub RpcAddOns>); +pub struct OptimismAddOns( + pub RpcAddOns, OptimismEngineValidatorBuilder>, +); impl Default for OptimismAddOns { fn default() -> Self { @@ -142,12 +143,14 @@ impl Default for OptimismAddOns { impl OptimismAddOns { /// Create a new instance with the given `sequencer_http` URL. pub fn new(sequencer_http: Option) -> Self { - Self(RpcAddOns::new(move |ctx| OpEthApi::new(ctx, sequencer_http))) + Self(RpcAddOns::new(move |ctx| OpEthApi::new(ctx, sequencer_http), Default::default())) } } -impl>> NodeAddOns - for OptimismAddOns +impl NodeAddOns for OptimismAddOns +where + N: FullNodeComponents>, + OptimismEngineValidator: EngineValidator<::Engine>, { type Handle = RpcHandle>; @@ -159,8 +162,10 @@ impl>> NodeAddOn } } -impl>> RethRpcAddOns - for OptimismAddOns +impl RethRpcAddOns for OptimismAddOns +where + N: FullNodeComponents>, + OptimismEngineValidator: EngineValidator<::Engine>, { type EthApi = OpEthApi; @@ -458,12 +463,12 @@ pub struct OptimismEngineValidatorBuilder; impl EngineValidatorBuilder for OptimismEngineValidatorBuilder where Types: NodeTypesWithEngine, - Node: FullNodeTypes, + Node: FullNodeComponents, OptimismEngineValidator: EngineValidator, { type Validator = OptimismEngineValidator; - async fn build_validator(self, ctx: &BuilderContext) -> eyre::Result { - Ok(OptimismEngineValidator::new(ctx.chain_spec())) + async fn build(self, ctx: &AddOnsContext<'_, Node>) -> eyre::Result { + Ok(OptimismEngineValidator::new(ctx.config.chain.clone())) } } diff --git a/examples/custom-engine-types/src/main.rs b/examples/custom-engine-types/src/main.rs index f833da86236e..135c4f3f2474 100644 --- a/examples/custom-engine-types/src/main.rs +++ b/examples/custom-engine-types/src/main.rs @@ -34,12 +34,15 @@ use alloy_rpc_types::{ use reth::{ api::PayloadTypes, builder::{ - components::{ComponentsBuilder, EngineValidatorBuilder, PayloadServiceBuilder}, + components::{ComponentsBuilder, PayloadServiceBuilder}, node::{NodeTypes, NodeTypesWithEngine}, + rpc::{EngineValidatorBuilder, RpcAddOns}, BuilderContext, FullNodeTypes, Node, NodeAdapter, NodeBuilder, NodeComponentsBuilder, PayloadBuilderConfig, }, + network::NetworkHandle, providers::{CanonStateSubscriptions, StateProviderFactory}, + rpc::eth::EthApi, tasks::TaskManager, transaction_pool::TransactionPool, }; @@ -50,13 +53,13 @@ use reth_basic_payload_builder::{ use reth_chainspec::{Chain, ChainSpec, ChainSpecProvider}; use reth_node_api::{ payload::{EngineApiMessageVersion, EngineObjectValidationError, PayloadOrAttributes}, - validate_version_specific_fields, EngineTypes, EngineValidator, PayloadAttributes, - PayloadBuilderAttributes, + validate_version_specific_fields, AddOnsContext, EngineTypes, EngineValidator, + FullNodeComponents, PayloadAttributes, PayloadBuilderAttributes, }; use reth_node_core::{args::RpcServerArgs, node_config::NodeConfig}; use reth_node_ethereum::{ node::{ - EthereumAddOns, EthereumConsensusBuilder, EthereumExecutorBuilder, EthereumNetworkBuilder, + EthereumConsensusBuilder, EthereumExecutorBuilder, EthereumNetworkBuilder, EthereumPoolBuilder, }, EthEvmConfig, @@ -202,12 +205,14 @@ pub struct CustomEngineValidatorBuilder; impl EngineValidatorBuilder for CustomEngineValidatorBuilder where - N: FullNodeTypes>, + N: FullNodeComponents< + Types: NodeTypesWithEngine, + >, { type Validator = CustomEngineValidator; - async fn build_validator(self, ctx: &BuilderContext) -> eyre::Result { - Ok(CustomEngineValidator { chain_spec: ctx.chain_spec() }) + async fn build(self, ctx: &AddOnsContext<'_, N>) -> eyre::Result { + Ok(CustomEngineValidator { chain_spec: ctx.config.chain.clone() }) } } @@ -226,6 +231,18 @@ impl NodeTypesWithEngine for MyCustomNode { type Engine = CustomEngineTypes; } +/// Custom addons configuring RPC types +pub type MyNodeAddOns = RpcAddOns< + N, + EthApi< + ::Provider, + ::Pool, + NetworkHandle, + ::Evm, + >, + CustomEngineValidatorBuilder, +>; + /// Implement the Node trait for the custom node /// /// This provides a preset configuration for the node @@ -240,9 +257,8 @@ where EthereumNetworkBuilder, EthereumExecutorBuilder, EthereumConsensusBuilder, - CustomEngineValidatorBuilder, >; - type AddOns = EthereumAddOns< + type AddOns = MyNodeAddOns< NodeAdapter>::Components>, >; @@ -254,11 +270,10 @@ where .network(EthereumNetworkBuilder::default()) .executor(EthereumExecutorBuilder::default()) .consensus(EthereumConsensusBuilder::default()) - .engine_validator(CustomEngineValidatorBuilder::default()) } fn add_ons(&self) -> Self::AddOns { - EthereumAddOns::default() + MyNodeAddOns::default() } } From 3bd695ee630f3979a2ea53f2308bdb1c9b2f18c1 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sat, 19 Oct 2024 14:48:35 +0200 Subject: [PATCH 086/113] feat: update el requests for devnet 4 (#11865) Co-authored-by: Matthias Seitz --- Cargo.lock | 229 ++++++++++++------ Cargo.toml | 127 +++++----- bin/reth-bench/src/authenticated_transport.rs | 3 +- bin/reth-bench/src/valid_payload.rs | 8 - .../src/commands/debug_cmd/replay_engine.rs | 4 +- crates/blockchain-tree/src/blockchain_tree.rs | 1 - crates/chain-state/src/in_memory.rs | 3 +- crates/chain-state/src/test_utils.rs | 6 +- crates/chainspec/Cargo.toml | 1 - crates/chainspec/src/spec.rs | 10 +- crates/cli/commands/src/stage/drop.rs | 1 - crates/consensus/auto-seal/Cargo.toml | 1 + crates/consensus/auto-seal/src/lib.rs | 10 +- crates/consensus/beacon/src/engine/handle.rs | 11 +- crates/consensus/beacon/src/engine/message.rs | 5 + crates/consensus/beacon/src/engine/mod.rs | 23 +- .../consensus/beacon/src/engine/test_utils.rs | 2 +- crates/consensus/common/src/validation.rs | 27 +-- crates/consensus/consensus/Cargo.toml | 1 + crates/consensus/consensus/src/lib.rs | 27 ++- crates/e2e-test-utils/src/transaction.rs | 3 +- .../engine/invalid-block-hooks/src/witness.rs | 2 +- crates/engine/local/src/miner.rs | 2 + crates/engine/tree/src/tree/mod.rs | 26 +- crates/engine/util/src/engine_store.rs | 8 +- crates/engine/util/src/reorg.rs | 74 +++--- crates/engine/util/src/skip_new_payload.rs | 14 +- crates/ethereum/consensus/Cargo.toml | 1 + crates/ethereum/consensus/src/lib.rs | 8 +- crates/ethereum/consensus/src/validation.rs | 19 +- .../ethereum/engine-primitives/src/payload.rs | 19 +- crates/ethereum/evm/src/eip6110.rs | 91 +++---- crates/ethereum/evm/src/execute.rs | 61 +++-- crates/ethereum/evm/src/strategy.rs | 52 ++-- crates/ethereum/payload/Cargo.toml | 3 +- crates/ethereum/payload/src/lib.rs | 17 +- crates/evm/execution-types/Cargo.toml | 7 +- crates/evm/execution-types/src/execute.rs | 6 +- .../execution-types/src/execution_outcome.rs | 86 ++----- crates/evm/src/execute.rs | 20 +- crates/evm/src/system_calls/eip7002.rs | 49 +--- crates/evm/src/system_calls/eip7251.rs | 53 +--- crates/evm/src/system_calls/mod.rs | 19 +- crates/evm/src/test_utils.rs | 6 +- crates/exex/exex/src/backfill/test_utils.rs | 4 +- crates/net/eth-wire-types/src/blocks.rs | 10 +- crates/net/eth-wire-types/src/header.rs | 6 +- crates/net/p2p/src/full_block.rs | 16 -- crates/optimism/evm/Cargo.toml | 3 +- crates/optimism/evm/src/execute.rs | 7 +- crates/optimism/evm/src/lib.rs | 1 - crates/optimism/evm/src/strategy.rs | 9 +- crates/optimism/payload/src/builder.rs | 4 +- crates/optimism/payload/src/payload.rs | 6 +- crates/optimism/primitives/src/bedrock.rs | 2 +- crates/optimism/rpc/src/eth/receipt.rs | 2 - crates/optimism/storage/src/lib.rs | 3 +- crates/payload/validator/Cargo.toml | 2 + crates/payload/validator/src/lib.rs | 13 +- crates/primitives-traits/Cargo.toml | 2 +- crates/primitives-traits/src/block/body.rs | 17 +- .../src/header/test_utils.rs | 2 +- crates/primitives-traits/src/lib.rs | 3 - crates/primitives-traits/src/mod.rs | 0 crates/primitives-traits/src/request.rs | 58 ----- crates/primitives/Cargo.toml | 2 - crates/primitives/src/alloy_compat.rs | 3 - crates/primitives/src/block.rs | 71 +----- crates/primitives/src/lib.rs | 2 +- crates/primitives/src/proofs.rs | 11 +- crates/primitives/src/transaction/mod.rs | 40 +-- crates/revm/Cargo.toml | 3 + crates/revm/src/batch.rs | 7 +- crates/rpc/rpc-api/src/engine.rs | 7 +- crates/rpc/rpc-engine-api/src/engine_api.rs | 42 +++- crates/rpc/rpc-engine-api/tests/it/payload.rs | 15 +- .../rpc-eth-api/src/helpers/pending_block.rs | 20 +- crates/rpc/rpc-eth-types/src/receipt.rs | 2 - crates/rpc/rpc-types-compat/src/block.rs | 4 +- .../rpc-types-compat/src/engine/payload.rs | 137 ++--------- crates/rpc/rpc/src/debug.rs | 2 +- crates/rpc/rpc/src/otterscan.rs | 1 - crates/rpc/rpc/src/txpool.rs | 2 +- crates/stages/stages/src/stages/bodies.rs | 14 -- .../codecs/src/alloy/authorization_list.rs | 4 +- crates/storage/codecs/src/alloy/header.rs | 10 +- crates/storage/codecs/src/alloy/mod.rs | 3 - crates/storage/codecs/src/alloy/request.rs | 40 --- crates/storage/db-api/src/models/mod.rs | 4 +- crates/storage/db/src/tables/mod.rs | 7 +- .../src/providers/blockchain_provider.rs | 55 +---- .../src/providers/database/metrics.rs | 4 - .../provider/src/providers/database/mod.rs | 14 +- .../src/providers/database/provider.rs | 150 +++--------- crates/storage/provider/src/providers/mod.rs | 12 +- .../src/providers/static_file/manager.rs | 15 +- .../storage/provider/src/test_utils/blocks.rs | 1 - .../storage/provider/src/test_utils/mock.rs | 16 +- .../storage/provider/src/test_utils/noop.rs | 12 +- crates/storage/storage-api/src/block.rs | 5 +- crates/storage/storage-api/src/lib.rs | 3 - crates/storage/storage-api/src/requests.rs | 14 -- docs/crates/db.md | 4 +- testing/ef-tests/src/models.rs | 4 +- testing/testing-utils/Cargo.toml | 4 +- testing/testing-utils/src/generators.rs | 47 +--- 106 files changed, 800 insertions(+), 1329 deletions(-) delete mode 100644 crates/primitives-traits/src/mod.rs delete mode 100644 crates/primitives-traits/src/request.rs delete mode 100644 crates/storage/codecs/src/alloy/request.rs delete mode 100644 crates/storage/storage-api/src/requests.rs diff --git a/Cargo.lock b/Cargo.lock index 98bfe1f8e002..82f42b07b16f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -112,9 +112,9 @@ dependencies = [ [[package]] name = "alloy-consensus" -version = "0.4.2" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "705687d5bfd019fee57cf9e206b27b30a9a9617535d5590a02b171e813208f8e" +checksum = "42642aed67f938363d9c7543e5ca4163cfb4205d9ec15fe933dc4e865d2932dd" dependencies = [ "alloy-eips", "alloy-primitives", @@ -161,9 +161,9 @@ dependencies = [ [[package]] name = "alloy-eip7702" -version = "0.1.1" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea59dc42102bc9a1905dc57901edc6dd48b9f38115df86c7d252acba70d71d04" +checksum = "eeffd2590ce780ddfaa9d0ae340eb2b4e08627650c4676eef537cef0b4bf535d" dependencies = [ "alloy-primitives", "alloy-rlp", @@ -176,9 +176,9 @@ dependencies = [ [[package]] name = "alloy-eips" -version = "0.4.2" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ffb906284a1e1f63c4607da2068c8197458a352d0b3e9796e67353d72a9be85" +checksum = "9fbc52a30df46f9831ed74557dfad0d94b12420393662a8b9ef90e2d6c8cb4b0" dependencies = [ "alloy-eip2930", "alloy-eip7702", @@ -188,6 +188,8 @@ dependencies = [ "arbitrary", "c-kzg", "derive_more 1.0.0", + "ethereum_ssz", + "ethereum_ssz_derive", "once_cell", "serde", "sha2 0.10.8", @@ -195,9 +197,9 @@ dependencies = [ [[package]] name = "alloy-genesis" -version = "0.4.2" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8429cf4554eed9b40feec7f4451113e76596086447550275e3def933faf47ce3" +checksum = "0787d1688b9806290313cc335d416cc7ee39b11e3245f3d218544c62572d92ba" dependencies = [ "alloy-primitives", "alloy-serde", @@ -218,9 +220,9 @@ dependencies = [ [[package]] name = "alloy-json-rpc" -version = "0.4.2" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8fa8a1a3c4cbd221f2b8e3693aeb328fca79a757fe556ed08e47bbbc2a70db7" +checksum = "d55a16a5f9ca498a217c060414bcd1c43e934235dc8058b31b87dcd69ff4f105" dependencies = [ "alloy-primitives", "alloy-sol-types", @@ -232,9 +234,9 @@ dependencies = [ [[package]] name = "alloy-network" -version = "0.4.2" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85fa23a6a9d612b52e402c995f2d582c25165ec03ac6edf64c861a76bc5b87cd" +checksum = "3d236a8c3e1d5adc09b1b63c81815fc9b757d9a4ba9482cc899f9679b55dd437" dependencies = [ "alloy-consensus", "alloy-eips", @@ -253,9 +255,9 @@ dependencies = [ [[package]] name = "alloy-network-primitives" -version = "0.4.2" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "801492711d4392b2ccf5fc0bc69e299fa1aab15167d74dcaa9aab96a54f684bd" +checksum = "cd15a0990fa8a56d85a42d6a689719aa4eebf5e2f1a5c5354658c0bfc52cac9a" dependencies = [ "alloy-consensus", "alloy-eips", @@ -266,9 +268,9 @@ dependencies = [ [[package]] name = "alloy-node-bindings" -version = "0.4.2" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f1334a738aa1710cb8227441b3fcc319202ce78e967ef37406940242df4a454" +checksum = "2249f3c3ce446cf4063fe3d1aa7530823643c2706a1cc63045e0683ebc497a0a" dependencies = [ "alloy-genesis", "alloy-primitives", @@ -315,9 +317,9 @@ dependencies = [ [[package]] name = "alloy-provider" -version = "0.4.2" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcfaa4ffec0af04e3555686b8aacbcdf7d13638133a0672749209069750f78a6" +checksum = "316f522bb6f9ac3805132112197957013b570e20cfdad058e8339dae6030c849" dependencies = [ "alloy-chains", "alloy-consensus", @@ -341,21 +343,24 @@ dependencies = [ "futures", "futures-utils-wasm", "lru", + "parking_lot 0.12.3", "pin-project", "reqwest", + "schnellru", "serde", "serde_json", "thiserror", "tokio", "tracing", "url", + "wasmtimer", ] [[package]] name = "alloy-pubsub" -version = "0.4.2" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f32cef487122ae75c91eb50154c70801d71fabdb976fec6c49e0af5e6486ab15" +checksum = "222cd9b17b1c5ad48de51a88ffbdb17f17145170288f22662f80ac88739125e6" dependencies = [ "alloy-json-rpc", "alloy-primitives", @@ -394,9 +399,9 @@ dependencies = [ [[package]] name = "alloy-rpc-client" -version = "0.4.2" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "370143ed581aace6e663342d21d209c6b2e34ee6142f7d6675adb518deeaf0dc" +checksum = "5b2ab59712c594c9624aaa69e38e4d38f180cb569f1fa46cdaf8c21fd50793e5" dependencies = [ "alloy-json-rpc", "alloy-primitives", @@ -414,13 +419,14 @@ dependencies = [ "tower 0.5.1", "tracing", "url", + "wasmtimer", ] [[package]] name = "alloy-rpc-types" -version = "0.4.2" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ffc534b7919e18f35e3aa1f507b6f3d9d92ec298463a9f6beaac112809d8d06" +checksum = "ba21284319e12d053baa204d438db6c1577aedd94c1298e4becefdac1f9cec87" dependencies = [ "alloy-primitives", "alloy-rpc-types-engine", @@ -431,9 +437,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-admin" -version = "0.4.2" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb520ed46cc5b7d8c014a73fdd77b6a310383a2a5c0a5ae3c9b8055881f062b7" +checksum = "416cc9f391d0b876c4c8da85f7131e771a88a55b917cc9a35e1724d9409e3b1c" dependencies = [ "alloy-genesis", "alloy-primitives", @@ -443,9 +449,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-anvil" -version = "0.4.2" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d780adaa5d95b07ad92006b2feb68ecfa7e2015f7d5976ceaac4c906c73ebd07" +checksum = "ba40bea86c3102b9ed9b3be579e32e0b3e54e766248d873de5fc0437238c8df2" dependencies = [ "alloy-primitives", "alloy-serde", @@ -454,9 +460,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-beacon" -version = "0.4.2" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a8dc5980fe30203d698627cddb5f0cedc57f900c8b5e1229c8b9448e37acb4a" +checksum = "b535781fe224c101c3d957b514cb9f438d165ff0280e5c0b2f87a0d9a2950593" dependencies = [ "alloy-eips", "alloy-primitives", @@ -468,9 +474,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-debug" -version = "0.4.2" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59d8f8c5bfb160081a772f1f68eb9a37e8929c4ef74e5d01f5b78c2b645a5c5e" +checksum = "4303deacf4cbf12ed4431a5a1bbc3284f0defb4b8b72d9aa2b888656cc5ae657" dependencies = [ "alloy-primitives", "serde", @@ -478,9 +484,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-engine" -version = "0.4.2" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0285c4c09f838ab830048b780d7f4a4f460f309aa1194bb049843309524c64c" +checksum = "44848fced3b42260b9cb61f22102246636dfe5a2d0132f8d10a617df3cb1a74b" dependencies = [ "alloy-consensus", "alloy-eips", @@ -488,6 +494,8 @@ dependencies = [ "alloy-rlp", "alloy-serde", "derive_more 1.0.0", + "ethereum_ssz", + "ethereum_ssz_derive", "jsonrpsee-types", "jsonwebtoken", "rand 0.8.5", @@ -497,9 +505,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-eth" -version = "0.4.2" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413f4aa3ccf2c3e4234a047c5fa4727916d7daf25a89f9b765df0ba09784fd87" +checksum = "35894711990019fafff0012b82b9176cbb744516eb2a9bbe6b8e5cae522163ee" dependencies = [ "alloy-consensus", "alloy-eips", @@ -517,9 +525,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-mev" -version = "0.4.2" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cec23ce56c869eec5f6b6fd6a8a92b5aa0cfaf8d7be3a96502e537554dc7430" +checksum = "cac6250cad380a005ecb5ffc6d2facf03df0e72628d819a63dd8c3ade7a766ff" dependencies = [ "alloy-eips", "alloy-primitives", @@ -530,9 +538,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-trace" -version = "0.4.2" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "017cad3e5793c5613588c1f9732bcbad77e820ba7d0feaba3527749f856fdbc5" +checksum = "f568c5624881896d8a25e19acbdcbabadd8df339427ea2f10b2ee447d57c4509" dependencies = [ "alloy-primitives", "alloy-rpc-types-eth", @@ -544,9 +552,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-txpool" -version = "0.4.2" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b230e321c416be7f50530159392b4c41a45596d40d97e185575bcd0b545e521" +checksum = "d4a37d2e1ed9b7daf20ad0b3e0092613cbae46737e0e988b23caa556c7067ce6" dependencies = [ "alloy-primitives", "alloy-rpc-types-eth", @@ -556,9 +564,9 @@ dependencies = [ [[package]] name = "alloy-serde" -version = "0.4.2" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dff0ab1cdd43ca001e324dc27ee0e8606bd2161d6623c63e0e0b8c4dfc13600" +checksum = "2843c195675f06b29c09a4315cccdc233ab5bdc7c0a3775909f9f0cab5e9ae0f" dependencies = [ "alloy-primitives", "arbitrary", @@ -568,9 +576,9 @@ dependencies = [ [[package]] name = "alloy-signer" -version = "0.4.2" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fd4e0ad79c81a27ca659be5d176ca12399141659fef2bcbfdc848da478f4504" +checksum = "88b2a00d9803dfef99963303ffe41a7bf2221f3342f0a503d6741a9f4a18e5e5" dependencies = [ "alloy-primitives", "async-trait", @@ -582,9 +590,9 @@ dependencies = [ [[package]] name = "alloy-signer-local" -version = "0.4.2" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "494e0a256f3e99f2426f994bcd1be312c02cb8f88260088dacb33a8b8936475f" +checksum = "5a2505d4f8c98dcae86152d58d549cb4bcf953f8352fca903410e0a0ef535571" dependencies = [ "alloy-consensus", "alloy-network", @@ -670,9 +678,9 @@ dependencies = [ [[package]] name = "alloy-transport" -version = "0.4.2" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ac3e97dad3d31770db0fc89bd6a63b789fbae78963086733f960cf32c483904" +checksum = "9dc2c8f6b8c227ef0398f702d954c4ab572c2ead3c1ed4a5157aa1cbaf959747" dependencies = [ "alloy-json-rpc", "base64 0.22.1", @@ -685,13 +693,14 @@ dependencies = [ "tower 0.5.1", "tracing", "url", + "wasmtimer", ] [[package]] name = "alloy-transport-http" -version = "0.4.2" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b367dcccada5b28987c2296717ee04b9a5637aacd78eacb1726ef211678b5212" +checksum = "dd328e990d57f4c4e63899fb2c26877597d6503f8e0022a3d71b2d753ecbfc0c" dependencies = [ "alloy-json-rpc", "alloy-transport", @@ -704,9 +713,9 @@ dependencies = [ [[package]] name = "alloy-transport-ipc" -version = "0.4.2" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b90cf9cde7f2fce617da52768ee28f522264b282d148384a4ca0ea85af04fa3a" +checksum = "89aea26aaf1d67904a7ff95ec4a24ddd5e7d419a6945f641b885962d7c2803e2" dependencies = [ "alloy-json-rpc", "alloy-pubsub", @@ -723,9 +732,9 @@ dependencies = [ [[package]] name = "alloy-transport-ws" -version = "0.4.2" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7153b88690de6a50bba81c11e1d706bc41dbb90126d607404d60b763f6a3947f" +checksum = "e222e950ecc4ea12fbfb524b9a2275cac2cd5f57c8ce25bcaf1bd3ff80dd8fc8" dependencies = [ "alloy-pubsub", "alloy-transport", @@ -2665,6 +2674,47 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "ethereum_serde_utils" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70cbccfccf81d67bff0ab36e591fa536c8a935b078a7b0e58c1d00d418332fc9" +dependencies = [ + "alloy-primitives", + "hex", + "serde", + "serde_derive", + "serde_json", +] + +[[package]] +name = "ethereum_ssz" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfbba28f4f3f32d92c06a64f5bf6c4537b5d4e21f28c689bd2bbaecfea4e0d3e" +dependencies = [ + "alloy-primitives", + "derivative", + "ethereum_serde_utils", + "itertools 0.13.0", + "serde", + "serde_derive", + "smallvec", + "typenum", +] + +[[package]] +name = "ethereum_ssz_derive" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d37845ba7c16bf4be8be4b5786f03a2ba5f2fda0d7f9e7cb2282f69cff420d7" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.79", +] + [[package]] name = "event-listener" version = "2.5.3" @@ -5157,9 +5207,9 @@ checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" [[package]] name = "op-alloy-consensus" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ea7162170c6f3cad8f67f4dd7108e3f78349fd553da5b8bebff1e7ef8f38896" +checksum = "99d49163f952491820088dd0e66f3a35d63337c3066eceff0a931bf83a8e2101" dependencies = [ "alloy-consensus", "alloy-eips", @@ -5175,9 +5225,9 @@ dependencies = [ [[package]] name = "op-alloy-genesis" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f3d31dfbbd8dd898c7512f8ce7d30103980485416f668566100b0ed0994b958" +checksum = "8e46c2ab105f679f0cbfbc3fb762f3456d4b8556c841e667fc8f3c2226eb6c1e" dependencies = [ "alloy-consensus", "alloy-eips", @@ -5189,9 +5239,9 @@ dependencies = [ [[package]] name = "op-alloy-network" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d113b325527ba7da271a8793f1c14bdf7f035ce9e0611e668c36fc6812568c7f" +checksum = "75ff1ea317441b9eb6317b24d13f9088e3b14ef48b15bfb6a125ca404df036d8" dependencies = [ "alloy-consensus", "alloy-network", @@ -5203,9 +5253,9 @@ dependencies = [ [[package]] name = "op-alloy-protocol" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "310873e4fbfc41986716c4fb6000a8b49d025d932d2c261af58271c434b05288" +checksum = "6c439457b2a1791325603fc18a94cc175e0b4b1127f11ff8a45071f05d044dcb" dependencies = [ "alloy-consensus", "alloy-eips", @@ -5220,9 +5270,9 @@ dependencies = [ [[package]] name = "op-alloy-rpc-types" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "323c65880e2561aa87f74f8af260fd15b9cc930c448c88a60ae95af86c88c634" +checksum = "9c9556293835232b019ec9c6fd84e4265a3151111af60ea09b5b513e3dbed41c" dependencies = [ "alloy-consensus", "alloy-eips", @@ -5237,16 +5287,18 @@ dependencies = [ [[package]] name = "op-alloy-rpc-types-engine" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349e7b420f45d1a00216ec4c65fcf3f0057a841bc39732c405c85ae782b94121" +checksum = "8a42a5ac4e07ed226b6a2aeefaad9b2cc7ec160e372ba626a4214d681a355fc2" dependencies = [ "alloy-primitives", "alloy-rpc-types-engine", "alloy-serde", "derive_more 1.0.0", + "ethereum_ssz", "op-alloy-protocol", "serde", + "snap", ] [[package]] @@ -6310,6 +6362,7 @@ dependencies = [ name = "reth-auto-seal-consensus" version = "1.1.0" dependencies = [ + "alloy-eips", "alloy-primitives", "alloy-rpc-types-engine", "futures-util", @@ -6700,6 +6753,7 @@ dependencies = [ name = "reth-consensus" version = "1.1.0" dependencies = [ + "alloy-eips", "alloy-primitives", "auto_impl", "derive_more 1.0.0", @@ -7275,6 +7329,7 @@ name = "reth-ethereum-consensus" version = "1.1.0" dependencies = [ "alloy-consensus", + "alloy-eips", "alloy-primitives", "reth-chainspec", "reth-consensus", @@ -7327,6 +7382,7 @@ name = "reth-ethereum-payload-builder" version = "1.1.0" dependencies = [ "alloy-consensus", + "alloy-eips", "alloy-primitives", "reth-basic-payload-builder", "reth-chain-state", @@ -8343,6 +8399,8 @@ dependencies = [ name = "reth-payload-validator" version = "1.1.0" dependencies = [ + "alloy-eips", + "alloy-primitives", "alloy-rpc-types", "reth-chainspec", "reth-primitives", @@ -8524,6 +8582,7 @@ dependencies = [ name = "reth-revm" version = "1.1.0" dependencies = [ + "alloy-eips", "alloy-primitives", "reth-chainspec", "reth-consensus-common", @@ -9274,9 +9333,9 @@ dependencies = [ [[package]] name = "revm" -version = "14.0.3" +version = "16.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "641702b12847f9ed418d552f4fcabe536d867a2c980e96b6e7e25d7b992f929f" +checksum = "34e44692d5736cc44c697a372e507890f8797f06d1541c5f4b9bec594d90fd8a" dependencies = [ "auto_impl", "cfg-if", @@ -9289,9 +9348,9 @@ dependencies = [ [[package]] name = "revm-inspectors" -version = "0.8.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43c44af0bf801f48d25f7baf25cf72aff4c02d610f83b428175228162fef0246" +checksum = "a64e2246ad480167548724eb9c9c66945241b867c7d50894de3ca860c9823a45" dependencies = [ "alloy-primitives", "alloy-rpc-types-eth", @@ -9308,9 +9367,9 @@ dependencies = [ [[package]] name = "revm-interpreter" -version = "10.0.3" +version = "12.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e5e14002afae20b5bf1566f22316122f42f57517000e559c55b25bf7a49cba2" +checksum = "6f89940d17d5d077570de1977f52f69049595322e237cb6c754c3d47f668f023" dependencies = [ "revm-primitives", "serde", @@ -9318,9 +9377,9 @@ dependencies = [ [[package]] name = "revm-precompile" -version = "11.0.3" +version = "13.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3198c06247e8d4ad0d1312591edf049b0de4ddffa9fecb625c318fd67db8639b" +checksum = "d8f816aaea3245cbdbe7fdd84955df33597f9322c7912c3e3ba7bc855e03211f" dependencies = [ "aurora-engine-modexp", "blst", @@ -9338,9 +9397,9 @@ dependencies = [ [[package]] name = "revm-primitives" -version = "10.0.0" +version = "12.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f1525851a03aff9a9d6a1d018b414d76252d6802ab54695b27093ecd7e7a101" +checksum = "532411bbde45a46707c1d434dcdc29866cf261c1b748fb01b303ce3b4310b361" dependencies = [ "alloy-eip2930", "alloy-eip7702", @@ -11355,6 +11414,20 @@ dependencies = [ "web-sys", ] +[[package]] +name = "wasmtimer" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7ed9d8b15c7fb594d72bfb4b5a276f3d2029333cd93a932f376f5937f6f80ee" +dependencies = [ + "futures", + "js-sys", + "parking_lot 0.12.3", + "pin-utils", + "slab", + "wasm-bindgen", +] + [[package]] name = "web-sys" version = "0.3.72" diff --git a/Cargo.toml b/Cargo.toml index 54111096902c..6c66e501ef4a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -410,9 +410,9 @@ reth-trie-db = { path = "crates/trie/db" } reth-trie-parallel = { path = "crates/trie/parallel" } # revm -revm = { version = "14.0.3", features = ["std"], default-features = false } -revm-inspectors = "0.8.1" -revm-primitives = { version = "10.0.0", features = [ +revm = { version = "16.0.0", features = ["std"], default-features = false } +revm-inspectors = "0.9.0" +revm-primitives = { version = "12.0.0", features = [ "std", ], default-features = false } @@ -424,45 +424,45 @@ alloy-rlp = "0.3.4" alloy-sol-types = "0.8.0" alloy-trie = { version = "0.7", default-features = false } -alloy-consensus = { version = "0.4.2", default-features = false } -alloy-eips = { version = "0.4.2", default-features = false } -alloy-genesis = { version = "0.4.2", default-features = false } -alloy-json-rpc = { version = "0.4.2", default-features = false } -alloy-network = { version = "0.4.2", default-features = false } -alloy-network-primitives = { version = "0.4.2", default-features = false } -alloy-node-bindings = { version = "0.4.2", default-features = false } -alloy-provider = { version = "0.4.2", features = [ +alloy-consensus = { version = "0.5.2", default-features = false } +alloy-eips = { version = "0.5.2", default-features = false } +alloy-genesis = { version = "0.5.2", default-features = false } +alloy-json-rpc = { version = "0.5.2", default-features = false } +alloy-network = { version = "0.5.2", default-features = false } +alloy-network-primitives = { version = "0.5.2", default-features = false } +alloy-node-bindings = { version = "0.5.2", default-features = false } +alloy-provider = { version = "0.5.2", features = [ "reqwest", ], default-features = false } -alloy-pubsub = { version = "0.4.2", default-features = false } -alloy-rpc-client = { version = "0.4.2", default-features = false } -alloy-rpc-types = { version = "0.4.2", features = [ +alloy-pubsub = { version = "0.5.2", default-features = false } +alloy-rpc-client = { version = "0.5.2", default-features = false } +alloy-rpc-types = { version = "0.5.2", features = [ "eth", ], default-features = false } -alloy-rpc-types-admin = { version = "0.4.2", default-features = false } -alloy-rpc-types-anvil = { version = "0.4.2", default-features = false } -alloy-rpc-types-beacon = { version = "0.4.2", default-features = false } -alloy-rpc-types-debug = { version = "0.4.2", default-features = false } -alloy-rpc-types-engine = { version = "0.4.2", default-features = false } -alloy-rpc-types-eth = { version = "0.4.2", default-features = false } -alloy-rpc-types-mev = { version = "0.4.2", default-features = false } -alloy-rpc-types-trace = { version = "0.4.2", default-features = false } -alloy-rpc-types-txpool = { version = "0.4.2", default-features = false } -alloy-serde = { version = "0.4.2", default-features = false } -alloy-signer = { version = "0.4.2", default-features = false } -alloy-signer-local = { version = "0.4.2", default-features = false } -alloy-transport = { version = "0.4.2" } -alloy-transport-http = { version = "0.4.2", features = [ +alloy-rpc-types-admin = { version = "0.5.2", default-features = false } +alloy-rpc-types-anvil = { version = "0.5.2", default-features = false } +alloy-rpc-types-beacon = { version = "0.5.2", default-features = false } +alloy-rpc-types-debug = { version = "0.5.2", default-features = false } +alloy-rpc-types-engine = { version = "0.5.2", default-features = false } +alloy-rpc-types-eth = { version = "0.5.2", default-features = false } +alloy-rpc-types-mev = { version = "0.5.2", default-features = false } +alloy-rpc-types-trace = { version = "0.5.2", default-features = false } +alloy-rpc-types-txpool = { version = "0.5.2", default-features = false } +alloy-serde = { version = "0.5.2", default-features = false } +alloy-signer = { version = "0.5.2", default-features = false } +alloy-signer-local = { version = "0.5.2", default-features = false } +alloy-transport = { version = "0.5.2" } +alloy-transport-http = { version = "0.5.2", features = [ "reqwest-rustls-tls", ], default-features = false } -alloy-transport-ipc = { version = "0.4.2", default-features = false } -alloy-transport-ws = { version = "0.4.2", default-features = false } +alloy-transport-ipc = { version = "0.5.2", default-features = false } +alloy-transport-ws = { version = "0.5.2", default-features = false } # op -op-alloy-rpc-types = "0.4" -op-alloy-rpc-types-engine = "0.4" -op-alloy-network = "0.4" -op-alloy-consensus = "0.4" +op-alloy-rpc-types = "0.5" +op-alloy-rpc-types-engine = "0.5" +op-alloy-network = "0.5" +op-alloy-consensus = "0.5" # misc aquamarine = "0.5" @@ -593,30 +593,35 @@ tikv-jemalloc-ctl = "0.6" tikv-jemallocator = "0.6" tracy-client = "0.17.3" -[patch.crates-io] -#alloy-consensus = { git = "https://github.com/alloy-rs/alloy", rev = "8c499409"} -#alloy-eips = { git = "https://github.com/alloy-rs/alloy", rev = "8c499409"} -#alloy-genesis = { git = "https://github.com/alloy-rs/alloy", rev = "8c499409"} -#alloy-json-rpc = { git = "https://github.com/alloy-rs/alloy", rev = "8c499409"} -#alloy-network = { git = "https://github.com/alloy-rs/alloy", rev = "8c499409"} -#alloy-node-bindings = { git = "https://github.com/alloy-rs/alloy", rev = "8c499409"} -#alloy-provider = { git = "https://github.com/alloy-rs/alloy", rev = "8c499409"} -#alloy-pubsub = { git = "https://github.com/alloy-rs/alloy", rev = "8c499409"} -#alloy-rpc-client = { git = "https://github.com/alloy-rs/alloy", rev = "8c499409"} -#alloy-rpc-types = { git = "https://github.com/alloy-rs/alloy", rev = "8c499409"} -#alloy-rpc-types-admin = { git = "https://github.com/alloy-rs/alloy", rev = "8c499409"} -#alloy-rpc-types-anvil = { git = "https://github.com/alloy-rs/alloy", rev = "8c499409"} -#alloy-rpc-types-beacon = { git = "https://github.com/alloy-rs/alloy", rev = "8c499409"} -#alloy-rpc-types-debug = { git = "https://github.com/alloy-rs/alloy", rev = "8c499409"} -#alloy-rpc-types-engine = { git = "https://github.com/alloy-rs/alloy", rev = "8c499409"} -#alloy-rpc-types-eth = { git = "https://github.com/alloy-rs/alloy", rev = "8c499409"} -#alloy-rpc-types-mev = { git = "https://github.com/alloy-rs/alloy", rev = "8c499409"} -#alloy-rpc-types-trace = { git = "https://github.com/alloy-rs/alloy", rev = "8c499409"} -#alloy-rpc-types-txpool = { git = "https://github.com/alloy-rs/alloy", rev = "8c499409"} -#alloy-serde = { git = "https://github.com/alloy-rs/alloy", rev = "8c499409"} -#alloy-signer = { git = "https://github.com/alloy-rs/alloy", rev = "8c499409"} -#alloy-signer-local = { git = "https://github.com/alloy-rs/alloy", rev = "8c499409"} -#alloy-transport = { git = "https://github.com/alloy-rs/alloy", rev = "8c499409"} -#alloy-transport-http = { git = "https://github.com/alloy-rs/alloy", rev = "8c499409"} -#alloy-transport-ipc = { git = "https://github.com/alloy-rs/alloy", rev = "8c499409"} -#alloy-transport-ws = { git = "https://github.com/alloy-rs/alloy", rev = "8c499409"} +#[patch.crates-io] +#alloy-consensus = { git = "https://github.com/alloy-rs/alloy", rev = "a971b3a" } +#alloy-eips = { git = "https://github.com/alloy-rs/alloy", rev = "a971b3a" } +#alloy-genesis = { git = "https://github.com/alloy-rs/alloy", rev = "a971b3a" } +#alloy-json-rpc = { git = "https://github.com/alloy-rs/alloy", rev = "a971b3a" } +#alloy-network = { git = "https://github.com/alloy-rs/alloy", rev = "a971b3a" } +#alloy-node-bindings = { git = "https://github.com/alloy-rs/alloy", rev = "a971b3a" } +#alloy-provider = { git = "https://github.com/alloy-rs/alloy", rev = "a971b3a" } +#alloy-pubsub = { git = "https://github.com/alloy-rs/alloy", rev = "a971b3a" } +#alloy-rpc-client = { git = "https://github.com/alloy-rs/alloy", rev = "a971b3a" } +#alloy-rpc-types = { git = "https://github.com/alloy-rs/alloy", rev = "a971b3a" } +#alloy-rpc-types-admin = { git = "https://github.com/alloy-rs/alloy", rev = "a971b3a" } +#alloy-rpc-types-anvil = { git = "https://github.com/alloy-rs/alloy", rev = "a971b3a" } +#alloy-rpc-types-beacon = { git = "https://github.com/alloy-rs/alloy", rev = "a971b3a" } +#alloy-rpc-types-debug = { git = "https://github.com/alloy-rs/alloy", rev = "a971b3a" } +#alloy-rpc-types-engine = { git = "https://github.com/alloy-rs/alloy", rev = "a971b3a" } +#alloy-rpc-types-eth = { git = "https://github.com/alloy-rs/alloy", rev = "a971b3a" } +#alloy-rpc-types-mev = { git = "https://github.com/alloy-rs/alloy", rev = "a971b3a" } +#alloy-rpc-types-trace = { git = "https://github.com/alloy-rs/alloy", rev = "a971b3a" } +#alloy-rpc-types-txpool = { git = "https://github.com/alloy-rs/alloy", rev = "a971b3a" } +#alloy-serde = { git = "https://github.com/alloy-rs/alloy", rev = "a971b3a" } +#alloy-signer = { git = "https://github.com/alloy-rs/alloy", rev = "a971b3a" } +#alloy-signer-local = { git = "https://github.com/alloy-rs/alloy", rev = "a971b3a" } +#alloy-transport = { git = "https://github.com/alloy-rs/alloy", rev = "a971b3a" } +#alloy-transport-http = { git = "https://github.com/alloy-rs/alloy", rev = "a971b3a" } +#alloy-transport-ipc = { git = "https://github.com/alloy-rs/alloy", rev = "a971b3a" } +#alloy-transport-ws = { git = "https://github.com/alloy-rs/alloy", rev = "a971b3a" } + +#op-alloy-rpc-types = { git = "https://github.com/alloy-rs/op-alloy", rev = "6a042e7681b1" } +#op-alloy-rpc-types-engine = { git = "https://github.com/alloy-rs/op-alloy", rev = "6a042e7681b1" } +#op-alloy-network = { git = "https://github.com/alloy-rs/op-alloy", rev = "6a042e7681b1" } +#op-alloy-consensus = { git = "https://github.com/alloy-rs/op-alloy", rev = "6a042e7681b1" } diff --git a/bin/reth-bench/src/authenticated_transport.rs b/bin/reth-bench/src/authenticated_transport.rs index c946d244de9e..72c4fd298898 100644 --- a/bin/reth-bench/src/authenticated_transport.rs +++ b/bin/reth-bench/src/authenticated_transport.rs @@ -84,7 +84,8 @@ impl InnerTransport { let (auth, claims) = build_auth(jwt).map_err(|e| AuthenticatedTransportError::InvalidJwt(e.to_string()))?; - let inner = WsConnect { url: url.to_string(), auth: Some(auth) } + let inner = WsConnect::new(url.clone()) + .with_auth(auth) .into_service() .await .map(Self::Ws) diff --git a/bin/reth-bench/src/valid_payload.rs b/bin/reth-bench/src/valid_payload.rs index 6353aea71233..b00f4ddcd64b 100644 --- a/bin/reth-bench/src/valid_payload.rs +++ b/bin/reth-bench/src/valid_payload.rs @@ -215,14 +215,6 @@ pub(crate) async fn call_new_payload>( versioned_hashes: Vec, ) -> TransportResult { match payload { - ExecutionPayload::V4(_payload) => { - todo!("V4 payloads not supported yet"); - // auth_provider - // .new_payload_v4_wait(payload, versioned_hashes, parent_beacon_block_root, ...) - // .await?; - // - // Ok(EngineApiMessageVersion::V4) - } ExecutionPayload::V3(payload) => { // We expect the caller let parent_beacon_block_root = parent_beacon_block_root diff --git a/bin/reth/src/commands/debug_cmd/replay_engine.rs b/bin/reth/src/commands/debug_cmd/replay_engine.rs index cbffa1f0e076..de497cbe0070 100644 --- a/bin/reth/src/commands/debug_cmd/replay_engine.rs +++ b/bin/reth/src/commands/debug_cmd/replay_engine.rs @@ -171,7 +171,9 @@ impl> Command { debug!(target: "reth::cli", ?response, "Received for forkchoice updated"); } StoredEngineApiMessage::NewPayload { payload, cancun_fields } => { - let response = beacon_engine_handle.new_payload(payload, cancun_fields).await?; + // todo: prague (last arg) + let response = + beacon_engine_handle.new_payload(payload, cancun_fields, None).await?; debug!(target: "reth::cli", ?response, "Received for new payload"); } }; diff --git a/crates/blockchain-tree/src/blockchain_tree.rs b/crates/blockchain-tree/src/blockchain_tree.rs index db43dffcd36a..1e2ed2a4a2ed 100644 --- a/crates/blockchain-tree/src/blockchain_tree.rs +++ b/crates/blockchain-tree/src/blockchain_tree.rs @@ -1635,7 +1635,6 @@ mod tests { transactions: body.clone().into_iter().map(|tx| tx.into_signed()).collect(), ommers: Vec::new(), withdrawals: Some(Withdrawals::default()), - requests: None, }, }, body.iter().map(|tx| tx.signer()).collect(), diff --git a/crates/chain-state/src/in_memory.rs b/crates/chain-state/src/in_memory.rs index f157da5ff450..be33e1fd79a8 100644 --- a/crates/chain-state/src/in_memory.rs +++ b/crates/chain-state/src/in_memory.rs @@ -865,10 +865,11 @@ impl NewCanonicalChain { mod tests { use super::*; use crate::test_utils::TestBlockBuilder; + use alloy_eips::eip7685::Requests; use alloy_primitives::{map::HashSet, BlockNumber, Bytes, StorageKey, StorageValue}; use rand::Rng; use reth_errors::ProviderResult; - use reth_primitives::{Account, Bytecode, Receipt, Requests}; + use reth_primitives::{Account, Bytecode, Receipt}; use reth_storage_api::{ AccountReader, BlockHashReader, StateProofProvider, StateProvider, StateRootProvider, StorageRootProvider, diff --git a/crates/chain-state/src/test_utils.rs b/crates/chain-state/src/test_utils.rs index a820bb5cf018..f1648ab6bff4 100644 --- a/crates/chain-state/src/test_utils.rs +++ b/crates/chain-state/src/test_utils.rs @@ -3,6 +3,7 @@ use crate::{ CanonStateSubscriptions, }; use alloy_consensus::{Transaction as _, TxEip1559, EMPTY_ROOT_HASH}; +use alloy_eips::eip7685::Requests; use alloy_primitives::{Address, BlockNumber, Sealable, B256, U256}; use alloy_signer::SignerSync; use alloy_signer_local::PrivateKeySigner; @@ -12,8 +13,8 @@ use reth_execution_types::{Chain, ExecutionOutcome}; use reth_primitives::{ constants::EIP1559_INITIAL_BASE_FEE, proofs::{calculate_receipt_root, calculate_transaction_root, calculate_withdrawals_root}, - BlockBody, Header, Receipt, Receipts, Requests, SealedBlock, SealedBlockWithSenders, - SealedHeader, Transaction, TransactionSigned, TransactionSignedEcRecovered, + BlockBody, Header, Receipt, Receipts, SealedBlock, SealedBlockWithSenders, SealedHeader, + Transaction, TransactionSigned, TransactionSignedEcRecovered, }; use reth_trie::{root::state_root_unhashed, updates::TrieUpdates, HashedPostState}; use revm::{db::BundleState, primitives::AccountInfo}; @@ -169,7 +170,6 @@ impl TestBlockBuilder { transactions: transactions.into_iter().map(|tx| tx.into_signed()).collect(), ommers: Vec::new(), withdrawals: Some(vec![].into()), - requests: None, }, }; diff --git a/crates/chainspec/Cargo.toml b/crates/chainspec/Cargo.toml index 2864427c2af6..87df28322a6e 100644 --- a/crates/chainspec/Cargo.toml +++ b/crates/chainspec/Cargo.toml @@ -22,7 +22,6 @@ alloy-chains = { workspace = true, features = ["serde", "rlp"] } alloy-eips = { workspace = true, features = ["serde"] } alloy-genesis.workspace = true alloy-primitives = { workspace = true, features = ["rand", "rlp"] } -alloy-trie.workspace = true alloy-consensus.workspace = true # misc diff --git a/crates/chainspec/src/spec.rs b/crates/chainspec/src/spec.rs index 59e1a5ce1e15..a7f45727dd8e 100644 --- a/crates/chainspec/src/spec.rs +++ b/crates/chainspec/src/spec.rs @@ -3,9 +3,9 @@ pub use alloy_eips::eip1559::BaseFeeParams; use alloc::{boxed::Box, sync::Arc, vec::Vec}; use alloy_chains::{Chain, NamedChain}; use alloy_consensus::constants::EMPTY_WITHDRAWALS; +use alloy_eips::eip7685::EMPTY_REQUESTS_HASH; use alloy_genesis::Genesis; use alloy_primitives::{address, b256, Address, BlockNumber, B256, U256}; -use alloy_trie::EMPTY_ROOT_HASH; use derive_more::From; use alloy_consensus::constants::{DEV_GENESIS_HASH, MAINNET_GENESIS_HASH}; @@ -284,8 +284,9 @@ impl ChainSpec { }; // If Prague is activated at genesis we set requests root to an empty trie root. - let requests_root = - self.is_prague_active_at_timestamp(self.genesis.timestamp).then_some(EMPTY_ROOT_HASH); + let requests_hash = self + .is_prague_active_at_timestamp(self.genesis.timestamp) + .then_some(EMPTY_REQUESTS_HASH); Header { gas_limit: self.genesis.gas_limit, @@ -301,7 +302,7 @@ impl ChainSpec { parent_beacon_block_root, blob_gas_used: blob_gas_used.map(Into::into), excess_blob_gas: excess_blob_gas.map(Into::into), - requests_root, + requests_hash, ..Default::default() } } @@ -940,6 +941,7 @@ mod tests { use alloy_chains::Chain; use alloy_genesis::{ChainConfig, GenesisAccount}; use alloy_primitives::{b256, hex}; + use alloy_trie::EMPTY_ROOT_HASH; use reth_ethereum_forks::{ForkCondition, ForkHash, ForkId, Head}; use reth_trie_common::TrieAccount; diff --git a/crates/cli/commands/src/stage/drop.rs b/crates/cli/commands/src/stage/drop.rs index 9e0396404b37..3a277cabd185 100644 --- a/crates/cli/commands/src/stage/drop.rs +++ b/crates/cli/commands/src/stage/drop.rs @@ -81,7 +81,6 @@ impl> Command tx.clear::()?; tx.clear::()?; tx.clear::()?; - tx.clear::()?; reset_stage_checkpoint(tx, StageId::Bodies)?; insert_genesis_header(&provider_rw.0, &static_file_provider, &self.env.chain)?; diff --git a/crates/consensus/auto-seal/Cargo.toml b/crates/consensus/auto-seal/Cargo.toml index b4b281230336..249858711414 100644 --- a/crates/consensus/auto-seal/Cargo.toml +++ b/crates/consensus/auto-seal/Cargo.toml @@ -31,6 +31,7 @@ reth-tokio-util.workspace = true reth-trie.workspace = true # ethereum +alloy-eips.workspace = true alloy-primitives.workspace = true revm-primitives.workspace = true alloy-rpc-types-engine.workspace = true diff --git a/crates/consensus/auto-seal/src/lib.rs b/crates/consensus/auto-seal/src/lib.rs index 261227f1074e..16299e19ba45 100644 --- a/crates/consensus/auto-seal/src/lib.rs +++ b/crates/consensus/auto-seal/src/lib.rs @@ -15,6 +15,7 @@ #![cfg_attr(not(test), warn(unused_crate_dependencies))] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] +use alloy_eips::eip7685::Requests; use alloy_primitives::{BlockHash, BlockNumber, Bloom, B256, U256}; use reth_beacon_consensus::BeaconEngineMessage; use reth_chainspec::{EthChainSpec, EthereumHardforks}; @@ -25,7 +26,7 @@ use reth_execution_errors::{ }; use reth_execution_types::ExecutionOutcome; use reth_primitives::{ - proofs, Block, BlockBody, BlockHashOrNumber, BlockWithSenders, Header, Requests, SealedBlock, + proofs, Block, BlockBody, BlockHashOrNumber, BlockWithSenders, Header, SealedBlock, SealedHeader, TransactionSigned, Withdrawals, }; use reth_provider::{BlockReaderIdExt, StateProviderFactory, StateRootProvider}; @@ -301,7 +302,7 @@ impl StorageInner { timestamp, base_fee_per_gas, blob_gas_used, - requests_root: requests.map(|r| proofs::calculate_requests_root(&r.0)), + requests_hash: requests.map(|r| r.requests_hash()), ..Default::default() }; @@ -366,7 +367,6 @@ impl StorageInner { transactions, ommers: ommers.clone(), withdrawals: withdrawals.clone(), - requests: requests.clone(), }, } .with_recovered_senders() @@ -390,7 +390,7 @@ impl StorageInner { // root here let Block { mut header, body, .. } = block.block; - let body = BlockBody { transactions: body.transactions, ommers, withdrawals, requests }; + let body = BlockBody { transactions: body.transactions, ommers, withdrawals }; trace!(target: "consensus::auto", ?execution_outcome, ?header, ?body, "executed block, calculating state root and completing header"); @@ -682,7 +682,7 @@ mod tests { timestamp, base_fee_per_gas: None, blob_gas_used: Some(0), - requests_root: None, + requests_hash: None, excess_blob_gas: Some(0), ..Default::default() } diff --git a/crates/consensus/beacon/src/engine/handle.rs b/crates/consensus/beacon/src/engine/handle.rs index 65b7c38df918..1f4445901645 100644 --- a/crates/consensus/beacon/src/engine/handle.rs +++ b/crates/consensus/beacon/src/engine/handle.rs @@ -4,6 +4,7 @@ use crate::{ engine::message::OnForkChoiceUpdated, BeaconConsensusEngineEvent, BeaconEngineMessage, BeaconForkChoiceUpdateError, BeaconOnNewPayloadError, }; +use alloy_primitives::Bytes; use alloy_rpc_types_engine::{ CancunPayloadFields, ExecutionPayload, ForkchoiceState, ForkchoiceUpdated, PayloadStatus, }; @@ -47,9 +48,17 @@ where &self, payload: ExecutionPayload, cancun_fields: Option, + execution_requests: Option>, ) -> Result { let (tx, rx) = oneshot::channel(); - let _ = self.to_engine.send(BeaconEngineMessage::NewPayload { payload, cancun_fields, tx }); + // HACK(onbjerg): We should have a pectra payload fields struct, this is just a temporary + // workaround. + let _ = self.to_engine.send(BeaconEngineMessage::NewPayload { + payload, + cancun_fields, + execution_requests, + tx, + }); rx.await.map_err(|_| BeaconOnNewPayloadError::EngineUnavailable)? } diff --git a/crates/consensus/beacon/src/engine/message.rs b/crates/consensus/beacon/src/engine/message.rs index fdaad0cc4b0d..45d0c57f45ed 100644 --- a/crates/consensus/beacon/src/engine/message.rs +++ b/crates/consensus/beacon/src/engine/message.rs @@ -1,4 +1,5 @@ use crate::engine::{error::BeaconOnNewPayloadError, forkchoice::ForkchoiceStatus}; +use alloy_primitives::Bytes; use alloy_rpc_types_engine::{ CancunPayloadFields, ExecutionPayload, ForkChoiceUpdateResult, ForkchoiceState, ForkchoiceUpdateError, ForkchoiceUpdated, PayloadId, PayloadStatus, PayloadStatusEnum, @@ -146,6 +147,10 @@ pub enum BeaconEngineMessage { payload: ExecutionPayload, /// The cancun-related newPayload fields, if any. cancun_fields: Option, + // HACK(onbjerg): We should have a pectra payload fields struct, this is just a temporary + // workaround. + /// The pectra EIP-7685 execution requests. + execution_requests: Option>, /// The sender for returning payload status result. tx: oneshot::Sender>, }, diff --git a/crates/consensus/beacon/src/engine/mod.rs b/crates/consensus/beacon/src/engine/mod.rs index ccea982bfbd9..edd3d6db3239 100644 --- a/crates/consensus/beacon/src/engine/mod.rs +++ b/crates/consensus/beacon/src/engine/mod.rs @@ -1,4 +1,4 @@ -use alloy_primitives::{BlockNumber, B256}; +use alloy_primitives::{BlockNumber, Bytes, B256}; use alloy_rpc_types_engine::{ CancunPayloadFields, ExecutionPayload, ForkchoiceState, PayloadStatus, PayloadStatusEnum, PayloadValidationError, @@ -1085,6 +1085,9 @@ where &mut self, payload: ExecutionPayload, cancun_fields: Option, + // HACK(onbjerg): We should have a pectra payload fields struct, this is just a temporary + // workaround. + execution_requests: Option>, ) -> Result, BeaconOnNewPayloadError> { self.metrics.new_payload_messages.increment(1); @@ -1114,10 +1117,11 @@ where // // This validation **MUST** be instantly run in all cases even during active sync process. let parent_hash = payload.parent_hash(); - let block = match self - .payload_validator - .ensure_well_formed_payload(payload, cancun_fields.into()) - { + let block = match self.payload_validator.ensure_well_formed_payload( + payload, + cancun_fields.into(), + execution_requests, + ) { Ok(block) => block, Err(error) => { error!(target: "consensus::engine", %error, "Invalid payload"); @@ -1862,8 +1866,13 @@ where BeaconEngineMessage::ForkchoiceUpdated { state, payload_attrs, tx } => { this.on_forkchoice_updated(state, payload_attrs, tx); } - BeaconEngineMessage::NewPayload { payload, cancun_fields, tx } => { - match this.on_new_payload(payload, cancun_fields) { + BeaconEngineMessage::NewPayload { + payload, + cancun_fields, + execution_requests, + tx, + } => { + match this.on_new_payload(payload, cancun_fields, execution_requests) { Ok(Either::Right(block)) => { this.set_blockchain_tree_action( BlockchainTreeAction::InsertNewPayload { block, tx }, diff --git a/crates/consensus/beacon/src/engine/test_utils.rs b/crates/consensus/beacon/src/engine/test_utils.rs index 633ae03d8ad9..7e9e1ec6b26d 100644 --- a/crates/consensus/beacon/src/engine/test_utils.rs +++ b/crates/consensus/beacon/src/engine/test_utils.rs @@ -70,7 +70,7 @@ impl TestEnv { payload: T, cancun_fields: Option, ) -> Result { - self.engine_handle.new_payload(payload.into(), cancun_fields).await + self.engine_handle.new_payload(payload.into(), cancun_fields, None).await } /// Sends the `ExecutionPayload` message to the consensus engine and retries if the engine diff --git a/crates/consensus/common/src/validation.rs b/crates/consensus/common/src/validation.rs index 4c2e6b192e72..dabb8c3c34d2 100644 --- a/crates/consensus/common/src/validation.rs +++ b/crates/consensus/common/src/validation.rs @@ -75,24 +75,6 @@ pub fn validate_cancun_gas(block: &SealedBlock) -> Result<(), ConsensusError> { Ok(()) } -/// Validate that requests root is present if Prague is active. -/// -/// See [EIP-7685]: General purpose execution layer requests -/// -/// [EIP-7685]: https://eips.ethereum.org/EIPS/eip-7685 -#[inline] -pub fn validate_prague_request(block: &SealedBlock) -> Result<(), ConsensusError> { - let requests_root = - block.body.calculate_requests_root().ok_or(ConsensusError::BodyRequestsMissing)?; - let header_requests_root = block.requests_root.ok_or(ConsensusError::RequestsRootMissing)?; - if requests_root != *header_requests_root { - return Err(ConsensusError::BodyRequestsRootDiff( - GotExpected { got: requests_root, expected: header_requests_root }.into(), - )); - } - Ok(()) -} - /// Validate a block without regard for state: /// /// - Compares the ommer hash in the block header to the block body @@ -125,10 +107,6 @@ pub fn validate_block_pre_execution( validate_cancun_gas(block)?; } - if chain_spec.is_prague_active_at_timestamp(block.timestamp) { - validate_prague_request(block)?; - } - Ok(()) } @@ -458,7 +436,7 @@ mod tests { blob_gas_used: None, excess_blob_gas: None, parent_beacon_block_root: None, - requests_root: None + requests_hash: None }; // size: 0x9b5 @@ -478,7 +456,7 @@ mod tests { ( SealedBlock { header: SealedHeader::new(header, seal), - body: BlockBody { transactions, ommers, withdrawals: None, requests: None }, + body: BlockBody { transactions, ommers, withdrawals: None }, }, parent, ) @@ -550,7 +528,6 @@ mod tests { transactions: vec![transaction], ommers: vec![], withdrawals: Some(Withdrawals::default()), - requests: None, }; let block = SealedBlock::new(header, body); diff --git a/crates/consensus/consensus/Cargo.toml b/crates/consensus/consensus/Cargo.toml index 660b43865ea7..1736caab5433 100644 --- a/crates/consensus/consensus/Cargo.toml +++ b/crates/consensus/consensus/Cargo.toml @@ -15,6 +15,7 @@ workspace = true reth-primitives.workspace = true # ethereum +alloy-eips.workspace = true alloy-primitives.workspace = true # misc diff --git a/crates/consensus/consensus/src/lib.rs b/crates/consensus/consensus/src/lib.rs index 91b93c8a75e1..4bf5da3b152f 100644 --- a/crates/consensus/consensus/src/lib.rs +++ b/crates/consensus/consensus/src/lib.rs @@ -12,10 +12,11 @@ extern crate alloc; use alloc::{fmt::Debug, vec::Vec}; +use alloy_eips::eip7685::Requests; use alloy_primitives::{BlockHash, BlockNumber, Bloom, B256, U256}; use reth_primitives::{ constants::MINIMUM_GAS_LIMIT, BlockWithSenders, GotExpected, GotExpectedBoxed, Header, - InvalidTransactionError, Receipt, Request, SealedBlock, SealedHeader, + InvalidTransactionError, Receipt, SealedBlock, SealedHeader, }; /// A consensus implementation that does nothing. @@ -31,12 +32,12 @@ pub struct PostExecutionInput<'a> { /// Receipts of the block. pub receipts: &'a [Receipt], /// EIP-7685 requests of the block. - pub requests: &'a [Request], + pub requests: &'a Requests, } impl<'a> PostExecutionInput<'a> { /// Creates a new instance of `PostExecutionInput`. - pub const fn new(receipts: &'a [Receipt], requests: &'a [Request]) -> Self { + pub const fn new(receipts: &'a [Receipt], requests: &'a Requests) -> Self { Self { receipts, requests } } } @@ -170,10 +171,10 @@ pub enum ConsensusError { #[display("mismatched block withdrawals root: {_0}")] BodyWithdrawalsRootDiff(GotExpectedBoxed), - /// Error when the requests root in the block is different from the expected requests - /// root. - #[display("mismatched block requests root: {_0}")] - BodyRequestsRootDiff(GotExpectedBoxed), + /// Error when the requests hash in the block is different from the expected requests + /// hash. + #[display("mismatched block requests hash: {_0}")] + BodyRequestsHashDiff(GotExpectedBoxed), /// Error when a block with a specific hash and number is already known. #[display("block with [hash={hash}, number={number}] is already known")] @@ -248,17 +249,17 @@ pub enum ConsensusError { #[display("missing withdrawals root")] WithdrawalsRootMissing, - /// Error when the requests root is missing. - #[display("missing requests root")] - RequestsRootMissing, + /// Error when the requests hash is missing. + #[display("missing requests hash")] + RequestsHashMissing, /// Error when an unexpected withdrawals root is encountered. #[display("unexpected withdrawals root")] WithdrawalsRootUnexpected, - /// Error when an unexpected requests root is encountered. - #[display("unexpected requests root")] - RequestsRootUnexpected, + /// Error when an unexpected requests hash is encountered. + #[display("unexpected requests hash")] + RequestsHashUnexpected, /// Error when withdrawals are missing. #[display("missing withdrawals")] diff --git a/crates/e2e-test-utils/src/transaction.rs b/crates/e2e-test-utils/src/transaction.rs index 04960304442d..58a25dc12579 100644 --- a/crates/e2e-test-utils/src/transaction.rs +++ b/crates/e2e-test-utils/src/transaction.rs @@ -56,8 +56,7 @@ impl TransactionTestContext { delegate_to: Address, wallet: PrivateKeySigner, ) -> TxEnvelope { - let authorization = - Authorization { chain_id: U256::from(chain_id), address: delegate_to, nonce: 0 }; + let authorization = Authorization { chain_id, address: delegate_to, nonce: 0 }; let signature = wallet .sign_hash_sync(&authorization.signature_hash()) .expect("could not sign authorization"); diff --git a/crates/engine/invalid-block-hooks/src/witness.rs b/crates/engine/invalid-block-hooks/src/witness.rs index bb227e304198..ab73a81904df 100644 --- a/crates/engine/invalid-block-hooks/src/witness.rs +++ b/crates/engine/invalid-block-hooks/src/witness.rs @@ -162,7 +162,7 @@ where let response = ExecutionWitness { state: HashMap::from_iter(state), codes: Default::default(), - keys: Some(state_preimages), + keys: state_preimages, }; let re_executed_witness_path = self.save_file( format!("{}_{}.witness.re_executed.json", block.number, block.hash()), diff --git a/crates/engine/local/src/miner.rs b/crates/engine/local/src/miner.rs index 8bcb7083aab0..552cbd047764 100644 --- a/crates/engine/local/src/miner.rs +++ b/crates/engine/local/src/miner.rs @@ -222,6 +222,8 @@ where self.to_engine.send(BeaconEngineMessage::NewPayload { payload: block_to_payload(payload.block().clone()), cancun_fields, + // todo: prague + execution_requests: None, tx, })?; diff --git a/crates/engine/tree/src/tree/mod.rs b/crates/engine/tree/src/tree/mod.rs index 3eadbbd522db..c63c8fbe2916 100644 --- a/crates/engine/tree/src/tree/mod.rs +++ b/crates/engine/tree/src/tree/mod.rs @@ -7,7 +7,7 @@ use crate::{ use alloy_eips::BlockNumHash; use alloy_primitives::{ map::{HashMap, HashSet}, - BlockNumber, B256, U256, + BlockNumber, Bytes, B256, U256, }; use alloy_rpc_types_engine::{ CancunPayloadFields, ExecutionPayload, ForkchoiceState, PayloadStatus, PayloadStatusEnum, @@ -721,6 +721,7 @@ where &mut self, payload: ExecutionPayload, cancun_fields: Option, + execution_requests: Option>, ) -> Result, InsertBlockFatalError> { trace!(target: "engine::tree", "invoked new payload"); self.metrics.engine.new_payload_messages.increment(1); @@ -751,10 +752,11 @@ where // // This validation **MUST** be instantly run in all cases even during active sync process. let parent_hash = payload.parent_hash(); - let block = match self - .payload_validator - .ensure_well_formed_payload(payload, cancun_fields.into()) - { + let block = match self.payload_validator.ensure_well_formed_payload( + payload, + cancun_fields.into(), + execution_requests, + ) { Ok(block) => block, Err(error) => { error!(target: "engine::tree", %error, "Invalid payload"); @@ -1236,8 +1238,14 @@ where error!(target: "engine::tree", "Failed to send event: {err:?}"); } } - BeaconEngineMessage::NewPayload { payload, cancun_fields, tx } => { - let output = self.on_new_payload(payload, cancun_fields); + BeaconEngineMessage::NewPayload { + payload, + cancun_fields, + execution_requests, + tx, + } => { + let output = + self.on_new_payload(payload, cancun_fields, execution_requests); if let Err(err) = tx.send(output.map(|o| o.outcome).map_err(|e| { reth_beacon_consensus::BeaconOnNewPayloadError::Internal( Box::new(e), @@ -2852,6 +2860,7 @@ mod tests { parent_beacon_block_root: block.parent_beacon_block_root.unwrap(), versioned_hashes: vec![], }), + None, ) .unwrap(); } @@ -3114,7 +3123,7 @@ mod tests { let mut test_harness = TestHarness::new(HOLESKY.clone()); - let outcome = test_harness.tree.on_new_payload(payload.into(), None).unwrap(); + let outcome = test_harness.tree.on_new_payload(payload.into(), None, None).unwrap(); assert!(outcome.outcome.is_syncing()); // ensure block is buffered @@ -3159,6 +3168,7 @@ mod tests { BeaconEngineMessage::NewPayload { payload: payload.clone().into(), cancun_fields: None, + execution_requests: None, tx, } .into(), diff --git a/crates/engine/util/src/engine_store.rs b/crates/engine/util/src/engine_store.rs index 1f3445199611..de193bf3bbe0 100644 --- a/crates/engine/util/src/engine_store.rs +++ b/crates/engine/util/src/engine_store.rs @@ -73,7 +73,13 @@ impl EngineMessageStore { })?, )?; } - BeaconEngineMessage::NewPayload { payload, cancun_fields, tx: _tx } => { + // todo(onbjerg): execution requests + BeaconEngineMessage::NewPayload { + payload, + cancun_fields, + execution_requests: _, + tx: _tx, + } => { let filename = format!("{}-new_payload-{}.json", timestamp, payload.block_hash()); fs::write( self.path.join(filename), diff --git a/crates/engine/util/src/reorg.rs b/crates/engine/util/src/reorg.rs index abfa23a57b32..90b5c90aa952 100644 --- a/crates/engine/util/src/reorg.rs +++ b/crates/engine/util/src/reorg.rs @@ -1,7 +1,7 @@ //! Stream wrapper that simulates reorgs. use alloy_consensus::Transaction; -use alloy_primitives::U256; +use alloy_primitives::{Bytes, U256}; use alloy_rpc_types_engine::{ CancunPayloadFields, ExecutionPayload, ForkchoiceState, PayloadStatus, }; @@ -147,7 +147,12 @@ where let next = ready!(this.stream.poll_next_unpin(cx)); let item = match (next, &this.last_forkchoice_state) { ( - Some(BeaconEngineMessage::NewPayload { payload, cancun_fields, tx }), + Some(BeaconEngineMessage::NewPayload { + payload, + cancun_fields, + execution_requests, + tx, + }), Some(last_forkchoice_state), ) if this.forkchoice_states_forwarded > this.frequency && // Only enter reorg state if new payload attaches to current head. @@ -162,26 +167,29 @@ where // forkchoice state. We will rely on CL to reorg us back to canonical chain. // TODO: This is an expensive blocking operation, ideally it's spawned as a task // so that the stream could yield the control back. - let (reorg_payload, reorg_cancun_fields) = match create_reorg_head( - this.provider, - this.evm_config, - this.payload_validator, - *this.depth, - payload.clone(), - cancun_fields.clone(), - ) { - Ok(result) => result, - Err(error) => { - error!(target: "engine::stream::reorg", %error, "Error attempting to create reorg head"); - // Forward the payload and attempt to create reorg on top of - // the next one - return Poll::Ready(Some(BeaconEngineMessage::NewPayload { - payload, - cancun_fields, - tx, - })) - } - }; + let (reorg_payload, reorg_cancun_fields, reorg_execution_requests) = + match create_reorg_head( + this.provider, + this.evm_config, + this.payload_validator, + *this.depth, + payload.clone(), + cancun_fields.clone(), + execution_requests.clone(), + ) { + Ok(result) => result, + Err(error) => { + error!(target: "engine::stream::reorg", %error, "Error attempting to create reorg head"); + // Forward the payload and attempt to create reorg on top of + // the next one + return Poll::Ready(Some(BeaconEngineMessage::NewPayload { + payload, + cancun_fields, + execution_requests, + tx, + })) + } + }; let reorg_forkchoice_state = ForkchoiceState { finalized_block_hash: last_forkchoice_state.finalized_block_hash, safe_block_hash: last_forkchoice_state.safe_block_hash, @@ -197,11 +205,17 @@ where let queue = VecDeque::from([ // Current payload - BeaconEngineMessage::NewPayload { payload, cancun_fields, tx }, + BeaconEngineMessage::NewPayload { + payload, + cancun_fields, + execution_requests, + tx, + }, // Reorg payload BeaconEngineMessage::NewPayload { payload: reorg_payload, cancun_fields: reorg_cancun_fields, + execution_requests: reorg_execution_requests, tx: reorg_payload_tx, }, // Reorg forkchoice state @@ -236,7 +250,8 @@ fn create_reorg_head( mut depth: usize, next_payload: ExecutionPayload, next_cancun_fields: Option, -) -> RethResult<(ExecutionPayload, Option)> + next_execution_requests: Option>, +) -> RethResult<(ExecutionPayload, Option, Option>)> where Provider: BlockReader + StateProviderFactory, Evm: ConfigureEvm
, @@ -246,7 +261,11 @@ where // Ensure next payload is valid. let next_block = payload_validator - .ensure_well_formed_payload(next_payload, next_cancun_fields.into()) + .ensure_well_formed_payload( + next_payload, + next_cancun_fields.into(), + next_execution_requests, + ) .map_err(RethError::msg)?; // Fetch reorg target block depending on its depth and its parent. @@ -401,7 +420,7 @@ where transactions_root: proofs::calculate_transaction_root(&transactions), receipts_root: outcome.receipts_root_slow(reorg_target.header.number).unwrap(), logs_bloom: outcome.block_logs_bloom(reorg_target.header.number).unwrap(), - requests_root: None, // TODO(prague) + requests_hash: None, // TODO(prague) gas_used: cumulative_gas_used, blob_gas_used: blob_gas_used.map(Into::into), excess_blob_gas: excess_blob_gas.map(Into::into), @@ -411,7 +430,6 @@ where transactions, ommers: reorg_target.body.ommers, withdrawals: reorg_target.body.withdrawals, - requests: None, // TODO(prague) }, } .seal_slow(); @@ -422,5 +440,7 @@ where .header .parent_beacon_block_root .map(|root| CancunPayloadFields { parent_beacon_block_root: root, versioned_hashes }), + // todo(prague) + None, )) } diff --git a/crates/engine/util/src/skip_new_payload.rs b/crates/engine/util/src/skip_new_payload.rs index d2450711ecfc..47c48282eef6 100644 --- a/crates/engine/util/src/skip_new_payload.rs +++ b/crates/engine/util/src/skip_new_payload.rs @@ -41,7 +41,12 @@ where loop { let next = ready!(this.stream.poll_next_unpin(cx)); let item = match next { - Some(BeaconEngineMessage::NewPayload { payload, cancun_fields, tx }) => { + Some(BeaconEngineMessage::NewPayload { + payload, + cancun_fields, + execution_requests, + tx, + }) => { if this.skipped < this.threshold { *this.skipped += 1; tracing::warn!( @@ -56,7 +61,12 @@ where continue } *this.skipped = 0; - Some(BeaconEngineMessage::NewPayload { payload, cancun_fields, tx }) + Some(BeaconEngineMessage::NewPayload { + payload, + cancun_fields, + execution_requests, + tx, + }) } next => next, }; diff --git a/crates/ethereum/consensus/Cargo.toml b/crates/ethereum/consensus/Cargo.toml index af934d3e2b62..bace4195ca63 100644 --- a/crates/ethereum/consensus/Cargo.toml +++ b/crates/ethereum/consensus/Cargo.toml @@ -18,6 +18,7 @@ reth-primitives.workspace = true reth-consensus.workspace = true # alloy +alloy-eips.workspace = true alloy-primitives.workspace = true alloy-consensus.workspace = true diff --git a/crates/ethereum/consensus/src/lib.rs b/crates/ethereum/consensus/src/lib.rs index 8f2a8a720427..dd286584a598 100644 --- a/crates/ethereum/consensus/src/lib.rs +++ b/crates/ethereum/consensus/src/lib.rs @@ -121,11 +121,11 @@ impl Consensu } if self.chain_spec.is_prague_active_at_timestamp(header.timestamp) { - if header.requests_root.is_none() { - return Err(ConsensusError::RequestsRootMissing) + if header.requests_hash.is_none() { + return Err(ConsensusError::RequestsHashMissing) } - } else if header.requests_root.is_some() { - return Err(ConsensusError::RequestsRootUnexpected) + } else if header.requests_hash.is_some() { + return Err(ConsensusError::RequestsHashUnexpected) } Ok(()) diff --git a/crates/ethereum/consensus/src/validation.rs b/crates/ethereum/consensus/src/validation.rs index e510a91ab964..f990ecc57d82 100644 --- a/crates/ethereum/consensus/src/validation.rs +++ b/crates/ethereum/consensus/src/validation.rs @@ -1,7 +1,8 @@ +use alloy_eips::eip7685::Requests; use alloy_primitives::{Bloom, B256}; use reth_chainspec::EthereumHardforks; use reth_consensus::ConsensusError; -use reth_primitives::{gas_spent_by_transactions, BlockWithSenders, GotExpected, Receipt, Request}; +use reth_primitives::{gas_spent_by_transactions, BlockWithSenders, GotExpected, Receipt}; /// Validate a block with regard to execution results: /// @@ -11,7 +12,7 @@ pub fn validate_block_post_execution( block: &BlockWithSenders, chain_spec: &ChainSpec, receipts: &[Receipt], - requests: &[Request], + requests: &Requests, ) -> Result<(), ConsensusError> { // Check if gas used matches the value set in header. let cumulative_gas_used = @@ -36,15 +37,15 @@ pub fn validate_block_post_execution( } } - // Validate that the header requests root matches the calculated requests root + // Validate that the header requests hash matches the calculated requests hash if chain_spec.is_prague_active_at_timestamp(block.timestamp) { - let Some(header_requests_root) = block.header.requests_root else { - return Err(ConsensusError::RequestsRootMissing) + let Some(header_requests_hash) = block.header.requests_hash else { + return Err(ConsensusError::RequestsHashMissing) }; - let requests_root = reth_primitives::proofs::calculate_requests_root(requests); - if requests_root != header_requests_root { - return Err(ConsensusError::BodyRequestsRootDiff( - GotExpected::new(requests_root, header_requests_root).into(), + let requests_hash = requests.requests_hash(); + if requests_hash != header_requests_hash { + return Err(ConsensusError::BodyRequestsHashDiff( + GotExpected::new(requests_hash, header_requests_hash).into(), )) } } diff --git a/crates/ethereum/engine-primitives/src/payload.rs b/crates/ethereum/engine-primitives/src/payload.rs index ae370fdb9d7b..1ad9c5450ee7 100644 --- a/crates/ethereum/engine-primitives/src/payload.rs +++ b/crates/ethereum/engine-primitives/src/payload.rs @@ -1,6 +1,6 @@ //! Contains types required for building a payload. -use alloy_eips::eip4844::BlobTransactionSidecar; +use alloy_eips::{eip4844::BlobTransactionSidecar, eip7685::Requests}; use alloy_primitives::{Address, B256, U256}; use alloy_rlp::Encodable; use alloy_rpc_types_engine::{ @@ -11,8 +11,7 @@ use reth_chain_state::ExecutedBlock; use reth_payload_primitives::{BuiltPayload, PayloadBuilderAttributes}; use reth_primitives::{SealedBlock, Withdrawals}; use reth_rpc_types_compat::engine::payload::{ - block_to_payload_v1, block_to_payload_v3, block_to_payload_v4, - convert_block_to_payload_field_v2, + block_to_payload_v1, block_to_payload_v3, convert_block_to_payload_field_v2, }; use std::convert::Infallible; @@ -142,10 +141,17 @@ impl From for ExecutionPayloadEnvelopeV3 { impl From for ExecutionPayloadEnvelopeV4 { fn from(value: EthBuiltPayload) -> Self { - let EthBuiltPayload { block, fees, sidecars, .. } = value; - + let EthBuiltPayload { block, fees, sidecars, executed_block, .. } = value; + + // if we have an executed block, we pop off the first set of requests from the execution + // outcome. the assumption here is that there will always only be one block in the execution + // outcome. + let execution_requests = executed_block + .and_then(|block| block.execution_outcome().requests.first().cloned()) + .map(Requests::take) + .unwrap_or_default(); Self { - execution_payload: block_to_payload_v4(block), + execution_payload: block_to_payload_v3(block), block_value: fees, // From the engine API spec: // @@ -157,6 +163,7 @@ impl From for ExecutionPayloadEnvelopeV4 { // should_override_builder: false, blobs_bundle: sidecars.into_iter().map(Into::into).collect::>().into(), + execution_requests, } } } diff --git a/crates/ethereum/evm/src/eip6110.rs b/crates/ethereum/evm/src/eip6110.rs index e78becd960cf..4cf1c6ae9da5 100644 --- a/crates/ethereum/evm/src/eip6110.rs +++ b/crates/ethereum/evm/src/eip6110.rs @@ -1,11 +1,11 @@ //! EIP-6110 deposit requests parsing use alloc::{string::ToString, vec::Vec}; -use alloy_eips::eip6110::{DepositRequest, MAINNET_DEPOSIT_CONTRACT_ADDRESS}; -use alloy_primitives::Log; +use alloy_eips::eip6110::MAINNET_DEPOSIT_CONTRACT_ADDRESS; +use alloy_primitives::{Bytes, Log}; use alloy_sol_types::{sol, SolEvent}; use reth_chainspec::ChainSpec; use reth_evm::execute::BlockValidationError; -use reth_primitives::{Receipt, Request}; +use reth_primitives::Receipt; sol! { #[allow(missing_docs)] @@ -20,73 +20,57 @@ sol! { /// Parse [deposit contract](https://etherscan.io/address/0x00000000219ab540356cbb839cbe05303d7705fa) /// (address is from the passed [`ChainSpec`]) deposits from receipts, and return them as a -/// [vector](Vec) of (requests)[Request]. +/// [vector](Vec) of (requests)[`alloy_eips::eip7685::Requests`]. pub fn parse_deposits_from_receipts<'a, I>( chain_spec: &ChainSpec, receipts: I, -) -> Result, BlockValidationError> +) -> Result where I: IntoIterator, { + let mut requests = Vec::new(); let deposit_contract_address = chain_spec .deposit_contract .as_ref() .map_or(MAINNET_DEPOSIT_CONTRACT_ADDRESS, |contract| contract.address); - receipts + let logs: Vec<_> = receipts .into_iter() - .flat_map(|receipt| receipt.logs.iter()) - // No need to filter for topic because there's only one event and that's the Deposit event - // in the deposit contract. + .flat_map(|receipt| &receipt.logs) + // No need to filter for topic because there's only one event and that's the Deposit + // event in the deposit contract. .filter(|log| log.address == deposit_contract_address) - .map(|log| { - let decoded_log = DepositEvent::decode_log(log, false)?; - let deposit = parse_deposit_from_log(&decoded_log); - Ok(Request::DepositRequest(deposit)) - }) - .collect::, _>>() - .map_err(|err: alloy_sol_types::Error| { - BlockValidationError::DepositRequestDecode(err.to_string()) - }) + .collect(); + + for log in &logs { + let decoded_log = + DepositEvent::decode_log(log, false).map_err(|err: alloy_sol_types::Error| { + BlockValidationError::DepositRequestDecode(err.to_string()) + })?; + requests.extend(parse_deposit_from_log(&decoded_log).as_ref()) + } + + Ok(requests.into()) } -fn parse_deposit_from_log(log: &Log) -> DepositRequest { +fn parse_deposit_from_log(log: &Log) -> Bytes { // SAFETY: These `expect` https://github.com/ethereum/consensus-specs/blob/5f48840f4d768bf0e0a8156a3ed06ec333589007/solidity_deposit_contract/deposit_contract.sol#L107-L110 // are safe because the `DepositEvent` is the only event in the deposit contract and the length // checks are done there. - DepositRequest { - pubkey: log - .pubkey - .as_ref() - .try_into() - .expect("pubkey length should be enforced in deposit contract"), - withdrawal_credentials: log - .withdrawal_credentials - .as_ref() - .try_into() - .expect("withdrawal_credentials length should be enforced in deposit contract"), - amount: u64::from_le_bytes( - log.amount - .as_ref() - .try_into() - .expect("amount length should be enforced in deposit contract"), - ), - signature: log - .signature - .as_ref() - .try_into() - .expect("signature length should be enforced in deposit contract"), - index: u64::from_le_bytes( - log.index - .as_ref() - .try_into() - .expect("deposit index length should be enforced in deposit contract"), - ), - } + [ + log.pubkey.as_ref(), + log.withdrawal_credentials.as_ref(), + log.amount.as_ref(), + log.signature.as_ref(), + log.index.as_ref(), + ] + .concat() + .into() } #[cfg(test)] mod tests { use super::*; + use alloy_primitives::bytes; use reth_chainspec::MAINNET; use reth_primitives::TxType; @@ -119,9 +103,12 @@ mod tests { }, ]; - let requests = parse_deposits_from_receipts(&MAINNET, &receipts).unwrap(); - assert_eq!(requests.len(), 2); - assert_eq!(requests[0].as_deposit_request().unwrap().amount, 32e9 as u64); - assert_eq!(requests[1].as_deposit_request().unwrap().amount, 32e9 as u64); + let request_data = parse_deposits_from_receipts(&MAINNET, &receipts).unwrap(); + assert_eq!( + request_data, + bytes!( + "998c8086669bf65e24581cda47d8537966e9f5066fc6ffdcba910a1bfb91eae7a4873fcce166a1c4ea217e6b1afd396201000000000000000000000001c340fb72ed14d4eaa71f7633ee9e33b88d4f39004059730700000098ddbffd700c1aac324cfdf0492ff289223661eb26718ce3651ba2469b22f480d56efab432ed91af05a006bde0c1ea68134e0acd8cacca0c13ad1f716db874b44abfcc966368019753174753bca3af2ea84bc569c46f76592a91e97f311eddece474160000000000a1a2ba870a90e889aa594a0cc1c6feffb94c2d8f65646c937f1f456a315ef649533e25a4614d8f4f66ebdb06481b90af0100000000000000000000000a0f04a231efbc29e1db7d086300ff550211c2f60040597307000000ad416d590e1a7f52baff770a12835b68904efad22cc9f8ba531e50cbbd26f32b9c7373cf6538a0577f501e4d3e3e63e208767bcccaae94e1e3720bfb734a286f9c017d17af46536545ccb7ca94d71f295e71f6d25bf978c09ada6f8d3f7ba039e374160000000000" + ) + ); } } diff --git a/crates/ethereum/evm/src/execute.rs b/crates/ethereum/evm/src/execute.rs index 9c7748a561f0..428458fcd04a 100644 --- a/crates/ethereum/evm/src/execute.rs +++ b/crates/ethereum/evm/src/execute.rs @@ -4,8 +4,9 @@ use crate::{ dao_fork::{DAO_HARDFORK_BENEFICIARY, DAO_HARDKFORK_ACCOUNTS}, EthEvmConfig, }; -use alloc::{boxed::Box, sync::Arc, vec, vec::Vec}; +use alloc::{boxed::Box, sync::Arc, vec::Vec}; use alloy_consensus::Transaction as _; +use alloy_eips::eip7685::Requests; use alloy_primitives::{BlockNumber, U256}; use core::fmt::Display; use reth_chainspec::{ChainSpec, EthereumHardforks, MAINNET}; @@ -19,7 +20,7 @@ use reth_evm::{ ConfigureEvm, }; use reth_execution_types::ExecutionOutcome; -use reth_primitives::{BlockWithSenders, EthereumHardfork, Header, Receipt, Request}; +use reth_primitives::{BlockWithSenders, EthereumHardfork, Header, Receipt}; use reth_prune_types::PruneModes; use reth_revm::{ batch::BlockBatchRecord, @@ -104,7 +105,7 @@ where #[derive(Debug, Clone)] struct EthExecuteOutput { receipts: Vec, - requests: Vec, + requests: Requests, gas_used: u64, } @@ -122,7 +123,7 @@ where EvmConfig: ConfigureEvm
, { /// Executes the transactions in the block and returns the receipts of the transactions in the - /// block, the total gas used and the list of EIP-7685 [requests](Request). + /// block, the total gas used and the list of EIP-7685 [requests](Requests). /// /// This applies the pre-execution and post-execution changes that require an [EVM](Evm), and /// executes the transactions. @@ -205,11 +206,11 @@ where let deposit_requests = crate::eip6110::parse_deposits_from_receipts(&self.chain_spec, &receipts)?; - let post_execution_requests = system_caller.apply_post_execution_changes(&mut evm)?; - - [deposit_requests, post_execution_requests].concat() + let mut requests = Requests::new(vec![deposit_requests]); + requests.extend(system_caller.apply_post_execution_changes(&mut evm)?); + requests } else { - vec![] + Requests::default() }; Ok(EthExecuteOutput { receipts, requests, gas_used: cumulative_gas_used }) @@ -283,7 +284,7 @@ where /// Execute a single block and apply the state changes to the internal state. /// /// Returns the receipts of the transactions in the block, the total gas used and the list of - /// EIP-7685 [requests](Request). + /// EIP-7685 [requests](Requests). /// /// Returns an error if execution fails. fn execute_without_verification_with_state_hook( @@ -494,11 +495,12 @@ where #[cfg(test)] mod tests { use super::*; - use alloy_consensus::{TxLegacy, EMPTY_ROOT_HASH}; + use alloy_consensus::TxLegacy; use alloy_eips::{ eip2935::{HISTORY_STORAGE_ADDRESS, HISTORY_STORAGE_CODE}, eip4788::{BEACON_ROOTS_ADDRESS, BEACON_ROOTS_CODE, SYSTEM_ADDRESS}, eip7002::{WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS, WITHDRAWAL_REQUEST_PREDEPLOY_CODE}, + eip7685::EMPTY_REQUESTS_HASH, }; use alloy_primitives::{b256, fixed_bytes, keccak256, Bytes, TxKind, B256}; use reth_chainspec::{ChainSpecBuilder, ForkCondition}; @@ -583,7 +585,6 @@ mod tests { transactions: vec![], ommers: vec![], withdrawals: None, - requests: None, }, }, senders: vec![], @@ -612,12 +613,7 @@ mod tests { &BlockWithSenders { block: Block { header: header.clone(), - body: BlockBody { - transactions: vec![], - ommers: vec![], - withdrawals: None, - requests: None, - }, + body: BlockBody { transactions: vec![], ommers: vec![], withdrawals: None }, }, senders: vec![], }, @@ -684,7 +680,6 @@ mod tests { transactions: vec![], ommers: vec![], withdrawals: None, - requests: None, }, }, senders: vec![], @@ -739,7 +734,6 @@ mod tests { transactions: vec![], ommers: vec![], withdrawals: None, - requests: None, }, }, senders: vec![], @@ -1016,7 +1010,7 @@ mod tests { parent_hash: B256::random(), timestamp: 1, number: fork_activation_block, - requests_root: Some(EMPTY_ROOT_HASH), + requests_hash: Some(EMPTY_REQUESTS_HASH), ..Header::default() }; let provider = executor_provider(chain_spec); @@ -1075,7 +1069,7 @@ mod tests { parent_hash: B256::random(), timestamp: 1, number: fork_activation_block, - requests_root: Some(EMPTY_ROOT_HASH), + requests_hash: Some(EMPTY_REQUESTS_HASH), ..Header::default() }; @@ -1121,7 +1115,7 @@ mod tests { ); let mut header = chain_spec.genesis_header().clone(); - header.requests_root = Some(EMPTY_ROOT_HASH); + header.requests_hash = Some(EMPTY_REQUESTS_HASH); let header_hash = header.hash_slow(); let provider = executor_provider(chain_spec); @@ -1159,7 +1153,7 @@ mod tests { parent_hash: header_hash, timestamp: 1, number: 1, - requests_root: Some(EMPTY_ROOT_HASH), + requests_hash: Some(EMPTY_REQUESTS_HASH), ..Header::default() }; let header_hash = header.hash_slow(); @@ -1196,7 +1190,7 @@ mod tests { parent_hash: header_hash, timestamp: 1, number: 2, - requests_root: Some(EMPTY_ROOT_HASH), + requests_hash: Some(EMPTY_REQUESTS_HASH), ..Header::default() }; @@ -1254,15 +1248,16 @@ mod tests { HashMap::default(), ); - // https://github.com/lightclient/7002asm/blob/e0d68e04d15f25057af7b6d180423d94b6b3bdb3/test/Contract.t.sol.in#L49-L64 + // https://github.com/lightclient/sys-asm/blob/9282bdb9fd64e024e27f60f507486ffb2183cba2/test/Withdrawal.t.sol.in#L36 let validator_public_key = fixed_bytes!("111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111"); - let withdrawal_amount = fixed_bytes!("2222222222222222"); + let withdrawal_amount = fixed_bytes!("0203040506070809"); let input: Bytes = [&validator_public_key[..], &withdrawal_amount[..]].concat().into(); assert_eq!(input.len(), 56); let mut header = chain_spec.genesis_header().clone(); header.gas_limit = 1_500_000; - header.gas_used = 134_807; + // measured + header.gas_used = 135_856; header.receipts_root = b256!("b31a3e47b902e9211c4d349af4e4c5604ce388471e79ca008907ae4616bb0ed3"); @@ -1272,10 +1267,10 @@ mod tests { chain_id: Some(chain_spec.chain.id()), nonce: 1, gas_price: header.base_fee_per_gas.unwrap().into(), - gas_limit: 134_807, + gas_limit: header.gas_used, to: TxKind::Call(WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS), // `MIN_WITHDRAWAL_REQUEST_FEE` - value: U256::from(1), + value: U256::from(2), input, }), ); @@ -1302,11 +1297,9 @@ mod tests { let receipt = receipts.first().unwrap(); assert!(receipt.success); - let request = requests.first().unwrap(); - let withdrawal_request = request.as_withdrawal_request().unwrap(); - assert_eq!(withdrawal_request.source_address, sender_address); - assert_eq!(withdrawal_request.validator_pubkey, validator_public_key); - assert_eq!(withdrawal_request.amount, u64::from_be_bytes(withdrawal_amount.into())); + assert!(requests[0].is_empty(), "there should be no deposits"); + assert!(!requests[1].is_empty(), "there should be a withdrawal"); + assert!(requests[2].is_empty(), "there should be no consolidations"); } #[test] diff --git a/crates/ethereum/evm/src/strategy.rs b/crates/ethereum/evm/src/strategy.rs index 7a297be498a3..714f673c8582 100644 --- a/crates/ethereum/evm/src/strategy.rs +++ b/crates/ethereum/evm/src/strategy.rs @@ -6,6 +6,7 @@ use crate::{ }; use alloc::sync::Arc; use alloy_consensus::Transaction as _; +use alloy_eips::eip7685::Requests; use core::fmt::Display; use reth_chainspec::{ChainSpec, EthereumHardfork, EthereumHardforks, MAINNET}; use reth_consensus::ConsensusError; @@ -18,7 +19,7 @@ use reth_evm::{ system_calls::{OnStateHook, SystemCaller}, ConfigureEvm, ConfigureEvmEnv, }; -use reth_primitives::{BlockWithSenders, Header, Receipt, Request}; +use reth_primitives::{BlockWithSenders, Header, Receipt}; use reth_revm::{ db::{states::bundle_state::BundleRetention, BundleState}, state_change::post_block_balance_increments, @@ -194,7 +195,7 @@ where block: &BlockWithSenders, total_difficulty: U256, receipts: &[Receipt], - ) -> Result, Self::Error> { + ) -> Result { let env = self.evm_env_for_block(&block.header, total_difficulty); let mut evm = self.evm_config.evm_with_env(&mut self.state, env); @@ -203,12 +204,11 @@ where let deposit_requests = crate::eip6110::parse_deposits_from_receipts(&self.chain_spec, receipts)?; - let post_execution_requests = - self.system_caller.apply_post_execution_changes(&mut evm)?; - - [deposit_requests, post_execution_requests].concat() + let mut requests = Requests::new(vec![deposit_requests]); + requests.extend(self.system_caller.apply_post_execution_changes(&mut evm)?); + requests } else { - vec![] + Requests::default() }; drop(evm); @@ -257,7 +257,7 @@ where &self, block: &BlockWithSenders, receipts: &[Receipt], - requests: &[Request], + requests: &Requests, ) -> Result<(), ConsensusError> { validate_block_post_execution(block, &self.chain_spec.clone(), receipts, requests) } @@ -266,11 +266,12 @@ where #[cfg(test)] mod tests { use super::*; - use alloy_consensus::{TxLegacy, EMPTY_ROOT_HASH}; + use alloy_consensus::TxLegacy; use alloy_eips::{ eip2935::{HISTORY_STORAGE_ADDRESS, HISTORY_STORAGE_CODE}, eip4788::{BEACON_ROOTS_ADDRESS, BEACON_ROOTS_CODE, SYSTEM_ADDRESS}, eip7002::{WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS, WITHDRAWAL_REQUEST_PREDEPLOY_CODE}, + eip7685::EMPTY_REQUESTS_HASH, }; use alloy_primitives::{b256, fixed_bytes, keccak256, Bytes, TxKind, B256}; use reth_chainspec::{ChainSpecBuilder, ForkCondition}; @@ -365,7 +366,6 @@ mod tests { transactions: vec![], ommers: vec![], withdrawals: None, - requests: None, }, }, senders: vec![], @@ -397,7 +397,6 @@ mod tests { transactions: vec![], ommers: vec![], withdrawals: None, - requests: None, }, }, senders: vec![], @@ -468,7 +467,6 @@ mod tests { transactions: vec![], ommers: vec![], withdrawals: None, - requests: None, }, }, senders: vec![], @@ -523,7 +521,6 @@ mod tests { transactions: vec![], ommers: vec![], withdrawals: None, - requests: None, }, }, senders: vec![], @@ -797,7 +794,7 @@ mod tests { parent_hash: B256::random(), timestamp: 1, number: fork_activation_block, - requests_root: Some(EMPTY_ROOT_HASH), + requests_hash: Some(EMPTY_REQUESTS_HASH), ..Header::default() }; let provider = executor_provider(chain_spec); @@ -855,7 +852,7 @@ mod tests { parent_hash: B256::random(), timestamp: 1, number: fork_activation_block, - requests_root: Some(EMPTY_ROOT_HASH), + requests_hash: Some(EMPTY_REQUESTS_HASH), ..Header::default() }; @@ -901,7 +898,7 @@ mod tests { ); let mut header = chain_spec.genesis_header().clone(); - header.requests_root = Some(EMPTY_ROOT_HASH); + header.requests_hash = Some(EMPTY_REQUESTS_HASH); let header_hash = header.hash_slow(); let provider = executor_provider(chain_spec); @@ -938,7 +935,7 @@ mod tests { parent_hash: header_hash, timestamp: 1, number: 1, - requests_root: Some(EMPTY_ROOT_HASH), + requests_hash: Some(EMPTY_REQUESTS_HASH), ..Header::default() }; let header_hash = header.hash_slow(); @@ -977,7 +974,7 @@ mod tests { parent_hash: header_hash, timestamp: 1, number: 2, - requests_root: Some(EMPTY_ROOT_HASH), + requests_hash: Some(EMPTY_REQUESTS_HASH), ..Header::default() }; @@ -1039,15 +1036,16 @@ mod tests { HashMap::default(), ); - // https://github.com/lightclient/7002asm/blob/e0d68e04d15f25057af7b6d180423d94b6b3bdb3/test/Contract.t.sol.in#L49-L64 + // https://github.com/lightclient/sys-asm/blob/9282bdb9fd64e024e27f60f507486ffb2183cba2/test/Withdrawal.t.sol.in#L36 let validator_public_key = fixed_bytes!("111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111"); - let withdrawal_amount = fixed_bytes!("2222222222222222"); + let withdrawal_amount = fixed_bytes!("0203040506070809"); let input: Bytes = [&validator_public_key[..], &withdrawal_amount[..]].concat().into(); assert_eq!(input.len(), 56); let mut header = chain_spec.genesis_header().clone(); header.gas_limit = 1_500_000; - header.gas_used = 134_807; + // measured + header.gas_used = 135_856; header.receipts_root = b256!("b31a3e47b902e9211c4d349af4e4c5604ce388471e79ca008907ae4616bb0ed3"); @@ -1057,10 +1055,10 @@ mod tests { chain_id: Some(chain_spec.chain.id()), nonce: 1, gas_price: header.base_fee_per_gas.unwrap().into(), - gas_limit: 134_807, + gas_limit: header.gas_used, to: TxKind::Call(WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS), // `MIN_WITHDRAWAL_REQUEST_FEE` - value: U256::from(1), + value: U256::from(2), input, }), ); @@ -1087,11 +1085,9 @@ mod tests { let receipt = receipts.first().unwrap(); assert!(receipt.success); - let request = requests.first().unwrap(); - let withdrawal_request = request.as_withdrawal_request().unwrap(); - assert_eq!(withdrawal_request.source_address, sender_address); - assert_eq!(withdrawal_request.validator_pubkey, validator_public_key); - assert_eq!(withdrawal_request.amount, u64::from_be_bytes(withdrawal_amount.into())); + assert!(requests[0].is_empty(), "there should be no deposits"); + assert!(!requests[1].is_empty(), "there should be a withdrawal"); + assert!(requests[2].is_empty(), "there should be no consolidations"); } #[test] diff --git a/crates/ethereum/payload/Cargo.toml b/crates/ethereum/payload/Cargo.toml index ce37a4f8ea4f..443e837b2ed1 100644 --- a/crates/ethereum/payload/Cargo.toml +++ b/crates/ethereum/payload/Cargo.toml @@ -33,8 +33,9 @@ revm.workspace = true revm-primitives.workspace = true # alloy -alloy-primitives.workspace = true +alloy-eips.workspace = true alloy-consensus.workspace = true +alloy-primitives.workspace = true # misc tracing.workspace = true diff --git a/crates/ethereum/payload/src/lib.rs b/crates/ethereum/payload/src/lib.rs index dcf54fc02489..e09228302e4c 100644 --- a/crates/ethereum/payload/src/lib.rs +++ b/crates/ethereum/payload/src/lib.rs @@ -10,6 +10,7 @@ #![allow(clippy::useless_let_if_seq)] use alloy_consensus::EMPTY_OMMER_ROOT_HASH; +use alloy_eips::eip7685::Requests; use alloy_primitives::U256; use reth_basic_payload_builder::{ commit_withdrawals, is_better_payload, BuildArguments, BuildOutcome, PayloadBuilder, @@ -25,7 +26,7 @@ use reth_payload_builder::{EthBuiltPayload, EthPayloadBuilderAttributes}; use reth_payload_primitives::{PayloadBuilderAttributes, PayloadBuilderError}; use reth_primitives::{ constants::{eip4844::MAX_DATA_GAS_PER_BLOCK, BEACON_NONCE}, - proofs::{self, calculate_requests_root}, + proofs::{self}, revm_primitives::{BlockEnv, CfgEnvWithHandlerCfg}, Block, BlockBody, EthereumHardforks, Header, Receipt, }; @@ -308,9 +309,7 @@ where } // calculate the requests and the requests root - let (requests, requests_root) = if chain_spec - .is_prague_active_at_timestamp(attributes.timestamp) - { + let requests = if chain_spec.is_prague_active_at_timestamp(attributes.timestamp) { let deposit_requests = parse_deposits_from_receipts(&chain_spec, receipts.iter().flatten()) .map_err(|err| PayloadBuilderError::Internal(RethError::Execution(err.into())))?; let withdrawal_requests = system_caller @@ -328,11 +327,9 @@ where ) .map_err(|err| PayloadBuilderError::Internal(err.into()))?; - let requests = [deposit_requests, withdrawal_requests, consolidation_requests].concat(); - let requests_root = calculate_requests_root(&requests); - (Some(requests.into()), Some(requests_root)) + Some(Requests::new(vec![deposit_requests, withdrawal_requests, consolidation_requests])) } else { - (None, None) + None }; let WithdrawalsOutcome { withdrawals_root, withdrawals } = @@ -414,13 +411,13 @@ where parent_beacon_block_root: attributes.parent_beacon_block_root, blob_gas_used: blob_gas_used.map(Into::into), excess_blob_gas: excess_blob_gas.map(Into::into), - requests_root, + requests_hash: requests.map(|r| r.requests_hash()), }; // seal the block let block = Block { header, - body: BlockBody { transactions: executed_txs, ommers: vec![], withdrawals, requests }, + body: BlockBody { transactions: executed_txs, ommers: vec![], withdrawals }, }; let sealed_block = block.seal_slow(); diff --git a/crates/evm/execution-types/Cargo.toml b/crates/evm/execution-types/Cargo.toml index 9bd6537326b1..49e9623021e5 100644 --- a/crates/evm/execution-types/Cargo.toml +++ b/crates/evm/execution-types/Cargo.toml @@ -25,7 +25,6 @@ serde = { workspace = true, optional = true } serde_with = { workspace = true, optional = true } [dev-dependencies] -alloy-eips.workspace = true arbitrary.workspace = true bincode.workspace = true rand.workspace = true @@ -35,5 +34,9 @@ reth-primitives = { workspace = true, features = ["arbitrary", "test-utils"] } default = ["std"] optimism = ["reth-primitives/optimism", "revm/optimism"] serde = ["dep:serde", "reth-trie/serde", "revm/serde"] -serde-bincode-compat = ["reth-primitives/serde-bincode-compat", "reth-trie/serde-bincode-compat", "serde_with"] +serde-bincode-compat = [ + "reth-primitives/serde-bincode-compat", + "reth-trie/serde-bincode-compat", + "serde_with", +] std = [] diff --git a/crates/evm/execution-types/src/execute.rs b/crates/evm/execution-types/src/execute.rs index 0cf5d7050793..ae5ad2c0b7c5 100644 --- a/crates/evm/execution-types/src/execute.rs +++ b/crates/evm/execution-types/src/execute.rs @@ -1,5 +1,5 @@ +use alloy_eips::eip7685::Requests; use alloy_primitives::U256; -use reth_primitives::Request; use revm::db::BundleState; /// A helper type for ethereum block inputs that consists of a block and the total difficulty. @@ -33,8 +33,8 @@ pub struct BlockExecutionOutput { pub state: BundleState, /// All the receipts of the transactions in the block. pub receipts: Vec, - /// All the EIP-7685 requests of the transactions in the block. - pub requests: Vec, + /// All the EIP-7685 requests in the block. + pub requests: Requests, /// The total gas used by the block. pub gas_used: u64, } diff --git a/crates/evm/execution-types/src/execution_outcome.rs b/crates/evm/execution-types/src/execution_outcome.rs index 08ddf9e4167b..0fde01547f7e 100644 --- a/crates/evm/execution-types/src/execution_outcome.rs +++ b/crates/evm/execution-types/src/execution_outcome.rs @@ -1,6 +1,7 @@ use crate::BlockExecutionOutput; +use alloy_eips::eip7685::Requests; use alloy_primitives::{Address, BlockNumber, Bloom, Log, B256, U256}; -use reth_primitives::{logs_bloom, Account, Bytecode, Receipt, Receipts, Requests, StorageEntry}; +use reth_primitives::{logs_bloom, Account, Bytecode, Receipt, Receipts, StorageEntry}; use reth_trie::HashedPostState; use revm::{ db::{states::BundleState, BundleAccount}, @@ -357,7 +358,7 @@ impl From<(BlockExecutionOutput, BlockNumber)> for ExecutionOutcome { bundle: value.0.state, receipts: Receipts::from(value.0.receipts), first_block: value.1, - requests: vec![Requests::from(value.0.requests)], + requests: vec![value.0.requests], } } } @@ -365,9 +366,9 @@ impl From<(BlockExecutionOutput, BlockNumber)> for ExecutionOutcome { #[cfg(test)] mod tests { use super::*; - use alloy_eips::{eip6110::DepositRequest, eip7002::WithdrawalRequest}; - use alloy_primitives::{Address, FixedBytes, LogData, B256}; - use reth_primitives::{Receipts, Request, Requests, TxType}; + use alloy_eips::eip7685::Requests; + use alloy_primitives::{bytes, Address, LogData, B256}; + use reth_primitives::{Receipts, TxType}; use std::collections::HashMap; #[test] @@ -393,29 +394,8 @@ mod tests { })]], }; - // Create a Requests object with a vector of requests, including DepositRequest and - // WithdrawalRequest - let requests = vec![Requests(vec![ - Request::DepositRequest(DepositRequest { - pubkey: FixedBytes::<48>::from([1; 48]), - withdrawal_credentials: B256::from([0; 32]), - amount: 1111, - signature: FixedBytes::<96>::from([2; 96]), - index: 222, - }), - Request::DepositRequest(DepositRequest { - pubkey: FixedBytes::<48>::from([23; 48]), - withdrawal_credentials: B256::from([0; 32]), - amount: 34343, - signature: FixedBytes::<96>::from([43; 96]), - index: 1212, - }), - Request::WithdrawalRequest(WithdrawalRequest { - source_address: Address::from([1; 20]), - validator_pubkey: FixedBytes::<48>::from([10; 48]), - amount: 72, - }), - ])]; + // Create a Requests object with a vector of requests + let requests = vec![Requests::new(vec![bytes!("dead"), bytes!("beef"), bytes!("beebee")])]; // Define the first block number let first_block = 123; @@ -657,17 +637,12 @@ mod tests { // Define the first block number let first_block = 123; - // Create a DepositRequest object with specific attributes. - let request = Request::DepositRequest(DepositRequest { - pubkey: FixedBytes::<48>::from([1; 48]), - withdrawal_credentials: B256::from([0; 32]), - amount: 1111, - signature: FixedBytes::<96>::from([2; 96]), - index: 222, - }); + // Create a request. + let request = bytes!("deadbeef"); // Create a vector of Requests containing the request. - let requests = vec![Requests(vec![request]), Requests(vec![request])]; + let requests = + vec![Requests::new(vec![request.clone()]), Requests::new(vec![request.clone()])]; // Create a ExecutionOutcome object with the created bundle, receipts, requests, and // first_block @@ -681,7 +656,7 @@ mod tests { assert_eq!(exec_res.receipts, Receipts { receipt_vec: vec![vec![Some(receipt)]] }); // Assert that the requests are properly cut after reverting to the initial block number. - assert_eq!(exec_res.requests, vec![Requests(vec![request])]); + assert_eq!(exec_res.requests, vec![Requests::new(vec![request])]); // Assert that the revert_to method returns false when attempting to revert to a block // number greater than the initial block number. @@ -709,17 +684,11 @@ mod tests { // Create a Receipts object containing the receipt. let receipts = Receipts { receipt_vec: vec![vec![Some(receipt.clone())]] }; - // Create a DepositRequest object with specific attributes. - let request = Request::DepositRequest(DepositRequest { - pubkey: FixedBytes::<48>::from([1; 48]), - withdrawal_credentials: B256::from([0; 32]), - amount: 1111, - signature: FixedBytes::<96>::from([2; 96]), - index: 222, - }); + // Create a request. + let request = bytes!("deadbeef"); // Create a vector of Requests containing the request. - let requests = vec![Requests(vec![request])]; + let requests = vec![Requests::new(vec![request.clone()])]; // Define the initial block number. let first_block = 123; @@ -739,7 +708,7 @@ mod tests { receipts: Receipts { receipt_vec: vec![vec![Some(receipt.clone())], vec![Some(receipt)]] }, - requests: vec![Requests(vec![request]), Requests(vec![request])], + requests: vec![Requests::new(vec![request.clone()]), Requests::new(vec![request])], first_block: 123, } ); @@ -771,18 +740,15 @@ mod tests { // Define the first block number let first_block = 123; - // Create a DepositRequest object with specific attributes. - let request = Request::DepositRequest(DepositRequest { - pubkey: FixedBytes::<48>::from([1; 48]), - withdrawal_credentials: B256::from([0; 32]), - amount: 1111, - signature: FixedBytes::<96>::from([2; 96]), - index: 222, - }); + // Create a request. + let request = bytes!("deadbeef"); // Create a vector of Requests containing the request. - let requests = - vec![Requests(vec![request]), Requests(vec![request]), Requests(vec![request])]; + let requests = vec![ + Requests::new(vec![request.clone()]), + Requests::new(vec![request.clone()]), + Requests::new(vec![request.clone()]), + ]; // Create a ExecutionOutcome object with the created bundle, receipts, requests, and // first_block @@ -796,7 +762,7 @@ mod tests { let lower_execution_outcome = ExecutionOutcome { bundle: Default::default(), receipts: Receipts { receipt_vec: vec![vec![Some(receipt.clone())]] }, - requests: vec![Requests(vec![request])], + requests: vec![Requests::new(vec![request.clone()])], first_block, }; @@ -806,7 +772,7 @@ mod tests { receipts: Receipts { receipt_vec: vec![vec![Some(receipt.clone())], vec![Some(receipt)]], }, - requests: vec![Requests(vec![request]), Requests(vec![request])], + requests: vec![Requests::new(vec![request.clone()]), Requests::new(vec![request])], first_block: 124, }; diff --git a/crates/evm/src/execute.rs b/crates/evm/src/execute.rs index f52325b43e8f..d7c8590eea85 100644 --- a/crates/evm/src/execute.rs +++ b/crates/evm/src/execute.rs @@ -9,10 +9,11 @@ pub use reth_storage_errors::provider::ProviderError; use crate::system_calls::OnStateHook; use alloc::{boxed::Box, vec::Vec}; +use alloy_eips::eip7685::Requests; use alloy_primitives::BlockNumber; use core::{fmt::Display, marker::PhantomData}; use reth_consensus::ConsensusError; -use reth_primitives::{BlockWithSenders, Receipt, Request}; +use reth_primitives::{BlockWithSenders, Receipt}; use reth_prune_types::PruneModes; use reth_revm::batch::BlockBatchRecord; use revm::{db::BundleState, State}; @@ -190,7 +191,7 @@ pub trait BlockExecutionStrategy { block: &BlockWithSenders, total_difficulty: U256, receipts: &[Receipt], - ) -> Result, Self::Error>; + ) -> Result; /// Returns a reference to the current state. fn state_ref(&self) -> &State; @@ -209,7 +210,7 @@ pub trait BlockExecutionStrategy { &self, block: &BlockWithSenders, receipts: &[Receipt], - requests: &[Request], + requests: &Requests, ) -> Result<(), ConsensusError>; } @@ -450,10 +451,10 @@ where #[cfg(test)] mod tests { use super::*; - use alloy_eips::eip6110::DepositRequest; use alloy_primitives::U256; use reth_chainspec::{ChainSpec, MAINNET}; use revm::db::{CacheDB, EmptyDBTyped}; + use revm_primitives::bytes; use std::sync::Arc; #[derive(Clone, Default)] @@ -545,14 +546,14 @@ mod tests { _evm_config: EvmConfig, state: State, execute_transactions_result: (Vec, u64), - apply_post_execution_changes_result: Vec, + apply_post_execution_changes_result: Requests, finish_result: BundleState, } #[derive(Clone)] struct TestExecutorStrategyFactory { execute_transactions_result: (Vec, u64), - apply_post_execution_changes_result: Vec, + apply_post_execution_changes_result: Requests, finish_result: BundleState, } @@ -607,7 +608,7 @@ mod tests { _block: &BlockWithSenders, _total_difficulty: U256, _receipts: &[Receipt], - ) -> Result, Self::Error> { + ) -> Result { Ok(self.apply_post_execution_changes_result.clone()) } @@ -629,7 +630,7 @@ mod tests { &self, _block: &BlockWithSenders, _receipts: &[Receipt], - _requests: &[Request], + _requests: &Requests, ) -> Result<(), ConsensusError> { Ok(()) } @@ -651,8 +652,7 @@ mod tests { let expected_gas_used = 10; let expected_receipts = vec![Receipt::default()]; let expected_execute_transactions_result = (expected_receipts.clone(), expected_gas_used); - let expected_apply_post_execution_changes_result = - vec![Request::DepositRequest(DepositRequest::default())]; + let expected_apply_post_execution_changes_result = Requests::new(vec![bytes!("deadbeef")]); let expected_finish_result = BundleState::default(); let strategy_factory = TestExecutorStrategyFactory { diff --git a/crates/evm/src/system_calls/eip7002.rs b/crates/evm/src/system_calls/eip7002.rs index 9af944e42a53..5e36f2bdeb93 100644 --- a/crates/evm/src/system_calls/eip7002.rs +++ b/crates/evm/src/system_calls/eip7002.rs @@ -1,10 +1,10 @@ //! [EIP-7002](https://eips.ethereum.org/EIPS/eip-7002) system call implementation. use crate::ConfigureEvm; -use alloc::{boxed::Box, format, string::ToString, vec::Vec}; -use alloy_eips::eip7002::{WithdrawalRequest, WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS}; -use alloy_primitives::{bytes::Buf, Address, Bytes, FixedBytes}; +use alloc::{boxed::Box, format}; +use alloy_eips::eip7002::WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS; +use alloy_primitives::Bytes; use reth_execution_errors::{BlockExecutionError, BlockValidationError}; -use reth_primitives::{Header, Request}; +use reth_primitives::Header; use revm::{interpreter::Host, Database, Evm}; use revm_primitives::{ExecutionResult, ResultAndState}; @@ -62,52 +62,23 @@ where Ok(res) } -/// Parses the withdrawal requests from the execution output. +/// Calls the withdrawals requests system contract, and returns the requests from the execution +/// output. #[inline] -pub(crate) fn post_commit(result: ExecutionResult) -> Result, BlockExecutionError> { - let mut data = match result { +pub(crate) fn post_commit(result: ExecutionResult) -> Result { + match result { ExecutionResult::Success { output, .. } => Ok(output.into_data()), ExecutionResult::Revert { output, .. } => { Err(BlockValidationError::WithdrawalRequestsContractCall { message: format!("execution reverted: {output}"), - }) + } + .into()) } ExecutionResult::Halt { reason, .. } => { Err(BlockValidationError::WithdrawalRequestsContractCall { message: format!("execution halted: {reason:?}"), - }) - } - }?; - - // Withdrawals are encoded as a series of withdrawal requests, each with the following - // format: - // - // +------+--------+--------+ - // | addr | pubkey | amount | - // +------+--------+--------+ - // 20 48 8 - - const WITHDRAWAL_REQUEST_SIZE: usize = 20 + 48 + 8; - let mut withdrawal_requests = Vec::with_capacity(data.len() / WITHDRAWAL_REQUEST_SIZE); - while data.has_remaining() { - if data.remaining() < WITHDRAWAL_REQUEST_SIZE { - return Err(BlockValidationError::WithdrawalRequestsContractCall { - message: "invalid withdrawal request length".to_string(), } .into()) } - - let mut source_address = Address::ZERO; - data.copy_to_slice(source_address.as_mut_slice()); - - let mut validator_pubkey = FixedBytes::<48>::ZERO; - data.copy_to_slice(validator_pubkey.as_mut_slice()); - - let amount = data.get_u64(); - - withdrawal_requests - .push(WithdrawalRequest { source_address, validator_pubkey, amount }.into()); } - - Ok(withdrawal_requests) } diff --git a/crates/evm/src/system_calls/eip7251.rs b/crates/evm/src/system_calls/eip7251.rs index f09d4be81afc..7a55c7a5aeab 100644 --- a/crates/evm/src/system_calls/eip7251.rs +++ b/crates/evm/src/system_calls/eip7251.rs @@ -1,10 +1,10 @@ //! [EIP-7251](https://eips.ethereum.org/EIPS/eip-7251) system call implementation. use crate::ConfigureEvm; -use alloc::{boxed::Box, format, string::ToString, vec::Vec}; -use alloy_eips::eip7251::{ConsolidationRequest, CONSOLIDATION_REQUEST_PREDEPLOY_ADDRESS}; -use alloy_primitives::{bytes::Buf, Address, Bytes, FixedBytes}; +use alloc::{boxed::Box, format}; +use alloy_eips::eip7251::CONSOLIDATION_REQUEST_PREDEPLOY_ADDRESS; +use alloy_primitives::Bytes; use reth_execution_errors::{BlockExecutionError, BlockValidationError}; -use reth_primitives::{Header, Request}; +use reth_primitives::Header; use revm::{interpreter::Host, Database, Evm}; use revm_primitives::{ExecutionResult, ResultAndState}; @@ -64,56 +64,23 @@ where Ok(res) } -/// Parses the consolidation requests from the execution output. +/// Calls the consolidation requests system contract, and returns the requests from the execution +/// output. #[inline] -pub(crate) fn post_commit(result: ExecutionResult) -> Result, BlockExecutionError> { - let mut data = match result { +pub(crate) fn post_commit(result: ExecutionResult) -> Result { + match result { ExecutionResult::Success { output, .. } => Ok(output.into_data()), ExecutionResult::Revert { output, .. } => { Err(BlockValidationError::ConsolidationRequestsContractCall { message: format!("execution reverted: {output}"), - }) + } + .into()) } ExecutionResult::Halt { reason, .. } => { Err(BlockValidationError::ConsolidationRequestsContractCall { message: format!("execution halted: {reason:?}"), - }) - } - }?; - - // Consolidations are encoded as a series of consolidation requests, each with the following - // format: - // - // +------+--------+---------------+ - // | addr | pubkey | target pubkey | - // +------+--------+---------------+ - // 20 48 48 - - const CONSOLIDATION_REQUEST_SIZE: usize = 20 + 48 + 48; - let mut consolidation_requests = Vec::with_capacity(data.len() / CONSOLIDATION_REQUEST_SIZE); - while data.has_remaining() { - if data.remaining() < CONSOLIDATION_REQUEST_SIZE { - return Err(BlockValidationError::ConsolidationRequestsContractCall { - message: "invalid consolidation request length".to_string(), } .into()) } - - let mut source_address = Address::ZERO; - data.copy_to_slice(source_address.as_mut_slice()); - - let mut source_pubkey = FixedBytes::<48>::ZERO; - data.copy_to_slice(source_pubkey.as_mut_slice()); - - let mut target_pubkey = FixedBytes::<48>::ZERO; - data.copy_to_slice(target_pubkey.as_mut_slice()); - - consolidation_requests.push(Request::ConsolidationRequest(ConsolidationRequest { - source_address, - source_pubkey, - target_pubkey, - })); } - - Ok(consolidation_requests) } diff --git a/crates/evm/src/system_calls/mod.rs b/crates/evm/src/system_calls/mod.rs index 5dc3f35bd3a2..d71dcfedabb2 100644 --- a/crates/evm/src/system_calls/mod.rs +++ b/crates/evm/src/system_calls/mod.rs @@ -1,11 +1,13 @@ //! System contract call functions. use crate::ConfigureEvm; -use alloc::{boxed::Box, vec::Vec}; +use alloc::{boxed::Box, vec}; +use alloy_eips::eip7685::Requests; +use alloy_primitives::Bytes; use core::fmt::Display; use reth_chainspec::EthereumHardforks; use reth_execution_errors::BlockExecutionError; -use reth_primitives::{Block, Header, Request}; +use reth_primitives::{Block, Header}; use revm::{Database, DatabaseCommit, Evm}; use revm_primitives::{BlockEnv, CfgEnvWithHandlerCfg, EnvWithHandlerCfg, ResultAndState, B256}; @@ -119,17 +121,18 @@ where pub fn apply_post_execution_changes( &mut self, evm: &mut Evm<'_, Ext, DB>, - ) -> Result, BlockExecutionError> + ) -> Result where DB: Database + DatabaseCommit, DB::Error: Display, { + // todo // Collect all EIP-7685 requests let withdrawal_requests = self.apply_withdrawal_requests_contract_call(evm)?; // Collect all EIP-7251 requests let consolidation_requests = self.apply_consolidation_requests_contract_call(evm)?; - Ok([withdrawal_requests, consolidation_requests].concat()) + Ok(Requests::new(vec![withdrawal_requests, consolidation_requests])) } /// Applies the pre-block call to the EIP-2935 blockhashes contract. @@ -247,7 +250,7 @@ where db: &mut DB, initialized_cfg: &CfgEnvWithHandlerCfg, initialized_block_env: &BlockEnv, - ) -> Result, BlockExecutionError> + ) -> Result where DB: Database + DatabaseCommit, DB::Error: Display, @@ -263,7 +266,7 @@ where pub fn apply_withdrawal_requests_contract_call( &mut self, evm: &mut Evm<'_, Ext, DB>, - ) -> Result, BlockExecutionError> + ) -> Result where DB: Database + DatabaseCommit, DB::Error: Display, @@ -285,7 +288,7 @@ where db: &mut DB, initialized_cfg: &CfgEnvWithHandlerCfg, initialized_block_env: &BlockEnv, - ) -> Result, BlockExecutionError> + ) -> Result where DB: Database + DatabaseCommit, DB::Error: Display, @@ -301,7 +304,7 @@ where pub fn apply_consolidation_requests_contract_call( &mut self, evm: &mut Evm<'_, Ext, DB>, - ) -> Result, BlockExecutionError> + ) -> Result where DB: Database + DatabaseCommit, DB::Error: Display, diff --git a/crates/evm/src/test_utils.rs b/crates/evm/src/test_utils.rs index 261b36420b4b..c20f43dca9d4 100644 --- a/crates/evm/src/test_utils.rs +++ b/crates/evm/src/test_utils.rs @@ -7,6 +7,7 @@ use crate::{ }, system_calls::OnStateHook, }; +use alloy_eips::eip7685::Requests; use alloy_primitives::BlockNumber; use parking_lot::Mutex; use reth_execution_errors::BlockExecutionError; @@ -62,7 +63,10 @@ impl Executor for MockExecutorProvider { Ok(BlockExecutionOutput { state: bundle, receipts: receipts.into_iter().flatten().flatten().collect(), - requests: requests.into_iter().flatten().collect(), + requests: requests.into_iter().fold(Requests::default(), |mut reqs, req| { + reqs.extend(req); + reqs + }), gas_used: 0, }) } diff --git a/crates/exex/exex/src/backfill/test_utils.rs b/crates/exex/exex/src/backfill/test_utils.rs index 1c793975c755..5eaf92bfefc8 100644 --- a/crates/exex/exex/src/backfill/test_utils.rs +++ b/crates/exex/exex/src/backfill/test_utils.rs @@ -10,7 +10,7 @@ use reth_evm::execute::{ }; use reth_evm_ethereum::execute::EthExecutorProvider; use reth_primitives::{ - constants::ETH_TO_WEI, Block, BlockBody, BlockWithSenders, Header, Receipt, Requests, + constants::ETH_TO_WEI, Block, BlockBody, BlockWithSenders, Header, Receipt, SealedBlockWithSenders, Transaction, }; use reth_provider::{ @@ -29,7 +29,7 @@ pub(crate) fn to_execution_outcome( bundle: block_execution_output.state.clone(), receipts: block_execution_output.receipts.clone().into(), first_block: block_number, - requests: vec![Requests(block_execution_output.requests.clone())], + requests: vec![block_execution_output.requests.clone()], } } diff --git a/crates/net/eth-wire-types/src/blocks.rs b/crates/net/eth-wire-types/src/blocks.rs index 6e5483f3a0e0..d60c63fc1f6e 100644 --- a/crates/net/eth-wire-types/src/blocks.rs +++ b/crates/net/eth-wire-types/src/blocks.rs @@ -277,7 +277,7 @@ mod tests { blob_gas_used: None, excess_blob_gas: None, parent_beacon_block_root: None, - requests_root: None + requests_hash: None }, ]), }.encode(&mut data); @@ -312,7 +312,7 @@ mod tests { blob_gas_used: None, excess_blob_gas: None, parent_beacon_block_root: None, - requests_root: None + requests_hash: None }, ]), }; @@ -412,11 +412,10 @@ mod tests { blob_gas_used: None, excess_blob_gas: None, parent_beacon_block_root: None, - requests_root: None + requests_hash: None }, ], withdrawals: None, - requests: None } ]), }; @@ -488,11 +487,10 @@ mod tests { blob_gas_used: None, excess_blob_gas: None, parent_beacon_block_root: None, - requests_root: None + requests_hash: None }, ], withdrawals: None, - requests: None } ]), }; diff --git a/crates/net/eth-wire-types/src/header.rs b/crates/net/eth-wire-types/src/header.rs index b25a7568b222..8c11bfa82bb6 100644 --- a/crates/net/eth-wire-types/src/header.rs +++ b/crates/net/eth-wire-types/src/header.rs @@ -143,7 +143,7 @@ mod tests { blob_gas_used: None, excess_blob_gas: None, parent_beacon_block_root: None, - requests_root: None + requests_hash: None }; assert_eq!(header.hash_slow(), expected_hash); } @@ -256,7 +256,7 @@ mod tests { blob_gas_used: Some(0x020000), excess_blob_gas: Some(0), parent_beacon_block_root: None, - requests_root: None, + requests_hash: None, }; let header = Header::decode(&mut data.as_slice()).unwrap(); @@ -296,7 +296,7 @@ mod tests { parent_beacon_block_root: None, blob_gas_used: Some(0), excess_blob_gas: Some(0x1600000), - requests_root: None, + requests_hash: None, }; let header = Header::decode(&mut data.as_slice()).unwrap(); diff --git a/crates/net/p2p/src/full_block.rs b/crates/net/p2p/src/full_block.rs index 0116f1348810..e5129b686741 100644 --- a/crates/net/p2p/src/full_block.rs +++ b/crates/net/p2p/src/full_block.rs @@ -347,22 +347,6 @@ fn ensure_valid_body_response( _ => return Err(ConsensusError::WithdrawalsRootUnexpected), } - match (header.requests_root, &block.requests) { - (Some(header_requests_root), Some(requests)) => { - let requests = requests.0.as_slice(); - let requests_root = reth_primitives::proofs::calculate_requests_root(requests); - if requests_root != header_requests_root { - return Err(ConsensusError::BodyRequestsRootDiff( - GotExpected { got: requests_root, expected: header_requests_root }.into(), - )) - } - } - (None, None) => { - // this is ok because we assume the fork is not active in this case - } - _ => return Err(ConsensusError::RequestsRootUnexpected), - } - Ok(()) } diff --git a/crates/optimism/evm/Cargo.toml b/crates/optimism/evm/Cargo.toml index a1e2021a4ad7..f251347c58b4 100644 --- a/crates/optimism/evm/Cargo.toml +++ b/crates/optimism/evm/Cargo.toml @@ -23,6 +23,7 @@ reth-prune-types.workspace = true reth-consensus.workspace = true # ethereum +alloy-eips.workspace = true alloy-primitives.workspace = true op-alloy-consensus.workspace = true alloy-consensus.workspace = true @@ -41,8 +42,6 @@ derive_more.workspace = true tracing.workspace = true [dev-dependencies] -alloy-eips.workspace = true - reth-evm = { workspace = true, features = ["test-utils"] } reth-revm = { workspace = true, features = ["test-utils"] } reth-primitives = { workspace = true, features = ["test-utils"] } diff --git a/crates/optimism/evm/src/execute.rs b/crates/optimism/evm/src/execute.rs index 263420623212..3a86f5bbae4a 100644 --- a/crates/optimism/evm/src/execute.rs +++ b/crates/optimism/evm/src/execute.rs @@ -5,6 +5,7 @@ use crate::{ }; use alloc::{boxed::Box, sync::Arc, vec::Vec}; use alloy_consensus::Transaction as _; +use alloy_eips::eip7685::Requests; use alloy_primitives::{BlockNumber, U256}; use core::fmt::Display; use reth_chainspec::{ChainSpec, EthereumHardforks}; @@ -380,7 +381,7 @@ where Ok(BlockExecutionOutput { state: self.state.take_bundle(), receipts, - requests: vec![], + requests: Requests::default(), gas_used, }) } @@ -403,7 +404,7 @@ where Ok(BlockExecutionOutput { state: self.state.take_bundle(), receipts, - requests: vec![], + requests: Requests::default(), gas_used, }) } @@ -429,7 +430,7 @@ where Ok(BlockExecutionOutput { state: self.state.take_bundle(), receipts, - requests: vec![], + requests: Requests::default(), gas_used, }) } diff --git a/crates/optimism/evm/src/lib.rs b/crates/optimism/evm/src/lib.rs index 3eda2878cae4..ffc82fde43cb 100644 --- a/crates/optimism/evm/src/lib.rs +++ b/crates/optimism/evm/src/lib.rs @@ -10,7 +10,6 @@ // The `optimism` feature must be enabled to use this crate. #![cfg(feature = "optimism")] -#[macro_use] extern crate alloc; use alloc::{sync::Arc, vec::Vec}; diff --git a/crates/optimism/evm/src/strategy.rs b/crates/optimism/evm/src/strategy.rs index 9ba43604ea0b..199a8a4d3277 100644 --- a/crates/optimism/evm/src/strategy.rs +++ b/crates/optimism/evm/src/strategy.rs @@ -3,6 +3,7 @@ use crate::{l1::ensure_create2_deployer, OptimismBlockExecutionError, OptimismEvmConfig}; use alloc::{boxed::Box, sync::Arc, vec::Vec}; use alloy_consensus::Transaction as _; +use alloy_eips::eip7685::Requests; use core::fmt::Display; use reth_chainspec::EthereumHardforks; use reth_consensus::ConsensusError; @@ -17,7 +18,7 @@ use reth_evm::{ use reth_optimism_chainspec::OpChainSpec; use reth_optimism_consensus::validate_block_post_execution; use reth_optimism_forks::OptimismHardfork; -use reth_primitives::{BlockWithSenders, Header, Receipt, Request, TxType}; +use reth_primitives::{BlockWithSenders, Header, Receipt, TxType}; use reth_revm::{ db::{states::bundle_state::BundleRetention, BundleState}, state_change::post_block_balance_increments, @@ -235,7 +236,7 @@ where block: &BlockWithSenders, total_difficulty: U256, _receipts: &[Receipt], - ) -> Result, Self::Error> { + ) -> Result { let balance_increments = post_block_balance_increments(&self.chain_spec.clone(), block, total_difficulty); // increment balances @@ -243,7 +244,7 @@ where .increment_balances(balance_increments) .map_err(|_| BlockValidationError::IncrementBalanceFailed)?; - Ok(vec![]) + Ok(Requests::default()) } fn state_ref(&self) -> &State { @@ -267,7 +268,7 @@ where &self, block: &BlockWithSenders, receipts: &[Receipt], - _requests: &[Request], + _requests: &Requests, ) -> Result<(), ConsensusError> { validate_block_post_execution(block, &self.chain_spec.clone(), receipts) } diff --git a/crates/optimism/payload/src/builder.rs b/crates/optimism/payload/src/builder.rs index e590635f524e..b6ab9b87956b 100644 --- a/crates/optimism/payload/src/builder.rs +++ b/crates/optimism/payload/src/builder.rs @@ -507,13 +507,13 @@ where parent_beacon_block_root: attributes.payload_attributes.parent_beacon_block_root, blob_gas_used, excess_blob_gas: excess_blob_gas.map(Into::into), - requests_root: None, + requests_hash: None, }; // seal the block let block = Block { header, - body: BlockBody { transactions: executed_txs, ommers: vec![], withdrawals, requests: None }, + body: BlockBody { transactions: executed_txs, ommers: vec![], withdrawals }, }; let sealed_block = block.seal_slow(); diff --git a/crates/optimism/payload/src/payload.rs b/crates/optimism/payload/src/payload.rs index 122c2fde5269..d5d1620e54b9 100644 --- a/crates/optimism/payload/src/payload.rs +++ b/crates/optimism/payload/src/payload.rs @@ -18,8 +18,7 @@ use reth_primitives::{ transaction::WithEncoded, BlobTransactionSidecar, SealedBlock, TransactionSigned, Withdrawals, }; use reth_rpc_types_compat::engine::payload::{ - block_to_payload_v1, block_to_payload_v3, block_to_payload_v4, - convert_block_to_payload_field_v2, + block_to_payload_v1, block_to_payload_v3, convert_block_to_payload_field_v2, }; use std::sync::Arc; @@ -249,7 +248,7 @@ impl From for OpExecutionPayloadEnvelopeV4 { B256::ZERO }; Self { - execution_payload: block_to_payload_v4(block), + execution_payload: block_to_payload_v3(block), block_value: fees, // From the engine API spec: // @@ -262,6 +261,7 @@ impl From for OpExecutionPayloadEnvelopeV4 { should_override_builder: false, blobs_bundle: sidecars.into_iter().map(Into::into).collect::>().into(), parent_beacon_block_root, + execution_requests: vec![], } } } diff --git a/crates/optimism/primitives/src/bedrock.rs b/crates/optimism/primitives/src/bedrock.rs index bd42298588fe..7153ae3155c7 100644 --- a/crates/optimism/primitives/src/bedrock.rs +++ b/crates/optimism/primitives/src/bedrock.rs @@ -85,7 +85,7 @@ pub const BEDROCK_HEADER: Header = Header { blob_gas_used: None, excess_blob_gas: None, parent_beacon_block_root: None, - requests_root: None, + requests_hash: None, }; /// Bedrock total difficulty on Optimism Mainnet. diff --git a/crates/optimism/rpc/src/eth/receipt.rs b/crates/optimism/rpc/src/eth/receipt.rs index 200b626d8c3a..f2f09cdc7ff4 100644 --- a/crates/optimism/rpc/src/eth/receipt.rs +++ b/crates/optimism/rpc/src/eth/receipt.rs @@ -227,7 +227,6 @@ impl OpReceiptBuilder { from, to, contract_address, - state_root, authorization_list, } = core_receipt; @@ -265,7 +264,6 @@ impl OpReceiptBuilder { from, to, contract_address, - state_root, authorization_list, }; diff --git a/crates/optimism/storage/src/lib.rs b/crates/optimism/storage/src/lib.rs index d435ed1d884a..347b690c5c72 100644 --- a/crates/optimism/storage/src/lib.rs +++ b/crates/optimism/storage/src/lib.rs @@ -16,7 +16,7 @@ mod tests { CompactClientVersion, CompactU256, CompactU64, StoredBlockBodyIndices, StoredBlockOmmers, StoredBlockWithdrawals, }; - use reth_primitives::{Account, Receipt, ReceiptWithBloom, Requests, Withdrawals}; + use reth_primitives::{Account, Receipt, ReceiptWithBloom, Withdrawals}; use reth_prune_types::{PruneCheckpoint, PruneMode, PruneSegment}; use reth_stages_types::{ AccountHashingCheckpoint, CheckpointBlockRange, EntitiesCheckpoint, ExecutionCheckpoint, @@ -74,6 +74,5 @@ mod tests { validate_bitflag_backwards_compat!(StoredBlockWithdrawals, UnusedBits::Zero); validate_bitflag_backwards_compat!(StorageHashingCheckpoint, UnusedBits::NotZero); validate_bitflag_backwards_compat!(Withdrawals, UnusedBits::Zero); - validate_bitflag_backwards_compat!(Requests, UnusedBits::Zero); } } diff --git a/crates/payload/validator/Cargo.toml b/crates/payload/validator/Cargo.toml index 2662b987f889..a96799d7bcec 100644 --- a/crates/payload/validator/Cargo.toml +++ b/crates/payload/validator/Cargo.toml @@ -18,4 +18,6 @@ reth-primitives.workspace = true reth-rpc-types-compat.workspace = true # alloy +alloy-eips.workspace = true +alloy-primitives.workspace = true alloy-rpc-types = { workspace = true, features = ["engine"] } diff --git a/crates/payload/validator/src/lib.rs b/crates/payload/validator/src/lib.rs index 55002b0a98be..fdcd9244a434 100644 --- a/crates/payload/validator/src/lib.rs +++ b/crates/payload/validator/src/lib.rs @@ -8,6 +8,8 @@ #![cfg_attr(not(test), warn(unused_crate_dependencies))] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] +use alloy_eips::eip7685::Requests; +use alloy_primitives::Bytes; use alloy_rpc_types::engine::{ExecutionPayload, MaybeCancunPayloadFields, PayloadError}; use reth_chainspec::EthereumHardforks; use reth_primitives::SealedBlock; @@ -112,12 +114,17 @@ impl ExecutionPayloadValidator { &self, payload: ExecutionPayload, cancun_fields: MaybeCancunPayloadFields, + execution_requests: Option>, ) -> Result { let expected_hash = payload.block_hash(); // First parse the block - let sealed_block = - try_into_block(payload, cancun_fields.parent_beacon_block_root())?.seal_slow(); + let sealed_block = try_into_block( + payload, + cancun_fields.parent_beacon_block_root(), + execution_requests.map(Requests::new), + )? + .seal_slow(); // Ensure the hash included in the payload matches the block hash if expected_hash != sealed_block.hash() { @@ -162,7 +169,7 @@ impl ExecutionPayloadValidator { let shanghai_active = self.is_shanghai_active_at_timestamp(sealed_block.timestamp); if !shanghai_active && sealed_block.body.withdrawals.is_some() { // shanghai not active but withdrawals present - return Err(PayloadError::PreShanghaiBlockWithWitdrawals) + return Err(PayloadError::PreShanghaiBlockWithWithdrawals) } if !self.is_prague_active_at_timestamp(sealed_block.timestamp) && diff --git a/crates/primitives-traits/Cargo.toml b/crates/primitives-traits/Cargo.toml index b34987327ee8..2fec75666568 100644 --- a/crates/primitives-traits/Cargo.toml +++ b/crates/primitives-traits/Cargo.toml @@ -64,4 +64,4 @@ arbitrary = [ "dep:proptest", "dep:proptest-arbitrary-interop", ] -serde-bincode-compat = ["serde_with", "alloy-consensus/serde-bincode-compat"] \ No newline at end of file +serde-bincode-compat = ["serde_with", "alloy-consensus/serde-bincode-compat"] diff --git a/crates/primitives-traits/src/block/body.rs b/crates/primitives-traits/src/block/body.rs index 85eeda166c43..c9b673ec7241 100644 --- a/crates/primitives-traits/src/block/body.rs +++ b/crates/primitives-traits/src/block/body.rs @@ -2,8 +2,8 @@ use alloc::{fmt, vec::Vec}; -use alloy_consensus::{BlockHeader, Request, Transaction, TxType}; -use alloy_eips::eip4895::Withdrawal; +use alloy_consensus::{BlockHeader, Transaction, TxType}; +use alloy_eips::{eip4895::Withdrawal, eip7685::Requests}; use alloy_primitives::{Address, B256}; use crate::Block; @@ -30,9 +30,6 @@ pub trait BlockBody: /// Withdrawals in block. type Withdrawals: Iterator; - /// Requests in block. - type Requests: Iterator; - /// Returns reference to transactions in block. fn transactions(&self) -> &[Self::SignedTransaction]; @@ -43,8 +40,8 @@ pub trait BlockBody: /// Returns reference to uncle block headers. fn ommers(&self) -> &[Self::Header]; - /// Returns [`Request`] in block, if any. - fn requests(&self) -> Option<&Self::Requests>; + /// Returns [`Requests`] in block, if any. + fn requests(&self) -> Option<&Requests>; /// Create a [`Block`] from the body and its header. fn into_block>(self, header: Self::Header) -> T { @@ -63,12 +60,6 @@ pub trait BlockBody: // `Withdrawals` and `Withdrawals` moved to alloy fn calculate_withdrawals_root(&self) -> Option; - /// Calculate the requests root for the block body, if requests exist. If there are no - /// requests, this will return `None`. - // todo: can be default impl if `calculate_requests_root` made into a method on - // `Requests` and `Requests` moved to alloy - fn calculate_requests_root(&self) -> Option; - /// Recover signer addresses for all transactions in the block body. fn recover_signers(&self) -> Option>; diff --git a/crates/primitives-traits/src/header/test_utils.rs b/crates/primitives-traits/src/header/test_utils.rs index ef5c0d025360..c5f6e86b9db1 100644 --- a/crates/primitives-traits/src/header/test_utils.rs +++ b/crates/primitives-traits/src/header/test_utils.rs @@ -37,7 +37,7 @@ pub const fn generate_valid_header( } // Placeholder for future EIP adjustments - header.requests_root = None; + header.requests_hash = None; header } diff --git a/crates/primitives-traits/src/lib.rs b/crates/primitives-traits/src/lib.rs index dd10ac9c5f1e..a77669ec367e 100644 --- a/crates/primitives-traits/src/lib.rs +++ b/crates/primitives-traits/src/lib.rs @@ -29,9 +29,6 @@ pub use transaction::{signed::SignedTransaction, Transaction}; mod integer_list; pub use integer_list::{IntegerList, IntegerListError}; -pub mod request; -pub use request::{Request, Requests}; - pub mod block; pub use block::{body::BlockBody, Block}; diff --git a/crates/primitives-traits/src/mod.rs b/crates/primitives-traits/src/mod.rs deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/crates/primitives-traits/src/request.rs b/crates/primitives-traits/src/request.rs deleted file mode 100644 index c08af3fd6225..000000000000 --- a/crates/primitives-traits/src/request.rs +++ /dev/null @@ -1,58 +0,0 @@ -//! EIP-7685 requests. - -use alloc::vec::Vec; -pub use alloy_consensus::Request; -use alloy_eips::eip7685::{Decodable7685, Encodable7685}; -use alloy_rlp::{Decodable, Encodable}; -use derive_more::{Deref, DerefMut, From, IntoIterator}; -use reth_codecs::{add_arbitrary_tests, Compact}; -use revm_primitives::Bytes; -use serde::{Deserialize, Serialize}; - -/// A list of EIP-7685 requests. -#[derive( - Debug, - Clone, - PartialEq, - Eq, - Default, - Hash, - Deref, - DerefMut, - From, - IntoIterator, - Serialize, - Deserialize, - Compact, -)] -#[cfg_attr(any(test, feature = "arbitrary"), derive(arbitrary::Arbitrary))] -#[add_arbitrary_tests(compact)] -pub struct Requests(pub Vec); - -impl Encodable for Requests { - fn encode(&self, out: &mut dyn bytes::BufMut) { - let mut h = alloy_rlp::Header { list: true, payload_length: 0 }; - - let mut encoded = Vec::new(); - for req in &self.0 { - let encoded_req = req.encoded_7685(); - h.payload_length += encoded_req.len(); - encoded.push(Bytes::from(encoded_req)); - } - - h.encode(out); - for req in encoded { - req.encode(out); - } - } -} - -impl Decodable for Requests { - fn decode(buf: &mut &[u8]) -> alloy_rlp::Result { - Ok( as Decodable>::decode(buf)? - .into_iter() - .map(|bytes| Request::decode_7685(&mut bytes.as_ref())) - .collect::, alloy_eips::eip7685::Eip7685Error>>() - .map(Self)?) - } -} diff --git a/crates/primitives/Cargo.toml b/crates/primitives/Cargo.toml index 8596f8d766c5..05ccd9081a27 100644 --- a/crates/primitives/Cargo.toml +++ b/crates/primitives/Cargo.toml @@ -60,7 +60,6 @@ zstd = { workspace = true, features = ["experimental"], optional = true } # arbitrary utils arbitrary = { workspace = true, features = ["derive"], optional = true } -proptest = { workspace = true, optional = true } [dev-dependencies] # eth @@ -97,7 +96,6 @@ reth-codec = ["dep:reth-codecs", "dep:zstd", "dep:modular-bitfield", "std"] asm-keccak = ["alloy-primitives/asm-keccak"] arbitrary = [ "dep:arbitrary", - "dep:proptest", "alloy-eips/arbitrary", "rand", "reth-codec", diff --git a/crates/primitives/src/alloy_compat.rs b/crates/primitives/src/alloy_compat.rs index 0ac1458c5ac2..917baef66612 100644 --- a/crates/primitives/src/alloy_compat.rs +++ b/crates/primitives/src/alloy_compat.rs @@ -48,9 +48,6 @@ impl TryFrom Option { - None - } -} - /// Ethereum full block. /// /// Withdrawals can be optionally included at the end of the RLP encoded message. @@ -120,7 +109,6 @@ mod block_rlp { transactions: Vec, ommers: Vec
, withdrawals: Option, - requests: Option, } #[derive(RlpEncodable)] @@ -130,50 +118,34 @@ mod block_rlp { transactions: &'a Vec, ommers: &'a Vec
, withdrawals: Option<&'a Withdrawals>, - requests: Option<&'a Requests>, } impl<'a> From<&'a Block> for HelperRef<'a, Header> { fn from(block: &'a Block) -> Self { - let Block { header, body: BlockBody { transactions, ommers, withdrawals, requests } } = - block; - Self { - header, - transactions, - ommers, - withdrawals: withdrawals.as_ref(), - requests: requests.as_ref(), - } + let Block { header, body: BlockBody { transactions, ommers, withdrawals } } = block; + Self { header, transactions, ommers, withdrawals: withdrawals.as_ref() } } } impl<'a> From<&'a SealedBlock> for HelperRef<'a, SealedHeader> { fn from(block: &'a SealedBlock) -> Self { - let SealedBlock { - header, - body: BlockBody { transactions, ommers, withdrawals, requests }, - } = block; - Self { - header, - transactions, - ommers, - withdrawals: withdrawals.as_ref(), - requests: requests.as_ref(), - } + let SealedBlock { header, body: BlockBody { transactions, ommers, withdrawals } } = + block; + Self { header, transactions, ommers, withdrawals: withdrawals.as_ref() } } } impl Decodable for Block { fn decode(b: &mut &[u8]) -> alloy_rlp::Result { - let Helper { header, transactions, ommers, withdrawals, requests } = Helper::decode(b)?; - Ok(Self { header, body: BlockBody { transactions, ommers, withdrawals, requests } }) + let Helper { header, transactions, ommers, withdrawals } = Helper::decode(b)?; + Ok(Self { header, body: BlockBody { transactions, ommers, withdrawals } }) } } impl Decodable for SealedBlock { fn decode(b: &mut &[u8]) -> alloy_rlp::Result { - let Helper { header, transactions, ommers, withdrawals, requests } = Helper::decode(b)?; - Ok(Self { header, body: BlockBody { transactions, ommers, withdrawals, requests } }) + let Helper { header, transactions, ommers, withdrawals } = Helper::decode(b)?; + Ok(Self { header, body: BlockBody { transactions, ommers, withdrawals } }) } } @@ -215,13 +187,7 @@ impl<'a> arbitrary::Arbitrary<'a> for Block { Ok(Self { header: u.arbitrary()?, - body: BlockBody { - transactions, - ommers, - // for now just generate empty requests, see HACK above - requests: u.arbitrary()?, - withdrawals: u.arbitrary()?, - }, + body: BlockBody { transactions, ommers, withdrawals: u.arbitrary()? }, }) } } @@ -570,8 +536,6 @@ pub struct BlockBody { pub ommers: Vec
, /// Withdrawals in the block. pub withdrawals: Option, - /// Requests in the block. - pub requests: Option, } impl BlockBody { @@ -596,12 +560,6 @@ impl BlockBody { self.withdrawals.as_ref().map(|w| crate::proofs::calculate_withdrawals_root(w)) } - /// Calculate the requests root for the block body, if requests exist. If there are no - /// requests, this will return `None`. - pub fn calculate_requests_root(&self) -> Option { - self.requests.as_ref().map(|r| crate::proofs::calculate_requests_root(&r.0)) - } - /// Recover signer addresses for all transactions in the block body. pub fn recover_signers(&self) -> Option> { TransactionSigned::recover_signers(&self.transactions, self.transactions.len()) @@ -670,7 +628,6 @@ impl From for BlockBody { transactions: block.body.transactions, ommers: block.body.ommers, withdrawals: block.body.withdrawals, - requests: block.body.requests, } } } @@ -692,8 +649,7 @@ impl<'a> arbitrary::Arbitrary<'a> for BlockBody { }) .collect::>>()?; - // for now just generate empty requests, see HACK above - Ok(Self { transactions, ommers, requests: None, withdrawals: u.arbitrary()? }) + Ok(Self { transactions, ommers, withdrawals: u.arbitrary()? }) } } @@ -703,7 +659,7 @@ pub(super) mod serde_bincode_compat { use alloc::{borrow::Cow, vec::Vec}; use alloy_consensus::serde_bincode_compat::Header; use alloy_primitives::Address; - use reth_primitives_traits::{serde_bincode_compat::SealedHeader, Requests, Withdrawals}; + use reth_primitives_traits::{serde_bincode_compat::SealedHeader, Withdrawals}; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde_with::{DeserializeAs, SerializeAs}; @@ -729,7 +685,6 @@ pub(super) mod serde_bincode_compat { transactions: Vec>, ommers: Vec>, withdrawals: Cow<'a, Option>, - requests: Cow<'a, Option>, } impl<'a> From<&'a super::BlockBody> for BlockBody<'a> { @@ -738,7 +693,6 @@ pub(super) mod serde_bincode_compat { transactions: value.transactions.iter().map(Into::into).collect(), ommers: value.ommers.iter().map(Into::into).collect(), withdrawals: Cow::Borrowed(&value.withdrawals), - requests: Cow::Borrowed(&value.requests), } } } @@ -749,7 +703,6 @@ pub(super) mod serde_bincode_compat { transactions: value.transactions.into_iter().map(Into::into).collect(), ommers: value.ommers.into_iter().map(Into::into).collect(), withdrawals: value.withdrawals.into_owned(), - requests: value.requests.into_owned(), } } } diff --git a/crates/primitives/src/lib.rs b/crates/primitives/src/lib.rs index a9e8c08203d0..7a9a6bf457fb 100644 --- a/crates/primitives/src/lib.rs +++ b/crates/primitives/src/lib.rs @@ -45,7 +45,7 @@ pub use receipt::{ }; pub use reth_primitives_traits::{ logs_bloom, Account, Bytecode, GotExpected, GotExpectedBoxed, Header, HeaderError, Log, - LogData, Request, Requests, SealedHeader, StorageEntry, Withdrawal, Withdrawals, + LogData, SealedHeader, StorageEntry, Withdrawal, Withdrawals, }; pub use static_file::StaticFileSegment; diff --git a/crates/primitives/src/proofs.rs b/crates/primitives/src/proofs.rs index 4efbb588e10d..1697246702a4 100644 --- a/crates/primitives/src/proofs.rs +++ b/crates/primitives/src/proofs.rs @@ -1,11 +1,11 @@ //! Helper function for calculating Merkle proofs and hashes. use crate::{ - Header, Receipt, ReceiptWithBloom, ReceiptWithBloomRef, Request, TransactionSigned, Withdrawal, + Header, Receipt, ReceiptWithBloom, ReceiptWithBloomRef, TransactionSigned, Withdrawal, }; use alloc::vec::Vec; use alloy_consensus::EMPTY_OMMER_ROOT_HASH; -use alloy_eips::{eip2718::Encodable2718, eip7685::Encodable7685}; +use alloy_eips::eip2718::Encodable2718; use alloy_primitives::{keccak256, B256}; use reth_trie_common::root::{ordered_trie_root, ordered_trie_root_with_encoder}; @@ -29,13 +29,6 @@ pub fn calculate_receipt_root(receipts: &[ReceiptWithBloom]) -> B256 { ordered_trie_root_with_encoder(receipts, |r, buf| r.encode_inner(buf, false)) } -/// Calculate [EIP-7685](https://eips.ethereum.org/EIPS/eip-7685) requests root. -/// -/// NOTE: The requests are encoded as `id + request` -pub fn calculate_requests_root(requests: &[Request]) -> B256 { - ordered_trie_root_with_encoder(requests, |item, buf| item.encode_7685(buf)) -} - /// Calculates the receipt root for a header. pub fn calculate_receipt_root_ref(receipts: &[ReceiptWithBloomRef<'_>]) -> B256 { ordered_trie_root_with_encoder(receipts, |r, buf| r.encode_inner(buf, false)) diff --git a/crates/primitives/src/transaction/mod.rs b/crates/primitives/src/transaction/mod.rs index b7eeeadc8970..1d410da1ea8f 100644 --- a/crates/primitives/src/transaction/mod.rs +++ b/crates/primitives/src/transaction/mod.rs @@ -802,18 +802,6 @@ impl alloy_consensus::Transaction for Transaction { } } - fn to(&self) -> TxKind { - match self { - Self::Legacy(tx) => tx.to(), - Self::Eip2930(tx) => tx.to(), - Self::Eip1559(tx) => tx.to(), - Self::Eip4844(tx) => tx.to(), - Self::Eip7702(tx) => tx.to(), - #[cfg(feature = "optimism")] - Self::Deposit(tx) => tx.to(), - } - } - fn value(&self) -> U256 { match self { Self::Legacy(tx) => tx.value(), @@ -826,7 +814,7 @@ impl alloy_consensus::Transaction for Transaction { } } - fn input(&self) -> &[u8] { + fn input(&self) -> &Bytes { match self { Self::Legacy(tx) => tx.input(), Self::Eip2930(tx) => tx.input(), @@ -885,6 +873,18 @@ impl alloy_consensus::Transaction for Transaction { Self::Deposit(tx) => tx.authorization_list(), } } + + fn kind(&self) -> TxKind { + match self { + Self::Legacy(tx) => tx.kind(), + Self::Eip2930(tx) => tx.kind(), + Self::Eip1559(tx) => tx.kind(), + Self::Eip4844(tx) => tx.kind(), + Self::Eip7702(tx) => tx.kind(), + #[cfg(feature = "optimism")] + Self::Deposit(tx) => tx.kind(), + } + } } /// Signed transaction without its Hash. Used type for inserting into the DB. @@ -1383,15 +1383,11 @@ impl alloy_consensus::Transaction for TransactionSigned { self.deref().priority_fee_or_price() } - fn to(&self) -> TxKind { - alloy_consensus::Transaction::to(self.deref()) - } - fn value(&self) -> U256 { self.deref().value() } - fn input(&self) -> &[u8] { + fn input(&self) -> &Bytes { self.deref().input() } @@ -1410,6 +1406,10 @@ impl alloy_consensus::Transaction for TransactionSigned { fn authorization_list(&self) -> Option<&[SignedAuthorization]> { self.deref().authorization_list() } + + fn kind(&self) -> TxKind { + self.deref().kind() + } } impl From for TransactionSigned { @@ -2242,8 +2242,8 @@ mod tests { let tx = TransactionSigned::decode_2718(&mut data.as_slice()).unwrap(); let sender = tx.recover_signer().unwrap(); assert_eq!(sender, address!("001e2b7dE757bA469a57bF6b23d982458a07eFcE")); - assert_eq!(tx.to(), Some(address!("D9e1459A7A482635700cBc20BBAF52D495Ab9C96")).into()); - assert_eq!(tx.input(), hex!("1b55ba3a")); + assert_eq!(tx.to(), Some(address!("D9e1459A7A482635700cBc20BBAF52D495Ab9C96"))); + assert_eq!(tx.input().as_ref(), hex!("1b55ba3a")); let encoded = tx.encoded_2718(); assert_eq!(encoded.as_ref(), data.to_vec()); } diff --git a/crates/revm/Cargo.toml b/crates/revm/Cargo.toml index b2d3bccde6bc..5772af0dc797 100644 --- a/crates/revm/Cargo.toml +++ b/crates/revm/Cargo.toml @@ -21,6 +21,9 @@ reth-consensus-common.workspace = true reth-prune-types.workspace = true reth-storage-api.workspace = true reth-trie = { workspace = true, optional = true } + +# alloy +alloy-eips.workspace = true alloy-primitives.workspace = true # revm diff --git a/crates/revm/src/batch.rs b/crates/revm/src/batch.rs index a63681aa1321..be3ef0a37821 100644 --- a/crates/revm/src/batch.rs +++ b/crates/revm/src/batch.rs @@ -1,9 +1,10 @@ //! Helper for handling execution of multiple blocks. use alloc::vec::Vec; +use alloy_eips::eip7685::Requests; use alloy_primitives::{map::HashSet, Address, BlockNumber}; use reth_execution_errors::{BlockExecutionError, InternalBlockExecutionError}; -use reth_primitives::{Receipt, Receipts, Request, Requests}; +use reth_primitives::{Receipt, Receipts}; use reth_prune_types::{PruneMode, PruneModes, PruneSegmentError, MINIMUM_PRUNING_DISTANCE}; use revm::db::states::bundle_state::BundleRetention; @@ -170,8 +171,8 @@ impl BlockBatchRecord { } /// Save EIP-7685 requests to the executor. - pub fn save_requests(&mut self, requests: Vec) { - self.requests.push(requests.into()); + pub fn save_requests(&mut self, requests: Requests) { + self.requests.push(requests); } } diff --git a/crates/rpc/rpc-api/src/engine.rs b/crates/rpc/rpc-api/src/engine.rs index eedada8ffa7a..e89f7b8d3982 100644 --- a/crates/rpc/rpc-api/src/engine.rs +++ b/crates/rpc/rpc-api/src/engine.rs @@ -11,8 +11,8 @@ use alloy_rpc_types::{ }; use alloy_rpc_types_engine::{ ClientVersionV1, ExecutionPayloadBodiesV1, ExecutionPayloadInputV2, ExecutionPayloadV1, - ExecutionPayloadV3, ExecutionPayloadV4, ForkchoiceState, ForkchoiceUpdated, PayloadId, - PayloadStatus, TransitionConfiguration, + ExecutionPayloadV3, ForkchoiceState, ForkchoiceUpdated, PayloadId, PayloadStatus, + TransitionConfiguration, }; use alloy_rpc_types_eth::transaction::TransactionRequest; use alloy_serde::JsonStorageKey; @@ -54,9 +54,10 @@ pub trait EngineApi { #[method(name = "newPayloadV4")] async fn new_payload_v4( &self, - payload: ExecutionPayloadV4, + payload: ExecutionPayloadV3, versioned_hashes: Vec, parent_beacon_block_root: B256, + execution_requests: Vec, ) -> RpcResult; /// See also diff --git a/crates/rpc/rpc-engine-api/src/engine_api.rs b/crates/rpc/rpc-engine-api/src/engine_api.rs index fb7f98ed203e..d0b19a7b4d6d 100644 --- a/crates/rpc/rpc-engine-api/src/engine_api.rs +++ b/crates/rpc/rpc-engine-api/src/engine_api.rs @@ -2,11 +2,11 @@ use crate::{ capabilities::EngineCapabilities, metrics::EngineApiMetrics, EngineApiError, EngineApiResult, }; use alloy_eips::eip4844::BlobAndProofV1; -use alloy_primitives::{BlockHash, BlockNumber, B256, U64}; +use alloy_primitives::{BlockHash, BlockNumber, Bytes, B256, U64}; use alloy_rpc_types_engine::{ CancunPayloadFields, ClientVersionV1, ExecutionPayload, ExecutionPayloadBodiesV1, - ExecutionPayloadInputV2, ExecutionPayloadV1, ExecutionPayloadV3, ExecutionPayloadV4, - ForkchoiceState, ForkchoiceUpdated, PayloadId, PayloadStatus, TransitionConfiguration, + ExecutionPayloadInputV2, ExecutionPayloadV1, ExecutionPayloadV3, ForkchoiceState, + ForkchoiceUpdated, PayloadId, PayloadStatus, TransitionConfiguration, }; use async_trait::async_trait; use jsonrpsee_core::RpcResult; @@ -140,7 +140,7 @@ where self.inner .validator .validate_version_specific_fields(EngineApiMessageVersion::V1, payload_or_attrs)?; - Ok(self.inner.beacon_consensus.new_payload(payload, None).await?) + Ok(self.inner.beacon_consensus.new_payload(payload, None, None).await?) } /// See also @@ -156,7 +156,7 @@ where self.inner .validator .validate_version_specific_fields(EngineApiMessageVersion::V2, payload_or_attrs)?; - Ok(self.inner.beacon_consensus.new_payload(payload, None).await?) + Ok(self.inner.beacon_consensus.new_payload(payload, None, None).await?) } /// See also @@ -178,15 +178,18 @@ where let cancun_fields = CancunPayloadFields { versioned_hashes, parent_beacon_block_root }; - Ok(self.inner.beacon_consensus.new_payload(payload, Some(cancun_fields)).await?) + Ok(self.inner.beacon_consensus.new_payload(payload, Some(cancun_fields), None).await?) } /// See also pub async fn new_payload_v4( &self, - payload: ExecutionPayloadV4, + payload: ExecutionPayloadV3, versioned_hashes: Vec, parent_beacon_block_root: B256, + // TODO(onbjerg): Figure out why we even get these here, since we'll check the requests + // from execution against the requests root in the header. + execution_requests: Vec, ) -> EngineApiResult { let payload = ExecutionPayload::from(payload); let payload_or_attrs = @@ -200,7 +203,13 @@ where let cancun_fields = CancunPayloadFields { versioned_hashes, parent_beacon_block_root }; - Ok(self.inner.beacon_consensus.new_payload(payload, Some(cancun_fields)).await?) + // HACK(onbjerg): We should have a pectra payload fields struct, this is just a temporary + // workaround. + Ok(self + .inner + .beacon_consensus + .new_payload(payload, Some(cancun_fields), Some(execution_requests)) + .await?) } /// Sends a message to the beacon consensus engine to update the fork choice _without_ @@ -370,7 +379,7 @@ where .map_err(|_| EngineApiError::UnknownPayload)? .try_into() .map_err(|_| { - warn!("could not transform built payload into ExecutionPayloadV4"); + warn!("could not transform built payload into ExecutionPayloadV3"); EngineApiError::UnknownPayload }) } @@ -665,15 +674,22 @@ where /// See also async fn new_payload_v4( &self, - payload: ExecutionPayloadV4, + payload: ExecutionPayloadV3, versioned_hashes: Vec, parent_beacon_block_root: B256, + execution_requests: Vec, ) -> RpcResult { trace!(target: "rpc::engine", "Serving engine_newPayloadV4"); let start = Instant::now(); - let gas_used = payload.payload_inner.payload_inner.payload_inner.gas_used; - let res = - Self::new_payload_v4(self, payload, versioned_hashes, parent_beacon_block_root).await; + let gas_used = payload.payload_inner.payload_inner.gas_used; + let res = Self::new_payload_v4( + self, + payload, + versioned_hashes, + parent_beacon_block_root, + execution_requests, + ) + .await; let elapsed = start.elapsed(); self.inner.metrics.latency.new_payload_v4.record(elapsed); self.inner.metrics.new_payload_response.update_response_metrics(&res, gas_used, elapsed); diff --git a/crates/rpc/rpc-engine-api/tests/it/payload.rs b/crates/rpc/rpc-engine-api/tests/it/payload.rs index c08c30c1de09..007a62db045b 100644 --- a/crates/rpc/rpc-engine-api/tests/it/payload.rs +++ b/crates/rpc/rpc-engine-api/tests/it/payload.rs @@ -75,7 +75,7 @@ fn payload_validation() { b }); - assert_matches!(try_into_sealed_block(block_with_valid_extra_data, None), Ok(_)); + assert_matches!(try_into_sealed_block(block_with_valid_extra_data, None, None), Ok(_)); // Invalid extra data let block_with_invalid_extra_data = Bytes::from_static(&[0; 33]); @@ -84,7 +84,7 @@ fn payload_validation() { b }); assert_matches!( - try_into_sealed_block(invalid_extra_data_block,None), + try_into_sealed_block(invalid_extra_data_block, None, None), Err(PayloadError::ExtraData(data)) if data == block_with_invalid_extra_data ); @@ -94,8 +94,7 @@ fn payload_validation() { b }); assert_matches!( - - try_into_sealed_block(block_with_zero_base_fee,None), + try_into_sealed_block(block_with_zero_base_fee, None, None), Err(PayloadError::BaseFee(val)) if val.is_zero() ); @@ -114,8 +113,7 @@ fn payload_validation() { b }); assert_matches!( - try_into_sealed_block(block_with_ommers.clone(),None), - + try_into_sealed_block(block_with_ommers.clone(), None, None), Err(PayloadError::BlockHash { consensus, .. }) if consensus == block_with_ommers.block_hash() ); @@ -126,9 +124,8 @@ fn payload_validation() { b }); assert_matches!( - try_into_sealed_block(block_with_difficulty.clone(),None), + try_into_sealed_block(block_with_difficulty.clone(), None, None), Err(PayloadError::BlockHash { consensus, .. }) if consensus == block_with_difficulty.block_hash() - ); // None zero nonce @@ -137,7 +134,7 @@ fn payload_validation() { b }); assert_matches!( - try_into_sealed_block(block_with_nonce.clone(),None), + try_into_sealed_block(block_with_nonce.clone(), None, None), Err(PayloadError::BlockHash { consensus, .. }) if consensus == block_with_nonce.block_hash() ); diff --git a/crates/rpc/rpc-eth-api/src/helpers/pending_block.rs b/crates/rpc/rpc-eth-api/src/helpers/pending_block.rs index 832cf17055a5..5e12e41e5500 100644 --- a/crates/rpc/rpc-eth-api/src/helpers/pending_block.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/pending_block.rs @@ -5,7 +5,8 @@ use std::time::{Duration, Instant}; use crate::{EthApiTypes, FromEthApiError, FromEvmError}; -use alloy_consensus::{EMPTY_OMMER_ROOT_HASH, EMPTY_ROOT_HASH}; +use alloy_consensus::EMPTY_OMMER_ROOT_HASH; +use alloy_eips::eip7685::EMPTY_REQUESTS_HASH; use alloy_primitives::{BlockNumber, B256, U256}; use alloy_rpc_types::BlockNumberOrTag; use futures::Future; @@ -19,7 +20,7 @@ use reth_primitives::{ BlockEnv, CfgEnv, CfgEnvWithHandlerCfg, EVMError, Env, ExecutionResult, InvalidTransaction, ResultAndState, SpecId, }, - Block, BlockBody, Header, Receipt, Requests, SealedBlockWithSenders, SealedHeader, + Block, BlockBody, Header, Receipt, SealedBlockWithSenders, SealedHeader, TransactionSignedEcRecovered, }; use reth_provider::{ @@ -417,14 +418,9 @@ pub trait LoadPendingBlock: EthApiTypes { let blob_gas_used = (cfg.handler_cfg.spec_id >= SpecId::CANCUN).then_some(sum_blob_gas_used); - // note(onbjerg): the rpc spec has not been changed to include requests, so for now we just - // set these to empty - let (requests, requests_root) = - if chain_spec.is_prague_active_at_timestamp(block_env.timestamp.to::()) { - (Some(Requests::default()), Some(EMPTY_ROOT_HASH)) - } else { - (None, None) - }; + let requests_hash = chain_spec + .is_prague_active_at_timestamp(block_env.timestamp.to::()) + .then_some(EMPTY_REQUESTS_HASH); let header = Header { parent_hash, @@ -447,7 +443,7 @@ pub trait LoadPendingBlock: EthApiTypes { excess_blob_gas: block_env.get_blob_excess_gas().map(Into::into), extra_data: Default::default(), parent_beacon_block_root, - requests_root, + requests_hash, }; // Convert Vec> to Vec @@ -456,7 +452,7 @@ pub trait LoadPendingBlock: EthApiTypes { // seal the block let block = Block { header, - body: BlockBody { transactions: executed_txs, ommers: vec![], withdrawals, requests }, + body: BlockBody { transactions: executed_txs, ommers: vec![], withdrawals }, }; Ok((SealedBlockWithSenders { block: block.seal_slow(), senders }, receipts)) } diff --git a/crates/rpc/rpc-eth-types/src/receipt.rs b/crates/rpc/rpc-eth-types/src/receipt.rs index 2668291e2c8c..c3232f2383b8 100644 --- a/crates/rpc/rpc-eth-types/src/receipt.rs +++ b/crates/rpc/rpc-eth-types/src/receipt.rs @@ -102,8 +102,6 @@ impl ReceiptBuilder { gas_used: gas_used as u128, contract_address, effective_gas_price: transaction.effective_gas_price(meta.base_fee), - // TODO pre-byzantium receipts have a post-transaction state root - state_root: None, // EIP-4844 fields blob_gas_price, blob_gas_used: blob_gas_used.map(u128::from), diff --git a/crates/rpc/rpc-types-compat/src/block.rs b/crates/rpc/rpc-types-compat/src/block.rs index fc8ea9e1c487..a650a69c1c1f 100644 --- a/crates/rpc/rpc-types-compat/src/block.rs +++ b/crates/rpc/rpc-types-compat/src/block.rs @@ -124,7 +124,7 @@ pub fn from_primitive_with_hash(primitive_header: reth_primitives::SealedHeader) blob_gas_used, excess_blob_gas, parent_beacon_block_root, - requests_root, + requests_hash, } = header; Header { @@ -150,7 +150,7 @@ pub fn from_primitive_with_hash(primitive_header: reth_primitives::SealedHeader) excess_blob_gas, parent_beacon_block_root, total_difficulty: None, - requests_root, + requests_hash, } } diff --git a/crates/rpc/rpc-types-compat/src/engine/payload.rs b/crates/rpc/rpc-types-compat/src/engine/payload.rs index 3bbee2b00eaa..b63b7453aeb0 100644 --- a/crates/rpc/rpc-types-compat/src/engine/payload.rs +++ b/crates/rpc/rpc-types-compat/src/engine/payload.rs @@ -2,16 +2,18 @@ //! Ethereum's Engine use alloy_consensus::{constants::MAXIMUM_EXTRA_DATA_SIZE, EMPTY_OMMER_ROOT_HASH}; -use alloy_eips::eip2718::{Decodable2718, Encodable2718}; +use alloy_eips::{ + eip2718::{Decodable2718, Encodable2718}, + eip7685::Requests, +}; use alloy_primitives::{B256, U256}; use alloy_rpc_types_engine::{ payload::{ExecutionPayloadBodyV1, ExecutionPayloadFieldV2, ExecutionPayloadInputV2}, - ExecutionPayload, ExecutionPayloadV1, ExecutionPayloadV2, ExecutionPayloadV3, - ExecutionPayloadV4, PayloadError, + ExecutionPayload, ExecutionPayloadV1, ExecutionPayloadV2, ExecutionPayloadV3, PayloadError, }; use reth_primitives::{ proofs::{self}, - Block, BlockBody, Header, Request, SealedBlock, TransactionSigned, Withdrawals, + Block, BlockBody, Header, SealedBlock, TransactionSigned, Withdrawals, }; /// Converts [`ExecutionPayloadV1`] to [`Block`] @@ -67,7 +69,7 @@ pub fn try_payload_v1_to_block(payload: ExecutionPayloadV1) -> Result Result Result { - let ExecutionPayloadV4 { - payload_inner, - deposit_requests, - withdrawal_requests, - consolidation_requests, - } = payload; - let mut block = try_payload_v3_to_block(payload_inner)?; - - // attach requests with asc type identifiers - let requests = deposit_requests - .into_iter() - .map(Request::DepositRequest) - .chain(withdrawal_requests.into_iter().map(Request::WithdrawalRequest)) - .chain(consolidation_requests.into_iter().map(Request::ConsolidationRequest)) - .collect::>(); - - let requests_root = proofs::calculate_requests_root(&requests); - block.header.requests_root = Some(requests_root); - block.body.requests = Some(requests.into()); - - Ok(block) -} - /// Converts [`SealedBlock`] to [`ExecutionPayload`] pub fn block_to_payload(value: SealedBlock) -> ExecutionPayload { - if value.header.requests_root.is_some() { + if value.header.requests_hash.is_some() { // block with requests root: V3 - ExecutionPayload::V4(block_to_payload_v4(value)) + ExecutionPayload::V3(block_to_payload_v3(value)) } else if value.header.parent_beacon_block_root.is_some() { // block with parent beacon block root: V3 ExecutionPayload::V3(block_to_payload_v3(value)) @@ -217,37 +194,6 @@ pub fn block_to_payload_v3(value: SealedBlock) -> ExecutionPayloadV3 { } } -/// Converts [`SealedBlock`] to [`ExecutionPayloadV4`] -pub fn block_to_payload_v4(mut value: SealedBlock) -> ExecutionPayloadV4 { - let (deposit_requests, withdrawal_requests, consolidation_requests) = - value.body.requests.take().unwrap_or_default().into_iter().fold( - (Vec::new(), Vec::new(), Vec::new()), - |(mut deposits, mut withdrawals, mut consolidation_requests), request| { - match request { - Request::DepositRequest(r) => { - deposits.push(r); - } - Request::WithdrawalRequest(r) => { - withdrawals.push(r); - } - Request::ConsolidationRequest(r) => { - consolidation_requests.push(r); - } - _ => {} - }; - - (deposits, withdrawals, consolidation_requests) - }, - ); - - ExecutionPayloadV4 { - deposit_requests, - withdrawal_requests, - consolidation_requests, - payload_inner: block_to_payload_v3(value), - } -} - /// Converts [`SealedBlock`] to [`ExecutionPayloadFieldV2`] pub fn convert_block_to_payload_field_v2(value: SealedBlock) -> ExecutionPayloadFieldV2 { // if there are withdrawals, return V2 @@ -312,15 +258,16 @@ pub fn convert_block_to_payload_input_v2(value: SealedBlock) -> ExecutionPayload pub fn try_into_block( value: ExecutionPayload, parent_beacon_block_root: Option, + execution_requests: Option, ) -> Result { let mut base_payload = match value { ExecutionPayload::V1(payload) => try_payload_v1_to_block(payload)?, ExecutionPayload::V2(payload) => try_payload_v2_to_block(payload)?, ExecutionPayload::V3(payload) => try_payload_v3_to_block(payload)?, - ExecutionPayload::V4(payload) => try_payload_v4_to_block(payload)?, }; base_payload.header.parent_beacon_block_root = parent_beacon_block_root; + base_payload.header.requests_hash = execution_requests.map(|reqs| reqs.requests_hash()); Ok(base_payload) } @@ -338,9 +285,10 @@ pub fn try_into_block( pub fn try_into_sealed_block( payload: ExecutionPayload, parent_beacon_block_root: Option, + execution_requests: Option, ) -> Result { let block_hash = payload.block_hash(); - let base_payload = try_into_block(payload, parent_beacon_block_root)?; + let base_payload = try_into_block(payload, parent_beacon_block_root, execution_requests)?; // validate block hash and return validate_block_hash(block_hash, base_payload) @@ -404,13 +352,12 @@ pub fn execution_payload_from_sealed_block(value: SealedBlock) -> ExecutionPaylo #[cfg(test)] mod tests { use super::{ - block_to_payload_v3, try_into_block, try_payload_v3_to_block, try_payload_v4_to_block, - validate_block_hash, + block_to_payload_v3, try_into_block, try_payload_v3_to_block, validate_block_hash, }; use alloy_primitives::{b256, hex, Bytes, U256}; use alloy_rpc_types_engine::{ CancunPayloadFields, ExecutionPayload, ExecutionPayloadV1, ExecutionPayloadV2, - ExecutionPayloadV3, ExecutionPayloadV4, + ExecutionPayloadV3, }; #[test] @@ -628,60 +575,10 @@ mod tests { let cancun_fields = CancunPayloadFields { parent_beacon_block_root, versioned_hashes }; // convert into block - let block = try_into_block(payload, Some(cancun_fields.parent_beacon_block_root)).unwrap(); + let block = + try_into_block(payload, Some(cancun_fields.parent_beacon_block_root), None).unwrap(); // Ensure the actual hash is calculated if we set the fields to what they should be validate_block_hash(block_hash_with_blob_fee_fields, block).unwrap(); } - - #[test] - fn parse_payload_v4() { - let s = r#"{ - "baseFeePerGas": "0x2ada43", - "blobGasUsed": "0x0", - "blockHash": "0x86eeb2a4b656499f313b601e1dcaedfeacccab27131b6d4ea99bc69a57607f7d", - "blockNumber": "0x2c", - "depositRequests": [ - { - "amount": "0xe8d4a51000", - "index": "0x0", - "pubkey": "0xaab5f2b3aad5c2075faf0c1d8937c7de51a53b765a21b4173eb2975878cea05d9ed3428b77f16a981716aa32af74c464", - "signature": "0xa889cd238be2dae44f2a3c24c04d686c548f6f82eb44d4604e1bc455b6960efb72b117e878068a8f2cfb91ad84b7ebce05b9254207aa51a1e8a3383d75b5a5bd2439f707636ea5b17b2b594b989c93b000b33e5dff6e4bed9d53a6d2d6889b0c", - "withdrawalCredentials": "0x00ab9364f8bf7561862ea0fc3b69c424c94ace406c4dc36ddfbf8a9d72051c80" - }, - { - "amount": "0xe8d4a51000", - "index": "0x1", - "pubkey": "0xb0b1b3b51cf688ead965a954c5cc206ba4e76f3f8efac60656ae708a9aad63487a2ca1fb30ccaf2ebe1028a2b2886b1b", - "signature": "0xb9759766e9bb191b1c457ae1da6cdf71a23fb9d8bc9f845eaa49ee4af280b3b9720ac4d81e64b1b50a65db7b8b4e76f1176a12e19d293d75574600e99fbdfecc1ab48edaeeffb3226cd47691d24473821dad0c6ff3973f03e4aa89f418933a56", - "withdrawalCredentials": "0x002d2b75f4a27f78e585a4735a40ab2437eceb12ec39938a94dc785a54d62513" - } - ], - "excessBlobGas": "0x0", - "extraData": "0x726574682f76302e322e302d626574612e372f6c696e7578", - "feeRecipient": "0x8943545177806ed17b9f23f0a21ee5948ecaa776", - "gasLimit": "0x1855e85", - "gasUsed": "0x25f98", - "logsBloom": "0x10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000", - "parentHash": "0xd753194ef19b5c566b7eca6e9ebcca03895b548e1e93a20a23d922ba0bc210d4", - "prevRandao": "0x8c52256fd491776dc32f531ad4c0dc1444684741bca15f54c9cd40c60142df90", - "receiptsRoot": "0x510e7fb94279897e5dcd6c1795f6137d8fe02e49e871bfea7999fd21a89f66aa", - "stateRoot": "0x59ae0706a2b47162666fc7af3e30ff7aa34154954b68cc6aed58c3af3d58c9c2", - "timestamp": "0x6643c5a9", - "transactions": [ - "0x02f9021e8330182480843b9aca0085174876e80083030d40944242424242424242424242424242424242424242893635c9adc5dea00000b901a422895118000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000012049f42823819771c6bbbd9cb6649850083fd3b6e5d0beb1069342c32d65a3b0990000000000000000000000000000000000000000000000000000000000000030aab5f2b3aad5c2075faf0c1d8937c7de51a53b765a21b4173eb2975878cea05d9ed3428b77f16a981716aa32af74c46400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000ab9364f8bf7561862ea0fc3b69c424c94ace406c4dc36ddfbf8a9d72051c800000000000000000000000000000000000000000000000000000000000000060a889cd238be2dae44f2a3c24c04d686c548f6f82eb44d4604e1bc455b6960efb72b117e878068a8f2cfb91ad84b7ebce05b9254207aa51a1e8a3383d75b5a5bd2439f707636ea5b17b2b594b989c93b000b33e5dff6e4bed9d53a6d2d6889b0cc080a0db786f0d89923949e533680524f003cebd66f32fbd30429a6b6bfbd3258dcf60a05241c54e05574765f7ddc1a742ae06b044edfe02bffb202bf172be97397eeca9", - "0x02f9021e8330182401843b9aca0085174876e80083030d40944242424242424242424242424242424242424242893635c9adc5dea00000b901a422895118000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120d694d6a0b0103651aafd87db6c88297175d7317c6e6da53ccf706c3c991c91fd0000000000000000000000000000000000000000000000000000000000000030b0b1b3b51cf688ead965a954c5cc206ba4e76f3f8efac60656ae708a9aad63487a2ca1fb30ccaf2ebe1028a2b2886b1b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020002d2b75f4a27f78e585a4735a40ab2437eceb12ec39938a94dc785a54d625130000000000000000000000000000000000000000000000000000000000000060b9759766e9bb191b1c457ae1da6cdf71a23fb9d8bc9f845eaa49ee4af280b3b9720ac4d81e64b1b50a65db7b8b4e76f1176a12e19d293d75574600e99fbdfecc1ab48edaeeffb3226cd47691d24473821dad0c6ff3973f03e4aa89f418933a56c080a099dc5b94a51e9b91a6425b1fed9792863006496ab71a4178524819d7db0c5e88a0119748e62700234079d91ae80f4676f9e0f71b260e9b46ef9b4aff331d3c2318" - ], - "withdrawalRequests": [], - "withdrawals": [], - "consolidationRequests": [] - }"#; - - let payload = serde_json::from_str::(s).unwrap(); - let mut block = try_payload_v4_to_block(payload).unwrap(); - block.header.parent_beacon_block_root = - Some(b256!("d9851db05fa63593f75e2b12c4bba9f47740613ca57da3b523a381b8c27f3297")); - let hash = block.seal_slow().hash(); - assert_eq!(hash, b256!("86eeb2a4b656499f313b601e1dcaedfeacccab27131b6d4ea99bc69a57607f7d")) - } } diff --git a/crates/rpc/rpc/src/debug.rs b/crates/rpc/rpc/src/debug.rs index 164f402e44cc..66465ef474aa 100644 --- a/crates/rpc/rpc/src/debug.rs +++ b/crates/rpc/rpc/src/debug.rs @@ -686,7 +686,7 @@ where let state = state_provider.witness(Default::default(), hashed_state).map_err(Into::into)?; - Ok(ExecutionWitness { state: state.into_iter().collect(), codes, keys: Some(keys) }) + Ok(ExecutionWitness { state: state.into_iter().collect(), codes, keys }) }) .await } diff --git a/crates/rpc/rpc/src/otterscan.rs b/crates/rpc/rpc/src/otterscan.rs index 45722978f9f5..024bdd172fb9 100644 --- a/crates/rpc/rpc/src/otterscan.rs +++ b/crates/rpc/rpc/src/otterscan.rs @@ -261,7 +261,6 @@ where from: receipt.from(), to: receipt.to(), contract_address: receipt.contract_address(), - state_root: receipt.state_root(), authorization_list: receipt .authorization_list() .map(<[SignedAuthorization]>::to_vec), diff --git a/crates/rpc/rpc/src/txpool.rs b/crates/rpc/rpc/src/txpool.rs index d40cdc5cdbbf..47aaac0bbfd5 100644 --- a/crates/rpc/rpc/src/txpool.rs +++ b/crates/rpc/rpc/src/txpool.rs @@ -101,7 +101,7 @@ where entry.insert( tx.nonce().to_string(), TxpoolInspectSummary { - to: tx.to().into(), + to: tx.to(), value: tx.value(), gas: tx.gas_limit() as u128, gas_price: tx.transaction.max_fee_per_gas(), diff --git a/crates/stages/stages/src/stages/bodies.rs b/crates/stages/stages/src/stages/bodies.rs index 2d441dee292a..93d8a1229921 100644 --- a/crates/stages/stages/src/stages/bodies.rs +++ b/crates/stages/stages/src/stages/bodies.rs @@ -121,7 +121,6 @@ where let mut tx_block_cursor = tx.cursor_write::()?; let mut ommers_cursor = tx.cursor_write::()?; let mut withdrawals_cursor = tx.cursor_write::()?; - let mut requests_cursor = tx.cursor_write::()?; // Get id for the next tx_num of zero if there are no transactions. let mut next_tx_num = tx_block_cursor.last()?.map(|(id, _)| id + 1).unwrap_or_default(); @@ -234,13 +233,6 @@ where .append(block_number, StoredBlockWithdrawals { withdrawals })?; } } - - // Write requests if any - if let Some(requests) = block.body.requests { - if !requests.0.is_empty() { - requests_cursor.append(block_number, requests)?; - } - } } BlockResponse::Empty(_) => {} }; @@ -276,7 +268,6 @@ where let mut body_cursor = tx.cursor_write::()?; let mut ommers_cursor = tx.cursor_write::()?; let mut withdrawals_cursor = tx.cursor_write::()?; - let mut requests_cursor = tx.cursor_write::()?; // Cursors to unwind transitions let mut tx_block_cursor = tx.cursor_write::()?; @@ -296,11 +287,6 @@ where withdrawals_cursor.delete_current()?; } - // Delete the requests entry if any - if requests_cursor.seek_exact(number)?.is_some() { - requests_cursor.delete_current()?; - } - // Delete all transaction to block values. if !block_meta.is_empty() && tx_block_cursor.seek_exact(block_meta.last_tx_num())?.is_some() diff --git a/crates/storage/codecs/src/alloy/authorization_list.rs b/crates/storage/codecs/src/alloy/authorization_list.rs index 3efe13590622..2b013c0d3c52 100644 --- a/crates/storage/codecs/src/alloy/authorization_list.rs +++ b/crates/storage/codecs/src/alloy/authorization_list.rs @@ -13,7 +13,7 @@ use reth_codecs_derive::add_arbitrary_tests; #[cfg_attr(test, derive(arbitrary::Arbitrary, serde::Serialize, serde::Deserialize))] #[add_arbitrary_tests(compact)] pub(crate) struct Authorization { - chain_id: U256, + chain_id: u64, address: Address, nonce: u64, } @@ -78,7 +78,7 @@ mod tests { #[test] fn test_roundtrip_compact_authorization_list_item() { let authorization = AlloyAuthorization { - chain_id: U256::from(1), + chain_id: 1u64, address: address!("dac17f958d2ee523a2206206994597c13d831ec7"), nonce: 1, } diff --git a/crates/storage/codecs/src/alloy/header.rs b/crates/storage/codecs/src/alloy/header.rs index 623eded9ee99..90e67b1e312c 100644 --- a/crates/storage/codecs/src/alloy/header.rs +++ b/crates/storage/codecs/src/alloy/header.rs @@ -45,7 +45,7 @@ pub(crate) struct Header { #[cfg_attr(test, derive(serde::Serialize, serde::Deserialize))] #[derive(Debug, Clone, PartialEq, Eq, Hash, Default, Compact)] pub(crate) struct HeaderExt { - requests_root: Option, + requests_hash: Option, } impl HeaderExt { @@ -53,7 +53,7 @@ impl HeaderExt { /// /// Required since [`Header`] uses `Option` as a field. const fn into_option(self) -> Option { - if self.requests_root.is_some() { + if self.requests_hash.is_some() { Some(self) } else { None @@ -66,7 +66,7 @@ impl Compact for AlloyHeader { where B: bytes::BufMut + AsMut<[u8]>, { - let extra_fields = HeaderExt { requests_root: self.requests_root }; + let extra_fields = HeaderExt { requests_hash: self.requests_hash }; let header = Header { parent_hash: self.parent_hash, @@ -116,7 +116,7 @@ impl Compact for AlloyHeader { blob_gas_used: header.blob_gas_used, excess_blob_gas: header.excess_blob_gas, parent_beacon_block_root: header.parent_beacon_block_root, - requests_root: header.extra_fields.and_then(|h| h.requests_root), + requests_hash: header.extra_fields.and_then(|h| h.requests_hash), extra_data: header.extra_data, }; (alloy_header, buf) @@ -176,7 +176,7 @@ mod tests { #[test] fn test_extra_fields() { let mut header = HOLESKY_BLOCK; - header.extra_fields = Some(HeaderExt { requests_root: Some(B256::random()) }); + header.extra_fields = Some(HeaderExt { requests_hash: Some(B256::random()) }); let mut encoded_header = vec![]; let len = header.to_compact(&mut encoded_header); diff --git a/crates/storage/codecs/src/alloy/mod.rs b/crates/storage/codecs/src/alloy/mod.rs index 942258d0647e..ed77876c5ce1 100644 --- a/crates/storage/codecs/src/alloy/mod.rs +++ b/crates/storage/codecs/src/alloy/mod.rs @@ -3,7 +3,6 @@ mod authorization_list; mod genesis_account; mod header; mod log; -mod request; mod signature; mod transaction; mod trie; @@ -14,7 +13,6 @@ mod withdrawal; mod tests { use crate::{ alloy::{ - authorization_list::Authorization, genesis_account::{GenesisAccount, GenesisAccountRef, StorageEntries, StorageEntry}, header::{Header, HeaderExt}, transaction::{ @@ -38,7 +36,6 @@ mod tests { validate_bitflag_backwards_compat!(StorageEntries, UnusedBits::Zero); validate_bitflag_backwards_compat!(StorageEntry, UnusedBits::Zero); - validate_bitflag_backwards_compat!(Authorization, UnusedBits::NotZero); validate_bitflag_backwards_compat!(GenesisAccountRef<'_>, UnusedBits::NotZero); validate_bitflag_backwards_compat!(GenesisAccount, UnusedBits::NotZero); validate_bitflag_backwards_compat!(TxEip1559, UnusedBits::NotZero); diff --git a/crates/storage/codecs/src/alloy/request.rs b/crates/storage/codecs/src/alloy/request.rs deleted file mode 100644 index 2447160beb6d..000000000000 --- a/crates/storage/codecs/src/alloy/request.rs +++ /dev/null @@ -1,40 +0,0 @@ -//! Native Compact codec impl for EIP-7685 requests. - -use crate::Compact; -use alloy_consensus::Request; -use alloy_eips::eip7685::{Decodable7685, Encodable7685}; -use alloy_primitives::Bytes; -use bytes::BufMut; - -impl Compact for Request { - fn to_compact(&self, buf: &mut B) -> usize - where - B: BufMut + AsMut<[u8]>, - { - let encoded: Bytes = self.encoded_7685().into(); - encoded.to_compact(buf) - } - - fn from_compact(buf: &[u8], _: usize) -> (Self, &[u8]) { - let (raw, buf) = Bytes::from_compact(buf, buf.len()); - - (Self::decode_7685(&mut raw.as_ref()).expect("invalid eip-7685 request in db"), buf) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use proptest::proptest; - use proptest_arbitrary_interop::arb; - - proptest! { - #[test] - fn roundtrip(request in arb::()) { - let mut buf = Vec::::new(); - request.to_compact(&mut buf); - let (decoded, _) = Request::from_compact(&buf, buf.len()); - assert_eq!(request, decoded); - } - } -} diff --git a/crates/storage/db-api/src/models/mod.rs b/crates/storage/db-api/src/models/mod.rs index 0f35a558a352..b077027f2970 100644 --- a/crates/storage/db-api/src/models/mod.rs +++ b/crates/storage/db-api/src/models/mod.rs @@ -8,7 +8,7 @@ use alloy_genesis::GenesisAccount; use alloy_primitives::{Address, Bytes, Log, B256, U256}; use reth_codecs::{add_arbitrary_tests, Compact}; use reth_primitives::{ - Account, Bytecode, Header, Receipt, Requests, StorageEntry, TransactionSignedNoHash, TxType, + Account, Bytecode, Header, Receipt, StorageEntry, TransactionSignedNoHash, TxType, }; use reth_prune_types::{PruneCheckpoint, PruneSegment}; use reth_stages_types::StageCheckpoint; @@ -230,7 +230,6 @@ impl_compression_for_compact!( StageCheckpoint, PruneCheckpoint, ClientVersion, - Requests, // Non-DB GenesisAccount ); @@ -366,6 +365,5 @@ mod tests { validate_bitflag_backwards_compat!(StoredBlockWithdrawals, UnusedBits::Zero); validate_bitflag_backwards_compat!(StorageHashingCheckpoint, UnusedBits::NotZero); validate_bitflag_backwards_compat!(Withdrawals, UnusedBits::Zero); - validate_bitflag_backwards_compat!(Requests, UnusedBits::Zero); } } diff --git a/crates/storage/db/src/tables/mod.rs b/crates/storage/db/src/tables/mod.rs index 83a063903e08..27f58f8a1f3d 100644 --- a/crates/storage/db/src/tables/mod.rs +++ b/crates/storage/db/src/tables/mod.rs @@ -30,9 +30,7 @@ use reth_db_api::{ }, table::{Decode, DupSort, Encode, Table}, }; -use reth_primitives::{ - Account, Bytecode, Header, Receipt, Requests, StorageEntry, TransactionSignedNoHash, -}; +use reth_primitives::{Account, Bytecode, Header, Receipt, StorageEntry, TransactionSignedNoHash}; use reth_primitives_traits::IntegerList; use reth_prune_types::{PruneCheckpoint, PruneSegment}; use reth_stages_types::StageCheckpoint; @@ -404,9 +402,6 @@ tables! { /// Stores the history of client versions that have accessed the database with write privileges by unix timestamp in seconds. table VersionHistory; - /// Stores EIP-7685 EL -> CL requests, indexed by block number. - table BlockRequests; - /// Stores generic chain state info, like the last finalized block. table ChainState; } diff --git a/crates/storage/provider/src/providers/blockchain_provider.rs b/crates/storage/provider/src/providers/blockchain_provider.rs index 9e6f32b33a3b..1866610e3f28 100644 --- a/crates/storage/provider/src/providers/blockchain_provider.rs +++ b/crates/storage/provider/src/providers/blockchain_provider.rs @@ -4,7 +4,7 @@ use crate::{ CanonStateSubscriptions, ChainSpecProvider, ChainStateBlockReader, ChangeSetReader, DatabaseProviderFactory, DatabaseProviderRO, EvmEnvProvider, HeaderProvider, ProviderError, ProviderFactory, PruneCheckpointReader, ReceiptProvider, ReceiptProviderIdExt, - RequestsProvider, StageCheckpointReader, StateProviderBox, StateProviderFactory, StateReader, + StageCheckpointReader, StateProviderBox, StateProviderFactory, StateReader, StaticFileProviderFactory, TransactionVariant, TransactionsProvider, WithdrawalsProvider, }; use alloy_eips::{BlockHashOrNumber, BlockId, BlockNumHash, BlockNumberOrTag, HashOrNumber}; @@ -1200,24 +1200,6 @@ impl WithdrawalsProvider for BlockchainProvider2 { } } -impl RequestsProvider for BlockchainProvider2 { - fn requests_by_block( - &self, - id: BlockHashOrNumber, - timestamp: u64, - ) -> ProviderResult> { - if !self.chain_spec().is_prague_active_at_timestamp(timestamp) { - return Ok(None) - } - - self.get_in_memory_or_storage_by_block( - id, - |db_provider| db_provider.requests_by_block(id, timestamp), - |block_state| Ok(block_state.block_ref().block().body.requests.clone()), - ) - } -} - impl StageCheckpointReader for BlockchainProvider2 { fn get_stage_checkpoint(&self, id: StageId) -> ProviderResult> { self.database.provider()?.get_stage_checkpoint(id) @@ -1747,8 +1729,8 @@ mod tests { use reth_storage_api::{ BlockHashReader, BlockIdReader, BlockNumReader, BlockReader, BlockReaderIdExt, BlockSource, ChangeSetReader, DatabaseProviderFactory, HeaderProvider, ReceiptProvider, - ReceiptProviderIdExt, RequestsProvider, StateProviderFactory, TransactionVariant, - TransactionsProvider, WithdrawalsProvider, + ReceiptProviderIdExt, StateProviderFactory, TransactionVariant, TransactionsProvider, + WithdrawalsProvider, }; use reth_testing_utils::generators::{ self, random_block, random_block_range, random_changeset_range, random_eoa_accounts, @@ -2849,37 +2831,6 @@ mod tests { Ok(()) } - #[test] - fn test_requests_provider() -> eyre::Result<()> { - let mut rng = generators::rng(); - let chain_spec = Arc::new(ChainSpecBuilder::mainnet().prague_activated().build()); - let (provider, database_blocks, in_memory_blocks, _) = - provider_with_chain_spec_and_random_blocks( - &mut rng, - chain_spec.clone(), - TEST_BLOCKS_COUNT, - TEST_BLOCKS_COUNT, - BlockRangeParams { requests_count: Some(1..2), ..Default::default() }, - )?; - - let database_block = database_blocks.first().unwrap().clone(); - let in_memory_block = in_memory_blocks.last().unwrap().clone(); - - let prague_timestamp = - chain_spec.hardforks.fork(EthereumHardfork::Prague).as_timestamp().unwrap(); - - assert_eq!( - provider.requests_by_block(database_block.number.into(), prague_timestamp,)?, - database_block.body.requests.clone() - ); - assert_eq!( - provider.requests_by_block(in_memory_block.number.into(), prague_timestamp,)?, - in_memory_block.body.requests.clone() - ); - - Ok(()) - } - #[test] fn test_state_provider_factory() -> eyre::Result<()> { let mut rng = generators::rng(); diff --git a/crates/storage/provider/src/providers/database/metrics.rs b/crates/storage/provider/src/providers/database/metrics.rs index ba43298c36b5..7e9ee7202c01 100644 --- a/crates/storage/provider/src/providers/database/metrics.rs +++ b/crates/storage/provider/src/providers/database/metrics.rs @@ -61,7 +61,6 @@ pub(crate) enum Action { InsertTransactions, InsertTransactionHashNumbers, InsertBlockWithdrawals, - InsertBlockRequests, InsertBlockBodyIndices, InsertTransactionBlocks, GetNextTxNum, @@ -106,8 +105,6 @@ struct DatabaseProviderMetrics { insert_tx_hash_numbers: Histogram, /// Duration of insert block withdrawals insert_block_withdrawals: Histogram, - /// Duration of insert block requests - insert_block_requests: Histogram, /// Duration of insert block body indices insert_block_body_indices: Histogram, /// Duration of insert transaction blocks @@ -139,7 +136,6 @@ impl DatabaseProviderMetrics { Action::InsertTransactions => self.insert_transactions.record(duration), Action::InsertTransactionHashNumbers => self.insert_tx_hash_numbers.record(duration), Action::InsertBlockWithdrawals => self.insert_block_withdrawals.record(duration), - Action::InsertBlockRequests => self.insert_block_requests.record(duration), Action::InsertBlockBodyIndices => self.insert_block_body_indices.record(duration), Action::InsertTransactionBlocks => self.insert_tx_blocks.record(duration), Action::GetNextTxNum => self.get_next_tx_num.record(duration), diff --git a/crates/storage/provider/src/providers/database/mod.rs b/crates/storage/provider/src/providers/database/mod.rs index 520b514527b2..54186dca6f69 100644 --- a/crates/storage/provider/src/providers/database/mod.rs +++ b/crates/storage/provider/src/providers/database/mod.rs @@ -4,8 +4,8 @@ use crate::{ traits::{BlockSource, ReceiptProvider}, BlockHashReader, BlockNumReader, BlockReader, ChainSpecProvider, DatabaseProviderFactory, EvmEnvProvider, HeaderProvider, HeaderSyncGap, HeaderSyncGapProvider, ProviderError, - PruneCheckpointReader, RequestsProvider, StageCheckpointReader, StateProviderBox, - StaticFileProviderFactory, TransactionVariant, TransactionsProvider, WithdrawalsProvider, + PruneCheckpointReader, StageCheckpointReader, StateProviderBox, StaticFileProviderFactory, + TransactionVariant, TransactionsProvider, WithdrawalsProvider, }; use alloy_eips::BlockHashOrNumber; use alloy_primitives::{Address, BlockHash, BlockNumber, TxHash, TxNumber, B256, U256}; @@ -519,16 +519,6 @@ impl WithdrawalsProvider for ProviderFactory { } } -impl RequestsProvider for ProviderFactory { - fn requests_by_block( - &self, - id: BlockHashOrNumber, - timestamp: u64, - ) -> ProviderResult> { - self.provider()?.requests_by_block(id, timestamp) - } -} - impl StageCheckpointReader for ProviderFactory { fn get_stage_checkpoint(&self, id: StageId) -> ProviderResult> { self.provider()?.get_stage_checkpoint(id) diff --git a/crates/storage/provider/src/providers/database/provider.rs b/crates/storage/provider/src/providers/database/provider.rs index 8140700fabac..308fa364a3d3 100644 --- a/crates/storage/provider/src/providers/database/provider.rs +++ b/crates/storage/provider/src/providers/database/provider.rs @@ -11,10 +11,10 @@ use crate::{ DBProvider, EvmEnvProvider, HashingWriter, HeaderProvider, HeaderSyncGap, HeaderSyncGapProvider, HistoricalStateProvider, HistoricalStateProviderRef, HistoryWriter, LatestStateProvider, LatestStateProviderRef, OriginalValuesKnown, ProviderError, - PruneCheckpointReader, PruneCheckpointWriter, RequestsProvider, RevertsInit, - StageCheckpointReader, StateChangeWriter, StateProviderBox, StateReader, StateWriter, - StaticFileProviderFactory, StatsReader, StorageReader, StorageTrieWriter, TransactionVariant, - TransactionsProvider, TransactionsProviderExt, TrieWriter, WithdrawalsProvider, + PruneCheckpointReader, PruneCheckpointWriter, RevertsInit, StageCheckpointReader, + StateChangeWriter, StateProviderBox, StateReader, StateWriter, StaticFileProviderFactory, + StatsReader, StorageReader, StorageTrieWriter, TransactionVariant, TransactionsProvider, + TransactionsProviderExt, TrieWriter, WithdrawalsProvider, }; use alloy_eips::BlockHashOrNumber; use alloy_primitives::{keccak256, Address, BlockHash, BlockNumber, TxHash, TxNumber, B256, U256}; @@ -40,7 +40,7 @@ use reth_evm::ConfigureEvmEnv; use reth_execution_types::{Chain, ExecutionOutcome}; use reth_network_p2p::headers::downloader::SyncTarget; use reth_primitives::{ - Account, Block, BlockBody, BlockWithSenders, Bytecode, GotExpected, Header, Receipt, Requests, + Account, Block, BlockBody, BlockWithSenders, Bytecode, GotExpected, Header, Receipt, SealedBlock, SealedBlockWithSenders, SealedHeader, StaticFileSegment, StorageEntry, TransactionMeta, TransactionSigned, TransactionSignedEcRecovered, TransactionSignedNoHash, Withdrawal, Withdrawals, @@ -500,7 +500,6 @@ impl DatabaseProvider { Vec
, Vec
, Option, - Option, ) -> ProviderResult>, { let Some(block_number) = self.convert_hash_or_number(id)? else { return Ok(None) }; @@ -509,7 +508,6 @@ impl DatabaseProvider { let ommers = self.ommers(block_number.into())?.unwrap_or_default(); let withdrawals = self.withdrawals_by_block(block_number.into(), header.as_ref().timestamp)?; - let requests = self.requests_by_block(block_number.into(), header.as_ref().timestamp)?; // Get the block body // @@ -540,7 +538,7 @@ impl DatabaseProvider { }) .collect(); - construct_block(header, body, senders, ommers, withdrawals, requests) + construct_block(header, body, senders, ommers, withdrawals) } /// Returns a range of blocks from the database. @@ -551,7 +549,6 @@ impl DatabaseProvider { /// - Range of transaction numbers /// – Ommers /// – Withdrawals - /// – Requests /// – Senders fn block_range( &self, @@ -563,13 +560,7 @@ impl DatabaseProvider { Spec: EthereumHardforks, H: AsRef
, HF: FnOnce(RangeInclusive) -> ProviderResult>, - F: FnMut( - H, - Range, - Vec
, - Option, - Option, - ) -> ProviderResult, + F: FnMut(H, Range, Vec
, Option) -> ProviderResult, { if range.is_empty() { return Ok(Vec::new()) @@ -581,7 +572,6 @@ impl DatabaseProvider { let headers = headers_range(range)?; let mut ommers_cursor = self.tx.cursor_read::()?; let mut withdrawals_cursor = self.tx.cursor_read::()?; - let mut requests_cursor = self.tx.cursor_read::()?; let mut block_body_cursor = self.tx.cursor_read::()?; for header in headers { @@ -608,13 +598,6 @@ impl DatabaseProvider { } else { None }; - let requests = - if self.chain_spec.is_prague_active_at_timestamp(header_ref.timestamp) { - (requests_cursor.seek_exact(header_ref.number)?.unwrap_or_default().1) - .into() - } else { - None - }; let ommers = if self.chain_spec.final_paris_total_difficulty(header_ref.number).is_some() { Vec::new() @@ -625,7 +608,7 @@ impl DatabaseProvider { .unwrap_or_default() }; - if let Ok(b) = assemble_block(header, tx_range, ommers, withdrawals, requests) { + if let Ok(b) = assemble_block(header, tx_range, ommers, withdrawals) { blocks.push(b); } } @@ -643,7 +626,6 @@ impl DatabaseProvider { /// - Transactions /// – Ommers /// – Withdrawals - /// – Requests /// – Senders fn block_with_senders_range( &self, @@ -660,14 +642,13 @@ impl DatabaseProvider { Vec, Vec
, Option, - Option, Vec
, ) -> ProviderResult, { let mut tx_cursor = self.tx.cursor_read::()?; let mut senders_cursor = self.tx.cursor_read::()?; - self.block_range(range, headers_range, |header, tx_range, ommers, withdrawals, requests| { + self.block_range(range, headers_range, |header, tx_range, ommers, withdrawals| { let (body, senders) = if tx_range.is_empty() { (Vec::new(), Vec::new()) } else { @@ -699,7 +680,7 @@ impl DatabaseProvider { (body, senders) }; - assemble_block(header, body, ommers, withdrawals, requests, senders) + assemble_block(header, body, ommers, withdrawals, senders) }) } @@ -781,7 +762,6 @@ impl DatabaseProvider { // - Bodies (transactions) // - Uncles/ommers // - Withdrawals - // - Requests // - Signers let block_headers = self.get::(range.clone())?; @@ -792,7 +772,6 @@ impl DatabaseProvider { let block_header_hashes = self.get::(range.clone())?; let block_ommers = self.get::(range.clone())?; let block_withdrawals = self.get::(range.clone())?; - let block_requests = self.get::(range.clone())?; let block_tx = self.get_block_transaction_range(range)?; let mut blocks = Vec::with_capacity(block_headers.len()); @@ -805,10 +784,8 @@ impl DatabaseProvider { // Ommers can be empty for some blocks let mut block_ommers_iter = block_ommers.into_iter(); let mut block_withdrawals_iter = block_withdrawals.into_iter(); - let mut block_requests_iter = block_requests.into_iter(); let mut block_ommers = block_ommers_iter.next(); let mut block_withdrawals = block_withdrawals_iter.next(); - let mut block_requests = block_requests_iter.next(); for ((main_block_number, header), (_, header_hash), (_, tx)) in izip!(block_header_iter, block_header_hashes_iter, block_tx_iter) @@ -841,24 +818,10 @@ impl DatabaseProvider { withdrawals = None } - // requests can be missing - let prague_is_active = self.chain_spec.is_prague_active_at_timestamp(header.timestamp); - let mut requests = Some(Requests::default()); - if prague_is_active { - if let Some((block_number, _)) = block_requests.as_ref() { - if *block_number == main_block_number { - requests = Some(block_requests.take().unwrap().1); - block_requests = block_requests_iter.next(); - } - } - } else { - requests = None; - } - blocks.push(SealedBlockWithSenders { block: SealedBlock { header, - body: BlockBody { transactions, ommers, withdrawals, requests }, + body: BlockBody { transactions, ommers, withdrawals }, }, senders, }) @@ -1222,7 +1185,6 @@ impl DatabaseProvider { /// * [`CanonicalHeaders`](tables::CanonicalHeaders) /// * [`BlockOmmers`](tables::BlockOmmers) /// * [`BlockWithdrawals`](tables::BlockWithdrawals) - /// * [`BlockRequests`](tables::BlockRequests) /// * [`HeaderTerminalDifficulties`](tables::HeaderTerminalDifficulties) /// /// This will also remove transaction data according to @@ -1242,7 +1204,6 @@ impl DatabaseProvider { self.remove::(range.clone())?; self.remove::(range.clone())?; self.remove::(range.clone())?; - self.remove::(range.clone())?; self.remove_block_transaction_range(range.clone())?; self.remove::(range)?; @@ -1256,7 +1217,6 @@ impl DatabaseProvider { /// * [`CanonicalHeaders`](tables::CanonicalHeaders) /// * [`BlockOmmers`](tables::BlockOmmers) /// * [`BlockWithdrawals`](tables::BlockWithdrawals) - /// * [`BlockRequests`](tables::BlockRequests) /// * [`HeaderTerminalDifficulties`](tables::HeaderTerminalDifficulties) /// /// This will also remove transaction data according to @@ -1274,7 +1234,6 @@ impl DatabaseProvider { // - Bodies (transactions) // - Uncles/ommers // - Withdrawals - // - Requests // - Signers let block_headers = self.take::(range.clone())?; @@ -1288,7 +1247,6 @@ impl DatabaseProvider { let block_header_hashes = self.take::(range.clone())?; let block_ommers = self.take::(range.clone())?; let block_withdrawals = self.take::(range.clone())?; - let block_requests = self.take::(range.clone())?; let block_tx = self.take_block_transaction_range(range.clone())?; let mut blocks = Vec::with_capacity(block_headers.len()); @@ -1304,10 +1262,8 @@ impl DatabaseProvider { // Ommers can be empty for some blocks let mut block_ommers_iter = block_ommers.into_iter(); let mut block_withdrawals_iter = block_withdrawals.into_iter(); - let mut block_requests_iter = block_requests.into_iter(); let mut block_ommers = block_ommers_iter.next(); let mut block_withdrawals = block_withdrawals_iter.next(); - let mut block_requests = block_requests_iter.next(); for ((main_block_number, header), (_, header_hash), (_, tx)) in izip!(block_header_iter, block_header_hashes_iter, block_tx_iter) @@ -1340,24 +1296,10 @@ impl DatabaseProvider { withdrawals = None } - // requests can be missing - let prague_is_active = self.chain_spec.is_prague_active_at_timestamp(header.timestamp); - let mut requests = Some(Requests::default()); - if prague_is_active { - if let Some((block_number, _)) = block_requests.as_ref() { - if *block_number == main_block_number { - requests = Some(block_requests.take().unwrap().1); - block_requests = block_requests_iter.next(); - } - } - } else { - requests = None; - } - blocks.push(SealedBlockWithSenders { block: SealedBlock { header, - body: BlockBody { transactions, ommers, withdrawals, requests }, + body: BlockBody { transactions, ommers, withdrawals }, }, senders, }) @@ -1726,7 +1668,6 @@ impl BlockReader for DatabasePr if let Some(header) = self.header_by_number(number)? { let withdrawals = self.withdrawals_by_block(number.into(), header.timestamp)?; let ommers = self.ommers(number.into())?.unwrap_or_default(); - let requests = self.requests_by_block(number.into(), header.timestamp)?; // If the body indices are not found, this means that the transactions either do not // exist in the database yet, or they do exit but are not indexed. // If they exist but are not indexed, we don't have enough @@ -1738,7 +1679,7 @@ impl BlockReader for DatabasePr return Ok(Some(Block { header, - body: BlockBody { transactions, ommers, withdrawals, requests }, + body: BlockBody { transactions, ommers, withdrawals }, })) } } @@ -1798,8 +1739,8 @@ impl BlockReader for DatabasePr id, transaction_kind, |block_number| self.header_by_number(block_number), - |header, transactions, senders, ommers, withdrawals, requests| { - Block { header, body: BlockBody { transactions, ommers, withdrawals, requests } } + |header, transactions, senders, ommers, withdrawals| { + Block { header, body: BlockBody { transactions, ommers, withdrawals } } // Note: we're using unchecked here because we know the block contains valid txs // wrt to its height and can ignore the s value check so pre // EIP-2 txs are allowed @@ -1819,17 +1760,14 @@ impl BlockReader for DatabasePr id, transaction_kind, |block_number| self.sealed_header(block_number), - |header, transactions, senders, ommers, withdrawals, requests| { - SealedBlock { - header, - body: BlockBody { transactions, ommers, withdrawals, requests }, - } - // Note: we're using unchecked here because we know the block contains valid txs - // wrt to its height and can ignore the s value check so pre - // EIP-2 txs are allowed - .try_with_senders_unchecked(senders) - .map(Some) - .map_err(|_| ProviderError::SenderRecoveryError) + |header, transactions, senders, ommers, withdrawals| { + SealedBlock { header, body: BlockBody { transactions, ommers, withdrawals } } + // Note: we're using unchecked here because we know the block contains valid txs + // wrt to its height and can ignore the s value check so pre + // EIP-2 txs are allowed + .try_with_senders_unchecked(senders) + .map(Some) + .map_err(|_| ProviderError::SenderRecoveryError) }, ) } @@ -1839,7 +1777,7 @@ impl BlockReader for DatabasePr self.block_range( range, |range| self.headers_range(range), - |header, tx_range, ommers, withdrawals, requests| { + |header, tx_range, ommers, withdrawals| { let transactions = if tx_range.is_empty() { Vec::new() } else { @@ -1848,10 +1786,7 @@ impl BlockReader for DatabasePr .map(Into::into) .collect() }; - Ok(Block { - header, - body: BlockBody { transactions, ommers, withdrawals, requests }, - }) + Ok(Block { header, body: BlockBody { transactions, ommers, withdrawals } }) }, ) } @@ -1863,8 +1798,8 @@ impl BlockReader for DatabasePr self.block_with_senders_range( range, |range| self.headers_range(range), - |header, transactions, ommers, withdrawals, requests, senders| { - Block { header, body: BlockBody { transactions, ommers, withdrawals, requests } } + |header, transactions, ommers, withdrawals, senders| { + Block { header, body: BlockBody { transactions, ommers, withdrawals } } .try_with_senders_unchecked(senders) .map_err(|_| ProviderError::SenderRecoveryError) }, @@ -1878,12 +1813,9 @@ impl BlockReader for DatabasePr self.block_with_senders_range( range, |range| self.sealed_headers_range(range), - |header, transactions, ommers, withdrawals, requests, senders| { + |header, transactions, ommers, withdrawals, senders| { SealedBlockWithSenders::new( - SealedBlock { - header, - body: BlockBody { transactions, ommers, withdrawals, requests }, - }, + SealedBlock { header, body: BlockBody { transactions, ommers, withdrawals } }, senders, ) .ok_or(ProviderError::SenderRecoveryError) @@ -2200,24 +2132,6 @@ impl WithdrawalsProvider } } -impl RequestsProvider - for DatabaseProvider -{ - fn requests_by_block( - &self, - id: BlockHashOrNumber, - timestamp: u64, - ) -> ProviderResult> { - if self.chain_spec.is_prague_active_at_timestamp(timestamp) { - if let Some(number) = self.convert_hash_or_number(id)? { - let requests = self.tx.get::(number)?; - return Ok(requests) - } - } - Ok(None) - } -} - impl EvmEnvProvider for DatabaseProvider { @@ -3413,7 +3327,6 @@ impl(block_number, requests)?; - durations_recorder.record_relative(metrics::Action::InsertBlockRequests); - } - let block_indices = StoredBlockBodyIndices { first_tx_num, tx_count }; self.tx.put::(block_number, block_indices.clone())?; durations_recorder.record_relative(metrics::Action::InsertBlockBodyIndices); diff --git a/crates/storage/provider/src/providers/mod.rs b/crates/storage/provider/src/providers/mod.rs index 561e1d974362..b98bbf5be472 100644 --- a/crates/storage/provider/src/providers/mod.rs +++ b/crates/storage/provider/src/providers/mod.rs @@ -3,7 +3,7 @@ use crate::{ BlockSource, BlockchainTreePendingStateProvider, CanonChainTracker, CanonStateNotifications, CanonStateSubscriptions, ChainSpecProvider, ChainStateBlockReader, ChangeSetReader, DatabaseProviderFactory, EvmEnvProvider, FullExecutionDataProvider, HeaderProvider, - ProviderError, PruneCheckpointReader, ReceiptProvider, ReceiptProviderIdExt, RequestsProvider, + ProviderError, PruneCheckpointReader, ReceiptProvider, ReceiptProviderIdExt, StageCheckpointReader, StateProviderBox, StateProviderFactory, StaticFileProviderFactory, TransactionVariant, TransactionsProvider, TreeViewer, WithdrawalsProvider, }; @@ -504,16 +504,6 @@ impl WithdrawalsProvider for BlockchainProvider { } } -impl RequestsProvider for BlockchainProvider { - fn requests_by_block( - &self, - id: BlockHashOrNumber, - timestamp: u64, - ) -> ProviderResult> { - self.database.requests_by_block(id, timestamp) - } -} - impl StageCheckpointReader for BlockchainProvider { fn get_stage_checkpoint(&self, id: StageId) -> ProviderResult> { self.database.provider()?.get_stage_checkpoint(id) diff --git a/crates/storage/provider/src/providers/static_file/manager.rs b/crates/storage/provider/src/providers/static_file/manager.rs index 6f5cf07c95c5..20d6a1b184b2 100644 --- a/crates/storage/provider/src/providers/static_file/manager.rs +++ b/crates/storage/provider/src/providers/static_file/manager.rs @@ -4,8 +4,8 @@ use super::{ }; use crate::{ to_range, BlockHashReader, BlockNumReader, BlockReader, BlockSource, HeaderProvider, - ReceiptProvider, RequestsProvider, StageCheckpointReader, StatsReader, TransactionVariant, - TransactionsProvider, TransactionsProviderExt, WithdrawalsProvider, + ReceiptProvider, StageCheckpointReader, StatsReader, TransactionVariant, TransactionsProvider, + TransactionsProviderExt, WithdrawalsProvider, }; use alloy_eips::BlockHashOrNumber; use alloy_primitives::{keccak256, Address, BlockHash, BlockNumber, TxHash, TxNumber, B256, U256}; @@ -1642,17 +1642,6 @@ impl WithdrawalsProvider for StaticFileProvider { } } -impl RequestsProvider for StaticFileProvider { - fn requests_by_block( - &self, - _id: BlockHashOrNumber, - _timestamp: u64, - ) -> ProviderResult> { - // Required data not present in static_files - Err(ProviderError::UnsupportedProvider) - } -} - impl StatsReader for StaticFileProvider { fn count_entries(&self) -> ProviderResult { match T::NAME { diff --git a/crates/storage/provider/src/test_utils/blocks.rs b/crates/storage/provider/src/test_utils/blocks.rs index 2a70664b1b3a..07486f5557cb 100644 --- a/crates/storage/provider/src/test_utils/blocks.rs +++ b/crates/storage/provider/src/test_utils/blocks.rs @@ -40,7 +40,6 @@ pub fn assert_genesis_block( ); assert_eq!(tx.table::().unwrap(), vec![]); assert_eq!(tx.table::().unwrap(), vec![]); - assert_eq!(tx.table::().unwrap(), vec![]); assert_eq!(tx.table::().unwrap(), vec![]); assert_eq!(tx.table::().unwrap(), vec![]); assert_eq!(tx.table::().unwrap(), vec![]); diff --git a/crates/storage/provider/src/test_utils/mock.rs b/crates/storage/provider/src/test_utils/mock.rs index c7c94b939ac3..08530acf0a7f 100644 --- a/crates/storage/provider/src/test_utils/mock.rs +++ b/crates/storage/provider/src/test_utils/mock.rs @@ -2,9 +2,9 @@ use crate::{ traits::{BlockSource, ReceiptProvider}, AccountReader, BlockExecutionReader, BlockHashReader, BlockIdReader, BlockNumReader, BlockReader, BlockReaderIdExt, ChainSpecProvider, ChangeSetReader, DatabaseProvider, - EvmEnvProvider, HeaderProvider, ReceiptProviderIdExt, RequestsProvider, StateProvider, - StateProviderBox, StateProviderFactory, StateReader, StateRootProvider, TransactionVariant, - TransactionsProvider, WithdrawalsProvider, + EvmEnvProvider, HeaderProvider, ReceiptProviderIdExt, StateProvider, StateProviderBox, + StateProviderFactory, StateReader, StateRootProvider, TransactionVariant, TransactionsProvider, + WithdrawalsProvider, }; use alloy_consensus::constants::EMPTY_ROOT_HASH; use alloy_eips::{BlockHashOrNumber, BlockId, BlockNumberOrTag}; @@ -809,16 +809,6 @@ impl WithdrawalsProvider for MockEthProvider { } } -impl RequestsProvider for MockEthProvider { - fn requests_by_block( - &self, - _id: BlockHashOrNumber, - _timestamp: u64, - ) -> ProviderResult> { - Ok(None) - } -} - impl ChangeSetReader for MockEthProvider { fn account_block_changeset( &self, diff --git a/crates/storage/provider/src/test_utils/noop.rs b/crates/storage/provider/src/test_utils/noop.rs index 0a205389c9b6..f6f7e185de63 100644 --- a/crates/storage/provider/src/test_utils/noop.rs +++ b/crates/storage/provider/src/test_utils/noop.rs @@ -37,7 +37,7 @@ use crate::{ traits::{BlockSource, ReceiptProvider}, AccountReader, BlockHashReader, BlockIdReader, BlockNumReader, BlockReader, BlockReaderIdExt, ChainSpecProvider, ChangeSetReader, EvmEnvProvider, HeaderProvider, PruneCheckpointReader, - ReceiptProviderIdExt, RequestsProvider, StageCheckpointReader, StateProvider, StateProviderBox, + ReceiptProviderIdExt, StageCheckpointReader, StateProvider, StateProviderBox, StateProviderFactory, StateRootProvider, StaticFileProviderFactory, TransactionVariant, TransactionsProvider, WithdrawalsProvider, }; @@ -539,16 +539,6 @@ impl WithdrawalsProvider for NoopProvider { } } -impl RequestsProvider for NoopProvider { - fn requests_by_block( - &self, - _id: BlockHashOrNumber, - _timestamp: u64, - ) -> ProviderResult> { - Ok(None) - } -} - impl PruneCheckpointReader for NoopProvider { fn get_prune_checkpoint( &self, diff --git a/crates/storage/storage-api/src/block.rs b/crates/storage/storage-api/src/block.rs index a3b0cc7438f3..01238be745e2 100644 --- a/crates/storage/storage-api/src/block.rs +++ b/crates/storage/storage-api/src/block.rs @@ -1,6 +1,6 @@ use crate::{ - BlockNumReader, HeaderProvider, ReceiptProvider, ReceiptProviderIdExt, RequestsProvider, - TransactionVariant, TransactionsProvider, WithdrawalsProvider, + BlockNumReader, HeaderProvider, ReceiptProvider, ReceiptProviderIdExt, TransactionVariant, + TransactionsProvider, WithdrawalsProvider, }; use alloy_eips::{BlockHashOrNumber, BlockId, BlockNumberOrTag}; use alloy_primitives::{BlockNumber, Sealable, B256}; @@ -52,7 +52,6 @@ pub trait BlockReader: + HeaderProvider + TransactionsProvider + ReceiptProvider - + RequestsProvider + WithdrawalsProvider + Send + Sync diff --git a/crates/storage/storage-api/src/lib.rs b/crates/storage/storage-api/src/lib.rs index 3f93bbbde2f1..4e589242a91e 100644 --- a/crates/storage/storage-api/src/lib.rs +++ b/crates/storage/storage-api/src/lib.rs @@ -31,9 +31,6 @@ pub use prune_checkpoint::*; mod receipts; pub use receipts::*; -mod requests; -pub use requests::*; - mod stage_checkpoint; pub use stage_checkpoint::*; diff --git a/crates/storage/storage-api/src/requests.rs b/crates/storage/storage-api/src/requests.rs deleted file mode 100644 index 02818c429b62..000000000000 --- a/crates/storage/storage-api/src/requests.rs +++ /dev/null @@ -1,14 +0,0 @@ -use alloy_eips::BlockHashOrNumber; -use reth_primitives::Requests; -use reth_storage_errors::provider::ProviderResult; - -/// Client trait for fetching EIP-7685 [Requests] for blocks. -#[auto_impl::auto_impl(&, Arc)] -pub trait RequestsProvider: Send + Sync { - /// Get withdrawals by block id. - fn requests_by_block( - &self, - id: BlockHashOrNumber, - timestamp: u64, - ) -> ProviderResult>; -} diff --git a/docs/crates/db.md b/docs/crates/db.md index 3ccfb72e344a..79eeae5ee4ff 100644 --- a/docs/crates/db.md +++ b/docs/crates/db.md @@ -61,7 +61,6 @@ There are many tables within the node, all used to store different types of data - StageCheckpointProgresses - PruneCheckpoints - VersionHistory -- BlockRequests - ChainState
@@ -283,7 +282,6 @@ fn unwind(&mut self, provider: &DatabaseProviderRW, input: UnwindInput) { let mut body_cursor = tx.cursor_write::()?; let mut ommers_cursor = tx.cursor_write::()?; let mut withdrawals_cursor = tx.cursor_write::()?; - let mut requests_cursor = tx.cursor_write::()?; // Cursors to unwind transitions let mut tx_block_cursor = tx.cursor_write::()?; @@ -322,7 +320,7 @@ fn unwind(&mut self, provider: &DatabaseProviderRW, input: UnwindInput) { } ``` -This function first grabs a mutable cursor for the `BlockBodyIndices`, `BlockOmmers`, `BlockWithdrawals`, `BlockRequests`, `TransactionBlocks` tables. +This function first grabs a mutable cursor for the `BlockBodyIndices`, `BlockOmmers`, `BlockWithdrawals`, `TransactionBlocks` tables. Then it gets a walker of the block body cursor, and then walk backwards through the cursor to delete the block body entries from the last block number to the block number specified in the `UnwindInput` struct. diff --git a/testing/ef-tests/src/models.rs b/testing/ef-tests/src/models.rs index 3f3df15363a1..30e5e5bb20c2 100644 --- a/testing/ef-tests/src/models.rs +++ b/testing/ef-tests/src/models.rs @@ -87,7 +87,7 @@ pub struct Header { /// Parent beacon block root. pub parent_beacon_block_root: Option, /// Requests root. - pub requests_root: Option, + pub requests_hash: Option, } impl From
for SealedHeader { @@ -113,7 +113,7 @@ impl From
for SealedHeader { blob_gas_used: value.blob_gas_used.map(|v| v.to::()), excess_blob_gas: value.excess_blob_gas.map(|v| v.to::()), parent_beacon_block_root: value.parent_beacon_block_root, - requests_root: value.requests_root, + requests_hash: value.requests_hash, }; Self::new(header, value.hash) } diff --git a/testing/testing-utils/Cargo.toml b/testing/testing-utils/Cargo.toml index 49a59ecf6ae3..98bfeabdfb15 100644 --- a/testing/testing-utils/Cargo.toml +++ b/testing/testing-utils/Cargo.toml @@ -14,10 +14,12 @@ workspace = true [dependencies] reth-primitives = { workspace = true, features = ["secp256k1"] } -alloy-eips.workspace = true alloy-genesis.workspace = true alloy-primitives.workspace = true alloy-consensus.workspace = true rand.workspace = true secp256k1 = { workspace = true, features = ["rand"] } + +[dev-dependencies] +alloy-eips.workspace = true diff --git a/testing/testing-utils/src/generators.rs b/testing/testing-utils/src/generators.rs index d07af00ce4c2..571727cb2fd6 100644 --- a/testing/testing-utils/src/generators.rs +++ b/testing/testing-utils/src/generators.rs @@ -1,17 +1,14 @@ //! Generators for different data structures like block headers, block bodies and ranges of those. use alloy_consensus::{Transaction as _, TxLegacy}; -use alloy_eips::{ - eip6110::DepositRequest, eip7002::WithdrawalRequest, eip7251::ConsolidationRequest, -}; use alloy_primitives::{Address, BlockNumber, Bytes, Parity, Sealable, TxKind, B256, U256}; pub use rand::Rng; use rand::{ distributions::uniform::SampleRange, rngs::StdRng, seq::SliceRandom, thread_rng, SeedableRng, }; use reth_primitives::{ - proofs, sign_message, Account, BlockBody, Header, Log, Receipt, Request, Requests, SealedBlock, - SealedHeader, StorageEntry, Transaction, TransactionSigned, Withdrawal, Withdrawals, + proofs, sign_message, Account, BlockBody, Header, Log, Receipt, SealedBlock, SealedHeader, + StorageEntry, Transaction, TransactionSigned, Withdrawal, Withdrawals, }; use secp256k1::{Keypair, Secp256k1}; use std::{ @@ -201,11 +198,6 @@ pub fn random_block(rng: &mut R, number: u64, block_params: BlockParams) let transactions_root = proofs::calculate_transaction_root(&transactions); let ommers_hash = proofs::calculate_ommers_root(&ommers); - let requests = block_params - .requests_count - .map(|count| (0..count).map(|_| random_request(rng)).collect::>()); - let requests_root = requests.as_ref().map(|requests| proofs::calculate_requests_root(requests)); - let withdrawals = block_params.withdrawals_count.map(|count| { (0..count) .map(|i| Withdrawal { @@ -226,7 +218,8 @@ pub fn random_block(rng: &mut R, number: u64, block_params: BlockParams) transactions_root, ommers_hash, base_fee_per_gas: Some(rng.gen()), - requests_root, + // TODO(onbjerg): Proper EIP-7685 request support + requests_hash: None, withdrawals_root, ..Default::default() } @@ -236,12 +229,7 @@ pub fn random_block(rng: &mut R, number: u64, block_params: BlockParams) SealedBlock { header: SealedHeader::new(header, seal), - body: BlockBody { - transactions, - ommers, - withdrawals: withdrawals.map(Withdrawals::new), - requests: requests.map(Requests), - }, + body: BlockBody { transactions, ommers, withdrawals: withdrawals.map(Withdrawals::new) }, } } @@ -470,31 +458,6 @@ pub fn random_log(rng: &mut R, address: Option
, topics_count: O ) } -/// Generate random request -pub fn random_request(rng: &mut R) -> Request { - let request_type = rng.gen_range(0..3); - match request_type { - 0 => Request::DepositRequest(DepositRequest { - pubkey: rng.gen(), - withdrawal_credentials: rng.gen(), - amount: rng.gen(), - signature: rng.gen(), - index: rng.gen(), - }), - 1 => Request::WithdrawalRequest(WithdrawalRequest { - source_address: rng.gen(), - validator_pubkey: rng.gen(), - amount: rng.gen(), - }), - 2 => Request::ConsolidationRequest(ConsolidationRequest { - source_address: rng.gen(), - source_pubkey: rng.gen(), - target_pubkey: rng.gen(), - }), - _ => panic!("invalid request type"), - } -} - #[cfg(test)] mod tests { use super::*; From 3793b907eadc620687f0b65327cdbd4c4e6b1abf Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Sat, 19 Oct 2024 15:05:53 +0200 Subject: [PATCH 087/113] chore: better start finish persisted block logs (#11893) Co-authored-by: Oliver --- crates/engine/tree/src/tree/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/engine/tree/src/tree/mod.rs b/crates/engine/tree/src/tree/mod.rs index c63c8fbe2916..02802dff66cb 100644 --- a/crates/engine/tree/src/tree/mod.rs +++ b/crates/engine/tree/src/tree/mod.rs @@ -1145,6 +1145,7 @@ where if blocks_to_persist.is_empty() { debug!(target: "engine::tree", "Returned empty set of blocks to persist"); } else { + debug!(target: "engine::tree", blocks = ?blocks_to_persist.iter().map(|block| block.block.num_hash()).collect::>(), "Persisting blocks"); let (tx, rx) = oneshot::channel(); let _ = self.persistence.save_blocks(blocks_to_persist, tx); self.persistence_state.start(rx); @@ -1173,7 +1174,7 @@ where return Ok(()) }; - trace!(target: "engine::tree", ?last_persisted_block_hash, ?last_persisted_block_number, "Finished persisting, calling finish"); + debug!(target: "engine::tree", ?last_persisted_block_hash, ?last_persisted_block_number, "Finished persisting, calling finish"); self.persistence_state .finish(last_persisted_block_hash, last_persisted_block_number); self.on_new_persisted_block()?; From ddc5ac3fa750580eda224d37c086c4a7443728d4 Mon Sep 17 00:00:00 2001 From: Thomas Coratger <60488569+tcoratger@users.noreply.github.com> Date: Sat, 19 Oct 2024 15:12:28 +0200 Subject: [PATCH 088/113] refactor(rpc): small refactor in `trace_filter` (#11894) --- crates/rpc/rpc/src/trace.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/crates/rpc/rpc/src/trace.rs b/crates/rpc/rpc/src/trace.rs index 8ac532ff341d..b9b15b5366df 100644 --- a/crates/rpc/rpc/src/trace.rs +++ b/crates/rpc/rpc/src/trace.rs @@ -314,13 +314,15 @@ where // add reward traces for all blocks for block in &blocks { if let Some(base_block_reward) = self.calculate_base_block_reward(&block.header)? { - let mut traces = self.extract_reward_traces( - &block.header, - &block.body.ommers, - base_block_reward, + all_traces.extend( + self.extract_reward_traces( + &block.header, + &block.body.ommers, + base_block_reward, + ) + .into_iter() + .filter(|trace| matcher.matches(&trace.trace)), ); - traces.retain(|trace| matcher.matches(&trace.trace)); - all_traces.extend(traces); } else { // no block reward, means we're past the Paris hardfork and don't expect any rewards // because the blocks in ascending order From 1a1aa2f8c3acb4ae32b0d1dadc9221fdf75fabdd Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Sat, 19 Oct 2024 15:18:20 +0200 Subject: [PATCH 089/113] feat: add map_pool fn (#11890) --- crates/payload/basic/src/lib.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/crates/payload/basic/src/lib.rs b/crates/payload/basic/src/lib.rs index 7416283c1f5d..70d22250ddbe 100644 --- a/crates/payload/basic/src/lib.rs +++ b/crates/payload/basic/src/lib.rs @@ -799,6 +799,21 @@ impl BuildArguments(self, f: F) -> BuildArguments + where + F: FnOnce(Pool) -> P, + { + BuildArguments { + client: self.client, + pool: f(self.pool), + cached_reads: self.cached_reads, + config: self.config, + cancel: self.cancel, + best_payload: self.best_payload, + } + } } /// A trait for building payloads that encapsulate Ethereum transactions. From 1efa764b34f163e70890bbd54eac64ad2b6adcce Mon Sep 17 00:00:00 2001 From: Dan Cline <6798349+Rjected@users.noreply.github.com> Date: Sat, 19 Oct 2024 09:29:29 -0400 Subject: [PATCH 090/113] chore(engine): rename enveloped associated types to envelope (#11812) Co-authored-by: Matthias Seitz --- crates/e2e-test-utils/src/engine_api.rs | 6 ++-- crates/e2e-test-utils/src/node.rs | 6 ++-- crates/engine/primitives/src/lib.rs | 30 ++++++++++++++++---- crates/ethereum/engine-primitives/src/lib.rs | 6 ++-- crates/optimism/node/src/engine.rs | 6 ++-- crates/rpc/rpc-api/src/engine.rs | 15 ++++++++-- crates/rpc/rpc-engine-api/src/engine_api.rs | 12 ++++---- examples/custom-engine-types/src/main.rs | 6 ++-- 8 files changed, 57 insertions(+), 30 deletions(-) diff --git a/crates/e2e-test-utils/src/engine_api.rs b/crates/e2e-test-utils/src/engine_api.rs index 1b0ff9b54e71..f4aa8fdf5ff0 100644 --- a/crates/e2e-test-utils/src/engine_api.rs +++ b/crates/e2e-test-utils/src/engine_api.rs @@ -29,7 +29,7 @@ impl EngineApiTestContext { pub async fn get_payload_v3( &self, payload_id: PayloadId, - ) -> eyre::Result { + ) -> eyre::Result { Ok(EngineApiClient::::get_payload_v3(&self.engine_api_client, payload_id).await?) } @@ -50,10 +50,10 @@ impl EngineApiTestContext { versioned_hashes: Vec, ) -> eyre::Result where - E::ExecutionPayloadV3: From + PayloadEnvelopeExt, + E::ExecutionPayloadEnvelopeV3: From + PayloadEnvelopeExt, { // setup payload for submission - let envelope_v3: ::ExecutionPayloadV3 = payload.into(); + let envelope_v3: ::ExecutionPayloadEnvelopeV3 = payload.into(); // submit payload to engine api let submission = EngineApiClient::::new_payload_v3( diff --git a/crates/e2e-test-utils/src/node.rs b/crates/e2e-test-utils/src/node.rs index c22913ba2363..776a437a58e9 100644 --- a/crates/e2e-test-utils/src/node.rs +++ b/crates/e2e-test-utils/src/node.rs @@ -88,7 +88,7 @@ where attributes_generator: impl Fn(u64) -> Engine::PayloadBuilderAttributes + Copy, ) -> eyre::Result> where - Engine::ExecutionPayloadV3: From + PayloadEnvelopeExt, + Engine::ExecutionPayloadEnvelopeV3: From + PayloadEnvelopeExt, AddOns::EthApi: EthApiSpec + EthTransactions + TraceExt + FullEthApiTypes, { let mut chain = Vec::with_capacity(length as usize); @@ -113,7 +113,7 @@ where attributes_generator: impl Fn(u64) -> Engine::PayloadBuilderAttributes, ) -> eyre::Result<(Engine::BuiltPayload, Engine::PayloadBuilderAttributes)> where - ::ExecutionPayloadV3: + ::ExecutionPayloadEnvelopeV3: From + PayloadEnvelopeExt, { // trigger new payload building draining the pool @@ -135,7 +135,7 @@ where attributes_generator: impl Fn(u64) -> Engine::PayloadBuilderAttributes, ) -> eyre::Result<(Engine::BuiltPayload, Engine::PayloadBuilderAttributes)> where - ::ExecutionPayloadV3: + ::ExecutionPayloadEnvelopeV3: From + PayloadEnvelopeExt, { let (payload, eth_attr) = self.new_payload(attributes_generator).await?; diff --git a/crates/engine/primitives/src/lib.rs b/crates/engine/primitives/src/lib.rs index 2cf1366eb014..fab96b0d17e9 100644 --- a/crates/engine/primitives/src/lib.rs +++ b/crates/engine/primitives/src/lib.rs @@ -24,9 +24,9 @@ use serde::{de::DeserializeOwned, ser::Serialize}; pub trait EngineTypes: PayloadTypes< BuiltPayload: TryInto - + TryInto - + TryInto - + TryInto, + + TryInto + + TryInto + + TryInto, > + DeserializeOwned + Serialize + 'static @@ -34,11 +34,29 @@ pub trait EngineTypes: /// Execution Payload V1 type. type ExecutionPayloadV1: DeserializeOwned + Serialize + Clone + Unpin + Send + Sync + 'static; /// Execution Payload V2 type. - type ExecutionPayloadV2: DeserializeOwned + Serialize + Clone + Unpin + Send + Sync + 'static; + type ExecutionPayloadEnvelopeV2: DeserializeOwned + + Serialize + + Clone + + Unpin + + Send + + Sync + + 'static; /// Execution Payload V3 type. - type ExecutionPayloadV3: DeserializeOwned + Serialize + Clone + Unpin + Send + Sync + 'static; + type ExecutionPayloadEnvelopeV3: DeserializeOwned + + Serialize + + Clone + + Unpin + + Send + + Sync + + 'static; /// Execution Payload V4 type. - type ExecutionPayloadV4: DeserializeOwned + Serialize + Clone + Unpin + Send + Sync + 'static; + type ExecutionPayloadEnvelopeV4: DeserializeOwned + + Serialize + + Clone + + Unpin + + Send + + Sync + + 'static; } /// Type that validates the payloads sent to the engine. diff --git a/crates/ethereum/engine-primitives/src/lib.rs b/crates/ethereum/engine-primitives/src/lib.rs index 034a8c6bffbb..20a55883680b 100644 --- a/crates/ethereum/engine-primitives/src/lib.rs +++ b/crates/ethereum/engine-primitives/src/lib.rs @@ -44,9 +44,9 @@ where + TryInto, { type ExecutionPayloadV1 = ExecutionPayloadV1; - type ExecutionPayloadV2 = ExecutionPayloadEnvelopeV2; - type ExecutionPayloadV3 = ExecutionPayloadEnvelopeV3; - type ExecutionPayloadV4 = ExecutionPayloadEnvelopeV4; + type ExecutionPayloadEnvelopeV2 = ExecutionPayloadEnvelopeV2; + type ExecutionPayloadEnvelopeV3 = ExecutionPayloadEnvelopeV3; + type ExecutionPayloadEnvelopeV4 = ExecutionPayloadEnvelopeV4; } /// A default payload type for [`EthEngineTypes`] diff --git a/crates/optimism/node/src/engine.rs b/crates/optimism/node/src/engine.rs index a83f4c696a1c..cec609671a38 100644 --- a/crates/optimism/node/src/engine.rs +++ b/crates/optimism/node/src/engine.rs @@ -38,9 +38,9 @@ where + TryInto, { type ExecutionPayloadV1 = ExecutionPayloadV1; - type ExecutionPayloadV2 = ExecutionPayloadEnvelopeV2; - type ExecutionPayloadV3 = OpExecutionPayloadEnvelopeV3; - type ExecutionPayloadV4 = OpExecutionPayloadEnvelopeV4; + type ExecutionPayloadEnvelopeV2 = ExecutionPayloadEnvelopeV2; + type ExecutionPayloadEnvelopeV3 = OpExecutionPayloadEnvelopeV3; + type ExecutionPayloadEnvelopeV4 = OpExecutionPayloadEnvelopeV4; } /// A default payload type for [`OptimismEngineTypes`] diff --git a/crates/rpc/rpc-api/src/engine.rs b/crates/rpc/rpc-api/src/engine.rs index e89f7b8d3982..458768c38b19 100644 --- a/crates/rpc/rpc-api/src/engine.rs +++ b/crates/rpc/rpc-api/src/engine.rs @@ -118,7 +118,10 @@ pub trait EngineApi { /// payload build process at the time of receiving this call. Note: /// > Provider software MAY stop the corresponding build process after serving this call. #[method(name = "getPayloadV2")] - async fn get_payload_v2(&self, payload_id: PayloadId) -> RpcResult; + async fn get_payload_v2( + &self, + payload_id: PayloadId, + ) -> RpcResult; /// Post Cancun payload handler which also returns a blobs bundle. /// @@ -128,7 +131,10 @@ pub trait EngineApi { /// payload build process at the time of receiving this call. Note: /// > Provider software MAY stop the corresponding build process after serving this call. #[method(name = "getPayloadV3")] - async fn get_payload_v3(&self, payload_id: PayloadId) -> RpcResult; + async fn get_payload_v3( + &self, + payload_id: PayloadId, + ) -> RpcResult; /// Post Prague payload handler. /// @@ -138,7 +144,10 @@ pub trait EngineApi { /// payload build process at the time of receiving this call. Note: /// > Provider software MAY stop the corresponding build process after serving this call. #[method(name = "getPayloadV4")] - async fn get_payload_v4(&self, payload_id: PayloadId) -> RpcResult; + async fn get_payload_v4( + &self, + payload_id: PayloadId, + ) -> RpcResult; /// See also #[method(name = "getPayloadBodiesByHashV1")] diff --git a/crates/rpc/rpc-engine-api/src/engine_api.rs b/crates/rpc/rpc-engine-api/src/engine_api.rs index d0b19a7b4d6d..9450b2c92170 100644 --- a/crates/rpc/rpc-engine-api/src/engine_api.rs +++ b/crates/rpc/rpc-engine-api/src/engine_api.rs @@ -289,7 +289,7 @@ where pub async fn get_payload_v2( &self, payload_id: PayloadId, - ) -> EngineApiResult { + ) -> EngineApiResult { // First we fetch the payload attributes to check the timestamp let attributes = self.get_payload_attributes(payload_id).await?; @@ -324,7 +324,7 @@ where pub async fn get_payload_v3( &self, payload_id: PayloadId, - ) -> EngineApiResult { + ) -> EngineApiResult { // First we fetch the payload attributes to check the timestamp let attributes = self.get_payload_attributes(payload_id).await?; @@ -359,7 +359,7 @@ where pub async fn get_payload_v4( &self, payload_id: PayloadId, - ) -> EngineApiResult { + ) -> EngineApiResult { // First we fetch the payload attributes to check the timestamp let attributes = self.get_payload_attributes(payload_id).await?; @@ -778,7 +778,7 @@ where async fn get_payload_v2( &self, payload_id: PayloadId, - ) -> RpcResult { + ) -> RpcResult { trace!(target: "rpc::engine", "Serving engine_getPayloadV2"); let start = Instant::now(); let res = Self::get_payload_v2(self, payload_id).await; @@ -798,7 +798,7 @@ where async fn get_payload_v3( &self, payload_id: PayloadId, - ) -> RpcResult { + ) -> RpcResult { trace!(target: "rpc::engine", "Serving engine_getPayloadV3"); let start = Instant::now(); let res = Self::get_payload_v3(self, payload_id).await; @@ -818,7 +818,7 @@ where async fn get_payload_v4( &self, payload_id: PayloadId, - ) -> RpcResult { + ) -> RpcResult { trace!(target: "rpc::engine", "Serving engine_getPayloadV4"); let start = Instant::now(); let res = Self::get_payload_v4(self, payload_id).await; diff --git a/examples/custom-engine-types/src/main.rs b/examples/custom-engine-types/src/main.rs index 135c4f3f2474..46a7d7d9af93 100644 --- a/examples/custom-engine-types/src/main.rs +++ b/examples/custom-engine-types/src/main.rs @@ -157,9 +157,9 @@ impl PayloadTypes for CustomEngineTypes { impl EngineTypes for CustomEngineTypes { type ExecutionPayloadV1 = ExecutionPayloadV1; - type ExecutionPayloadV2 = ExecutionPayloadEnvelopeV2; - type ExecutionPayloadV3 = ExecutionPayloadEnvelopeV3; - type ExecutionPayloadV4 = ExecutionPayloadEnvelopeV4; + type ExecutionPayloadEnvelopeV2 = ExecutionPayloadEnvelopeV2; + type ExecutionPayloadEnvelopeV3 = ExecutionPayloadEnvelopeV3; + type ExecutionPayloadEnvelopeV4 = ExecutionPayloadEnvelopeV4; } /// Custom engine validator From c803012085d65eb3111e942eea1c7af42ca75114 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sat, 19 Oct 2024 17:17:14 +0200 Subject: [PATCH 091/113] chore: use `Requests` instead of `Vec` (#11895) --- Cargo.lock | 3 ++- crates/consensus/beacon/Cargo.toml | 1 + crates/consensus/beacon/src/engine/handle.rs | 4 ++-- crates/consensus/beacon/src/engine/message.rs | 4 ++-- crates/consensus/beacon/src/engine/mod.rs | 5 +++-- crates/engine/tree/src/tree/mod.rs | 5 +++-- crates/engine/util/Cargo.toml | 5 ++--- crates/engine/util/src/reorg.rs | 7 ++++--- crates/payload/validator/Cargo.toml | 1 - crates/payload/validator/src/lib.rs | 12 ++++-------- crates/rpc/rpc-api/src/engine.rs | 4 ++-- crates/rpc/rpc-engine-api/src/engine_api.rs | 8 ++++---- 12 files changed, 29 insertions(+), 30 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 82f42b07b16f..b3a39cb58748 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6417,6 +6417,7 @@ dependencies = [ name = "reth-beacon-consensus" version = "1.1.0" dependencies = [ + "alloy-eips", "alloy-genesis", "alloy-primitives", "alloy-rpc-types-engine", @@ -7217,6 +7218,7 @@ name = "reth-engine-util" version = "1.1.0" dependencies = [ "alloy-consensus", + "alloy-eips", "alloy-primitives", "alloy-rpc-types-engine", "eyre", @@ -8400,7 +8402,6 @@ name = "reth-payload-validator" version = "1.1.0" dependencies = [ "alloy-eips", - "alloy-primitives", "alloy-rpc-types", "reth-chainspec", "reth-primitives", diff --git a/crates/consensus/beacon/Cargo.toml b/crates/consensus/beacon/Cargo.toml index f1366812608c..192ae2b93df7 100644 --- a/crates/consensus/beacon/Cargo.toml +++ b/crates/consensus/beacon/Cargo.toml @@ -31,6 +31,7 @@ reth-node-types.workspace = true reth-chainspec = { workspace = true, optional = true } # ethereum +alloy-eips.workspace = true alloy-primitives.workspace = true alloy-rpc-types-engine.workspace = true diff --git a/crates/consensus/beacon/src/engine/handle.rs b/crates/consensus/beacon/src/engine/handle.rs index 1f4445901645..bb5c4dee174c 100644 --- a/crates/consensus/beacon/src/engine/handle.rs +++ b/crates/consensus/beacon/src/engine/handle.rs @@ -4,7 +4,7 @@ use crate::{ engine::message::OnForkChoiceUpdated, BeaconConsensusEngineEvent, BeaconEngineMessage, BeaconForkChoiceUpdateError, BeaconOnNewPayloadError, }; -use alloy_primitives::Bytes; +use alloy_eips::eip7685::Requests; use alloy_rpc_types_engine::{ CancunPayloadFields, ExecutionPayload, ForkchoiceState, ForkchoiceUpdated, PayloadStatus, }; @@ -48,7 +48,7 @@ where &self, payload: ExecutionPayload, cancun_fields: Option, - execution_requests: Option>, + execution_requests: Option, ) -> Result { let (tx, rx) = oneshot::channel(); // HACK(onbjerg): We should have a pectra payload fields struct, this is just a temporary diff --git a/crates/consensus/beacon/src/engine/message.rs b/crates/consensus/beacon/src/engine/message.rs index 45d0c57f45ed..56328f03db0b 100644 --- a/crates/consensus/beacon/src/engine/message.rs +++ b/crates/consensus/beacon/src/engine/message.rs @@ -1,5 +1,5 @@ use crate::engine::{error::BeaconOnNewPayloadError, forkchoice::ForkchoiceStatus}; -use alloy_primitives::Bytes; +use alloy_eips::eip7685::Requests; use alloy_rpc_types_engine::{ CancunPayloadFields, ExecutionPayload, ForkChoiceUpdateResult, ForkchoiceState, ForkchoiceUpdateError, ForkchoiceUpdated, PayloadId, PayloadStatus, PayloadStatusEnum, @@ -150,7 +150,7 @@ pub enum BeaconEngineMessage { // HACK(onbjerg): We should have a pectra payload fields struct, this is just a temporary // workaround. /// The pectra EIP-7685 execution requests. - execution_requests: Option>, + execution_requests: Option, /// The sender for returning payload status result. tx: oneshot::Sender>, }, diff --git a/crates/consensus/beacon/src/engine/mod.rs b/crates/consensus/beacon/src/engine/mod.rs index edd3d6db3239..cff648b2843b 100644 --- a/crates/consensus/beacon/src/engine/mod.rs +++ b/crates/consensus/beacon/src/engine/mod.rs @@ -1,4 +1,5 @@ -use alloy_primitives::{BlockNumber, Bytes, B256}; +use alloy_eips::eip7685::Requests; +use alloy_primitives::{BlockNumber, B256}; use alloy_rpc_types_engine::{ CancunPayloadFields, ExecutionPayload, ForkchoiceState, PayloadStatus, PayloadStatusEnum, PayloadValidationError, @@ -1087,7 +1088,7 @@ where cancun_fields: Option, // HACK(onbjerg): We should have a pectra payload fields struct, this is just a temporary // workaround. - execution_requests: Option>, + execution_requests: Option, ) -> Result, BeaconOnNewPayloadError> { self.metrics.new_payload_messages.increment(1); diff --git a/crates/engine/tree/src/tree/mod.rs b/crates/engine/tree/src/tree/mod.rs index 02802dff66cb..a2abd3f531df 100644 --- a/crates/engine/tree/src/tree/mod.rs +++ b/crates/engine/tree/src/tree/mod.rs @@ -7,7 +7,7 @@ use crate::{ use alloy_eips::BlockNumHash; use alloy_primitives::{ map::{HashMap, HashSet}, - BlockNumber, Bytes, B256, U256, + BlockNumber, B256, U256, }; use alloy_rpc_types_engine::{ CancunPayloadFields, ExecutionPayload, ForkchoiceState, PayloadStatus, PayloadStatusEnum, @@ -70,6 +70,7 @@ use crate::{ engine::{EngineApiKind, EngineApiRequest}, tree::metrics::EngineApiMetrics, }; +use alloy_eips::eip7685::Requests; pub use config::TreeConfig; pub use invalid_block_hook::{InvalidBlockHooks, NoopInvalidBlockHook}; pub use persistence_state::PersistenceState; @@ -721,7 +722,7 @@ where &mut self, payload: ExecutionPayload, cancun_fields: Option, - execution_requests: Option>, + execution_requests: Option, ) -> Result, InsertBlockFatalError> { trace!(target: "engine::tree", "invoked new payload"); self.metrics.engine.new_payload_messages.increment(1); diff --git a/crates/engine/util/Cargo.toml b/crates/engine/util/Cargo.toml index c11948b9405f..35a7e74bb219 100644 --- a/crates/engine/util/Cargo.toml +++ b/crates/engine/util/Cargo.toml @@ -27,6 +27,7 @@ revm-primitives.workspace = true reth-trie.workspace = true # alloy +alloy-eips.workspace = true alloy-primitives.workspace = true alloy-rpc-types-engine.workspace = true alloy-consensus.workspace = true @@ -49,6 +50,4 @@ itertools.workspace = true tracing.workspace = true [features] -optimism = [ - "reth-beacon-consensus/optimism", -] +optimism = ["reth-beacon-consensus/optimism"] diff --git a/crates/engine/util/src/reorg.rs b/crates/engine/util/src/reorg.rs index 90b5c90aa952..e07b18b92509 100644 --- a/crates/engine/util/src/reorg.rs +++ b/crates/engine/util/src/reorg.rs @@ -1,7 +1,8 @@ //! Stream wrapper that simulates reorgs. use alloy_consensus::Transaction; -use alloy_primitives::{Bytes, U256}; +use alloy_eips::eip7685::Requests; +use alloy_primitives::U256; use alloy_rpc_types_engine::{ CancunPayloadFields, ExecutionPayload, ForkchoiceState, PayloadStatus, }; @@ -250,8 +251,8 @@ fn create_reorg_head( mut depth: usize, next_payload: ExecutionPayload, next_cancun_fields: Option, - next_execution_requests: Option>, -) -> RethResult<(ExecutionPayload, Option, Option>)> + next_execution_requests: Option, +) -> RethResult<(ExecutionPayload, Option, Option)> where Provider: BlockReader + StateProviderFactory, Evm: ConfigureEvm
, diff --git a/crates/payload/validator/Cargo.toml b/crates/payload/validator/Cargo.toml index a96799d7bcec..619b99f28de2 100644 --- a/crates/payload/validator/Cargo.toml +++ b/crates/payload/validator/Cargo.toml @@ -19,5 +19,4 @@ reth-rpc-types-compat.workspace = true # alloy alloy-eips.workspace = true -alloy-primitives.workspace = true alloy-rpc-types = { workspace = true, features = ["engine"] } diff --git a/crates/payload/validator/src/lib.rs b/crates/payload/validator/src/lib.rs index fdcd9244a434..3ec7b206a5b1 100644 --- a/crates/payload/validator/src/lib.rs +++ b/crates/payload/validator/src/lib.rs @@ -9,7 +9,6 @@ #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] use alloy_eips::eip7685::Requests; -use alloy_primitives::Bytes; use alloy_rpc_types::engine::{ExecutionPayload, MaybeCancunPayloadFields, PayloadError}; use reth_chainspec::EthereumHardforks; use reth_primitives::SealedBlock; @@ -114,17 +113,14 @@ impl ExecutionPayloadValidator { &self, payload: ExecutionPayload, cancun_fields: MaybeCancunPayloadFields, - execution_requests: Option>, + execution_requests: Option, ) -> Result { let expected_hash = payload.block_hash(); // First parse the block - let sealed_block = try_into_block( - payload, - cancun_fields.parent_beacon_block_root(), - execution_requests.map(Requests::new), - )? - .seal_slow(); + let sealed_block = + try_into_block(payload, cancun_fields.parent_beacon_block_root(), execution_requests)? + .seal_slow(); // Ensure the hash included in the payload matches the block hash if expected_hash != sealed_block.hash() { diff --git a/crates/rpc/rpc-api/src/engine.rs b/crates/rpc/rpc-api/src/engine.rs index 458768c38b19..ddf6d846119d 100644 --- a/crates/rpc/rpc-api/src/engine.rs +++ b/crates/rpc/rpc-api/src/engine.rs @@ -3,7 +3,7 @@ //! This contains the `engine_` namespace and the subset of the `eth_` namespace that is exposed to //! the consensus client. -use alloy_eips::{eip4844::BlobAndProofV1, BlockId, BlockNumberOrTag}; +use alloy_eips::{eip4844::BlobAndProofV1, eip7685::Requests, BlockId, BlockNumberOrTag}; use alloy_json_rpc::RpcObject; use alloy_primitives::{Address, BlockHash, Bytes, B256, U256, U64}; use alloy_rpc_types::{ @@ -57,7 +57,7 @@ pub trait EngineApi { payload: ExecutionPayloadV3, versioned_hashes: Vec, parent_beacon_block_root: B256, - execution_requests: Vec, + execution_requests: Requests, ) -> RpcResult; /// See also diff --git a/crates/rpc/rpc-engine-api/src/engine_api.rs b/crates/rpc/rpc-engine-api/src/engine_api.rs index 9450b2c92170..ca055a77ea10 100644 --- a/crates/rpc/rpc-engine-api/src/engine_api.rs +++ b/crates/rpc/rpc-engine-api/src/engine_api.rs @@ -1,8 +1,8 @@ use crate::{ capabilities::EngineCapabilities, metrics::EngineApiMetrics, EngineApiError, EngineApiResult, }; -use alloy_eips::eip4844::BlobAndProofV1; -use alloy_primitives::{BlockHash, BlockNumber, Bytes, B256, U64}; +use alloy_eips::{eip4844::BlobAndProofV1, eip7685::Requests}; +use alloy_primitives::{BlockHash, BlockNumber, B256, U64}; use alloy_rpc_types_engine::{ CancunPayloadFields, ClientVersionV1, ExecutionPayload, ExecutionPayloadBodiesV1, ExecutionPayloadInputV2, ExecutionPayloadV1, ExecutionPayloadV3, ForkchoiceState, @@ -189,7 +189,7 @@ where parent_beacon_block_root: B256, // TODO(onbjerg): Figure out why we even get these here, since we'll check the requests // from execution against the requests root in the header. - execution_requests: Vec, + execution_requests: Requests, ) -> EngineApiResult { let payload = ExecutionPayload::from(payload); let payload_or_attrs = @@ -677,7 +677,7 @@ where payload: ExecutionPayloadV3, versioned_hashes: Vec, parent_beacon_block_root: B256, - execution_requests: Vec, + execution_requests: Requests, ) -> RpcResult { trace!(target: "rpc::engine", "Serving engine_newPayloadV4"); let start = Instant::now(); From a78de201b349c10afef2403ea4e6e57fe075f7bf Mon Sep 17 00:00:00 2001 From: Gerson <71728860+Gerson2102@users.noreply.github.com> Date: Sat, 19 Oct 2024 10:01:26 -0600 Subject: [PATCH 092/113] Refactor of state_change functionality (#11878) Co-authored-by: Matthias Seitz --- Cargo.lock | 6 +++--- crates/engine/invalid-block-hooks/src/witness.rs | 5 +++-- crates/engine/util/src/reorg.rs | 6 ++++-- crates/ethereum/evm/src/execute.rs | 2 +- crates/ethereum/evm/src/strategy.rs | 2 +- crates/evm/Cargo.toml | 2 ++ crates/evm/src/lib.rs | 1 + crates/{revm => evm}/src/state_change.rs | 2 ++ crates/optimism/evm/src/execute.rs | 6 ++---- crates/optimism/evm/src/strategy.rs | 2 +- crates/payload/basic/Cargo.toml | 2 +- crates/payload/basic/src/lib.rs | 2 +- crates/revm/Cargo.toml | 2 -- crates/revm/src/lib.rs | 3 --- crates/rpc/rpc-eth-api/src/helpers/pending_block.rs | 11 ++++++----- 15 files changed, 28 insertions(+), 26 deletions(-) rename crates/{revm => evm}/src/state_change.rs (99%) diff --git a/Cargo.lock b/Cargo.lock index b3a39cb58748..57dc9176b815 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6400,12 +6400,12 @@ dependencies = [ "futures-util", "metrics", "reth-chainspec", + "reth-evm", "reth-metrics", "reth-payload-builder", "reth-payload-primitives", "reth-primitives", "reth-provider", - "reth-revm", "reth-tasks", "reth-transaction-pool", "revm", @@ -7427,6 +7427,8 @@ dependencies = [ "parking_lot 0.12.3", "reth-chainspec", "reth-consensus", + "reth-consensus-common", + "reth-ethereum-forks", "reth-execution-errors", "reth-execution-types", "reth-metrics", @@ -8585,8 +8587,6 @@ version = "1.1.0" dependencies = [ "alloy-eips", "alloy-primitives", - "reth-chainspec", - "reth-consensus-common", "reth-ethereum-forks", "reth-execution-errors", "reth-primitives", diff --git a/crates/engine/invalid-block-hooks/src/witness.rs b/crates/engine/invalid-block-hooks/src/witness.rs index ab73a81904df..416c4adb40f8 100644 --- a/crates/engine/invalid-block-hooks/src/witness.rs +++ b/crates/engine/invalid-block-hooks/src/witness.rs @@ -6,14 +6,15 @@ use eyre::OptionExt; use pretty_assertions::Comparison; use reth_chainspec::{EthChainSpec, EthereumHardforks}; use reth_engine_primitives::InvalidBlockHook; -use reth_evm::{system_calls::SystemCaller, ConfigureEvm}; +use reth_evm::{ + state_change::post_block_balance_increments, system_calls::SystemCaller, ConfigureEvm, +}; use reth_primitives::{Header, Receipt, SealedBlockWithSenders, SealedHeader}; use reth_provider::{BlockExecutionOutput, ChainSpecProvider, StateProviderFactory}; use reth_revm::{ database::StateProviderDatabase, db::states::bundle_state::BundleRetention, primitives::{BlockEnv, CfgEnvWithHandlerCfg, EnvWithHandlerCfg}, - state_change::post_block_balance_increments, DatabaseCommit, StateBuilder, }; use reth_rpc_api::DebugApiClient; diff --git a/crates/engine/util/src/reorg.rs b/crates/engine/util/src/reorg.rs index e07b18b92509..85216e32fad0 100644 --- a/crates/engine/util/src/reorg.rs +++ b/crates/engine/util/src/reorg.rs @@ -12,14 +12,16 @@ use reth_beacon_consensus::{BeaconEngineMessage, BeaconOnNewPayloadError, OnFork use reth_engine_primitives::EngineTypes; use reth_errors::{BlockExecutionError, BlockValidationError, RethError, RethResult}; use reth_ethereum_forks::EthereumHardforks; -use reth_evm::{system_calls::SystemCaller, ConfigureEvm}; +use reth_evm::{ + state_change::post_block_withdrawals_balance_increments, system_calls::SystemCaller, + ConfigureEvm, +}; use reth_payload_validator::ExecutionPayloadValidator; use reth_primitives::{proofs, Block, BlockBody, Header, Receipt, Receipts}; use reth_provider::{BlockReader, ExecutionOutcome, ProviderError, StateProviderFactory}; use reth_revm::{ database::StateProviderDatabase, db::{states::bundle_state::BundleRetention, State}, - state_change::post_block_withdrawals_balance_increments, DatabaseCommit, }; use reth_rpc_types_compat::engine::payload::block_to_payload; diff --git a/crates/ethereum/evm/src/execute.rs b/crates/ethereum/evm/src/execute.rs index 428458fcd04a..b4a90d409903 100644 --- a/crates/ethereum/evm/src/execute.rs +++ b/crates/ethereum/evm/src/execute.rs @@ -16,6 +16,7 @@ use reth_evm::{ BatchExecutor, BlockExecutionError, BlockExecutionInput, BlockExecutionOutput, BlockExecutorProvider, BlockValidationError, Executor, ProviderError, }, + state_change::post_block_balance_increments, system_calls::{NoopHook, OnStateHook, SystemCaller}, ConfigureEvm, }; @@ -25,7 +26,6 @@ use reth_prune_types::PruneModes; use reth_revm::{ batch::BlockBatchRecord, db::{states::bundle_state::BundleRetention, State}, - state_change::post_block_balance_increments, Evm, }; use revm_primitives::{ diff --git a/crates/ethereum/evm/src/strategy.rs b/crates/ethereum/evm/src/strategy.rs index 714f673c8582..55fbfffc8e98 100644 --- a/crates/ethereum/evm/src/strategy.rs +++ b/crates/ethereum/evm/src/strategy.rs @@ -16,13 +16,13 @@ use reth_evm::{ BlockExecutionError, BlockExecutionStrategy, BlockExecutionStrategyFactory, BlockValidationError, ProviderError, }, + state_change::post_block_balance_increments, system_calls::{OnStateHook, SystemCaller}, ConfigureEvm, ConfigureEvmEnv, }; use reth_primitives::{BlockWithSenders, Header, Receipt}; use reth_revm::{ db::{states::bundle_state::BundleRetention, BundleState}, - state_change::post_block_balance_increments, Database, DatabaseCommit, State, }; use revm_primitives::{BlockEnv, CfgEnvWithHandlerCfg, EnvWithHandlerCfg, ResultAndState, U256}; diff --git a/crates/evm/Cargo.toml b/crates/evm/Cargo.toml index 6081eae420cc..6c16973b28b3 100644 --- a/crates/evm/Cargo.toml +++ b/crates/evm/Cargo.toml @@ -14,6 +14,7 @@ workspace = true # reth reth-chainspec.workspace = true reth-consensus.workspace = true +reth-consensus-common.workspace = true reth-execution-errors.workspace = true reth-execution-types.workspace = true reth-metrics = { workspace = true, optional = true } @@ -37,6 +38,7 @@ parking_lot = { workspace = true, optional = true } [dev-dependencies] parking_lot.workspace = true +reth-ethereum-forks.workspace = true [features] default = ["std"] diff --git a/crates/evm/src/lib.rs b/crates/evm/src/lib.rs index 66026a07c94e..b75feea83a15 100644 --- a/crates/evm/src/lib.rs +++ b/crates/evm/src/lib.rs @@ -31,6 +31,7 @@ pub mod execute; pub mod metrics; pub mod noop; pub mod provider; +pub mod state_change; pub mod system_calls; #[cfg(any(test, feature = "test-utils"))] diff --git a/crates/revm/src/state_change.rs b/crates/evm/src/state_change.rs similarity index 99% rename from crates/revm/src/state_change.rs rename to crates/evm/src/state_change.rs index afe92561bcd3..2d5209015271 100644 --- a/crates/revm/src/state_change.rs +++ b/crates/evm/src/state_change.rs @@ -1,3 +1,5 @@ +//! State changes that are not related to transactions. + use alloy_primitives::{map::HashMap, Address, U256}; use reth_chainspec::EthereumHardforks; use reth_consensus_common::calc; diff --git a/crates/optimism/evm/src/execute.rs b/crates/optimism/evm/src/execute.rs index 3a86f5bbae4a..d15cdee13d66 100644 --- a/crates/optimism/evm/src/execute.rs +++ b/crates/optimism/evm/src/execute.rs @@ -14,6 +14,7 @@ use reth_evm::{ BatchExecutor, BlockExecutionError, BlockExecutionInput, BlockExecutionOutput, BlockExecutorProvider, BlockValidationError, Executor, ProviderError, }, + state_change::post_block_balance_increments, system_calls::{NoopHook, OnStateHook, SystemCaller}, ConfigureEvm, }; @@ -22,10 +23,7 @@ use reth_optimism_consensus::validate_block_post_execution; use reth_optimism_forks::OptimismHardfork; use reth_primitives::{BlockWithSenders, Header, Receipt, Receipts, TxType}; use reth_prune_types::PruneModes; -use reth_revm::{ - batch::BlockBatchRecord, db::states::bundle_state::BundleRetention, - state_change::post_block_balance_increments, Evm, State, -}; +use reth_revm::{batch::BlockBatchRecord, db::states::bundle_state::BundleRetention, Evm, State}; use revm_primitives::{ db::{Database, DatabaseCommit}, BlockEnv, CfgEnvWithHandlerCfg, EnvWithHandlerCfg, ResultAndState, diff --git a/crates/optimism/evm/src/strategy.rs b/crates/optimism/evm/src/strategy.rs index 199a8a4d3277..c626bb66587c 100644 --- a/crates/optimism/evm/src/strategy.rs +++ b/crates/optimism/evm/src/strategy.rs @@ -12,6 +12,7 @@ use reth_evm::{ BlockExecutionError, BlockExecutionStrategy, BlockExecutionStrategyFactory, BlockValidationError, ProviderError, }, + state_change::post_block_balance_increments, system_calls::{OnStateHook, SystemCaller}, ConfigureEvm, ConfigureEvmEnv, }; @@ -21,7 +22,6 @@ use reth_optimism_forks::OptimismHardfork; use reth_primitives::{BlockWithSenders, Header, Receipt, TxType}; use reth_revm::{ db::{states::bundle_state::BundleRetention, BundleState}, - state_change::post_block_balance_increments, Database, State, }; use revm_primitives::{ diff --git a/crates/payload/basic/Cargo.toml b/crates/payload/basic/Cargo.toml index f201df0c1bd5..9047768892a9 100644 --- a/crates/payload/basic/Cargo.toml +++ b/crates/payload/basic/Cargo.toml @@ -15,12 +15,12 @@ workspace = true # reth reth-chainspec.workspace = true reth-primitives.workspace = true -reth-revm.workspace = true reth-transaction-pool.workspace = true reth-provider.workspace = true reth-payload-builder.workspace = true reth-payload-primitives.workspace = true reth-tasks.workspace = true +reth-evm.workspace = true # ethereum alloy-rlp.workspace = true diff --git a/crates/payload/basic/src/lib.rs b/crates/payload/basic/src/lib.rs index 70d22250ddbe..fcc8be9a88ed 100644 --- a/crates/payload/basic/src/lib.rs +++ b/crates/payload/basic/src/lib.rs @@ -14,6 +14,7 @@ use alloy_primitives::{Bytes, B256, U256}; use futures_core::ready; use futures_util::FutureExt; use reth_chainspec::{ChainSpec, EthereumHardforks}; +use reth_evm::state_change::post_block_withdrawals_balance_increments; use reth_payload_builder::{ database::CachedReads, KeepPayloadJobAlive, PayloadId, PayloadJob, PayloadJobGenerator, }; @@ -27,7 +28,6 @@ use reth_primitives::{ use reth_provider::{ BlockReaderIdExt, BlockSource, CanonStateNotification, ProviderError, StateProviderFactory, }; -use reth_revm::state_change::post_block_withdrawals_balance_increments; use reth_tasks::TaskSpawner; use reth_transaction_pool::TransactionPool; use revm::{Database, State}; diff --git a/crates/revm/Cargo.toml b/crates/revm/Cargo.toml index 5772af0dc797..668abb79e381 100644 --- a/crates/revm/Cargo.toml +++ b/crates/revm/Cargo.toml @@ -13,11 +13,9 @@ workspace = true [dependencies] # reth -reth-chainspec.workspace = true reth-primitives.workspace = true reth-storage-errors.workspace = true reth-execution-errors.workspace = true -reth-consensus-common.workspace = true reth-prune-types.workspace = true reth-storage-api.workspace = true reth-trie = { workspace = true, optional = true } diff --git a/crates/revm/src/lib.rs b/crates/revm/src/lib.rs index 5515357d0d23..02eb182ee119 100644 --- a/crates/revm/src/lib.rs +++ b/crates/revm/src/lib.rs @@ -16,9 +16,6 @@ pub mod database; pub mod batch; -/// State changes that are not related to transactions. -pub mod state_change; - /// Common test helpers #[cfg(any(test, feature = "test-utils"))] pub mod test_utils; diff --git a/crates/rpc/rpc-eth-api/src/helpers/pending_block.rs b/crates/rpc/rpc-eth-api/src/helpers/pending_block.rs index 5e12e41e5500..407ddf1874ab 100644 --- a/crates/rpc/rpc-eth-api/src/helpers/pending_block.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/pending_block.rs @@ -11,7 +11,10 @@ use alloy_primitives::{BlockNumber, B256, U256}; use alloy_rpc_types::BlockNumberOrTag; use futures::Future; use reth_chainspec::{EthChainSpec, EthereumHardforks}; -use reth_evm::{system_calls::SystemCaller, ConfigureEvm, ConfigureEvmEnv}; +use reth_evm::{ + state_change::post_block_withdrawals_balance_increments, system_calls::SystemCaller, + ConfigureEvm, ConfigureEvmEnv, +}; use reth_execution_types::ExecutionOutcome; use reth_primitives::{ constants::{eip4844::MAX_DATA_GAS_PER_BLOCK, BEACON_NONCE}, @@ -27,9 +30,7 @@ use reth_provider::{ BlockReader, BlockReaderIdExt, ChainSpecProvider, EvmEnvProvider, ProviderError, ReceiptProvider, StateProviderFactory, }; -use reth_revm::{ - database::StateProviderDatabase, state_change::post_block_withdrawals_balance_increments, -}; +use reth_revm::database::StateProviderDatabase; use reth_rpc_eth_types::{EthApiError, PendingBlock, PendingBlockEnv, PendingBlockEnvOrigin}; use reth_transaction_pool::{BestTransactionsAttributes, TransactionPool}; use reth_trie::HashedPostState; @@ -157,7 +158,7 @@ pub trait LoadPendingBlock: EthApiTypes { pending.origin.header().hash() == pending_block.block.parent_hash && now <= pending_block.expires_at { - return Ok(Some((pending_block.block.clone(), pending_block.receipts.clone()))) + return Ok(Some((pending_block.block.clone(), pending_block.receipts.clone()))); } } From f8969cbbc2afc9c77b02ac2711f2ba7fc83e2c95 Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Sat, 19 Oct 2024 18:14:02 +0200 Subject: [PATCH 093/113] docs: add hardfork checklist (#11897) Co-authored-by: Oliver --- HARDFORK-CHECKLIST.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 HARDFORK-CHECKLIST.md diff --git a/HARDFORK-CHECKLIST.md b/HARDFORK-CHECKLIST.md new file mode 100644 index 000000000000..80ebfc20c98f --- /dev/null +++ b/HARDFORK-CHECKLIST.md @@ -0,0 +1,21 @@ +# Non-exhaustive checklist for integrating new changes for an upcoming hard fork/devnet + +## Introducing new EIP types or changes to primitive types + +- Make required changes to primitive data structures on [alloy](https://github.com/alloy-rs/alloy) +- All new EIP data structures/constants/helpers etc. go into the `alloy-eips` crate at first. +- New transaction types go into `alloy-consensus` +- If there are changes to existing data structures, such as `Header` or `Block`, apply them to the types in `alloy-consensus` (e.g. new `request_hashes` field in Prague) + +## Engine API + +- If there are changes to the engine API (e.g. a new `engine_newPayloadVx` and `engine_getPayloadVx` pair) add the new types to the `alloy-rpc-types-engine` crate. +- If there are new parameters to the `engine_newPayloadVx` endpoint, add them to the `ExecutionPayloadSidecar` container type. This types contains all additional parameters that are required to convert an `ExecutionPayload` to an EL block. + +## Reth changes + +### Updates to the engine API + +- Add new endpoints to the `EngineApi` trait and implement endpoints. +- Update the `ExceuctionPayload` + `ExecutionPayloadSidecar` to `Block` conversion if there are any additional parameters. +- Update version specific validation checks in the `EngineValidator` trait. \ No newline at end of file From e2ecb6224dae896653ac2f624abc46b328b7a88b Mon Sep 17 00:00:00 2001 From: Hai | RISE <150876604+hai-rise@users.noreply.github.com> Date: Sat, 19 Oct 2024 23:54:07 +0700 Subject: [PATCH 094/113] chore: remove unused deps (#11898) --- Cargo.lock | 52 --------------------- bin/reth/Cargo.toml | 1 - book/sources/exex/remote/Cargo.toml | 10 ++-- crates/e2e-test-utils/Cargo.toml | 8 +--- crates/engine/tree/Cargo.toml | 3 +- crates/ethereum-forks/Cargo.toml | 1 - crates/ethereum/node/Cargo.toml | 2 - crates/exex/exex/Cargo.toml | 6 ++- crates/net/network-types/Cargo.toml | 2 +- crates/node/core/Cargo.toml | 1 - crates/node/metrics/Cargo.toml | 1 - crates/optimism/node/Cargo.toml | 13 ------ crates/optimism/primitives/Cargo.toml | 1 - crates/primitives/Cargo.toml | 1 - crates/rpc/rpc-api/Cargo.toml | 5 +- crates/rpc/rpc-builder/Cargo.toml | 2 - crates/stages/stages/Cargo.toml | 7 ++- crates/static-file/static-file/Cargo.toml | 3 -- crates/storage/codecs/Cargo.toml | 2 - crates/storage/db-models/Cargo.toml | 8 +--- crates/storage/db/Cargo.toml | 1 - crates/trie/db/Cargo.toml | 11 ----- crates/trie/parallel/Cargo.toml | 7 ++- crates/trie/sparse/Cargo.toml | 6 --- crates/trie/trie/Cargo.toml | 7 --- examples/custom-rlpx-subprotocol/Cargo.toml | 2 - examples/polygon-p2p/Cargo.toml | 1 - 27 files changed, 23 insertions(+), 141 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 57dc9176b815..62ff16bb9d60 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2881,8 +2881,6 @@ dependencies = [ "reth-network", "reth-network-api", "reth-node-ethereum", - "reth-primitives", - "reth-provider", "tokio", "tokio-stream", "tracing", @@ -2972,7 +2970,6 @@ dependencies = [ "reth-discv4", "reth-network", "reth-primitives", - "reth-provider", "reth-tracing", "secp256k1", "serde_json", @@ -6312,7 +6309,6 @@ dependencies = [ "reth-consensus-common", "reth-db", "reth-db-api", - "reth-discv4", "reth-downloaders", "reth-engine-util", "reth-errors", @@ -6708,7 +6704,6 @@ dependencies = [ "alloy-eips", "alloy-genesis", "alloy-primitives", - "alloy-rlp", "alloy-trie", "arbitrary", "bytes", @@ -6716,7 +6711,6 @@ dependencies = [ "op-alloy-consensus", "proptest", "proptest-arbitrary-interop", - "rand 0.8.5", "reth-codecs-derive", "serde", "serde_json", @@ -6817,7 +6811,6 @@ dependencies = [ "paste", "pprof", "proptest", - "rand 0.8.5", "reth-db-api", "reth-fs-util", "reth-libmdbx", @@ -7041,22 +7034,16 @@ dependencies = [ "eyre", "futures-util", "jsonrpsee", - "jsonrpsee-types", "op-alloy-rpc-types-engine", "reth", "reth-chainspec", "reth-db", - "reth-engine-local", "reth-network-peers", "reth-node-builder", - "reth-node-ethereum", "reth-payload-builder", "reth-payload-primitives", - "reth-primitives", "reth-provider", - "reth-rpc", "reth-rpc-layer", - "reth-rpc-types-compat", "reth-stages-types", "reth-tokio-util", "reth-tracing", @@ -7177,7 +7164,6 @@ dependencies = [ "assert_matches", "futures", "metrics", - "rand 0.8.5", "reth-beacon-consensus", "reth-blockchain-tree", "reth-blockchain-tree-api", @@ -7515,7 +7501,6 @@ dependencies = [ "reth-chain-state", "reth-chainspec", "reth-config", - "reth-db-api", "reth-db-common", "reth-evm", "reth-evm-ethereum", @@ -7984,7 +7969,6 @@ dependencies = [ "serde", "shellexpand", "strum", - "tempfile", "thiserror", "tokio", "toml", @@ -8001,7 +7985,6 @@ dependencies = [ "alloy-primitives", "eyre", "futures", - "futures-util", "reth", "reth-auto-seal-consensus", "reth-basic-payload-builder", @@ -8017,7 +8000,6 @@ dependencies = [ "reth-network", "reth-node-api", "reth-node-builder", - "reth-node-core", "reth-payload-builder", "reth-primitives", "reth-provider", @@ -8066,7 +8048,6 @@ dependencies = [ "metrics-util", "procfs 0.16.0", "reqwest", - "reth-chainspec", "reth-db-api", "reth-metrics", "reth-provider", @@ -8215,15 +8196,11 @@ dependencies = [ "alloy-genesis", "alloy-primitives", "alloy-rpc-types-engine", - "async-trait", "clap", "eyre", - "jsonrpsee", - "jsonrpsee-types", "op-alloy-consensus", "op-alloy-rpc-types-engine", "parking_lot 0.12.3", - "reqwest", "reth", "reth-auto-seal-consensus", "reth-basic-payload-builder", @@ -8231,7 +8208,6 @@ dependencies = [ "reth-chainspec", "reth-consensus", "reth-db", - "reth-discv5", "reth-e2e-test-utils", "reth-engine-local", "reth-evm", @@ -8248,18 +8224,12 @@ dependencies = [ "reth-primitives", "reth-provider", "reth-revm", - "reth-rpc", - "reth-rpc-eth-api", - "reth-rpc-eth-types", - "reth-rpc-types-compat", "reth-tracing", "reth-transaction-pool", "revm", "serde", "serde_json", - "thiserror", "tokio", - "tracing", ] [[package]] @@ -8303,7 +8273,6 @@ dependencies = [ "alloy-consensus", "alloy-primitives", "reth-primitives", - "reth-primitives-traits", ] [[package]] @@ -8688,7 +8657,6 @@ dependencies = [ "reth-network-peers", "reth-primitives", "reth-rpc-eth-api", - "serde_json", ] [[package]] @@ -8736,7 +8704,6 @@ dependencies = [ "reth-metrics", "reth-network-api", "reth-network-peers", - "reth-node-api", "reth-node-core", "reth-payload-builder", "reth-primitives", @@ -8750,7 +8717,6 @@ dependencies = [ "reth-rpc-server-types", "reth-rpc-types-compat", "reth-tasks", - "reth-tokio-util", "reth-tracing", "reth-transaction-pool", "serde", @@ -8973,7 +8939,6 @@ dependencies = [ "reth-testing-utils", "reth-trie", "reth-trie-db", - "serde_json", "tempfile", "thiserror", "tokio", @@ -9033,11 +8998,8 @@ dependencies = [ "assert_matches", "parking_lot 0.12.3", "rayon", - "reth-chainspec", "reth-db", "reth-db-api", - "reth-nippy-jar", - "reth-node-types", "reth-provider", "reth-prune-types", "reth-stages", @@ -9200,13 +9162,11 @@ dependencies = [ "auto_impl", "bincode", "criterion", - "derive_more 1.0.0", "itertools 0.13.0", "metrics", "proptest", "proptest-arbitrary-interop", "rayon", - "reth-chainspec", "reth-execution-errors", "reth-metrics", "reth-primitives", @@ -9217,7 +9177,6 @@ dependencies = [ "serde", "serde_json", "serde_with", - "tokio", "tracing", "triehash", ] @@ -9253,22 +9212,17 @@ dependencies = [ "alloy-consensus", "alloy-primitives", "alloy-rlp", - "auto_impl", "derive_more 1.0.0", - "itertools 0.13.0", "metrics", "proptest", "proptest-arbitrary-interop", - "rayon", "reth-chainspec", "reth-db", "reth-db-api", "reth-execution-errors", "reth-metrics", - "reth-node-types", "reth-primitives", "reth-provider", - "reth-stages-types", "reth-storage-errors", "reth-trie", "reth-trie-common", @@ -9276,8 +9230,6 @@ dependencies = [ "serde", "serde_json", "similar-asserts", - "tokio", - "tokio-stream", "tracing", "triehash", ] @@ -9297,7 +9249,6 @@ dependencies = [ "rand 0.8.5", "rayon", "reth-db", - "reth-db-api", "reth-execution-errors", "reth-metrics", "reth-primitives", @@ -9321,15 +9272,12 @@ dependencies = [ "pretty_assertions", "proptest", "rand 0.8.5", - "rayon", - "reth-primitives", "reth-testing-utils", "reth-tracing", "reth-trie", "reth-trie-common", "smallvec", "thiserror", - "tracing", ] [[package]] diff --git a/bin/reth/Cargo.toml b/bin/reth/Cargo.toml index 476f9cd5cec7..8b2b77dd665c 100644 --- a/bin/reth/Cargo.toml +++ b/bin/reth/Cargo.toml @@ -96,7 +96,6 @@ backon.workspace = true similar-asserts.workspace = true [dev-dependencies] -reth-discv4.workspace = true tempfile.workspace = true [features] diff --git a/book/sources/exex/remote/Cargo.toml b/book/sources/exex/remote/Cargo.toml index 6eeb848cacfe..6cca3a841f07 100644 --- a/book/sources/exex/remote/Cargo.toml +++ b/book/sources/exex/remote/Cargo.toml @@ -6,9 +6,11 @@ edition = "2021" [dependencies] # reth reth = { git = "https://github.com/paradigmxyz/reth.git" } -reth-exex = { git = "https://github.com/paradigmxyz/reth.git", features = ["serde"] } -reth-node-ethereum = { git = "https://github.com/paradigmxyz/reth.git"} -reth-node-api = { git = "https://github.com/paradigmxyz/reth.git"} +reth-exex = { git = "https://github.com/paradigmxyz/reth.git", features = [ + "serde", +] } +reth-node-ethereum = { git = "https://github.com/paradigmxyz/reth.git" } +reth-node-api = { git = "https://github.com/paradigmxyz/reth.git" } reth-tracing = { git = "https://github.com/paradigmxyz/reth.git" } # async @@ -49,4 +51,4 @@ path = "src/exex.rs" [[bin]] name = "consumer" -path = "src/consumer.rs" \ No newline at end of file +path = "src/consumer.rs" diff --git a/crates/e2e-test-utils/Cargo.toml b/crates/e2e-test-utils/Cargo.toml index 2742d704054e..9fa3e2b60ab1 100644 --- a/crates/e2e-test-utils/Cargo.toml +++ b/crates/e2e-test-utils/Cargo.toml @@ -13,11 +13,8 @@ workspace = true [dependencies] reth.workspace = true reth-chainspec.workspace = true -reth-engine-local.workspace = true -reth-primitives.workspace = true reth-tracing.workspace = true reth-db = { workspace = true, features = ["test-utils"] } -reth-rpc.workspace = true reth-rpc-layer.workspace = true reth-payload-builder = { workspace = true, features = ["test-utils"] } reth-payload-primitives.workspace = true @@ -26,11 +23,8 @@ reth-node-builder = { workspace = true, features = ["test-utils"] } reth-tokio-util.workspace = true reth-stages-types.workspace = true reth-network-peers.workspace = true -reth-node-ethereum.workspace = true -reth-rpc-types-compat.workspace = true # rpc -jsonrpsee-types.workspace = true jsonrpsee.workspace = true # ethereum @@ -48,4 +42,4 @@ alloy-signer-local = { workspace = true, features = ["mnemonic"] } alloy-rpc-types.workspace = true alloy-network.workspace = true alloy-consensus = { workspace = true, features = ["kzg"] } -tracing.workspace = true \ No newline at end of file +tracing.workspace = true diff --git a/crates/engine/tree/Cargo.toml b/crates/engine/tree/Cargo.toml index 91c9cd5422d0..3a618f4fd7a1 100644 --- a/crates/engine/tree/Cargo.toml +++ b/crates/engine/tree/Cargo.toml @@ -76,7 +76,6 @@ reth-chainspec.workspace = true alloy-rlp.workspace = true assert_matches.workspace = true -rand.workspace = true [features] test-utils = [ @@ -86,5 +85,5 @@ test-utils = [ "reth-prune-types", "reth-stages/test-utils", "reth-static-file", - "reth-tracing" + "reth-tracing", ] diff --git a/crates/ethereum-forks/Cargo.toml b/crates/ethereum-forks/Cargo.toml index 62ea234cd5bb..7b4b6c53c09d 100644 --- a/crates/ethereum-forks/Cargo.toml +++ b/crates/ethereum-forks/Cargo.toml @@ -35,7 +35,6 @@ auto_impl.workspace = true [dev-dependencies] arbitrary = { workspace = true, features = ["derive"] } -proptest.workspace = true alloy-consensus.workspace = true [features] diff --git a/crates/ethereum/node/Cargo.toml b/crates/ethereum/node/Cargo.toml index 213071cbfb50..29093adc8a36 100644 --- a/crates/ethereum/node/Cargo.toml +++ b/crates/ethereum/node/Cargo.toml @@ -43,14 +43,12 @@ reth-chainspec.workspace = true reth-db.workspace = true reth-exex.workspace = true reth-node-api.workspace = true -reth-node-core.workspace = true reth-e2e-test-utils.workspace = true reth-tasks.workspace = true futures.workspace = true alloy-primitives.workspace = true alloy-genesis.workspace = true tokio.workspace = true -futures-util.workspace = true serde_json.workspace = true alloy-consensus.workspace = true diff --git a/crates/exex/exex/Cargo.toml b/crates/exex/exex/Cargo.toml index 6a3815e4045b..27a9d1576c82 100644 --- a/crates/exex/exex/Cargo.toml +++ b/crates/exex/exex/Cargo.toml @@ -17,7 +17,10 @@ reth-chain-state.workspace = true reth-chainspec.workspace = true reth-config.workspace = true reth-evm.workspace = true -reth-exex-types = { workspace = true, features = ["serde", "serde-bincode-compat"] } +reth-exex-types = { workspace = true, features = [ + "serde", + "serde-bincode-compat", +] } reth-fs-util.workspace = true reth-metrics.workspace = true reth-node-api.workspace = true @@ -51,7 +54,6 @@ tracing.workspace = true [dev-dependencies] reth-blockchain-tree.workspace = true -reth-db-api.workspace = true reth-db-common.workspace = true reth-evm-ethereum.workspace = true reth-node-api.workspace = true diff --git a/crates/net/network-types/Cargo.toml b/crates/net/network-types/Cargo.toml index 97c8e65cbbc2..c9b8fdd5bf20 100644 --- a/crates/net/network-types/Cargo.toml +++ b/crates/net/network-types/Cargo.toml @@ -22,7 +22,7 @@ serde = { workspace = true, optional = true } humantime-serde = { workspace = true, optional = true } serde_json = { workspace = true } -# misc +# misc tracing.workspace = true [features] diff --git a/crates/node/core/Cargo.toml b/crates/node/core/Cargo.toml index d7d95751cc5c..a6ae1db5e01d 100644 --- a/crates/node/core/Cargo.toml +++ b/crates/node/core/Cargo.toml @@ -74,7 +74,6 @@ futures.workspace = true # test vectors generation proptest.workspace = true tokio.workspace = true -tempfile.workspace = true [features] optimism = ["reth-primitives/optimism"] diff --git a/crates/node/metrics/Cargo.toml b/crates/node/metrics/Cargo.toml index 76a3a7f66329..9efdbd4959db 100644 --- a/crates/node/metrics/Cargo.toml +++ b/crates/node/metrics/Cargo.toml @@ -35,7 +35,6 @@ procfs = "0.16.0" [dev-dependencies] reqwest.workspace = true -reth-chainspec.workspace = true socket2 = { version = "0.5", default-features = false } reth-provider = { workspace = true, features = ["test-utils"] } diff --git a/crates/optimism/node/Cargo.toml b/crates/optimism/node/Cargo.toml index 8e359e602657..fbe787d6e160 100644 --- a/crates/optimism/node/Cargo.toml +++ b/crates/optimism/node/Cargo.toml @@ -19,7 +19,6 @@ reth-payload-builder.workspace = true reth-auto-seal-consensus.workspace = true reth-basic-payload-builder.workspace = true reth-consensus.workspace = true -reth-rpc-types-compat.workspace = true reth-node-api.workspace = true reth-node-builder.workspace = true reth-tracing.workspace = true @@ -29,10 +28,6 @@ reth-network.workspace = true reth-evm.workspace = true reth-revm = { workspace = true, features = ["std"] } reth-beacon-consensus.workspace = true -reth-discv5.workspace = true -reth-rpc-eth-types.workspace = true -reth-rpc-eth-api.workspace = true -reth-rpc.workspace = true # op-reth reth-optimism-payload-builder.workspace = true @@ -51,21 +46,13 @@ alloy-primitives.workspace = true op-alloy-rpc-types-engine.workspace = true alloy-rpc-types-engine.workspace = true -# async -async-trait.workspace = true -reqwest = { workspace = true, features = ["rustls-tls-native-roots"] } -tracing.workspace = true - # misc clap.workspace = true serde.workspace = true eyre.workspace = true parking_lot.workspace = true -thiserror.workspace = true # rpc -jsonrpsee.workspace = true -jsonrpsee-types.workspace = true serde_json.workspace = true [dev-dependencies] diff --git a/crates/optimism/primitives/Cargo.toml b/crates/optimism/primitives/Cargo.toml index 2054de7305ba..a2d4c20a8b72 100644 --- a/crates/optimism/primitives/Cargo.toml +++ b/crates/optimism/primitives/Cargo.toml @@ -13,6 +13,5 @@ workspace = true [dependencies] reth-primitives.workspace = true -reth-primitives-traits.workspace = true alloy-primitives.workspace = true alloy-consensus.workspace = true diff --git a/crates/primitives/Cargo.toml b/crates/primitives/Cargo.toml index 05ccd9081a27..5661fb8f8467 100644 --- a/crates/primitives/Cargo.toml +++ b/crates/primitives/Cargo.toml @@ -75,7 +75,6 @@ alloy-genesis.workspace = true arbitrary = { workspace = true, features = ["derive"] } assert_matches.workspace = true bincode.workspace = true -modular-bitfield.workspace = true proptest-arbitrary-interop.workspace = true proptest.workspace = true rand.workspace = true diff --git a/crates/rpc/rpc-api/Cargo.toml b/crates/rpc/rpc-api/Cargo.toml index 6e9e469ec443..363e22955301 100644 --- a/crates/rpc/rpc-api/Cargo.toml +++ b/crates/rpc/rpc-api/Cargo.toml @@ -37,12 +37,9 @@ alloy-rpc-types-engine.workspace = true # misc jsonrpsee = { workspace = true, features = ["server", "macros"] } -[dev-dependencies] -serde_json.workspace = true - [features] client = [ "jsonrpsee/client", "jsonrpsee/async-client", - "reth-rpc-eth-api/client" + "reth-rpc-eth-api/client", ] diff --git a/crates/rpc/rpc-builder/Cargo.toml b/crates/rpc/rpc-builder/Cargo.toml index 817d2a3d76b8..cc72c2ebf92e 100644 --- a/crates/rpc/rpc-builder/Cargo.toml +++ b/crates/rpc/rpc-builder/Cargo.toml @@ -64,8 +64,6 @@ reth-rpc-api = { workspace = true, features = ["client"] } reth-rpc-engine-api.workspace = true reth-tracing.workspace = true reth-transaction-pool = { workspace = true, features = ["test-utils"] } -reth-tokio-util.workspace = true -reth-node-api.workspace = true reth-rpc-types-compat.workspace = true alloy-primitives.workspace = true diff --git a/crates/stages/stages/Cargo.toml b/crates/stages/stages/Cargo.toml index 3d4227d8a274..81f35a4b390b 100644 --- a/crates/stages/stages/Cargo.toml +++ b/crates/stages/stages/Cargo.toml @@ -24,7 +24,9 @@ reth-evm.workspace = true reth-exex.workspace = true reth-network-p2p.workspace = true reth-primitives = { workspace = true, features = ["secp256k1"] } -reth-primitives-traits = { workspace = true, features = ["serde-bincode-compat"] } +reth-primitives-traits = { workspace = true, features = [ + "serde-bincode-compat", +] } reth-provider.workspace = true reth-execution-types.workspace = true reth-prune.workspace = true @@ -82,9 +84,6 @@ tempfile.workspace = true # Stage benchmarks criterion = { workspace = true, features = ["async_tokio"] } -# io -serde_json.workspace = true - [target.'cfg(not(target_os = "windows"))'.dev-dependencies] pprof = { workspace = true, features = [ "flamegraph", diff --git a/crates/static-file/static-file/Cargo.toml b/crates/static-file/static-file/Cargo.toml index 8fa89e12e0ff..d22b116cdc59 100644 --- a/crates/static-file/static-file/Cargo.toml +++ b/crates/static-file/static-file/Cargo.toml @@ -13,17 +13,14 @@ workspace = true [dependencies] # reth -reth-chainspec.workspace = true reth-db.workspace = true reth-db-api.workspace = true reth-provider.workspace = true reth-storage-errors.workspace = true -reth-nippy-jar.workspace = true reth-tokio-util.workspace = true reth-prune-types.workspace = true reth-static-file-types.workspace = true reth-stages-types.workspace = true -reth-node-types.workspace = true alloy-primitives.workspace = true diff --git a/crates/storage/codecs/Cargo.toml b/crates/storage/codecs/Cargo.toml index 640ec8c9561f..21a1897f1c78 100644 --- a/crates/storage/codecs/Cargo.toml +++ b/crates/storage/codecs/Cargo.toml @@ -39,8 +39,6 @@ alloy-primitives = { workspace = true, features = [ "rand", ] } alloy-consensus = { workspace = true, features = ["arbitrary"] } -alloy-rlp.workspace = true -rand.workspace = true test-fuzz.workspace = true serde_json.workspace = true diff --git a/crates/storage/db-models/Cargo.toml b/crates/storage/db-models/Cargo.toml index 9bcd54f3860d..492178775b64 100644 --- a/crates/storage/db-models/Cargo.toml +++ b/crates/storage/db-models/Cargo.toml @@ -35,15 +35,9 @@ proptest = { workspace = true, optional = true } reth-primitives = { workspace = true, features = ["arbitrary"] } reth-codecs.workspace = true -arbitrary = { workspace = true, features = ["derive"] } proptest-arbitrary-interop.workspace = true -proptest.workspace = true test-fuzz.workspace = true [features] test-utils = ["arbitrary"] -arbitrary = [ - "reth-primitives/arbitrary", - "dep:arbitrary", - "dep:proptest", -] +arbitrary = ["reth-primitives/arbitrary", "dep:arbitrary", "dep:proptest"] diff --git a/crates/storage/db/Cargo.toml b/crates/storage/db/Cargo.toml index a075f7724637..356672f2548d 100644 --- a/crates/storage/db/Cargo.toml +++ b/crates/storage/db/Cargo.toml @@ -58,7 +58,6 @@ strum = { workspace = true, features = ["derive"], optional = true } [dev-dependencies] # reth libs with arbitrary reth-primitives = { workspace = true, features = ["arbitrary"] } -rand.workspace = true serde_json.workspace = true tempfile.workspace = true test-fuzz.workspace = true diff --git a/crates/trie/db/Cargo.toml b/crates/trie/db/Cargo.toml index a0e1acbce352..e75b0456eb9b 100644 --- a/crates/trie/db/Cargo.toml +++ b/crates/trie/db/Cargo.toml @@ -17,7 +17,6 @@ reth-primitives.workspace = true reth-execution-errors.workspace = true reth-db.workspace = true reth-db-api.workspace = true -reth-stages-types.workspace = true reth-storage-errors.workspace = true reth-trie-common.workspace = true reth-trie.workspace = true @@ -32,10 +31,7 @@ alloy-primitives.workspace = true tracing.workspace = true # misc -rayon.workspace = true derive_more.workspace = true -auto_impl.workspace = true -itertools.workspace = true # `metrics` feature reth-metrics = { workspace = true, optional = true } @@ -56,7 +52,6 @@ reth-provider = { workspace = true, features = ["test-utils"] } reth-storage-errors.workspace = true reth-trie-common = { workspace = true, features = ["test-utils", "arbitrary"] } reth-trie = { workspace = true, features = ["test-utils"] } -reth-node-types.workspace = true alloy-consensus.workspace = true @@ -66,12 +61,6 @@ triehash = "0.8" # misc proptest.workspace = true proptest-arbitrary-interop.workspace = true -tokio = { workspace = true, default-features = false, features = [ - "sync", - "rt", - "macros", -] } -tokio-stream.workspace = true serde_json.workspace = true similar-asserts.workspace = true diff --git a/crates/trie/parallel/Cargo.toml b/crates/trie/parallel/Cargo.toml index 64a4644bdce4..cc35fe9f914a 100644 --- a/crates/trie/parallel/Cargo.toml +++ b/crates/trie/parallel/Cargo.toml @@ -15,7 +15,6 @@ workspace = true # reth reth-primitives.workspace = true reth-db.workspace = true -reth-db-api.workspace = true reth-trie.workspace = true reth-trie-db.workspace = true reth-execution-errors.workspace = true @@ -46,7 +45,11 @@ reth-trie = { workspace = true, features = ["test-utils"] } # misc rand.workspace = true -tokio = { workspace = true, default-features = false, features = ["sync", "rt", "macros"] } +tokio = { workspace = true, default-features = false, features = [ + "sync", + "rt", + "macros", +] } rayon.workspace = true criterion = { workspace = true, features = ["async_tokio"] } proptest.workspace = true diff --git a/crates/trie/sparse/Cargo.toml b/crates/trie/sparse/Cargo.toml index 4ba6ed0f2ec6..26d036f57ff9 100644 --- a/crates/trie/sparse/Cargo.toml +++ b/crates/trie/sparse/Cargo.toml @@ -14,7 +14,6 @@ workspace = true [dependencies] # reth -reth-primitives.workspace = true reth-tracing.workspace = true reth-trie-common.workspace = true reth-trie.workspace = true @@ -23,16 +22,11 @@ reth-trie.workspace = true alloy-primitives.workspace = true alloy-rlp.workspace = true -# tracing -tracing.workspace = true - # misc -rayon.workspace = true smallvec = { workspace = true, features = ["const_new"] } thiserror.workspace = true [dev-dependencies] -reth-primitives = { workspace = true, features = ["test-utils", "arbitrary"] } reth-testing-utils.workspace = true reth-trie = { workspace = true, features = ["test-utils"] } reth-trie-common = { workspace = true, features = ["test-utils", "arbitrary"] } diff --git a/crates/trie/trie/Cargo.toml b/crates/trie/trie/Cargo.toml index 31b5ac3e25cd..77fc57397700 100644 --- a/crates/trie/trie/Cargo.toml +++ b/crates/trie/trie/Cargo.toml @@ -31,7 +31,6 @@ tracing.workspace = true # misc rayon.workspace = true -derive_more.workspace = true auto_impl.workspace = true itertools.workspace = true @@ -50,7 +49,6 @@ serde_with = { workspace = true, optional = true } [dev-dependencies] # reth -reth-chainspec.workspace = true reth-primitives = { workspace = true, features = ["test-utils", "arbitrary"] } reth-trie-common = { workspace = true, features = ["test-utils", "arbitrary"] } @@ -60,11 +58,6 @@ triehash = "0.8" # misc proptest.workspace = true proptest-arbitrary-interop.workspace = true -tokio = { workspace = true, default-features = false, features = [ - "sync", - "rt", - "macros", -] } serde_json.workspace = true criterion.workspace = true bincode.workspace = true diff --git a/examples/custom-rlpx-subprotocol/Cargo.toml b/examples/custom-rlpx-subprotocol/Cargo.toml index d59d16f35cfc..18c136671c06 100644 --- a/examples/custom-rlpx-subprotocol/Cargo.toml +++ b/examples/custom-rlpx-subprotocol/Cargo.toml @@ -13,8 +13,6 @@ reth-eth-wire.workspace = true reth-network.workspace = true reth-network-api.workspace = true reth-node-ethereum.workspace = true -reth-provider = { workspace = true, features = ["test-utils"] } -reth-primitives.workspace = true reth.workspace = true tokio-stream.workspace = true eyre.workspace = true diff --git a/examples/polygon-p2p/Cargo.toml b/examples/polygon-p2p/Cargo.toml index bdf9a27ce560..e18f32a64737 100644 --- a/examples/polygon-p2p/Cargo.toml +++ b/examples/polygon-p2p/Cargo.toml @@ -20,6 +20,5 @@ reth-primitives.workspace = true serde_json.workspace = true reth-tracing.workspace = true tokio-stream.workspace = true -reth-provider = { workspace = true, features = ["test-utils"] } reth-discv4 = { workspace = true, features = ["test-utils"] } alloy-primitives.workspace = true From d0ac83394616e97ccc559c92e0f594b18cfa4440 Mon Sep 17 00:00:00 2001 From: greged93 <82421016+greged93@users.noreply.github.com> Date: Sat, 19 Oct 2024 18:56:48 +0200 Subject: [PATCH 095/113] perf: avoid cloning in payload builder (#11899) --- crates/ethereum/payload/src/lib.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/crates/ethereum/payload/src/lib.rs b/crates/ethereum/payload/src/lib.rs index e09228302e4c..7f94acf723cf 100644 --- a/crates/ethereum/payload/src/lib.rs +++ b/crates/ethereum/payload/src/lib.rs @@ -339,11 +339,12 @@ where // and 4788 contract call db.merge_transitions(BundleRetention::Reverts); + let requests_hash = requests.as_ref().map(|requests| requests.requests_hash()); let execution_outcome = ExecutionOutcome::new( db.take_bundle(), - vec![receipts.clone()].into(), + vec![receipts].into(), block_number, - vec![requests.clone().unwrap_or_default()], + vec![requests.unwrap_or_default()], ); let receipts_root = execution_outcome.receipts_root_slow(block_number).expect("Number is in range"); @@ -411,7 +412,7 @@ where parent_beacon_block_root: attributes.parent_beacon_block_root, blob_gas_used: blob_gas_used.map(Into::into), excess_blob_gas: excess_blob_gas.map(Into::into), - requests_hash: requests.map(|r| r.requests_hash()), + requests_hash, }; // seal the block From cd828c06d9fa9638951060c6ca3772d9a7c619a6 Mon Sep 17 00:00:00 2001 From: Federico Gimenez Date: Sat, 19 Oct 2024 19:59:32 +0200 Subject: [PATCH 096/113] feat: switch to composable executor for Ethereum (#11838) --- Cargo.lock | 2 +- crates/ethereum/evm/Cargo.toml | 3 +- crates/ethereum/evm/src/execute.rs | 643 ++++------ crates/ethereum/evm/src/lib.rs | 4 +- crates/ethereum/evm/src/strategy.rs | 1176 ------------------ crates/ethereum/node/Cargo.toml | 1 + crates/ethereum/node/src/evm.rs | 4 +- crates/ethereum/node/src/lib.rs | 4 +- crates/ethereum/node/src/node.rs | 8 +- crates/rpc/rpc-builder/tests/it/utils.rs | 9 +- crates/stages/stages/src/stages/execution.rs | 8 +- examples/custom-evm/src/main.rs | 9 +- examples/stateful-precompile/src/main.rs | 15 +- 13 files changed, 277 insertions(+), 1609 deletions(-) delete mode 100644 crates/ethereum/evm/src/strategy.rs diff --git a/Cargo.lock b/Cargo.lock index 62ff16bb9d60..25a62d0c0432 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7443,7 +7443,6 @@ dependencies = [ "reth-evm", "reth-execution-types", "reth-primitives", - "reth-prune-types", "reth-revm", "reth-testing-utils", "revm-primitives", @@ -7995,6 +7994,7 @@ dependencies = [ "reth-e2e-test-utils", "reth-ethereum-engine-primitives", "reth-ethereum-payload-builder", + "reth-evm", "reth-evm-ethereum", "reth-exex", "reth-network", diff --git a/crates/ethereum/evm/Cargo.toml b/crates/ethereum/evm/Cargo.toml index 7215efa68c60..8cbc92f90f3d 100644 --- a/crates/ethereum/evm/Cargo.toml +++ b/crates/ethereum/evm/Cargo.toml @@ -18,8 +18,6 @@ reth-evm.workspace = true reth-primitives = { workspace = true, features = ["reth-codec"] } reth-revm.workspace = true reth-ethereum-consensus.workspace = true -reth-prune-types.workspace = true -reth-execution-types.workspace = true reth-consensus.workspace = true # Ethereum @@ -36,6 +34,7 @@ reth-testing-utils.workspace = true reth-evm = { workspace = true, features = ["test-utils"] } reth-revm = { workspace = true, features = ["test-utils"] } reth-primitives = { workspace = true, features = ["secp256k1"] } +reth-execution-types.workspace = true secp256k1.workspace = true serde_json.workspace = true alloy-genesis.workspace = true diff --git a/crates/ethereum/evm/src/execute.rs b/crates/ethereum/evm/src/execute.rs index b4a90d409903..185f351dd9f3 100644 --- a/crates/ethereum/evm/src/execute.rs +++ b/crates/ethereum/evm/src/execute.rs @@ -1,158 +1,161 @@ -//! Ethereum block executor. +//! Ethereum block execution strategy. use crate::{ dao_fork::{DAO_HARDFORK_BENEFICIARY, DAO_HARDKFORK_ACCOUNTS}, EthEvmConfig, }; -use alloc::{boxed::Box, sync::Arc, vec::Vec}; +use alloc::{boxed::Box, sync::Arc, vec, vec::Vec}; use alloy_consensus::Transaction as _; use alloy_eips::eip7685::Requests; -use alloy_primitives::{BlockNumber, U256}; use core::fmt::Display; -use reth_chainspec::{ChainSpec, EthereumHardforks, MAINNET}; +use reth_chainspec::{ChainSpec, EthereumHardfork, EthereumHardforks, MAINNET}; +use reth_consensus::ConsensusError; use reth_ethereum_consensus::validate_block_post_execution; use reth_evm::{ execute::{ - BatchExecutor, BlockExecutionError, BlockExecutionInput, BlockExecutionOutput, - BlockExecutorProvider, BlockValidationError, Executor, ProviderError, + BasicBlockExecutorProvider, BlockExecutionError, BlockExecutionStrategy, + BlockExecutionStrategyFactory, BlockValidationError, ProviderError, }, state_change::post_block_balance_increments, - system_calls::{NoopHook, OnStateHook, SystemCaller}, + system_calls::{OnStateHook, SystemCaller}, ConfigureEvm, }; -use reth_execution_types::ExecutionOutcome; -use reth_primitives::{BlockWithSenders, EthereumHardfork, Header, Receipt}; -use reth_prune_types::PruneModes; -use reth_revm::{ - batch::BlockBatchRecord, - db::{states::bundle_state::BundleRetention, State}, - Evm, -}; +use reth_primitives::{BlockWithSenders, Receipt}; +use reth_revm::db::{states::bundle_state::BundleRetention, BundleState, State}; use revm_primitives::{ db::{Database, DatabaseCommit}, - BlockEnv, CfgEnvWithHandlerCfg, EnvWithHandlerCfg, ResultAndState, + BlockEnv, CfgEnvWithHandlerCfg, EnvWithHandlerCfg, ResultAndState, U256, }; -/// Provides executors to execute regular ethereum blocks +/// Factory for [`EthExecutionStrategy`]. #[derive(Debug, Clone)] -pub struct EthExecutorProvider { +pub struct EthExecutionStrategyFactory { + /// The chainspec chain_spec: Arc, + /// How to create an EVM. evm_config: EvmConfig, } -impl EthExecutorProvider { - /// Creates a new default ethereum executor provider. +impl EthExecutionStrategyFactory { + /// Creates a new default ethereum executor strategy factory. pub fn ethereum(chain_spec: Arc) -> Self { Self::new(chain_spec.clone(), EthEvmConfig::new(chain_spec)) } - /// Returns a new provider for the mainnet. + /// Returns a new factory for the mainnet. pub fn mainnet() -> Self { Self::ethereum(MAINNET.clone()) } } -impl EthExecutorProvider { - /// Creates a new executor provider. +impl EthExecutionStrategyFactory { + /// Creates a new executor strategy factory. pub const fn new(chain_spec: Arc, evm_config: EvmConfig) -> Self { Self { chain_spec, evm_config } } } -impl EthExecutorProvider -where - EvmConfig: ConfigureEvm
, -{ - fn eth_executor(&self, db: DB) -> EthBlockExecutor - where - DB: Database>, - { - EthBlockExecutor::new( - self.chain_spec.clone(), - self.evm_config.clone(), - State::builder().with_database(db).with_bundle_update().without_state_clear().build(), - ) - } -} - -impl BlockExecutorProvider for EthExecutorProvider +impl BlockExecutionStrategyFactory for EthExecutionStrategyFactory where - EvmConfig: ConfigureEvm
, + EvmConfig: + Clone + Unpin + Sync + Send + 'static + ConfigureEvm
, { - type Executor + Display>> = - EthBlockExecutor; - - type BatchExecutor + Display>> = - EthBatchExecutor; + type Strategy + Display>> = + EthExecutionStrategy; - fn executor(&self, db: DB) -> Self::Executor + fn create_strategy(&self, db: DB) -> Self::Strategy where DB: Database + Display>, { - self.eth_executor(db) + let state = + State::builder().with_database(db).with_bundle_update().without_state_clear().build(); + EthExecutionStrategy::new(state, self.chain_spec.clone(), self.evm_config.clone()) } - - fn batch_executor(&self, db: DB) -> Self::BatchExecutor - where - DB: Database + Display>, - { - let executor = self.eth_executor(db); - EthBatchExecutor { executor, batch_record: BlockBatchRecord::default() } - } -} - -/// Helper type for the output of executing a block. -#[derive(Debug, Clone)] -struct EthExecuteOutput { - receipts: Vec, - requests: Requests, - gas_used: u64, } -/// Helper container type for EVM with chain spec. -#[derive(Debug, Clone)] -struct EthEvmExecutor { +/// Block execution strategy for Ethereum. +#[allow(missing_debug_implementations)] +pub struct EthExecutionStrategy +where + EvmConfig: Clone, +{ /// The chainspec chain_spec: Arc, /// How to create an EVM. evm_config: EvmConfig, + /// Current state for block execution. + state: State, + /// Utility to call system smart contracts. + system_caller: SystemCaller, } -impl EthEvmExecutor +impl EthExecutionStrategy where - EvmConfig: ConfigureEvm
, + EvmConfig: Clone, { - /// Executes the transactions in the block and returns the receipts of the transactions in the - /// block, the total gas used and the list of EIP-7685 [requests](Requests). - /// - /// This applies the pre-execution and post-execution changes that require an [EVM](Evm), and - /// executes the transactions. - /// - /// The optional `state_hook` will be executed with the state changes if present. + /// Creates a new [`EthExecutionStrategy`] + pub fn new(state: State, chain_spec: Arc, evm_config: EvmConfig) -> Self { + let system_caller = SystemCaller::new(evm_config.clone(), (*chain_spec).clone()); + Self { state, chain_spec, evm_config, system_caller } + } +} + +impl EthExecutionStrategy +where + DB: Database + Display>, + EvmConfig: ConfigureEvm
, +{ + /// Configures a new evm configuration and block environment for the given block. /// - /// # Note + /// # Caution /// - /// It does __not__ apply post-execution changes that do not require an [EVM](Evm), for that see - /// [`EthBlockExecutor::post_execution`]. - fn execute_state_transitions( + /// This does not initialize the tx environment. + fn evm_env_for_block( &self, + header: &alloy_consensus::Header, + total_difficulty: U256, + ) -> EnvWithHandlerCfg { + let mut cfg = CfgEnvWithHandlerCfg::new(Default::default(), Default::default()); + let mut block_env = BlockEnv::default(); + self.evm_config.fill_cfg_and_block_env(&mut cfg, &mut block_env, header, total_difficulty); + + EnvWithHandlerCfg::new_with_cfg_env(cfg, block_env, Default::default()) + } +} + +impl BlockExecutionStrategy for EthExecutionStrategy +where + DB: Database + Display>, + EvmConfig: ConfigureEvm
, +{ + type Error = BlockExecutionError; + + fn apply_pre_execution_changes( + &mut self, block: &BlockWithSenders, - mut evm: Evm<'_, Ext, &mut State>, - state_hook: Option, - ) -> Result - where - DB: Database, - DB::Error: Into + Display, - F: OnStateHook + 'static, - { - let mut system_caller = SystemCaller::new(self.evm_config.clone(), &self.chain_spec); - if let Some(hook) = state_hook { - system_caller.with_state_hook(Some(Box::new(hook) as Box)); - } + total_difficulty: U256, + ) -> Result<(), Self::Error> { + // Set state clear flag if the block is after the Spurious Dragon hardfork. + let state_clear_flag = + (*self.chain_spec).is_spurious_dragon_active_at_block(block.header.number); + self.state.set_state_clear_flag(state_clear_flag); + + let env = self.evm_env_for_block(&block.header, total_difficulty); + let mut evm = self.evm_config.evm_with_env(&mut self.state, env); + + self.system_caller.apply_pre_execution_changes(block, &mut evm)?; + + Ok(()) + } - system_caller.apply_pre_execution_changes(block, &mut evm)?; + fn execute_transactions( + &mut self, + block: &BlockWithSenders, + total_difficulty: U256, + ) -> Result<(Vec, u64), Self::Error> { + let env = self.evm_env_for_block(&block.header, total_difficulty); + let mut evm = self.evm_config.evm_with_env(&mut self.state, env); - // execute transactions let mut cumulative_gas_used = 0; let mut receipts = Vec::with_capacity(block.body.transactions.len()); for (sender, transaction) in block.transactions_with_sender() { @@ -178,7 +181,7 @@ where error: Box::new(new_err), } })?; - system_caller.on_state(&result_and_state); + self.system_caller.on_state(&result_and_state); let ResultAndState { result, state } = result_and_state; evm.db_mut().commit(state); @@ -200,137 +203,36 @@ where }, ); } + Ok((receipts, cumulative_gas_used)) + } + + fn apply_post_execution_changes( + &mut self, + block: &BlockWithSenders, + total_difficulty: U256, + receipts: &[Receipt], + ) -> Result { + let env = self.evm_env_for_block(&block.header, total_difficulty); + let mut evm = self.evm_config.evm_with_env(&mut self.state, env); let requests = if self.chain_spec.is_prague_active_at_timestamp(block.timestamp) { // Collect all EIP-6110 deposits let deposit_requests = - crate::eip6110::parse_deposits_from_receipts(&self.chain_spec, &receipts)?; + crate::eip6110::parse_deposits_from_receipts(&self.chain_spec, receipts)?; let mut requests = Requests::new(vec![deposit_requests]); - requests.extend(system_caller.apply_post_execution_changes(&mut evm)?); + requests.extend(self.system_caller.apply_post_execution_changes(&mut evm)?); requests } else { Requests::default() }; + drop(evm); - Ok(EthExecuteOutput { receipts, requests, gas_used: cumulative_gas_used }) - } -} - -/// A basic Ethereum block executor. -/// -/// Expected usage: -/// - Create a new instance of the executor. -/// - Execute the block. -#[derive(Debug)] -pub struct EthBlockExecutor { - /// Chain specific evm config that's used to execute a block. - executor: EthEvmExecutor, - /// The state to use for execution - state: State, -} - -impl EthBlockExecutor { - /// Creates a new Ethereum block executor. - pub const fn new(chain_spec: Arc, evm_config: EvmConfig, state: State) -> Self { - Self { executor: EthEvmExecutor { chain_spec, evm_config }, state } - } - - #[inline] - fn chain_spec(&self) -> &ChainSpec { - &self.executor.chain_spec - } - - /// Returns mutable reference to the state that wraps the underlying database. - #[allow(unused)] - fn state_mut(&mut self) -> &mut State { - &mut self.state - } -} - -impl EthBlockExecutor -where - EvmConfig: ConfigureEvm
, - DB: Database + Display>, -{ - /// Configures a new evm configuration and block environment for the given block. - /// - /// # Caution - /// - /// This does not initialize the tx environment. - fn evm_env_for_block(&self, header: &Header, total_difficulty: U256) -> EnvWithHandlerCfg { - let mut cfg = CfgEnvWithHandlerCfg::new(Default::default(), Default::default()); - let mut block_env = BlockEnv::default(); - self.executor.evm_config.fill_cfg_and_block_env( - &mut cfg, - &mut block_env, - header, - total_difficulty, - ); - - EnvWithHandlerCfg::new_with_cfg_env(cfg, block_env, Default::default()) - } - - /// Convenience method to invoke `execute_without_verification_with_state_hook` setting the - /// state hook as `None`. - fn execute_without_verification( - &mut self, - block: &BlockWithSenders, - total_difficulty: U256, - ) -> Result { - self.execute_without_verification_with_state_hook(block, total_difficulty, None::) - } - - /// Execute a single block and apply the state changes to the internal state. - /// - /// Returns the receipts of the transactions in the block, the total gas used and the list of - /// EIP-7685 [requests](Requests). - /// - /// Returns an error if execution fails. - fn execute_without_verification_with_state_hook( - &mut self, - block: &BlockWithSenders, - total_difficulty: U256, - state_hook: Option, - ) -> Result - where - F: OnStateHook + 'static, - { - // 1. prepare state on new block - self.on_new_block(&block.header); - - // 2. configure the evm and execute - let env = self.evm_env_for_block(&block.header, total_difficulty); - let output = { - let evm = self.executor.evm_config.evm_with_env(&mut self.state, env); - self.executor.execute_state_transitions(block, evm, state_hook) - }?; - - // 3. apply post execution changes - self.post_execution(block, total_difficulty)?; - - Ok(output) - } - - /// Apply settings before a new block is executed. - pub(crate) fn on_new_block(&mut self, header: &Header) { - // Set state clear flag if the block is after the Spurious Dragon hardfork. - let state_clear_flag = self.chain_spec().is_spurious_dragon_active_at_block(header.number); - self.state.set_state_clear_flag(state_clear_flag); - } - - /// Apply post execution state changes that do not require an [EVM](Evm), such as: block - /// rewards, withdrawals, and irregular DAO hardfork state change - pub fn post_execution( - &mut self, - block: &BlockWithSenders, - total_difficulty: U256, - ) -> Result<(), BlockExecutionError> { let mut balance_increments = - post_block_balance_increments(self.chain_spec(), block, total_difficulty); + post_block_balance_increments(&self.chain_spec, block, total_difficulty); // Irregular state change at Ethereum DAO hardfork - if self.chain_spec().fork(EthereumHardfork::Dao).transitions_at_block(block.number) { + if self.chain_spec.fork(EthereumHardfork::Dao).transitions_at_block(block.number) { // drain balances from hardcoded addresses. let drained_balance: u128 = self .state @@ -347,155 +249,59 @@ where .increment_balances(balance_increments) .map_err(|_| BlockValidationError::IncrementBalanceFailed)?; - Ok(()) + Ok(requests) } -} - -impl Executor for EthBlockExecutor -where - EvmConfig: ConfigureEvm
, - DB: Database + Display>, -{ - type Input<'a> = BlockExecutionInput<'a, BlockWithSenders>; - type Output = BlockExecutionOutput; - type Error = BlockExecutionError; - /// Executes the block and commits the changes to the internal state. - /// - /// Returns the receipts of the transactions in the block. - /// - /// Returns an error if the block could not be executed or failed verification. - fn execute(mut self, input: Self::Input<'_>) -> Result { - let BlockExecutionInput { block, total_difficulty } = input; - let EthExecuteOutput { receipts, requests, 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); - - Ok(BlockExecutionOutput { state: self.state.take_bundle(), receipts, requests, gas_used }) + fn state_ref(&self) -> &State { + &self.state } - fn execute_with_state_closure( - mut self, - input: Self::Input<'_>, - mut witness: F, - ) -> Result - where - F: FnMut(&State), - { - let BlockExecutionInput { block, total_difficulty } = input; - let EthExecuteOutput { receipts, requests, gas_used } = - self.execute_without_verification(block, total_difficulty)?; + fn state_mut(&mut self) -> &mut State { + &mut self.state + } - // NOTE: we need to merge keep the reverts for the bundle retention - self.state.merge_transitions(BundleRetention::Reverts); - witness(&self.state); - Ok(BlockExecutionOutput { state: self.state.take_bundle(), receipts, requests, gas_used }) + fn with_state_hook(&mut self, hook: Option>) { + self.system_caller.with_state_hook(hook); } - fn execute_with_state_hook( - mut self, - input: Self::Input<'_>, - state_hook: F, - ) -> Result - where - F: OnStateHook + 'static, - { - let BlockExecutionInput { block, total_difficulty } = input; - let EthExecuteOutput { receipts, requests, gas_used } = self - .execute_without_verification_with_state_hook( - block, - total_difficulty, - Some(state_hook), - )?; - - // NOTE: we need to merge keep the reverts for the bundle retention + fn finish(&mut self) -> BundleState { self.state.merge_transitions(BundleRetention::Reverts); - Ok(BlockExecutionOutput { state: self.state.take_bundle(), receipts, requests, gas_used }) + self.state.take_bundle() } -} -/// An executor for a batch of blocks. -/// -/// State changes are tracked until the executor is finalized. -#[derive(Debug)] -pub struct EthBatchExecutor { - /// The executor used to execute single blocks - /// - /// All state changes are committed to the [State]. - executor: EthBlockExecutor, - /// Keeps track of the batch and records receipts based on the configured prune mode - batch_record: BlockBatchRecord, -} -impl EthBatchExecutor { - /// Returns mutable reference to the state that wraps the underlying database. - #[allow(unused)] - fn state_mut(&mut self) -> &mut State { - self.executor.state_mut() + fn validate_block_post_execution( + &self, + block: &BlockWithSenders, + receipts: &[Receipt], + requests: &Requests, + ) -> Result<(), ConsensusError> { + validate_block_post_execution(block, &self.chain_spec.clone(), receipts, requests) } } -impl BatchExecutor for EthBatchExecutor -where - EvmConfig: ConfigureEvm
, - DB: Database + Display>, -{ - type Input<'a> = BlockExecutionInput<'a, BlockWithSenders>; - type Output = ExecutionOutcome; - type Error = BlockExecutionError; - - fn execute_and_verify_one(&mut self, input: Self::Input<'_>) -> Result<(), Self::Error> { - let BlockExecutionInput { block, total_difficulty } = input; - - if self.batch_record.first_block().is_none() { - self.batch_record.set_first_block(block.number); - } - - let EthExecuteOutput { receipts, requests, gas_used: _ } = - self.executor.execute_without_verification(block, total_difficulty)?; - - validate_block_post_execution(block, self.executor.chain_spec(), &receipts, &requests)?; - - // prepare the state according to the prune mode - let retention = self.batch_record.bundle_retention(block.number); - self.executor.state.merge_transitions(retention); - - // store receipts in the set - self.batch_record.save_receipts(receipts)?; - - // store requests in the set - self.batch_record.save_requests(requests); - - Ok(()) - } - - fn finalize(mut self) -> Self::Output { - ExecutionOutcome::new( - self.executor.state.take_bundle(), - self.batch_record.take_receipts(), - self.batch_record.first_block().unwrap_or_default(), - self.batch_record.take_requests(), - ) - } - - fn set_tip(&mut self, tip: BlockNumber) { - self.batch_record.set_tip(tip); - } +/// Helper type with backwards compatible methods to obtain Ethereum executor +/// providers. +#[derive(Debug)] +pub struct EthExecutorProvider; - fn set_prune_modes(&mut self, prune_modes: PruneModes) { - self.batch_record.set_prune_modes(prune_modes); +impl EthExecutorProvider { + /// Creates a new default ethereum executor provider. + pub fn ethereum( + chain_spec: Arc, + ) -> BasicBlockExecutorProvider { + BasicBlockExecutorProvider::new(EthExecutionStrategyFactory::ethereum(chain_spec)) } - fn size_hint(&self) -> Option { - Some(self.executor.state.bundle_state.size_hint()) + /// Returns a new provider for the mainnet. + pub fn mainnet() -> BasicBlockExecutorProvider { + BasicBlockExecutorProvider::new(EthExecutionStrategyFactory::mainnet()) } } #[cfg(test)] mod tests { use super::*; - use alloy_consensus::TxLegacy; + use alloy_consensus::{Header, TxLegacy}; use alloy_eips::{ eip2935::{HISTORY_STORAGE_ADDRESS, HISTORY_STORAGE_CODE}, eip4788::{BEACON_ROOTS_ADDRESS, BEACON_ROOTS_CODE, SYSTEM_ADDRESS}, @@ -504,6 +310,10 @@ mod tests { }; use alloy_primitives::{b256, fixed_bytes, keccak256, Bytes, TxKind, B256}; use reth_chainspec::{ChainSpecBuilder, ForkCondition}; + use reth_evm::execute::{ + BasicBlockExecutorProvider, BatchExecutor, BlockExecutorProvider, Executor, + }; + use reth_execution_types::BlockExecutionOutput; use reth_primitives::{ constants::ETH_TO_WEI, public_key_to_address, Account, Block, BlockBody, Transaction, }; @@ -553,8 +363,13 @@ mod tests { db } - fn executor_provider(chain_spec: Arc) -> EthExecutorProvider { - EthExecutorProvider { evm_config: EthEvmConfig::new(chain_spec.clone()), chain_spec } + fn executor_provider( + chain_spec: Arc, + ) -> BasicBlockExecutorProvider { + let strategy_factory = + EthExecutionStrategyFactory::new(chain_spec.clone(), EthEvmConfig::new(chain_spec)); + + BasicBlockExecutorProvider::new(strategy_factory) } #[test] @@ -573,10 +388,11 @@ mod tests { let provider = executor_provider(chain_spec); + let mut executor = provider.batch_executor(StateProviderDatabase::new(&db)); + // attempt to execute a block without parent beacon block root, expect err - let err = provider - .executor(StateProviderDatabase::new(&db)) - .execute( + let err = executor + .execute_and_verify_one( ( &BlockWithSenders { block: Block { @@ -605,19 +421,24 @@ mod tests { // fix header, set a gas limit header.parent_beacon_block_root = Some(B256::with_last_byte(0x69)); - let mut executor = provider.executor(StateProviderDatabase::new(&db)); - // Now execute a block with the fixed header, ensure that it does not fail executor - .execute_without_verification( - &BlockWithSenders { - block: Block { - header: header.clone(), - body: BlockBody { transactions: vec![], ommers: vec![], withdrawals: None }, + .execute_and_verify_one( + ( + &BlockWithSenders { + block: Block { + header: header.clone(), + body: BlockBody { + transactions: vec![], + ommers: vec![], + withdrawals: None, + }, + }, + senders: vec![], }, - senders: vec![], - }, - U256::ZERO, + U256::ZERO, + ) + .into(), ) .unwrap(); @@ -631,16 +452,17 @@ mod tests { let parent_beacon_block_root_index = timestamp_index % history_buffer_length + history_buffer_length; - // get timestamp storage and compare - let timestamp_storage = - executor.state.storage(BEACON_ROOTS_ADDRESS, U256::from(timestamp_index)).unwrap(); + let timestamp_storage = executor.with_state_mut(|state| { + state.storage(BEACON_ROOTS_ADDRESS, U256::from(timestamp_index)).unwrap() + }); assert_eq!(timestamp_storage, U256::from(header.timestamp)); // get parent beacon block root storage and compare - let parent_beacon_block_root_storage = executor - .state - .storage(BEACON_ROOTS_ADDRESS, U256::from(parent_beacon_block_root_index)) - .expect("storage value should exist"); + let parent_beacon_block_root_storage = executor.with_state_mut(|state| { + state + .storage(BEACON_ROOTS_ADDRESS, U256::from(parent_beacon_block_root_index)) + .expect("storage value should exist") + }); assert_eq!(parent_beacon_block_root_storage, U256::from(0x69)); } @@ -747,7 +569,8 @@ mod tests { ); // ensure that the nonce of the system address account has not changed - let nonce = executor.state_mut().basic(SYSTEM_ADDRESS).unwrap().unwrap().nonce; + let nonce = + executor.with_state_mut(|state| state.basic(SYSTEM_ADDRESS).unwrap().unwrap().nonce); assert_eq!(nonce, 0); } @@ -805,11 +628,12 @@ mod tests { // there is no system contract call so there should be NO STORAGE CHANGES // this means we'll check the transition state - let transition_state = executor - .state_mut() - .transition_state - .take() - .expect("the evm should be initialized with bundle updates"); + let transition_state = executor.with_state_mut(|state| { + state + .transition_state + .take() + .expect("the evm should be initialized with bundle updates") + }); // assert that it is the default (empty) transition state assert_eq!(transition_state, TransitionState::default()); @@ -867,17 +691,15 @@ mod tests { timestamp_index % history_buffer_length + history_buffer_length; // get timestamp storage and compare - let timestamp_storage = executor - .state_mut() - .storage(BEACON_ROOTS_ADDRESS, U256::from(timestamp_index)) - .unwrap(); + let timestamp_storage = executor.with_state_mut(|state| { + state.storage(BEACON_ROOTS_ADDRESS, U256::from(timestamp_index)).unwrap() + }); assert_eq!(timestamp_storage, U256::from(header.timestamp)); // get parent beacon block root storage and compare - let parent_beacon_block_root_storage = executor - .state_mut() - .storage(BEACON_ROOTS_ADDRESS, U256::from(parent_beacon_block_root_index)) - .unwrap(); + let parent_beacon_block_root_storage = executor.with_state_mut(|state| { + state.storage(BEACON_ROOTS_ADDRESS, U256::from(parent_beacon_block_root_index)).unwrap() + }); assert_eq!(parent_beacon_block_root_storage, U256::from(0x69)); } @@ -903,7 +725,6 @@ mod tests { db } - #[test] fn eip_2935_pre_fork() { let db = create_state_provider_with_block_hashes(1); @@ -942,12 +763,11 @@ mod tests { // // we load the account first, because revm expects it to be // loaded - executor.state_mut().basic(HISTORY_STORAGE_ADDRESS).unwrap(); - assert!(executor - .state_mut() + executor.with_state_mut(|state| state.basic(HISTORY_STORAGE_ADDRESS).unwrap()); + assert!(executor.with_state_mut(|state| state .storage(HISTORY_STORAGE_ADDRESS, U256::ZERO) .unwrap() - .is_zero()); + .is_zero())); } #[test] @@ -986,12 +806,11 @@ mod tests { // // we load the account first, because revm expects it to be // loaded - executor.state_mut().basic(HISTORY_STORAGE_ADDRESS).unwrap(); - assert!(executor - .state_mut() + executor.with_state_mut(|state| state.basic(HISTORY_STORAGE_ADDRESS).unwrap()); + assert!(executor.with_state_mut(|state| state .storage(HISTORY_STORAGE_ADDRESS, U256::ZERO) .unwrap() - .is_zero()); + .is_zero())); } #[test] @@ -1033,21 +852,20 @@ mod tests { ); // the hash for the ancestor of the fork activation block should be present - assert!(executor.state_mut().basic(HISTORY_STORAGE_ADDRESS).unwrap().is_some()); + assert!(executor + .with_state_mut(|state| state.basic(HISTORY_STORAGE_ADDRESS).unwrap().is_some())); assert_ne!( - executor - .state_mut() + executor.with_state_mut(|state| state .storage(HISTORY_STORAGE_ADDRESS, U256::from(fork_activation_block - 1)) - .unwrap(), + .unwrap()), U256::ZERO ); // the hash of the block itself should not be in storage - assert!(executor - .state_mut() + assert!(executor.with_state_mut(|state| state .storage(HISTORY_STORAGE_ADDRESS, U256::from(fork_activation_block)) .unwrap() - .is_zero()); + .is_zero())); } #[test] @@ -1090,15 +908,15 @@ mod tests { ); // the hash for the ancestor of the fork activation block should be present - assert!(executor.state_mut().basic(HISTORY_STORAGE_ADDRESS).unwrap().is_some()); + assert!(executor + .with_state_mut(|state| state.basic(HISTORY_STORAGE_ADDRESS).unwrap().is_some())); assert_ne!( - executor - .state_mut() + executor.with_state_mut(|state| state .storage( HISTORY_STORAGE_ADDRESS, U256::from(fork_activation_block % BLOCKHASH_SERVE_WINDOW as u64 - 1) ) - .unwrap(), + .unwrap()), U256::ZERO ); } @@ -1141,12 +959,11 @@ mod tests { // // we load the account first, because revm expects it to be // loaded - executor.state_mut().basic(HISTORY_STORAGE_ADDRESS).unwrap(); - assert!(executor - .state_mut() + executor.with_state_mut(|state| state.basic(HISTORY_STORAGE_ADDRESS).unwrap()); + assert!(executor.with_state_mut(|state| state .storage(HISTORY_STORAGE_ADDRESS, U256::ZERO) .unwrap() - .is_zero()); + .is_zero())); // attempt to execute block 1, this should not fail let header = Header { @@ -1174,16 +991,18 @@ mod tests { ); // the block hash of genesis should now be in storage, but not block 1 - assert!(executor.state_mut().basic(HISTORY_STORAGE_ADDRESS).unwrap().is_some()); + assert!(executor + .with_state_mut(|state| state.basic(HISTORY_STORAGE_ADDRESS).unwrap().is_some())); assert_ne!( - executor.state_mut().storage(HISTORY_STORAGE_ADDRESS, U256::ZERO).unwrap(), + executor.with_state_mut(|state| state + .storage(HISTORY_STORAGE_ADDRESS, U256::ZERO) + .unwrap()), U256::ZERO ); - assert!(executor - .state_mut() + assert!(executor.with_state_mut(|state| state .storage(HISTORY_STORAGE_ADDRESS, U256::from(1)) .unwrap() - .is_zero()); + .is_zero())); // attempt to execute block 2, this should not fail let header = Header { @@ -1210,20 +1029,24 @@ mod tests { ); // the block hash of genesis and block 1 should now be in storage, but not block 2 - assert!(executor.state_mut().basic(HISTORY_STORAGE_ADDRESS).unwrap().is_some()); + assert!(executor + .with_state_mut(|state| state.basic(HISTORY_STORAGE_ADDRESS).unwrap().is_some())); assert_ne!( - executor.state_mut().storage(HISTORY_STORAGE_ADDRESS, U256::ZERO).unwrap(), + executor.with_state_mut(|state| state + .storage(HISTORY_STORAGE_ADDRESS, U256::ZERO) + .unwrap()), U256::ZERO ); assert_ne!( - executor.state_mut().storage(HISTORY_STORAGE_ADDRESS, U256::from(1)).unwrap(), + executor.with_state_mut(|state| state + .storage(HISTORY_STORAGE_ADDRESS, U256::from(1)) + .unwrap()), U256::ZERO ); - assert!(executor - .state_mut() + assert!(executor.with_state_mut(|state| state .storage(HISTORY_STORAGE_ADDRESS, U256::from(2)) .unwrap() - .is_zero()); + .is_zero())); } #[test] diff --git a/crates/ethereum/evm/src/lib.rs b/crates/ethereum/evm/src/lib.rs index ac9bb5a0bbb5..9abb11976363 100644 --- a/crates/ethereum/evm/src/lib.rs +++ b/crates/ethereum/evm/src/lib.rs @@ -17,7 +17,7 @@ extern crate alloc; -use alloc::vec::Vec; +use alloc::{sync::Arc, vec::Vec}; use alloy_primitives::{Address, Bytes, TxKind, U256}; use reth_chainspec::{ChainSpec, Head}; use reth_evm::{ConfigureEvm, ConfigureEvmEnv, NextBlockEnvAttributes}; @@ -25,7 +25,6 @@ use reth_primitives::{transaction::FillTxEnv, Header, TransactionSigned}; use revm_primitives::{ AnalysisKind, BlobExcessGasAndPrice, BlockEnv, CfgEnv, CfgEnvWithHandlerCfg, Env, SpecId, TxEnv, }; -use std::sync::Arc; mod config; pub use config::{revm_spec, revm_spec_by_timestamp_after_merge}; @@ -33,7 +32,6 @@ use reth_ethereum_forks::EthereumHardfork; use reth_primitives::constants::EIP1559_INITIAL_BASE_FEE; pub mod execute; -pub mod strategy; /// Ethereum DAO hardfork state change data. pub mod dao_fork; diff --git a/crates/ethereum/evm/src/strategy.rs b/crates/ethereum/evm/src/strategy.rs deleted file mode 100644 index 55fbfffc8e98..000000000000 --- a/crates/ethereum/evm/src/strategy.rs +++ /dev/null @@ -1,1176 +0,0 @@ -//! Ethereum block execution strategy, - -use crate::{ - dao_fork::{DAO_HARDFORK_BENEFICIARY, DAO_HARDKFORK_ACCOUNTS}, - EthEvmConfig, -}; -use alloc::sync::Arc; -use alloy_consensus::Transaction as _; -use alloy_eips::eip7685::Requests; -use core::fmt::Display; -use reth_chainspec::{ChainSpec, EthereumHardfork, EthereumHardforks, MAINNET}; -use reth_consensus::ConsensusError; -use reth_ethereum_consensus::validate_block_post_execution; -use reth_evm::{ - execute::{ - BlockExecutionError, BlockExecutionStrategy, BlockExecutionStrategyFactory, - BlockValidationError, ProviderError, - }, - state_change::post_block_balance_increments, - system_calls::{OnStateHook, SystemCaller}, - ConfigureEvm, ConfigureEvmEnv, -}; -use reth_primitives::{BlockWithSenders, Header, Receipt}; -use reth_revm::{ - db::{states::bundle_state::BundleRetention, BundleState}, - Database, DatabaseCommit, State, -}; -use revm_primitives::{BlockEnv, CfgEnvWithHandlerCfg, EnvWithHandlerCfg, ResultAndState, U256}; - -/// Factory for [`EthExecutionStrategy`]. -#[derive(Debug, Clone)] -pub struct EthExecutionStrategyFactory { - /// The chainspec - chain_spec: Arc, - /// How to create an EVM. - evm_config: EvmConfig, -} - -impl EthExecutionStrategyFactory { - /// Creates a new default ethereum executor strategy factory. - pub fn ethereum(chain_spec: Arc) -> Self { - Self::new(chain_spec.clone(), EthEvmConfig::new(chain_spec)) - } - - /// Returns a new factory for the mainnet. - pub fn mainnet() -> Self { - Self::ethereum(MAINNET.clone()) - } -} - -impl EthExecutionStrategyFactory { - /// Creates a new executor strategy factory. - pub const fn new(chain_spec: Arc, evm_config: EvmConfig) -> Self { - Self { chain_spec, evm_config } - } -} - -impl BlockExecutionStrategyFactory for EthExecutionStrategyFactory { - type Strategy + Display>> = EthExecutionStrategy; - - fn create_strategy(&self, db: DB) -> Self::Strategy - where - DB: Database + Display>, - { - let state = - State::builder().with_database(db).with_bundle_update().without_state_clear().build(); - EthExecutionStrategy::new(state, self.chain_spec.clone(), self.evm_config.clone()) - } -} - -/// Block execution strategy for Ethereum. -#[allow(missing_debug_implementations)] -pub struct EthExecutionStrategy { - /// The chainspec - chain_spec: Arc, - /// How to create an EVM. - evm_config: EvmConfig, - /// Current state for block execution. - state: State, - /// Utility to call system smart contracts. - system_caller: SystemCaller, -} - -impl EthExecutionStrategy { - /// Creates a new [`EthExecutionStrategy`] - pub fn new(state: State, chain_spec: Arc, evm_config: EthEvmConfig) -> Self { - let system_caller = SystemCaller::new(evm_config.clone(), (*chain_spec).clone()); - Self { state, chain_spec, evm_config, system_caller } - } -} - -impl EthExecutionStrategy -where - DB: Database + Display>, - EvmConfig: ConfigureEvm
, -{ - /// Configures a new evm configuration and block environment for the given block. - /// - /// # Caution - /// - /// This does not initialize the tx environment. - fn evm_env_for_block(&self, header: &Header, total_difficulty: U256) -> EnvWithHandlerCfg { - let mut cfg = CfgEnvWithHandlerCfg::new(Default::default(), Default::default()); - let mut block_env = BlockEnv::default(); - self.evm_config.fill_cfg_and_block_env(&mut cfg, &mut block_env, header, total_difficulty); - - EnvWithHandlerCfg::new_with_cfg_env(cfg, block_env, Default::default()) - } -} - -impl BlockExecutionStrategy for EthExecutionStrategy -where - DB: Database + Display>, -{ - type Error = BlockExecutionError; - - fn apply_pre_execution_changes( - &mut self, - block: &BlockWithSenders, - total_difficulty: U256, - ) -> Result<(), Self::Error> { - // Set state clear flag if the block is after the Spurious Dragon hardfork. - let state_clear_flag = - (*self.chain_spec).is_spurious_dragon_active_at_block(block.header.number); - self.state.set_state_clear_flag(state_clear_flag); - - let env = self.evm_env_for_block(&block.header, total_difficulty); - let mut evm = self.evm_config.evm_with_env(&mut self.state, env); - - self.system_caller.apply_pre_execution_changes(block, &mut evm)?; - - Ok(()) - } - - fn execute_transactions( - &mut self, - block: &BlockWithSenders, - total_difficulty: U256, - ) -> Result<(Vec, u64), Self::Error> { - let env = self.evm_env_for_block(&block.header, total_difficulty); - let mut evm = self.evm_config.evm_with_env(&mut self.state, env); - - let mut cumulative_gas_used = 0; - let mut receipts = Vec::with_capacity(block.body.transactions.len()); - for (sender, transaction) in block.transactions_with_sender() { - // The sum of the transaction’s gas limit, Tg, and the gas utilized in this block prior, - // must be no greater than the block’s gasLimit. - let block_available_gas = block.header.gas_limit - cumulative_gas_used; - if transaction.gas_limit() > block_available_gas { - return Err(BlockValidationError::TransactionGasLimitMoreThanAvailableBlockGas { - transaction_gas_limit: transaction.gas_limit(), - block_available_gas, - } - .into()) - } - - self.evm_config.fill_tx_env(evm.tx_mut(), transaction, *sender); - - // Execute transaction. - let result_and_state = evm.transact().map_err(move |err| { - let new_err = err.map_db_err(|e| e.into()); - // Ensure hash is calculated for error log, if not already done - BlockValidationError::EVM { - hash: transaction.recalculate_hash(), - error: Box::new(new_err), - } - })?; - self.system_caller.on_state(&result_and_state); - let ResultAndState { result, state } = result_and_state; - evm.db_mut().commit(state); - - // append gas used - cumulative_gas_used += result.gas_used(); - - // Push transaction changeset and calculate header bloom filter for receipt. - receipts.push( - #[allow(clippy::needless_update)] // side-effect of optimism fields - Receipt { - tx_type: transaction.tx_type(), - // Success flag was added in `EIP-658: Embedding transaction status code in - // receipts`. - success: result.is_success(), - cumulative_gas_used, - // convert to reth log - logs: result.into_logs(), - ..Default::default() - }, - ); - } - Ok((receipts, cumulative_gas_used)) - } - - fn apply_post_execution_changes( - &mut self, - block: &BlockWithSenders, - total_difficulty: U256, - receipts: &[Receipt], - ) -> Result { - let env = self.evm_env_for_block(&block.header, total_difficulty); - let mut evm = self.evm_config.evm_with_env(&mut self.state, env); - - let requests = if self.chain_spec.is_prague_active_at_timestamp(block.timestamp) { - // Collect all EIP-6110 deposits - let deposit_requests = - crate::eip6110::parse_deposits_from_receipts(&self.chain_spec, receipts)?; - - let mut requests = Requests::new(vec![deposit_requests]); - requests.extend(self.system_caller.apply_post_execution_changes(&mut evm)?); - requests - } else { - Requests::default() - }; - drop(evm); - - let mut balance_increments = - post_block_balance_increments(&self.chain_spec, block, total_difficulty); - - // Irregular state change at Ethereum DAO hardfork - if self.chain_spec.fork(EthereumHardfork::Dao).transitions_at_block(block.number) { - // drain balances from hardcoded addresses. - let drained_balance: u128 = self - .state - .drain_balances(DAO_HARDKFORK_ACCOUNTS) - .map_err(|_| BlockValidationError::IncrementBalanceFailed)? - .into_iter() - .sum(); - - // return balance to DAO beneficiary. - *balance_increments.entry(DAO_HARDFORK_BENEFICIARY).or_default() += drained_balance; - } - // increment balances - self.state - .increment_balances(balance_increments) - .map_err(|_| BlockValidationError::IncrementBalanceFailed)?; - - Ok(requests) - } - - fn state_ref(&self) -> &State { - &self.state - } - - fn state_mut(&mut self) -> &mut State { - &mut self.state - } - - fn with_state_hook(&mut self, hook: Option>) { - self.system_caller.with_state_hook(hook); - } - - fn finish(&mut self) -> BundleState { - self.state.merge_transitions(BundleRetention::Reverts); - self.state.take_bundle() - } - - fn validate_block_post_execution( - &self, - block: &BlockWithSenders, - receipts: &[Receipt], - requests: &Requests, - ) -> Result<(), ConsensusError> { - validate_block_post_execution(block, &self.chain_spec.clone(), receipts, requests) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use alloy_consensus::TxLegacy; - use alloy_eips::{ - eip2935::{HISTORY_STORAGE_ADDRESS, HISTORY_STORAGE_CODE}, - eip4788::{BEACON_ROOTS_ADDRESS, BEACON_ROOTS_CODE, SYSTEM_ADDRESS}, - eip7002::{WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS, WITHDRAWAL_REQUEST_PREDEPLOY_CODE}, - eip7685::EMPTY_REQUESTS_HASH, - }; - use alloy_primitives::{b256, fixed_bytes, keccak256, Bytes, TxKind, B256}; - use reth_chainspec::{ChainSpecBuilder, ForkCondition}; - use reth_evm::execute::{ - BasicBlockExecutorProvider, BatchExecutor, BlockExecutorProvider, Executor, - }; - use reth_execution_types::BlockExecutionOutput; - use reth_primitives::{ - constants::ETH_TO_WEI, public_key_to_address, Account, Block, BlockBody, Transaction, - }; - use reth_revm::{ - database::StateProviderDatabase, test_utils::StateProviderTest, TransitionState, - }; - use reth_testing_utils::generators::{self, sign_tx_with_key_pair}; - use revm_primitives::BLOCKHASH_SERVE_WINDOW; - use secp256k1::{Keypair, Secp256k1}; - use std::collections::HashMap; - - fn create_state_provider_with_beacon_root_contract() -> StateProviderTest { - let mut db = StateProviderTest::default(); - - let beacon_root_contract_account = Account { - balance: U256::ZERO, - bytecode_hash: Some(keccak256(BEACON_ROOTS_CODE.clone())), - nonce: 1, - }; - - db.insert_account( - BEACON_ROOTS_ADDRESS, - beacon_root_contract_account, - Some(BEACON_ROOTS_CODE.clone()), - HashMap::default(), - ); - - db - } - - fn create_state_provider_with_withdrawal_requests_contract() -> StateProviderTest { - let mut db = StateProviderTest::default(); - - let withdrawal_requests_contract_account = Account { - nonce: 1, - balance: U256::ZERO, - bytecode_hash: Some(keccak256(WITHDRAWAL_REQUEST_PREDEPLOY_CODE.clone())), - }; - - db.insert_account( - WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS, - withdrawal_requests_contract_account, - Some(WITHDRAWAL_REQUEST_PREDEPLOY_CODE.clone()), - HashMap::default(), - ); - - db - } - - fn executor_provider( - chain_spec: Arc, - ) -> BasicBlockExecutorProvider { - let strategy_factory = - EthExecutionStrategyFactory::new(chain_spec.clone(), EthEvmConfig::new(chain_spec)); - - BasicBlockExecutorProvider::new(strategy_factory) - } - - #[test] - fn eip_4788_non_genesis_call() { - let mut header = - Header { timestamp: 1, number: 1, excess_blob_gas: Some(0), ..Header::default() }; - - let db = create_state_provider_with_beacon_root_contract(); - - let chain_spec = Arc::new( - ChainSpecBuilder::from(&*MAINNET) - .shanghai_activated() - .with_fork(EthereumHardfork::Cancun, ForkCondition::Timestamp(1)) - .build(), - ); - - let provider = executor_provider(chain_spec); - - let mut executor = provider.batch_executor(StateProviderDatabase::new(&db)); - - // attempt to execute a block without parent beacon block root, expect err - let err = executor - .execute_and_verify_one( - ( - &BlockWithSenders { - block: Block { - header: header.clone(), - body: BlockBody { - transactions: vec![], - ommers: vec![], - withdrawals: None, - }, - }, - senders: vec![], - }, - U256::ZERO, - ) - .into(), - ) - .expect_err( - "Executing cancun block without parent beacon block root field should fail", - ); - - assert_eq!( - err.as_validation().unwrap().clone(), - BlockValidationError::MissingParentBeaconBlockRoot - ); - - // fix header, set a gas limit - header.parent_beacon_block_root = Some(B256::with_last_byte(0x69)); - - // Now execute a block with the fixed header, ensure that it does not fail - executor - .execute_and_verify_one( - ( - &BlockWithSenders { - block: Block { - header: header.clone(), - body: BlockBody { - transactions: vec![], - ommers: vec![], - withdrawals: None, - }, - }, - senders: vec![], - }, - U256::ZERO, - ) - .into(), - ) - .unwrap(); - - // check the actual storage of the contract - it should be: - // * The storage value at header.timestamp % HISTORY_BUFFER_LENGTH should be - // header.timestamp - // * The storage value at header.timestamp % HISTORY_BUFFER_LENGTH + HISTORY_BUFFER_LENGTH - // // should be parent_beacon_block_root - let history_buffer_length = 8191u64; - let timestamp_index = header.timestamp % history_buffer_length; - let parent_beacon_block_root_index = - timestamp_index % history_buffer_length + history_buffer_length; - - let timestamp_storage = executor.with_state_mut(|state| { - state.storage(BEACON_ROOTS_ADDRESS, U256::from(timestamp_index)).unwrap() - }); - assert_eq!(timestamp_storage, U256::from(header.timestamp)); - - // get parent beacon block root storage and compare - let parent_beacon_block_root_storage = executor.with_state_mut(|state| { - state - .storage(BEACON_ROOTS_ADDRESS, U256::from(parent_beacon_block_root_index)) - .expect("storage value should exist") - }); - assert_eq!(parent_beacon_block_root_storage, U256::from(0x69)); - } - - #[test] - fn eip_4788_no_code_cancun() { - // This test ensures that we "silently fail" when cancun is active and there is no code at - // // BEACON_ROOTS_ADDRESS - let header = Header { - timestamp: 1, - number: 1, - parent_beacon_block_root: Some(B256::with_last_byte(0x69)), - excess_blob_gas: Some(0), - ..Header::default() - }; - - let db = StateProviderTest::default(); - - // DON'T deploy the contract at genesis - let chain_spec = Arc::new( - ChainSpecBuilder::from(&*MAINNET) - .shanghai_activated() - .with_fork(EthereumHardfork::Cancun, ForkCondition::Timestamp(1)) - .build(), - ); - - let provider = executor_provider(chain_spec); - - // attempt to execute an empty block with parent beacon block root, this should not fail - provider - .batch_executor(StateProviderDatabase::new(&db)) - .execute_and_verify_one( - ( - &BlockWithSenders { - block: Block { - header, - body: BlockBody { - transactions: vec![], - ommers: vec![], - withdrawals: None, - }, - }, - senders: vec![], - }, - U256::ZERO, - ) - .into(), - ) - .expect( - "Executing a block with no transactions while cancun is active should not fail", - ); - } - - #[test] - fn eip_4788_empty_account_call() { - // This test ensures that we do not increment the nonce of an empty SYSTEM_ADDRESS account - // // during the pre-block call - - let mut db = create_state_provider_with_beacon_root_contract(); - - // insert an empty SYSTEM_ADDRESS - db.insert_account(SYSTEM_ADDRESS, Account::default(), None, HashMap::default()); - - let chain_spec = Arc::new( - ChainSpecBuilder::from(&*MAINNET) - .shanghai_activated() - .with_fork(EthereumHardfork::Cancun, ForkCondition::Timestamp(1)) - .build(), - ); - - let provider = executor_provider(chain_spec); - - // construct the header for block one - let header = Header { - timestamp: 1, - number: 1, - parent_beacon_block_root: Some(B256::with_last_byte(0x69)), - excess_blob_gas: Some(0), - ..Header::default() - }; - - let mut executor = provider.batch_executor(StateProviderDatabase::new(&db)); - - // attempt to execute an empty block with parent beacon block root, this should not fail - executor - .execute_and_verify_one( - ( - &BlockWithSenders { - block: Block { - header, - body: BlockBody { - transactions: vec![], - ommers: vec![], - withdrawals: None, - }, - }, - senders: vec![], - }, - U256::ZERO, - ) - .into(), - ) - .expect( - "Executing a block with no transactions while cancun is active should not fail", - ); - - // ensure that the nonce of the system address account has not changed - let nonce = - executor.with_state_mut(|state| state.basic(SYSTEM_ADDRESS).unwrap().unwrap().nonce); - assert_eq!(nonce, 0); - } - - #[test] - fn eip_4788_genesis_call() { - let db = create_state_provider_with_beacon_root_contract(); - - // activate cancun at genesis - let chain_spec = Arc::new( - ChainSpecBuilder::from(&*MAINNET) - .shanghai_activated() - .with_fork(EthereumHardfork::Cancun, ForkCondition::Timestamp(0)) - .build(), - ); - - let mut header = chain_spec.genesis_header().clone(); - let provider = executor_provider(chain_spec); - let mut executor = provider.batch_executor(StateProviderDatabase::new(&db)); - - // attempt to execute the genesis block with non-zero parent beacon block root, expect err - header.parent_beacon_block_root = Some(B256::with_last_byte(0x69)); - let _err = executor - .execute_and_verify_one( - ( - &BlockWithSenders { - block: Block { header: header.clone(), body: Default::default() }, - senders: vec![], - }, - U256::ZERO, - ) - .into(), - ) - .expect_err( - "Executing genesis cancun block with non-zero parent beacon block root field - should fail", - ); - - // fix header - header.parent_beacon_block_root = Some(B256::ZERO); - - // now try to process the genesis block again, this time ensuring that a system contract - // call does not occur - executor - .execute_and_verify_one( - ( - &BlockWithSenders { - block: Block { header, body: Default::default() }, - senders: vec![], - }, - U256::ZERO, - ) - .into(), - ) - .unwrap(); - - // there is no system contract call so there should be NO STORAGE CHANGES - // this means we'll check the transition state - let transition_state = executor.with_state_mut(|state| { - state - .transition_state - .take() - .expect("the evm should be initialized with bundle updates") - }); - - // assert that it is the default (empty) transition state - assert_eq!(transition_state, TransitionState::default()); - } - - #[test] - fn eip_4788_high_base_fee() { - // This test ensures that if we have a base fee, then we don't return an error when the - // system contract is called, due to the gas price being less than the base fee. - let header = Header { - timestamp: 1, - number: 1, - parent_beacon_block_root: Some(B256::with_last_byte(0x69)), - base_fee_per_gas: Some(u64::MAX), - excess_blob_gas: Some(0), - ..Header::default() - }; - - let db = create_state_provider_with_beacon_root_contract(); - - let chain_spec = Arc::new( - ChainSpecBuilder::from(&*MAINNET) - .shanghai_activated() - .with_fork(EthereumHardfork::Cancun, ForkCondition::Timestamp(1)) - .build(), - ); - - let provider = executor_provider(chain_spec); - - // execute header - let mut executor = provider.batch_executor(StateProviderDatabase::new(&db)); - - // Now execute a block with the fixed header, ensure that it does not fail - executor - .execute_and_verify_one( - ( - &BlockWithSenders { - block: Block { header: header.clone(), body: Default::default() }, - senders: vec![], - }, - U256::ZERO, - ) - .into(), - ) - .unwrap(); - - // check the actual storage of the contract - it should be: - // * The storage value at header.timestamp % HISTORY_BUFFER_LENGTH should be - // header.timestamp - // * The storage value at header.timestamp % HISTORY_BUFFER_LENGTH + HISTORY_BUFFER_LENGTH - // // should be parent_beacon_block_root - let history_buffer_length = 8191u64; - let timestamp_index = header.timestamp % history_buffer_length; - let parent_beacon_block_root_index = - timestamp_index % history_buffer_length + history_buffer_length; - - // get timestamp storage and compare - let timestamp_storage = executor.with_state_mut(|state| { - state.storage(BEACON_ROOTS_ADDRESS, U256::from(timestamp_index)).unwrap() - }); - assert_eq!(timestamp_storage, U256::from(header.timestamp)); - - // get parent beacon block root storage and compare - let parent_beacon_block_root_storage = executor.with_state_mut(|state| { - state.storage(BEACON_ROOTS_ADDRESS, U256::from(parent_beacon_block_root_index)).unwrap() - }); - assert_eq!(parent_beacon_block_root_storage, U256::from(0x69)); - } - - /// Create a state provider with blockhashes and the EIP-2935 system contract. - fn create_state_provider_with_block_hashes(latest_block: u64) -> StateProviderTest { - let mut db = StateProviderTest::default(); - for block_number in 0..=latest_block { - db.insert_block_hash(block_number, keccak256(block_number.to_string())); - } - - let blockhashes_contract_account = Account { - balance: U256::ZERO, - bytecode_hash: Some(keccak256(HISTORY_STORAGE_CODE.clone())), - nonce: 1, - }; - - db.insert_account( - HISTORY_STORAGE_ADDRESS, - blockhashes_contract_account, - Some(HISTORY_STORAGE_CODE.clone()), - HashMap::default(), - ); - - db - } - #[test] - fn eip_2935_pre_fork() { - let db = create_state_provider_with_block_hashes(1); - - let chain_spec = Arc::new( - ChainSpecBuilder::from(&*MAINNET) - .shanghai_activated() - .with_fork(EthereumHardfork::Prague, ForkCondition::Never) - .build(), - ); - - let provider = executor_provider(chain_spec); - let mut executor = provider.batch_executor(StateProviderDatabase::new(&db)); - - // construct the header for block one - let header = Header { timestamp: 1, number: 1, ..Header::default() }; - - // attempt to execute an empty block, this should not fail - executor - .execute_and_verify_one( - ( - &BlockWithSenders { - block: Block { header, body: Default::default() }, - senders: vec![], - }, - U256::ZERO, - ) - .into(), - ) - .expect( - "Executing a block with no transactions while Prague is active should not fail", - ); - - // ensure that the block hash was *not* written to storage, since this is before the fork - // was activated - // - // we load the account first, because revm expects it to be - // loaded - executor.with_state_mut(|state| state.basic(HISTORY_STORAGE_ADDRESS).unwrap()); - assert!(executor.with_state_mut(|state| state - .storage(HISTORY_STORAGE_ADDRESS, U256::ZERO) - .unwrap() - .is_zero())); - } - - #[test] - fn eip_2935_fork_activation_genesis() { - let db = create_state_provider_with_block_hashes(0); - - let chain_spec = Arc::new( - ChainSpecBuilder::from(&*MAINNET) - .shanghai_activated() - .with_fork(EthereumHardfork::Prague, ForkCondition::Timestamp(0)) - .build(), - ); - - let header = chain_spec.genesis_header().clone(); - let provider = executor_provider(chain_spec); - let mut executor = provider.batch_executor(StateProviderDatabase::new(&db)); - - // attempt to execute genesis block, this should not fail - executor - .execute_and_verify_one( - ( - &BlockWithSenders { - block: Block { header, body: Default::default() }, - senders: vec![], - }, - U256::ZERO, - ) - .into(), - ) - .expect( - "Executing a block with no transactions while Prague is active should not fail", - ); - - // ensure that the block hash was *not* written to storage, since there are no blocks - // preceding genesis - // - // we load the account first, because revm expects it to be - // loaded - executor.with_state_mut(|state| state.basic(HISTORY_STORAGE_ADDRESS).unwrap()); - assert!(executor.with_state_mut(|state| state - .storage(HISTORY_STORAGE_ADDRESS, U256::ZERO) - .unwrap() - .is_zero())); - } - - #[test] - fn eip_2935_fork_activation_within_window_bounds() { - let fork_activation_block = (BLOCKHASH_SERVE_WINDOW - 10) as u64; - let db = create_state_provider_with_block_hashes(fork_activation_block); - - let chain_spec = Arc::new( - ChainSpecBuilder::from(&*MAINNET) - .shanghai_activated() - .with_fork(EthereumHardfork::Prague, ForkCondition::Timestamp(1)) - .build(), - ); - - let header = Header { - parent_hash: B256::random(), - timestamp: 1, - number: fork_activation_block, - requests_hash: Some(EMPTY_REQUESTS_HASH), - ..Header::default() - }; - let provider = executor_provider(chain_spec); - let mut executor = provider.batch_executor(StateProviderDatabase::new(&db)); - - // attempt to execute the fork activation block, this should not fail - executor - .execute_and_verify_one( - ( - &BlockWithSenders { - block: Block { header, body: Default::default() }, - senders: vec![], - }, - U256::ZERO, - ) - .into(), - ) - .expect( - "Executing a block with no transactions while Prague is active should not fail", - ); - - // the hash for the ancestor of the fork activation block should be present - assert!(executor - .with_state_mut(|state| state.basic(HISTORY_STORAGE_ADDRESS).unwrap().is_some())); - assert_ne!( - executor.with_state_mut(|state| state - .storage(HISTORY_STORAGE_ADDRESS, U256::from(fork_activation_block - 1)) - .unwrap()), - U256::ZERO - ); - - // the hash of the block itself should not be in storage - assert!(executor.with_state_mut(|state| state - .storage(HISTORY_STORAGE_ADDRESS, U256::from(fork_activation_block)) - .unwrap() - .is_zero())); - } - - #[test] - fn eip_2935_fork_activation_outside_window_bounds() { - let fork_activation_block = (BLOCKHASH_SERVE_WINDOW + 256) as u64; - let db = create_state_provider_with_block_hashes(fork_activation_block); - - let chain_spec = Arc::new( - ChainSpecBuilder::from(&*MAINNET) - .shanghai_activated() - .with_fork(EthereumHardfork::Prague, ForkCondition::Timestamp(1)) - .build(), - ); - - let provider = executor_provider(chain_spec); - let mut executor = provider.batch_executor(StateProviderDatabase::new(&db)); - - let header = Header { - parent_hash: B256::random(), - timestamp: 1, - number: fork_activation_block, - requests_hash: Some(EMPTY_REQUESTS_HASH), - ..Header::default() - }; - - // attempt to execute the fork activation block, this should not fail - executor - .execute_and_verify_one( - ( - &BlockWithSenders { - block: Block { header, body: Default::default() }, - senders: vec![], - }, - U256::ZERO, - ) - .into(), - ) - .expect( - "Executing a block with no transactions while Prague is active should not fail", - ); - - // the hash for the ancestor of the fork activation block should be present - assert!(executor - .with_state_mut(|state| state.basic(HISTORY_STORAGE_ADDRESS).unwrap().is_some())); - assert_ne!( - executor.with_state_mut(|state| state - .storage( - HISTORY_STORAGE_ADDRESS, - U256::from(fork_activation_block % BLOCKHASH_SERVE_WINDOW as u64 - 1) - ) - .unwrap()), - U256::ZERO - ); - } - - #[test] - fn eip_2935_state_transition_inside_fork() { - let db = create_state_provider_with_block_hashes(2); - - let chain_spec = Arc::new( - ChainSpecBuilder::from(&*MAINNET) - .shanghai_activated() - .with_fork(EthereumHardfork::Prague, ForkCondition::Timestamp(0)) - .build(), - ); - - let mut header = chain_spec.genesis_header().clone(); - header.requests_hash = Some(EMPTY_REQUESTS_HASH); - let header_hash = header.hash_slow(); - - let provider = executor_provider(chain_spec); - let mut executor = provider.batch_executor(StateProviderDatabase::new(&db)); - - // attempt to execute the genesis block, this should not fail - executor - .execute_and_verify_one( - ( - &BlockWithSenders { - block: Block { header, body: Default::default() }, - senders: vec![], - }, - U256::ZERO, - ) - .into(), - ) - .expect( - "Executing a block with no transactions while Prague is active should not fail", - ); - - // nothing should be written as the genesis has no ancestors - // - // we load the account first, because revm expects it to be - // loaded - executor.with_state_mut(|state| state.basic(HISTORY_STORAGE_ADDRESS).unwrap()); - assert!(executor.with_state_mut(|state| state - .storage(HISTORY_STORAGE_ADDRESS, U256::ZERO) - .unwrap() - .is_zero())); - - // attempt to execute block 1, this should not fail - let header = Header { - parent_hash: header_hash, - timestamp: 1, - number: 1, - requests_hash: Some(EMPTY_REQUESTS_HASH), - ..Header::default() - }; - let header_hash = header.hash_slow(); - - executor - .execute_and_verify_one( - ( - &BlockWithSenders { - block: Block { header, body: Default::default() }, - senders: vec![], - }, - U256::ZERO, - ) - .into(), - ) - .expect( - "Executing a block with no transactions while Prague is active should not fail", - ); - - // the block hash of genesis should now be in storage, but not block 1 - assert!(executor - .with_state_mut(|state| state.basic(HISTORY_STORAGE_ADDRESS).unwrap().is_some())); - assert_ne!( - executor.with_state_mut(|state| state - .storage(HISTORY_STORAGE_ADDRESS, U256::ZERO) - .unwrap()), - U256::ZERO - ); - assert!(executor.with_state_mut(|state| state - .storage(HISTORY_STORAGE_ADDRESS, U256::from(1)) - .unwrap() - .is_zero())); - - // attempt to execute block 2, this should not fail - let header = Header { - parent_hash: header_hash, - timestamp: 1, - number: 2, - requests_hash: Some(EMPTY_REQUESTS_HASH), - ..Header::default() - }; - - executor - .execute_and_verify_one( - ( - &BlockWithSenders { - block: Block { header, body: Default::default() }, - senders: vec![], - }, - U256::ZERO, - ) - .into(), - ) - .expect( - "Executing a block with no transactions while Prague is active should not fail", - ); - - // the block hash of genesis and block 1 should now be in storage, but not block 2 - assert!(executor - .with_state_mut(|state| state.basic(HISTORY_STORAGE_ADDRESS).unwrap().is_some())); - assert_ne!( - executor.with_state_mut(|state| state - .storage(HISTORY_STORAGE_ADDRESS, U256::ZERO) - .unwrap()), - U256::ZERO - ); - assert_ne!( - executor.with_state_mut(|state| state - .storage(HISTORY_STORAGE_ADDRESS, U256::from(1)) - .unwrap()), - U256::ZERO - ); - assert!(executor.with_state_mut(|state| state - .storage(HISTORY_STORAGE_ADDRESS, U256::from(2)) - .unwrap() - .is_zero())); - } - - #[test] - fn eip_7002() { - let chain_spec = Arc::new( - ChainSpecBuilder::from(&*MAINNET) - .shanghai_activated() - .with_fork(EthereumHardfork::Prague, ForkCondition::Timestamp(0)) - .build(), - ); - - let mut db = create_state_provider_with_withdrawal_requests_contract(); - - let secp = Secp256k1::new(); - let sender_key_pair = Keypair::new(&secp, &mut generators::rng()); - let sender_address = public_key_to_address(sender_key_pair.public_key()); - - db.insert_account( - sender_address, - Account { nonce: 1, balance: U256::from(ETH_TO_WEI), bytecode_hash: None }, - None, - HashMap::default(), - ); - - // https://github.com/lightclient/sys-asm/blob/9282bdb9fd64e024e27f60f507486ffb2183cba2/test/Withdrawal.t.sol.in#L36 - let validator_public_key = fixed_bytes!("111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111"); - let withdrawal_amount = fixed_bytes!("0203040506070809"); - let input: Bytes = [&validator_public_key[..], &withdrawal_amount[..]].concat().into(); - assert_eq!(input.len(), 56); - - let mut header = chain_spec.genesis_header().clone(); - header.gas_limit = 1_500_000; - // measured - header.gas_used = 135_856; - header.receipts_root = - b256!("b31a3e47b902e9211c4d349af4e4c5604ce388471e79ca008907ae4616bb0ed3"); - - let tx = sign_tx_with_key_pair( - sender_key_pair, - Transaction::Legacy(TxLegacy { - chain_id: Some(chain_spec.chain.id()), - nonce: 1, - gas_price: header.base_fee_per_gas.unwrap().into(), - gas_limit: header.gas_used, - to: TxKind::Call(WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS), - // `MIN_WITHDRAWAL_REQUEST_FEE` - value: U256::from(2), - input, - }), - ); - - let provider = executor_provider(chain_spec); - - let executor = provider.executor(StateProviderDatabase::new(&db)); - - let BlockExecutionOutput { receipts, requests, .. } = executor - .execute( - ( - &Block { - header, - body: BlockBody { transactions: vec![tx], ..Default::default() }, - } - .with_recovered_senders() - .unwrap(), - U256::ZERO, - ) - .into(), - ) - .unwrap(); - - let receipt = receipts.first().unwrap(); - assert!(receipt.success); - - assert!(requests[0].is_empty(), "there should be no deposits"); - assert!(!requests[1].is_empty(), "there should be a withdrawal"); - assert!(requests[2].is_empty(), "there should be no consolidations"); - } - - #[test] - fn block_gas_limit_error() { - // Create a chain specification with fork conditions set for Prague - let chain_spec = Arc::new( - ChainSpecBuilder::from(&*MAINNET) - .shanghai_activated() - .with_fork(EthereumHardfork::Prague, ForkCondition::Timestamp(0)) - .build(), - ); - - // Create a state provider with the withdrawal requests contract pre-deployed - let mut db = create_state_provider_with_withdrawal_requests_contract(); - - // Initialize Secp256k1 for key pair generation - let secp = Secp256k1::new(); - // Generate a new key pair for the sender - let sender_key_pair = Keypair::new(&secp, &mut generators::rng()); - // Get the sender's address from the public key - let sender_address = public_key_to_address(sender_key_pair.public_key()); - - // Insert the sender account into the state with a nonce of 1 and a balance of 1 ETH in Wei - db.insert_account( - sender_address, - Account { nonce: 1, balance: U256::from(ETH_TO_WEI), bytecode_hash: None }, - None, - HashMap::default(), - ); - - // Define the validator public key and withdrawal amount as fixed bytes - let validator_public_key = fixed_bytes!("111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111"); - let withdrawal_amount = fixed_bytes!("2222222222222222"); - // Concatenate the validator public key and withdrawal amount into a single byte array - let input: Bytes = [&validator_public_key[..], &withdrawal_amount[..]].concat().into(); - // Ensure the input length is 56 bytes - assert_eq!(input.len(), 56); - - // Create a genesis block header with a specified gas limit and gas used - let mut header = chain_spec.genesis_header().clone(); - header.gas_limit = 1_500_000; - header.gas_used = 134_807; - header.receipts_root = - b256!("b31a3e47b902e9211c4d349af4e4c5604ce388471e79ca008907ae4616bb0ed3"); - - // Create a transaction with a gas limit higher than the block gas limit - let tx = sign_tx_with_key_pair( - sender_key_pair, - Transaction::Legacy(TxLegacy { - chain_id: Some(chain_spec.chain.id()), - nonce: 1, - gas_price: header.base_fee_per_gas.unwrap().into(), - gas_limit: 2_500_000, // higher than block gas limit - to: TxKind::Call(WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS), - value: U256::from(1), - input, - }), - ); - - // Create an executor from the state provider - let executor = executor_provider(chain_spec).executor(StateProviderDatabase::new(&db)); - - // Execute the block and capture the result - let exec_result = executor.execute( - ( - &Block { header, body: BlockBody { transactions: vec![tx], ..Default::default() } } - .with_recovered_senders() - .unwrap(), - U256::ZERO, - ) - .into(), - ); - - // Check if the execution result is an error and assert the specific error type - match exec_result { - Ok(_) => panic!("Expected block gas limit error"), - Err(err) => assert_eq!( - *err.as_validation().unwrap(), - BlockValidationError::TransactionGasLimitMoreThanAvailableBlockGas { - transaction_gas_limit: 2_500_000, - block_available_gas: 1_500_000, - } - ), - } - } -} diff --git a/crates/ethereum/node/Cargo.toml b/crates/ethereum/node/Cargo.toml index 29093adc8a36..a3fe5ed45037 100644 --- a/crates/ethereum/node/Cargo.toml +++ b/crates/ethereum/node/Cargo.toml @@ -21,6 +21,7 @@ reth-tracing.workspace = true reth-provider.workspace = true reth-transaction-pool.workspace = true reth-network.workspace = true +reth-evm.workspace = true reth-evm-ethereum.workspace = true reth-consensus.workspace = true reth-auto-seal-consensus.workspace = true diff --git a/crates/ethereum/node/src/evm.rs b/crates/ethereum/node/src/evm.rs index d710d8d8d452..bcdcaac6bfa2 100644 --- a/crates/ethereum/node/src/evm.rs +++ b/crates/ethereum/node/src/evm.rs @@ -1,6 +1,8 @@ //! Ethereum EVM support #[doc(inline)] -pub use reth_evm_ethereum::execute::EthExecutorProvider; +pub use reth_evm::execute::BasicBlockExecutorProvider; +#[doc(inline)] +pub use reth_evm_ethereum::execute::{EthExecutionStrategyFactory, EthExecutorProvider}; #[doc(inline)] pub use reth_evm_ethereum::EthEvmConfig; diff --git a/crates/ethereum/node/src/lib.rs b/crates/ethereum/node/src/lib.rs index 37ebc33c22b8..421cee37fb03 100644 --- a/crates/ethereum/node/src/lib.rs +++ b/crates/ethereum/node/src/lib.rs @@ -14,7 +14,9 @@ use revm as _; pub use reth_ethereum_engine_primitives::EthEngineTypes; pub mod evm; -pub use evm::{EthEvmConfig, EthExecutorProvider}; +pub use evm::{ + BasicBlockExecutorProvider, EthEvmConfig, EthExecutionStrategyFactory, EthExecutorProvider, +}; pub mod node; pub use node::EthereumNode; diff --git a/crates/ethereum/node/src/node.rs b/crates/ethereum/node/src/node.rs index d3301b2082e9..3df46b4856f6 100644 --- a/crates/ethereum/node/src/node.rs +++ b/crates/ethereum/node/src/node.rs @@ -9,7 +9,8 @@ use reth_chainspec::ChainSpec; use reth_ethereum_engine_primitives::{ EthBuiltPayload, EthPayloadAttributes, EthPayloadBuilderAttributes, EthereumEngineValidator, }; -use reth_evm_ethereum::execute::EthExecutorProvider; +use reth_evm::execute::BasicBlockExecutorProvider; +use reth_evm_ethereum::execute::EthExecutionStrategyFactory; use reth_network::NetworkHandle; use reth_node_api::{ AddOnsContext, ConfigureEvm, EngineValidator, FullNodeComponents, NodePrimitives, @@ -136,7 +137,7 @@ where Node: FullNodeTypes, { type EVM = EthEvmConfig; - type Executor = EthExecutorProvider; + type Executor = BasicBlockExecutorProvider; async fn build_evm( self, @@ -144,7 +145,8 @@ where ) -> eyre::Result<(Self::EVM, Self::Executor)> { let chain_spec = ctx.chain_spec(); let evm_config = EthEvmConfig::new(ctx.chain_spec()); - let executor = EthExecutorProvider::new(chain_spec, evm_config.clone()); + let strategy_factory = EthExecutionStrategyFactory::new(chain_spec, evm_config.clone()); + let executor = BasicBlockExecutorProvider::new(strategy_factory); Ok((evm_config, executor)) } diff --git a/crates/rpc/rpc-builder/tests/it/utils.rs b/crates/rpc/rpc-builder/tests/it/utils.rs index 847de99564ef..44614ea49a85 100644 --- a/crates/rpc/rpc-builder/tests/it/utils.rs +++ b/crates/rpc/rpc-builder/tests/it/utils.rs @@ -4,7 +4,8 @@ use alloy_rpc_types_engine::{ClientCode, ClientVersionV1}; use reth_beacon_consensus::BeaconConsensusEngineHandle; use reth_chainspec::MAINNET; use reth_ethereum_engine_primitives::{EthEngineTypes, EthereumEngineValidator}; -use reth_evm_ethereum::{execute::EthExecutorProvider, EthEvmConfig}; +use reth_evm::execute::BasicBlockExecutorProvider; +use reth_evm_ethereum::{execute::EthExecutionStrategyFactory, EthEvmConfig}; use reth_network_api::noop::NoopNetwork; use reth_payload_builder::test_utils::spawn_test_payload_service; use reth_provider::test_utils::{NoopProvider, TestCanonStateSubscriptions}; @@ -124,7 +125,7 @@ pub fn test_rpc_builder() -> RpcModuleBuilder< TokioTaskExecutor, TestCanonStateSubscriptions, EthEvmConfig, - EthExecutorProvider, + BasicBlockExecutorProvider, > { RpcModuleBuilder::default() .with_provider(NoopProvider::default()) @@ -133,5 +134,7 @@ pub fn test_rpc_builder() -> RpcModuleBuilder< .with_executor(TokioTaskExecutor::default()) .with_events(TestCanonStateSubscriptions::default()) .with_evm_config(EthEvmConfig::new(MAINNET.clone())) - .with_block_executor(EthExecutorProvider::ethereum(MAINNET.clone())) + .with_block_executor( + BasicBlockExecutorProvider::new(EthExecutionStrategyFactory::mainnet()), + ) } diff --git a/crates/stages/stages/src/stages/execution.rs b/crates/stages/stages/src/stages/execution.rs index 7bb6ebc59e09..47cd9d0445a2 100644 --- a/crates/stages/stages/src/stages/execution.rs +++ b/crates/stages/stages/src/stages/execution.rs @@ -667,7 +667,8 @@ mod tests { use assert_matches::assert_matches; use reth_chainspec::ChainSpecBuilder; use reth_db_api::{models::AccountBeforeTx, transaction::DbTxMut}; - use reth_evm_ethereum::execute::EthExecutorProvider; + use reth_evm::execute::BasicBlockExecutorProvider; + use reth_evm_ethereum::execute::EthExecutionStrategyFactory; use reth_execution_errors::BlockValidationError; use reth_primitives::{Account, Bytecode, SealedBlock, StorageEntry}; use reth_provider::{ @@ -678,10 +679,11 @@ mod tests { use reth_stages_api::StageUnitCheckpoint; use std::collections::BTreeMap; - fn stage() -> ExecutionStage { - let executor_provider = EthExecutorProvider::ethereum(Arc::new( + fn stage() -> ExecutionStage> { + let strategy_factory = EthExecutionStrategyFactory::ethereum(Arc::new( ChainSpecBuilder::mainnet().berlin_activated().build(), )); + let executor_provider = BasicBlockExecutorProvider::new(strategy_factory); ExecutionStage::new( executor_provider, ExecutionStageThresholds { diff --git a/examples/custom-evm/src/main.rs b/examples/custom-evm/src/main.rs index 9c421f9c6a59..55063fc9bbcb 100644 --- a/examples/custom-evm/src/main.rs +++ b/examples/custom-evm/src/main.rs @@ -31,7 +31,7 @@ use reth_node_api::{ use reth_node_core::{args::RpcServerArgs, node_config::NodeConfig}; use reth_node_ethereum::{ node::{EthereumAddOns, EthereumPayloadBuilder}, - EthExecutorProvider, EthereumNode, + BasicBlockExecutorProvider, EthExecutionStrategyFactory, EthereumNode, }; use reth_primitives::{ revm_primitives::{CfgEnvWithHandlerCfg, TxEnv}, @@ -158,7 +158,7 @@ where Node: FullNodeTypes>, { type EVM = MyEvmConfig; - type Executor = EthExecutorProvider; + type Executor = BasicBlockExecutorProvider>; async fn build_evm( self, @@ -166,7 +166,10 @@ where ) -> eyre::Result<(Self::EVM, Self::Executor)> { Ok(( MyEvmConfig::new(ctx.chain_spec()), - EthExecutorProvider::new(ctx.chain_spec(), MyEvmConfig::new(ctx.chain_spec())), + BasicBlockExecutorProvider::new(EthExecutionStrategyFactory::new( + ctx.chain_spec(), + MyEvmConfig::new(ctx.chain_spec()), + )), )) } } diff --git a/examples/stateful-precompile/src/main.rs b/examples/stateful-precompile/src/main.rs index 26ebdfe4124b..b0165e4de26c 100644 --- a/examples/stateful-precompile/src/main.rs +++ b/examples/stateful-precompile/src/main.rs @@ -20,7 +20,10 @@ use reth::{ use reth_chainspec::{Chain, ChainSpec}; use reth_node_api::{ConfigureEvm, ConfigureEvmEnv, FullNodeTypes, NodeTypes}; use reth_node_core::{args::RpcServerArgs, node_config::NodeConfig}; -use reth_node_ethereum::{node::EthereumAddOns, EthEvmConfig, EthExecutorProvider, EthereumNode}; +use reth_node_ethereum::{ + node::EthereumAddOns, BasicBlockExecutorProvider, EthEvmConfig, EthExecutionStrategyFactory, + EthereumNode, +}; use reth_primitives::{ revm_primitives::{SpecId, StatefulPrecompileMut}, Header, TransactionSigned, @@ -224,7 +227,7 @@ where Node: FullNodeTypes>, { type EVM = MyEvmConfig; - type Executor = EthExecutorProvider; + type Executor = BasicBlockExecutorProvider>; async fn build_evm( self, @@ -234,7 +237,13 @@ where inner: EthEvmConfig::new(ctx.chain_spec()), precompile_cache: self.precompile_cache.clone(), }; - Ok((evm_config.clone(), EthExecutorProvider::new(ctx.chain_spec(), evm_config))) + Ok(( + evm_config.clone(), + BasicBlockExecutorProvider::new(EthExecutionStrategyFactory::new( + ctx.chain_spec(), + evm_config, + )), + )) } } From 6c026daf920b28cd7e97e63ef20fea6c58af0f45 Mon Sep 17 00:00:00 2001 From: greged93 <82421016+greged93@users.noreply.github.com> Date: Sat, 19 Oct 2024 22:20:23 +0200 Subject: [PATCH 097/113] docs: explain how to add metrics to grafana (#11875) --- etc/README.md | 79 ++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 75 insertions(+), 4 deletions(-) diff --git a/etc/README.md b/etc/README.md index f80b5b774b6d..28c71b04688b 100644 --- a/etc/README.md +++ b/etc/README.md @@ -2,7 +2,8 @@ This directory contains miscellaneous files, such as example Grafana dashboards and Prometheus configuration. -The files in this directory may undergo a lot of changes while reth is unstable, so do not expect them to necessarily be up to date. +The files in this directory may undergo a lot of changes while reth is unstable, so do not expect them to necessarily be +up to date. ### Overview @@ -11,8 +12,78 @@ The files in this directory may undergo a lot of changes while reth is unstable, ### Docker Compose -To run Reth, Grafana or Prometheus with Docker Compose, refer to the [docker docs](/book/installation/docker.md#using-docker-compose). +To run Reth, Grafana or Prometheus with Docker Compose, refer to +the [docker docs](/book/installation/docker.md#using-docker-compose). -### Import Grafana dashboards +### Grafana -Running Grafana in Docker makes it possible to import existing dashboards, refer to [docs on how to run only Grafana in Docker](/book/installation/docker.md#using-docker-compose#run-only-grafana-in-docker). \ No newline at end of file +#### Adding a new metric to Grafana + +To set up a new metric in Reth and its Grafana dashboard: + +1. Add the metric to the codebase following the [metrics section](../docs/design/metrics.md#creating-metrics) + documentation. + +2. Build the Reth image: + + ```bash + docker build . -t reth:local + ``` + + Modify the [docker-compose](./docker-compose.yml) file to use your locally built image for the Reth service. + +3. Run Docker Compose: + + ```bash + docker compose -f etc/docker-compose.yml -f etc/lighthouse.yml up -d + ``` + +4. Access Grafana: + + - Open `http://localhost:3000/` in a browser + - Log in with username and password `admin` + - Navigate to the `Dashboards` tab + +5. Create or modify a dashboard: + + - Select an existing dashboard or create a new one + - Click `Add` > `Visualization` to create a new panel + +6. Configure your metric panel: + + - Set a panel title and description + - Select metric(s) from the `Metrics browser` or use the `PromQL` terminal + - Document your metric(s) by setting units, legends, etc. + - When adding multiple metrics, use field overwrites if needed + +7. Save and arrange: + + - Click `Apply` to save the panel + - Drag the panel to desired position on the dashboard + +8. Export the dashboard: + + - Click `Share` > `Export` + - Toggle `Export for sharing externally` + - Click `Save to file` + +9. Update dashboard file: + - Replace the content of the corresponding file in the [dashboards folder](./grafana/dashboards) with the exported + JSON + +Your new metric is now integrated into the Reth Grafana dashboard. + +#### Import Grafana dashboards + +In order to import new Grafana dashboards or update a dashboard: + +1. Go to `Home` > `Dashboards` + +2. Click `New` > `Import` + +3. Drag the JSON dashboard file to import it + +4. If updating an existing dashboard, you will need to change the name and UID of the imported dashboard in order to + avoid conflict + +5. Delete the old dashboard From cf4a4454ecec03bab4be9cf3d8bccfbd0bb215df Mon Sep 17 00:00:00 2001 From: liamaharon Date: Sun, 20 Oct 2024 07:36:11 +1100 Subject: [PATCH 098/113] fix: feature propagation (#11888) Co-authored-by: Matthias Seitz Co-authored-by: Oliver --- .config/zepter.yaml | 40 +++++++++++++++++ .github/workflows/lint.yml | 17 ++++++++ Cargo.lock | 27 +++++++++++- Cargo.toml | 2 +- bin/reth-bench/Cargo.toml | 13 ++++-- bin/reth/Cargo.toml | 11 ++++- crates/blockchain-tree/Cargo.toml | 23 +++++++++- crates/chain-state/Cargo.toml | 14 +++--- crates/chainspec/Cargo.toml | 29 ++++++++++--- crates/consensus/auto-seal/Cargo.toml | 10 ++++- crates/consensus/beacon/Cargo.toml | 10 +++-- crates/consensus/consensus/Cargo.toml | 10 ++++- crates/engine/local/Cargo.toml | 6 ++- crates/engine/tree/Cargo.toml | 24 ++++++++--- crates/engine/util/Cargo.toml | 7 ++- crates/ethereum-forks/Cargo.toml | 27 +++++++++--- crates/ethereum/evm/Cargo.toml | 12 +++++- crates/ethereum/node/Cargo.toml | 15 ++++++- crates/evm/Cargo.toml | 23 +++++++++- crates/evm/execution-errors/Cargo.toml | 7 ++- crates/evm/execution-types/Cargo.toml | 24 ++++++++--- crates/exex/exex/Cargo.toml | 12 +++++- crates/exex/types/Cargo.toml | 15 ++++++- crates/net/discv4/Cargo.toml | 11 ++++- crates/net/dns/Cargo.toml | 13 +++++- crates/net/downloaders/Cargo.toml | 16 ++++--- crates/net/eth-wire-types/Cargo.toml | 24 ++++++++--- crates/net/eth-wire/Cargo.toml | 19 +++++++-- crates/net/network-api/Cargo.toml | 8 +++- crates/net/network/Cargo.toml | 32 +++++++++++++- crates/net/p2p/Cargo.toml | 14 +++++- crates/node/builder/Cargo.toml | 19 ++++++++- crates/node/core/Cargo.toml | 14 ++++-- crates/optimism/bin/Cargo.toml | 10 ++++- crates/optimism/chainspec/Cargo.toml | 18 ++++---- crates/optimism/cli/Cargo.toml | 13 +++--- crates/optimism/evm/Cargo.toml | 21 ++++++--- crates/optimism/hardforks/Cargo.toml | 12 +++++- crates/optimism/node/Cargo.toml | 42 +++++++++++++----- crates/optimism/payload/Cargo.toml | 11 +++-- crates/optimism/rpc/Cargo.toml | 9 ++-- crates/optimism/storage/Cargo.toml | 6 ++- crates/payload/builder/Cargo.toml | 8 +++- crates/primitives-traits/Cargo.toml | 34 +++++++++++---- crates/primitives/Cargo.toml | 59 +++++++++++++++++++------- crates/revm/Cargo.toml | 21 +++++++-- crates/stages/api/Cargo.toml | 7 ++- crates/stages/stages/Cargo.toml | 25 ++++++++--- crates/storage/codecs/Cargo.toml | 10 ++++- crates/storage/db-api/Cargo.toml | 26 +++++++++--- crates/storage/db-models/Cargo.toml | 13 +++++- crates/storage/db/Cargo.toml | 24 +++++++++-- crates/storage/errors/Cargo.toml | 6 ++- crates/storage/provider/Cargo.toml | 45 +++++++++++++++----- crates/transaction-pool/Cargo.toml | 40 ++++++++++++++--- crates/trie/common/Cargo.toml | 17 ++++++-- crates/trie/db/Cargo.toml | 22 +++++++++- crates/trie/trie/Cargo.toml | 20 +++++++-- testing/ef-tests/Cargo.toml | 6 ++- 59 files changed, 876 insertions(+), 197 deletions(-) create mode 100644 .config/zepter.yaml diff --git a/.config/zepter.yaml b/.config/zepter.yaml new file mode 100644 index 000000000000..8c6425f4ff0d --- /dev/null +++ b/.config/zepter.yaml @@ -0,0 +1,40 @@ +version: + format: 1 + # Minimum zepter version that is expected to work. This is just for printing a nice error + # message when someone tries to use an older version. + binary: 0.13.2 + +# The examples in the following comments assume crate `A` to have a dependency on crate `B`. +workflows: + check: + - [ + "lint", + # Check that `A` activates the features of `B`. + "propagate-feature", + # These are the features to check: + "--features=std,optimism,dev,asm-keccak,jemalloc,jemalloc-prof,tracy-allocator,serde-bincode-compat,serde,test-utils,arbitrary,bench", + # Do not try to add a new section into `[features]` of `A` only because `B` expose that feature. There are edge-cases where this is still needed, but we can add them manually. + "--left-side-feature-missing=ignore", + # Ignore the case that `A` it outside of the workspace. Otherwise it will report errors in external dependencies that we have no influence on. + "--left-side-outside-workspace=ignore", + # Auxillary flags: + "--offline", + "--locked", + "--show-path", + "--quiet", + ] + default: + # Running `zepter` with no subcommand will check & fix. + - [$check.0, "--fix"] + +# Will be displayed when any workflow fails: +help: + text: | + Reth uses the Zepter CLI to detect abnormalities in Cargo features, e.g. missing propagation. + + It looks like one more more checks failed; please check the console output. + + You can try to automatically address them by installing zepter (`cargo install zepter --locked`) and simply running `zepter` in the workspace root. + links: + - "https://github.com/paradigmxyz/reth/pull/11888" + - "https://github.com/ggwpez/zepter" diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 65c01c3a4912..1921859c2729 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -219,6 +219,22 @@ jobs: env: RUSTFLAGS: -D warnings + # Check crates correctly propagate features + feature-propagation: + runs-on: ubuntu-latest + timeout-minutes: 20 + steps: + - uses: actions/checkout@v4 + - name: fetch deps + run: | + # Eagerly pull dependencies + time cargo metadata --format-version=1 --locked > /dev/null + - name: run zepter + run: | + cargo install zepter -f --locked + zepter --version + time zepter run check + lint-success: name: lint success runs-on: ubuntu-latest @@ -236,6 +252,7 @@ jobs: - grafana - no-test-deps - features + - feature-propagation timeout-minutes: 30 steps: - name: Decide whether the needed jobs succeeded or failed diff --git a/Cargo.lock b/Cargo.lock index 25a62d0c0432..4def3dcabed7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -516,6 +516,7 @@ dependencies = [ "alloy-rlp", "alloy-serde", "alloy-sol-types", + "arbitrary", "derive_more 1.0.0", "itertools 0.13.0", "jsonrpsee-types", @@ -1497,6 +1498,17 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "bstr" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c" +dependencies = [ + "memchr", + "regex-automata 0.4.8", + "serde", +] + [[package]] name = "bumpalo" version = "3.16.0" @@ -2258,6 +2270,7 @@ dependencies = [ "lock_api", "once_cell", "parking_lot_core 0.9.10", + "serde", ] [[package]] @@ -3318,6 +3331,7 @@ version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ + "serde", "typenum", "version_check", "zeroize", @@ -4512,7 +4526,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" dependencies = [ "cfg-if", - "windows-targets 0.52.6", + "windows-targets 0.48.5", ] [[package]] @@ -4623,6 +4637,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47186c6da4d81ca383c7c47c1bfc80f4b95f4720514d860a5407aaf4233f9588" dependencies = [ "linked-hash-map", + "serde", ] [[package]] @@ -4645,6 +4660,7 @@ checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ "autocfg", "scopeguard", + "serde", ] [[package]] @@ -5009,6 +5025,7 @@ dependencies = [ "libc", "log", "mio 0.8.11", + "serde", "walkdir", "windows-sys 0.48.0", ] @@ -5277,6 +5294,7 @@ dependencies = [ "alloy-primitives", "alloy-rpc-types-eth", "alloy-serde", + "arbitrary", "op-alloy-consensus", "serde", "serde_json", @@ -5370,6 +5388,7 @@ version = "3.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "306800abfa29c7f16596b5970a588435e3d5b3149683d00c12b699cc19f895ee" dependencies = [ + "arbitrary", "arrayvec", "bitvec", "byte-slice-cast", @@ -10098,6 +10117,10 @@ name = "similar" version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1de1d4f81173b03af4c0cbed3c898f6bff5b870e4a7f5d6f4057d62a7a4b686e" +dependencies = [ + "bstr", + "unicode-segmentation", +] [[package]] name = "similar-asserts" @@ -10106,6 +10129,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfe85670573cd6f0fa97940f26e7e6601213c3b0555246c24234131f88c5709e" dependencies = [ "console", + "serde", "similar", ] @@ -11016,6 +11040,7 @@ dependencies = [ "parking_lot 0.12.3", "rand 0.8.5", "resolv-conf", + "serde", "smallvec", "thiserror", "tokio", diff --git a/Cargo.toml b/Cargo.toml index 6c66e501ef4a..5b6912c33f27 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -585,7 +585,7 @@ pprof = "0.13" proptest = "1.4" proptest-derive = "0.5" serial_test = { default-features = false, version = "3" } -similar-asserts = { default-features = false, version = "1.5.0" } +similar-asserts = { version = "1.5.0", features = ["serde"] } tempfile = "3.8" test-fuzz = "6" diff --git a/bin/reth-bench/Cargo.toml b/bin/reth-bench/Cargo.toml index e4e40daeca91..03844633a926 100644 --- a/bin/reth-bench/Cargo.toml +++ b/bin/reth-bench/Cargo.toml @@ -76,9 +76,16 @@ reth-tracing.workspace = true [features] default = ["jemalloc"] -asm-keccak = ["reth-primitives/asm-keccak"] - -jemalloc = ["reth-cli-util/jemalloc"] +asm-keccak = [ + "reth-primitives/asm-keccak", + "reth-node-core/asm-keccak", + "alloy-primitives/asm-keccak" +] + +jemalloc = [ + "reth-cli-util/jemalloc", + "reth-node-core/jemalloc" +] jemalloc-prof = ["reth-cli-util/jemalloc-prof"] tracy-allocator = ["reth-cli-util/tracy-allocator"] diff --git a/bin/reth/Cargo.toml b/bin/reth/Cargo.toml index 8b2b77dd665c..8380915d463e 100644 --- a/bin/reth/Cargo.toml +++ b/bin/reth/Cargo.toml @@ -103,14 +103,21 @@ default = ["jemalloc"] dev = ["reth-cli-commands/dev"] -asm-keccak = ["reth-node-core/asm-keccak", "reth-primitives/asm-keccak"] +asm-keccak = [ + "reth-node-core/asm-keccak", + "reth-primitives/asm-keccak", + "alloy-primitives/asm-keccak" +] jemalloc = [ "reth-cli-util/jemalloc", "reth-node-core/jemalloc", "reth-node-metrics/jemalloc", ] -jemalloc-prof = ["reth-cli-util/jemalloc"] +jemalloc-prof = [ + "reth-cli-util/jemalloc", + "reth-cli-util/jemalloc-prof" +] tracy-allocator = ["reth-cli-util/tracy-allocator"] min-error-logs = ["tracing/release_max_level_error"] diff --git a/crates/blockchain-tree/Cargo.toml b/crates/blockchain-tree/Cargo.toml index cff117c92b05..aa8fab16fa54 100644 --- a/crates/blockchain-tree/Cargo.toml +++ b/crates/blockchain-tree/Cargo.toml @@ -63,5 +63,24 @@ alloy-genesis.workspace = true alloy-consensus.workspace = true [features] -test-utils = [] -optimism = ["reth-primitives/optimism", "reth-provider/optimism"] +test-utils = [ + "reth-chainspec/test-utils", + "reth-consensus/test-utils", + "reth-evm/test-utils", + "reth-network/test-utils", + "reth-primitives/test-utils", + "reth-revm/test-utils", + "reth-stages-api/test-utils", + "reth-db/test-utils", + "reth-db-api/test-utils", + "reth-provider/test-utils", + "reth-trie-db/test-utils", + "reth-trie/test-utils" +] +optimism = [ + "reth-primitives/optimism", + "reth-provider/optimism", + "reth-execution-types/optimism", + "reth-db/optimism", + "reth-db-api/optimism" +] diff --git a/crates/chain-state/Cargo.toml b/crates/chain-state/Cargo.toml index c9691bec411c..9a88a3c54bc6 100644 --- a/crates/chain-state/Cargo.toml +++ b/crates/chain-state/Cargo.toml @@ -56,9 +56,13 @@ revm.workspace = true [features] test-utils = [ - "alloy-signer", - "alloy-signer-local", - "alloy-consensus", - "rand", - "revm" + "alloy-signer", + "alloy-signer-local", + "alloy-consensus", + "rand", + "revm", + "reth-chainspec/test-utils", + "reth-primitives/test-utils", + "reth-trie/test-utils", + "revm?/test-utils" ] diff --git a/crates/chainspec/Cargo.toml b/crates/chainspec/Cargo.toml index 87df28322a6e..5bac582cd8b6 100644 --- a/crates/chainspec/Cargo.toml +++ b/crates/chainspec/Cargo.toml @@ -40,11 +40,26 @@ alloy-genesis.workspace = true [features] default = ["std"] std = [ - "alloy-chains/std", - "alloy-eips/std", - "alloy-genesis/std", - "alloy-primitives/std", - "alloy-trie/std", + "alloy-chains/std", + "alloy-eips/std", + "alloy-genesis/std", + "alloy-primitives/std", + "alloy-trie/std", + "reth-primitives-traits/std", + "alloy-consensus/std", + "once_cell/std" +] +arbitrary = [ + "alloy-chains/arbitrary", + "reth-ethereum-forks/arbitrary", + "reth-primitives-traits/arbitrary", + "reth-trie-common/arbitrary", + "alloy-consensus/arbitrary", + "alloy-eips/arbitrary", + "alloy-primitives/arbitrary", + "alloy-trie/arbitrary" +] +test-utils = [ + "reth-primitives-traits/test-utils", + "reth-trie-common/test-utils" ] -arbitrary = ["alloy-chains/arbitrary"] -test-utils = [] diff --git a/crates/consensus/auto-seal/Cargo.toml b/crates/consensus/auto-seal/Cargo.toml index 249858711414..f2bfb43bcced 100644 --- a/crates/consensus/auto-seal/Cargo.toml +++ b/crates/consensus/auto-seal/Cargo.toml @@ -46,4 +46,12 @@ tokio-stream.workspace = true tracing.workspace = true [features] -optimism = ["reth-provider/optimism", "reth-optimism-consensus"] +optimism = [ + "reth-provider/optimism", + "reth-optimism-consensus", + "reth-beacon-consensus/optimism", + "reth-execution-types/optimism", + "reth-optimism-consensus?/optimism", + "reth-primitives/optimism", + "revm-primitives/optimism" +] diff --git a/crates/consensus/beacon/Cargo.toml b/crates/consensus/beacon/Cargo.toml index 192ae2b93df7..dd1e339319b6 100644 --- a/crates/consensus/beacon/Cargo.toml +++ b/crates/consensus/beacon/Cargo.toml @@ -78,8 +78,10 @@ assert_matches.workspace = true [features] optimism = [ - "reth-chainspec", - "reth-primitives/optimism", - "reth-provider/optimism", - "reth-blockchain-tree/optimism", + "reth-chainspec", + "reth-primitives/optimism", + "reth-provider/optimism", + "reth-blockchain-tree/optimism", + "reth-db/optimism", + "reth-db-api/optimism" ] diff --git a/crates/consensus/consensus/Cargo.toml b/crates/consensus/consensus/Cargo.toml index 1736caab5433..2faf3f2ac719 100644 --- a/crates/consensus/consensus/Cargo.toml +++ b/crates/consensus/consensus/Cargo.toml @@ -24,5 +24,11 @@ derive_more.workspace = true [features] default = ["std"] -std = [] -test-utils = [] +std = [ + "reth-primitives/std", + "alloy-primitives/std", + "alloy-eips/std" +] +test-utils = [ + "reth-primitives/test-utils" +] diff --git a/crates/engine/local/Cargo.toml b/crates/engine/local/Cargo.toml index f22ab1f8d560..d9dc63253399 100644 --- a/crates/engine/local/Cargo.toml +++ b/crates/engine/local/Cargo.toml @@ -46,4 +46,8 @@ op-alloy-rpc-types-engine = { workspace = true, optional = true } workspace = true [features] -optimism = ["op-alloy-rpc-types-engine"] +optimism = [ + "op-alloy-rpc-types-engine", + "reth-beacon-consensus/optimism", + "reth-provider/optimism" +] diff --git a/crates/engine/tree/Cargo.toml b/crates/engine/tree/Cargo.toml index 3a618f4fd7a1..6fe741db8833 100644 --- a/crates/engine/tree/Cargo.toml +++ b/crates/engine/tree/Cargo.toml @@ -79,11 +79,21 @@ assert_matches.workspace = true [features] test-utils = [ - "reth-db/test-utils", - "reth-chain-state/test-utils", - "reth-network-p2p/test-utils", - "reth-prune-types", - "reth-stages/test-utils", - "reth-static-file", - "reth-tracing", + "reth-db/test-utils", + "reth-chain-state/test-utils", + "reth-network-p2p/test-utils", + "reth-prune-types", + "reth-stages/test-utils", + "reth-static-file", + "reth-tracing", + "reth-blockchain-tree/test-utils", + "reth-chainspec/test-utils", + "reth-consensus/test-utils", + "reth-evm/test-utils", + "reth-payload-builder/test-utils", + "reth-primitives/test-utils", + "reth-revm/test-utils", + "reth-stages-api/test-utils", + "reth-provider/test-utils", + "reth-trie/test-utils" ] diff --git a/crates/engine/util/Cargo.toml b/crates/engine/util/Cargo.toml index 35a7e74bb219..07aa40165e2b 100644 --- a/crates/engine/util/Cargo.toml +++ b/crates/engine/util/Cargo.toml @@ -50,4 +50,9 @@ itertools.workspace = true tracing.workspace = true [features] -optimism = ["reth-beacon-consensus/optimism"] +optimism = [ + "reth-beacon-consensus/optimism", + "reth-primitives/optimism", + "reth-provider/optimism", + "revm-primitives/optimism" +] diff --git a/crates/ethereum-forks/Cargo.toml b/crates/ethereum-forks/Cargo.toml index 7b4b6c53c09d..9f7ce7ee8f39 100644 --- a/crates/ethereum-forks/Cargo.toml +++ b/crates/ethereum-forks/Cargo.toml @@ -39,12 +39,27 @@ alloy-consensus.workspace = true [features] default = ["std", "serde", "rustc-hash"] -arbitrary = ["dep:arbitrary", "dep:proptest", "dep:proptest-derive"] -serde = ["dep:serde"] +arbitrary = [ + "dep:arbitrary", + "dep:proptest", + "dep:proptest-derive", + "alloy-chains/arbitrary", + "alloy-consensus/arbitrary", + "alloy-primitives/arbitrary" +] +serde = [ + "dep:serde", + "alloy-chains/serde", + "alloy-consensus/serde", + "alloy-primitives/serde" +] std = [ - "alloy-chains/std", - "alloy-primitives/std", - "thiserror-no-std/std", - "rustc-hash/std", + "alloy-chains/std", + "alloy-primitives/std", + "thiserror-no-std/std", + "rustc-hash/std", + "alloy-consensus/std", + "once_cell/std", + "serde?/std" ] rustc-hash = ["dep:rustc-hash"] diff --git a/crates/ethereum/evm/Cargo.toml b/crates/ethereum/evm/Cargo.toml index 8cbc92f90f3d..17e870e61113 100644 --- a/crates/ethereum/evm/Cargo.toml +++ b/crates/ethereum/evm/Cargo.toml @@ -41,4 +41,14 @@ alloy-genesis.workspace = true [features] default = ["std"] -std = [] +std = [ + "reth-consensus/std", + "reth-primitives/std", + "reth-revm/std", + "alloy-consensus/std", + "alloy-eips/std", + "alloy-genesis/std", + "alloy-primitives/std", + "revm-primitives/std", + "secp256k1/std" +] diff --git a/crates/ethereum/node/Cargo.toml b/crates/ethereum/node/Cargo.toml index a3fe5ed45037..11555cdc4a53 100644 --- a/crates/ethereum/node/Cargo.toml +++ b/crates/ethereum/node/Cargo.toml @@ -55,4 +55,17 @@ alloy-consensus.workspace = true [features] default = [] -test-utils = ["reth-node-builder/test-utils"] +test-utils = [ + "reth-node-builder/test-utils", + "reth-chainspec/test-utils", + "reth-consensus/test-utils", + "reth-network/test-utils", + "reth-payload-builder/test-utils", + "reth-primitives/test-utils", + "reth-revm/test-utils", + "reth-db/test-utils", + "reth-provider/test-utils", + "reth-transaction-pool/test-utils", + "revm/test-utils", + "reth-evm/test-utils" +] diff --git a/crates/evm/Cargo.toml b/crates/evm/Cargo.toml index 6c16973b28b3..6a1e1fe0d727 100644 --- a/crates/evm/Cargo.toml +++ b/crates/evm/Cargo.toml @@ -42,5 +42,24 @@ reth-ethereum-forks.workspace = true [features] default = ["std"] -std = ["dep:metrics", "dep:reth-metrics"] -test-utils = ["dep:parking_lot"] +std = [ + "dep:metrics", + "dep:reth-metrics", + "reth-consensus/std", + "reth-primitives/std", + "reth-primitives-traits/std", + "reth-revm/std", + "alloy-eips/std", + "alloy-primitives/std", + "revm-primitives/std", + "revm/std" +] +test-utils = [ + "dep:parking_lot", + "reth-chainspec/test-utils", + "reth-consensus/test-utils", + "reth-primitives/test-utils", + "reth-primitives-traits/test-utils", + "reth-revm/test-utils", + "revm/test-utils" +] diff --git a/crates/evm/execution-errors/Cargo.toml b/crates/evm/execution-errors/Cargo.toml index d4f8534e7520..721c8055110d 100644 --- a/crates/evm/execution-errors/Cargo.toml +++ b/crates/evm/execution-errors/Cargo.toml @@ -26,4 +26,9 @@ derive_more.workspace = true [features] default = ["std"] -std = ["reth-consensus/std"] +std = [ + "reth-consensus/std", + "alloy-eips/std", + "alloy-primitives/std", + "revm-primitives/std" +] diff --git a/crates/evm/execution-types/Cargo.toml b/crates/evm/execution-types/Cargo.toml index 49e9623021e5..b6af3dee9afd 100644 --- a/crates/evm/execution-types/Cargo.toml +++ b/crates/evm/execution-types/Cargo.toml @@ -33,10 +33,24 @@ reth-primitives = { workspace = true, features = ["arbitrary", "test-utils"] } [features] default = ["std"] optimism = ["reth-primitives/optimism", "revm/optimism"] -serde = ["dep:serde", "reth-trie/serde", "revm/serde"] +serde = [ + "dep:serde", + "reth-trie/serde", + "revm/serde", + "alloy-eips/serde", + "alloy-primitives/serde", + "rand/serde" +] serde-bincode-compat = [ - "reth-primitives/serde-bincode-compat", - "reth-trie/serde-bincode-compat", - "serde_with", + "reth-primitives/serde-bincode-compat", + "reth-trie/serde-bincode-compat", + "serde_with", + "alloy-eips/serde-bincode-compat" +] +std = [ + "reth-primitives/std", + "alloy-eips/std", + "alloy-primitives/std", + "revm/std", + "serde?/std" ] -std = [] diff --git a/crates/exex/exex/Cargo.toml b/crates/exex/exex/Cargo.toml index 27a9d1576c82..903e11e784ea 100644 --- a/crates/exex/exex/Cargo.toml +++ b/crates/exex/exex/Cargo.toml @@ -70,4 +70,14 @@ tempfile.workspace = true [features] default = [] -serde = ["reth-provider/serde", "reth-exex-types/serde"] +serde = [ + "reth-provider/serde", + "reth-exex-types/serde", + "reth-revm/serde", + "alloy-consensus/serde", + "alloy-eips/serde", + "alloy-primitives/serde", + "parking_lot/serde", + "rand/serde", + "secp256k1/serde" +] diff --git a/crates/exex/types/Cargo.toml b/crates/exex/types/Cargo.toml index a146cbc22739..51097d6109c1 100644 --- a/crates/exex/types/Cargo.toml +++ b/crates/exex/types/Cargo.toml @@ -33,5 +33,16 @@ rand.workspace = true [features] default = [] -serde = ["dep:serde", "reth-execution-types/serde"] -serde-bincode-compat = ["reth-execution-types/serde-bincode-compat", "serde_with"] +serde = [ + "dep:serde", + "reth-execution-types/serde", + "alloy-eips/serde", + "alloy-primitives/serde", + "rand/serde" +] +serde-bincode-compat = [ + "reth-execution-types/serde-bincode-compat", + "serde_with", + "reth-primitives/serde-bincode-compat", + "alloy-eips/serde-bincode-compat" +] diff --git a/crates/net/discv4/Cargo.toml b/crates/net/discv4/Cargo.toml index fde652ef3978..f008d03b56fa 100644 --- a/crates/net/discv4/Cargo.toml +++ b/crates/net/discv4/Cargo.toml @@ -51,5 +51,14 @@ reth-tracing.workspace = true [features] default = ["serde"] -serde = ["dep:serde"] +serde = [ + "dep:serde", + "alloy-primitives/serde", + "discv5/serde", + "enr/serde", + "generic-array/serde", + "parking_lot/serde", + "rand?/serde", + "secp256k1/serde" +] test-utils = ["dep:rand"] diff --git a/crates/net/dns/Cargo.toml b/crates/net/dns/Cargo.toml index 2af72afcef65..a52f65057443 100644 --- a/crates/net/dns/Cargo.toml +++ b/crates/net/dns/Cargo.toml @@ -48,4 +48,15 @@ reth-tracing.workspace = true rand.workspace = true [features] -serde = ["dep:serde", "dep:serde_with"] +serde = [ + "dep:serde", + "dep:serde_with", + "alloy-chains/serde", + "alloy-primitives/serde", + "enr/serde", + "linked_hash_set/serde", + "parking_lot/serde", + "rand/serde", + "secp256k1/serde", + "trust-dns-resolver/serde" +] diff --git a/crates/net/downloaders/Cargo.toml b/crates/net/downloaders/Cargo.toml index 5e7f4dd47a27..272db6fc6d1c 100644 --- a/crates/net/downloaders/Cargo.toml +++ b/crates/net/downloaders/Cargo.toml @@ -71,10 +71,14 @@ tempfile.workspace = true [features] test-utils = [ - "dep:tempfile", - "dep:reth-db-api", - "reth-db/test-utils", - "reth-consensus/test-utils", - "reth-network-p2p/test-utils", - "reth-testing-utils", + "dep:tempfile", + "dep:reth-db-api", + "reth-db/test-utils", + "reth-consensus/test-utils", + "reth-network-p2p/test-utils", + "reth-testing-utils", + "reth-chainspec/test-utils", + "reth-primitives/test-utils", + "reth-db-api?/test-utils", + "reth-provider/test-utils" ] diff --git a/crates/net/eth-wire-types/Cargo.toml b/crates/net/eth-wire-types/Cargo.toml index 82c9fe37a44d..1d2b54872455 100644 --- a/crates/net/eth-wire-types/Cargo.toml +++ b/crates/net/eth-wire-types/Cargo.toml @@ -45,10 +45,22 @@ alloy-consensus.workspace = true [features] arbitrary = [ - "reth-primitives/arbitrary", - "alloy-chains/arbitrary", - "dep:arbitrary", - "dep:proptest", - "dep:proptest-arbitrary-interop", + "reth-primitives/arbitrary", + "alloy-chains/arbitrary", + "dep:arbitrary", + "dep:proptest", + "dep:proptest-arbitrary-interop", + "reth-chainspec/arbitrary", + "alloy-consensus/arbitrary", + "alloy-eips/arbitrary", + "alloy-primitives/arbitrary" +] +serde = [ + "dep:serde", + "alloy-chains/serde", + "alloy-consensus/serde", + "alloy-eips/serde", + "alloy-primitives/serde", + "bytes/serde", + "rand/serde" ] -serde = ["dep:serde"] diff --git a/crates/net/eth-wire/Cargo.toml b/crates/net/eth-wire/Cargo.toml index 6eea4bc4ac65..b0e256fdf637 100644 --- a/crates/net/eth-wire/Cargo.toml +++ b/crates/net/eth-wire/Cargo.toml @@ -66,11 +66,22 @@ alloy-eips.workspace = true [features] arbitrary = [ - "reth-primitives/arbitrary", - "reth-eth-wire-types/arbitrary", - "dep:arbitrary", + "reth-primitives/arbitrary", + "reth-eth-wire-types/arbitrary", + "dep:arbitrary", + "reth-chainspec/arbitrary", + "alloy-eips/arbitrary", + "alloy-primitives/arbitrary" +] +serde = [ + "dep:serde", + "reth-eth-wire-types/serde", + "alloy-eips/serde", + "alloy-primitives/serde", + "bytes/serde", + "rand/serde", + "secp256k1/serde" ] -serde = ["dep:serde", "reth-eth-wire-types/serde"] [[test]] name = "fuzz_roundtrip" diff --git a/crates/net/network-api/Cargo.toml b/crates/net/network-api/Cargo.toml index 650d749048c4..6d410e9db23b 100644 --- a/crates/net/network-api/Cargo.toml +++ b/crates/net/network-api/Cargo.toml @@ -40,4 +40,10 @@ derive_more.workspace = true [features] default = ["serde"] -serde = ["dep:serde"] +serde = [ + "dep:serde", + "reth-eth-wire-types/serde", + "reth-network-types/serde", + "alloy-primitives/serde", + "enr/serde" +] diff --git a/crates/net/network/Cargo.toml b/crates/net/network/Cargo.toml index 1d3af517af3f..f444aa7fe27c 100644 --- a/crates/net/network/Cargo.toml +++ b/crates/net/network/Cargo.toml @@ -101,8 +101,36 @@ criterion = { workspace = true, features = ["async_tokio", "html_reports"] } [features] default = ["serde"] geth-tests = [] -serde = ["dep:serde", "secp256k1/serde", "enr/serde", "reth-network-types/serde"] -test-utils = ["dep:reth-provider", "reth-provider?/test-utils", "dep:tempfile", "reth-transaction-pool/test-utils", "reth-network-types/test-utils"] +serde = [ + "dep:serde", + "secp256k1/serde", + "enr/serde", + "reth-network-types/serde", + "reth-dns-discovery/serde", + "reth-eth-wire/serde", + "reth-provider?/serde", + "alloy-consensus/serde", + "alloy-eips/serde", + "alloy-primitives/serde", + "discv5/serde", + "parking_lot/serde", + "rand/serde", + "smallvec/serde", + "url/serde" +] +test-utils = [ + "dep:reth-provider", + "reth-provider?/test-utils", + "dep:tempfile", + "reth-transaction-pool/test-utils", + "reth-network-types/test-utils", + "reth-chainspec/test-utils", + "reth-consensus/test-utils", + "reth-discv4/test-utils", + "reth-network/test-utils", + "reth-network-p2p/test-utils", + "reth-primitives/test-utils" +] [[bench]] name = "bench" diff --git a/crates/net/p2p/Cargo.toml b/crates/net/p2p/Cargo.toml index c43f7f5b347c..3b6d74c9dbeb 100644 --- a/crates/net/p2p/Cargo.toml +++ b/crates/net/p2p/Cargo.toml @@ -43,5 +43,15 @@ tokio = { workspace = true, features = ["full"] } [features] default = ["std"] -test-utils = ["reth-consensus/test-utils", "parking_lot"] -std = ["reth-consensus/std"] +test-utils = [ + "reth-consensus/test-utils", + "parking_lot", + "reth-network-types/test-utils", + "reth-primitives/test-utils" +] +std = [ + "reth-consensus/std", + "reth-primitives/std", + "alloy-eips/std", + "alloy-primitives/std" +] diff --git a/crates/node/builder/Cargo.toml b/crates/node/builder/Cargo.toml index 53e53cd2b856..86f755cb9206 100644 --- a/crates/node/builder/Cargo.toml +++ b/crates/node/builder/Cargo.toml @@ -96,4 +96,21 @@ tempfile.workspace = true [features] default = [] -test-utils = ["reth-db/test-utils"] +test-utils = [ + "reth-db/test-utils", + "reth-blockchain-tree/test-utils", + "reth-chain-state/test-utils", + "reth-chainspec/test-utils", + "reth-consensus/test-utils", + "reth-engine-tree/test-utils", + "reth-evm/test-utils", + "reth-downloaders/test-utils", + "reth-network/test-utils", + "reth-network-p2p/test-utils", + "reth-payload-builder/test-utils", + "reth-primitives/test-utils", + "reth-stages/test-utils", + "reth-db-api/test-utils", + "reth-provider/test-utils", + "reth-transaction-pool/test-utils" +] diff --git a/crates/node/core/Cargo.toml b/crates/node/core/Cargo.toml index a6ae1db5e01d..73c552f4d7a8 100644 --- a/crates/node/core/Cargo.toml +++ b/crates/node/core/Cargo.toml @@ -76,10 +76,18 @@ proptest.workspace = true tokio.workspace = true [features] -optimism = ["reth-primitives/optimism"] +optimism = [ + "reth-primitives/optimism", + "reth-db/optimism" +] # Features for vergen to generate correct env vars -jemalloc = [] -asm-keccak = [] +jemalloc = [ + "reth-cli-util/jemalloc" +] +asm-keccak = [ + "reth-primitives/asm-keccak", + "alloy-primitives/asm-keccak" +] [build-dependencies] vergen = { version = "8.0.0", features = ["build", "cargo", "git", "gitcl"] } diff --git a/crates/optimism/bin/Cargo.toml b/crates/optimism/bin/Cargo.toml index 2de0bb6ee181..f60ef36a4669 100644 --- a/crates/optimism/bin/Cargo.toml +++ b/crates/optimism/bin/Cargo.toml @@ -37,7 +37,15 @@ tracy-allocator = ["reth-cli-util/tracy-allocator"] asm-keccak = ["reth-optimism-cli/asm-keccak", "reth-optimism-node/asm-keccak"] -optimism = ["reth-optimism-cli/optimism", "reth-optimism-node/optimism"] +optimism = [ + "reth-optimism-cli/optimism", + "reth-optimism-node/optimism", + "reth-optimism-consensus/optimism", + "reth-optimism-evm/optimism", + "reth-optimism-payload-builder/optimism", + "reth-optimism-rpc/optimism", + "reth-provider/optimism" +] min-error-logs = ["tracing/release_max_level_error"] min-warn-logs = ["tracing/release_max_level_warn"] diff --git a/crates/optimism/chainspec/Cargo.toml b/crates/optimism/chainspec/Cargo.toml index efc9bf0b0126..6b068dabbf0c 100644 --- a/crates/optimism/chainspec/Cargo.toml +++ b/crates/optimism/chainspec/Cargo.toml @@ -45,12 +45,14 @@ op-alloy-rpc-types.workspace = true [features] default = ["std"] std = [ - "alloy-chains/std", - "alloy-genesis/std", - "alloy-primitives/std", - "op-alloy-rpc-types/std", - "reth-chainspec/std", - "reth-ethereum-forks/std", - "reth-primitives-traits/std", - "reth-optimism-forks/std", + "alloy-chains/std", + "alloy-genesis/std", + "alloy-primitives/std", + "op-alloy-rpc-types/std", + "reth-chainspec/std", + "reth-ethereum-forks/std", + "reth-primitives-traits/std", + "reth-optimism-forks/std", + "alloy-consensus/std", + "once_cell/std" ] diff --git a/crates/optimism/cli/Cargo.toml b/crates/optimism/cli/Cargo.toml index d53270cd62f8..7db41ccbe843 100644 --- a/crates/optimism/cli/Cargo.toml +++ b/crates/optimism/cli/Cargo.toml @@ -73,11 +73,14 @@ reth-cli-commands.workspace = true [features] optimism = [ - "reth-primitives/optimism", - "reth-optimism-evm/optimism", - "reth-provider/optimism", - "reth-node-core/optimism", - "reth-optimism-node/optimism", + "reth-primitives/optimism", + "reth-optimism-evm/optimism", + "reth-provider/optimism", + "reth-node-core/optimism", + "reth-optimism-node/optimism", + "reth-execution-types/optimism", + "reth-db/optimism", + "reth-db-api/optimism" ] asm-keccak = [ "alloy-primitives/asm-keccak", diff --git a/crates/optimism/evm/Cargo.toml b/crates/optimism/evm/Cargo.toml index f251347c58b4..f6b22ad14c8d 100644 --- a/crates/optimism/evm/Cargo.toml +++ b/crates/optimism/evm/Cargo.toml @@ -51,10 +51,21 @@ alloy-consensus.workspace = true [features] default = ["std"] -std = [] +std = [ + "reth-consensus/std", + "reth-primitives/std", + "reth-revm/std", + "alloy-consensus/std", + "alloy-eips/std", + "alloy-genesis/std", + "alloy-primitives/std", + "revm-primitives/std", + "revm/std" +] optimism = [ - "reth-primitives/optimism", - "reth-execution-types/optimism", - "reth-optimism-consensus/optimism", - "revm/optimism", + "reth-primitives/optimism", + "reth-execution-types/optimism", + "reth-optimism-consensus/optimism", + "revm/optimism", + "revm-primitives/optimism" ] diff --git a/crates/optimism/hardforks/Cargo.toml b/crates/optimism/hardforks/Cargo.toml index 815d50c6bcc4..c30566a54eb4 100644 --- a/crates/optimism/hardforks/Cargo.toml +++ b/crates/optimism/hardforks/Cargo.toml @@ -27,5 +27,13 @@ once_cell.workspace = true [features] default = ["std"] -std = [] -serde = ["dep:serde"] \ No newline at end of file +std = [ + "alloy-primitives/std", + "once_cell/std", + "serde?/std" +] +serde = [ + "dep:serde", + "alloy-chains/serde", + "alloy-primitives/serde" +] diff --git a/crates/optimism/node/Cargo.toml b/crates/optimism/node/Cargo.toml index fbe787d6e160..37cf4a328ea0 100644 --- a/crates/optimism/node/Cargo.toml +++ b/crates/optimism/node/Cargo.toml @@ -69,15 +69,35 @@ op-alloy-consensus.workspace = true [features] optimism = [ - "reth-primitives/optimism", - "reth-provider/optimism", - "reth-optimism-evm/optimism", - "reth-optimism-payload-builder/optimism", - "reth-beacon-consensus/optimism", - "revm/optimism", - "reth-auto-seal-consensus/optimism", - "reth-optimism-rpc/optimism", - "reth-engine-local/optimism", + "reth-primitives/optimism", + "reth-provider/optimism", + "reth-optimism-evm/optimism", + "reth-optimism-payload-builder/optimism", + "reth-beacon-consensus/optimism", + "revm/optimism", + "reth-auto-seal-consensus/optimism", + "reth-optimism-rpc/optimism", + "reth-engine-local/optimism", + "reth-optimism-consensus/optimism", + "reth-db/optimism" +] +asm-keccak = [ + "reth-primitives/asm-keccak", + "reth/asm-keccak", + "alloy-primitives/asm-keccak", + "revm/asm-keccak" +] +test-utils = [ + "reth-node-builder/test-utils", + "reth-chainspec/test-utils", + "reth-consensus/test-utils", + "reth-evm/test-utils", + "reth-network/test-utils", + "reth-payload-builder/test-utils", + "reth-primitives/test-utils", + "reth-revm/test-utils", + "reth-db/test-utils", + "reth-provider/test-utils", + "reth-transaction-pool/test-utils", + "revm/test-utils" ] -asm-keccak = ["reth-primitives/asm-keccak"] -test-utils = ["reth-node-builder/test-utils"] diff --git a/crates/optimism/payload/Cargo.toml b/crates/optimism/payload/Cargo.toml index 46cc82edb6ce..de61def83506 100644 --- a/crates/optimism/payload/Cargo.toml +++ b/crates/optimism/payload/Cargo.toml @@ -50,8 +50,11 @@ sha2.workspace = true [features] optimism = [ - "reth-primitives/optimism", - "reth-provider/optimism", - "reth-optimism-evm/optimism", - "revm/optimism", + "reth-primitives/optimism", + "reth-provider/optimism", + "reth-optimism-evm/optimism", + "revm/optimism", + "reth-execution-types/optimism", + "reth-optimism-consensus/optimism", + "revm-primitives/optimism" ] diff --git a/crates/optimism/rpc/Cargo.toml b/crates/optimism/rpc/Cargo.toml index 90984998ac7e..dc0f96c4012d 100644 --- a/crates/optimism/rpc/Cargo.toml +++ b/crates/optimism/rpc/Cargo.toml @@ -63,8 +63,9 @@ reth-optimism-chainspec.workspace = true [features] optimism = [ - "reth-optimism-evm/optimism", - "reth-primitives/optimism", - "reth-provider/optimism", - "revm/optimism", + "reth-optimism-evm/optimism", + "reth-primitives/optimism", + "reth-provider/optimism", + "revm/optimism", + "reth-optimism-consensus/optimism" ] diff --git a/crates/optimism/storage/Cargo.toml b/crates/optimism/storage/Cargo.toml index 107b64db3de0..2b18897d94a0 100644 --- a/crates/optimism/storage/Cargo.toml +++ b/crates/optimism/storage/Cargo.toml @@ -20,4 +20,8 @@ reth-prune-types.workspace = true reth-stages-types.workspace = true [features] -optimism = ["reth-primitives/optimism"] \ No newline at end of file +optimism = [ + "reth-primitives/optimism", + "reth-codecs/optimism", + "reth-db-api/optimism" +] diff --git a/crates/payload/builder/Cargo.toml b/crates/payload/builder/Cargo.toml index 71f63ce34c2d..3b71011e02e5 100644 --- a/crates/payload/builder/Cargo.toml +++ b/crates/payload/builder/Cargo.toml @@ -40,4 +40,10 @@ tracing.workspace = true revm.workspace = true [features] -test-utils = ["reth-chain-state"] +test-utils = [ + "reth-chain-state", + "reth-chain-state?/test-utils", + "reth-primitives/test-utils", + "reth-provider/test-utils", + "revm/test-utils" +] diff --git a/crates/primitives-traits/Cargo.toml b/crates/primitives-traits/Cargo.toml index 2fec75666568..9634da40f47c 100644 --- a/crates/primitives-traits/Cargo.toml +++ b/crates/primitives-traits/Cargo.toml @@ -54,14 +54,30 @@ test-fuzz.workspace = true [features] default = ["std"] -std = [] -test-utils = ["arbitrary"] +std = [ + "alloy-consensus/std", + "alloy-eips/std", + "alloy-genesis/std", + "alloy-primitives/std", + "revm-primitives/std", + "serde/std" +] +test-utils = [ + "arbitrary", + "reth-codecs/test-utils" +] arbitrary = [ - "std", - "alloy-consensus/arbitrary", - "alloy-primitives/arbitrary", - "dep:arbitrary", - "dep:proptest", - "dep:proptest-arbitrary-interop", + "std", + "alloy-consensus/arbitrary", + "alloy-primitives/arbitrary", + "dep:arbitrary", + "dep:proptest", + "dep:proptest-arbitrary-interop", + "alloy-eips/arbitrary", + "revm-primitives/arbitrary" +] +serde-bincode-compat = [ + "serde_with", + "alloy-consensus/serde-bincode-compat", + "alloy-eips/serde-bincode-compat" ] -serde-bincode-compat = ["serde_with", "alloy-consensus/serde-bincode-compat"] diff --git a/crates/primitives/Cargo.toml b/crates/primitives/Cargo.toml index 5661fb8f8467..566a114bebf9 100644 --- a/crates/primitives/Cargo.toml +++ b/crates/primitives/Cargo.toml @@ -90,18 +90,41 @@ pprof = { workspace = true, features = [ [features] default = ["c-kzg", "alloy-compat", "std", "reth-codec", "secp256k1"] -std = ["reth-primitives-traits/std"] +std = [ + "reth-primitives-traits/std", + "alloy-consensus/std", + "alloy-eips/std", + "alloy-genesis/std", + "alloy-primitives/std", + "alloy-serde?/std", + "k256/std", + "once_cell/std", + "revm-primitives/std", + "secp256k1?/std", + "serde/std" +] reth-codec = ["dep:reth-codecs", "dep:zstd", "dep:modular-bitfield", "std"] -asm-keccak = ["alloy-primitives/asm-keccak"] +asm-keccak = [ + "alloy-primitives/asm-keccak", + "revm-primitives/asm-keccak" +] arbitrary = [ - "dep:arbitrary", - "alloy-eips/arbitrary", - "rand", - "reth-codec", - "reth-ethereum-forks/arbitrary", - "reth-primitives-traits/arbitrary", - "revm-primitives/arbitrary", - "secp256k1", + "dep:arbitrary", + "alloy-eips/arbitrary", + "rand", + "reth-codec", + "reth-ethereum-forks/arbitrary", + "reth-primitives-traits/arbitrary", + "revm-primitives/arbitrary", + "secp256k1", + "reth-chainspec/arbitrary", + "reth-trie-common/arbitrary", + "alloy-consensus/arbitrary", + "alloy-primitives/arbitrary", + "alloy-rpc-types?/arbitrary", + "alloy-serde?/arbitrary", + "op-alloy-consensus?/arbitrary", + "op-alloy-rpc-types?/arbitrary" ] secp256k1 = ["dep:secp256k1"] c-kzg = [ @@ -121,12 +144,18 @@ alloy-compat = [ "dep:alloy-serde", "dep:op-alloy-rpc-types", ] -test-utils = ["reth-primitives-traits/test-utils"] +test-utils = [ + "reth-primitives-traits/test-utils", + "reth-chainspec/test-utils", + "reth-codecs?/test-utils", + "reth-trie-common/test-utils" +] serde-bincode-compat = [ - "alloy-consensus/serde-bincode-compat", - "op-alloy-consensus?/serde-bincode-compat", - "reth-primitives-traits/serde-bincode-compat", - "serde_with", + "alloy-consensus/serde-bincode-compat", + "op-alloy-consensus?/serde-bincode-compat", + "reth-primitives-traits/serde-bincode-compat", + "serde_with", + "alloy-eips/serde-bincode-compat" ] [[bench]] diff --git a/crates/revm/Cargo.toml b/crates/revm/Cargo.toml index 668abb79e381..8f670d364b8a 100644 --- a/crates/revm/Cargo.toml +++ b/crates/revm/Cargo.toml @@ -34,6 +34,21 @@ alloy-primitives.workspace = true [features] default = ["std"] -std = [] -test-utils = ["dep:reth-trie"] -serde = ["revm/serde"] +std = [ + "reth-primitives/std", + "alloy-primitives/std", + "revm/std", + "alloy-eips/std" +] +test-utils = [ + "dep:reth-trie", + "reth-primitives/test-utils", + "reth-trie?/test-utils", + "revm/test-utils" +] +serde = [ + "revm/serde", + "reth-trie?/serde", + "alloy-eips/serde", + "alloy-primitives/serde" +] diff --git a/crates/stages/api/Cargo.toml b/crates/stages/api/Cargo.toml index 352d3e024765..cba569a2a431 100644 --- a/crates/stages/api/Cargo.toml +++ b/crates/stages/api/Cargo.toml @@ -46,4 +46,9 @@ tokio-stream.workspace = true reth-testing-utils.workspace = true [features] -test-utils = [] +test-utils = [ + "reth-consensus/test-utils", + "reth-network-p2p/test-utils", + "reth-primitives-traits/test-utils", + "reth-provider/test-utils" +] diff --git a/crates/stages/stages/Cargo.toml b/crates/stages/stages/Cargo.toml index 81f35a4b390b..0b26cb6a1e79 100644 --- a/crates/stages/stages/Cargo.toml +++ b/crates/stages/stages/Cargo.toml @@ -93,13 +93,24 @@ pprof = { workspace = true, features = [ [features] test-utils = [ - "dep:reth-chainspec", - "reth-network-p2p/test-utils", - "reth-db/test-utils", - "reth-provider/test-utils", - "reth-stages-api/test-utils", - "dep:reth-testing-utils", - "dep:tempfile", + "dep:reth-chainspec", + "reth-network-p2p/test-utils", + "reth-db/test-utils", + "reth-provider/test-utils", + "reth-stages-api/test-utils", + "dep:reth-testing-utils", + "dep:tempfile", + "reth-chainspec?/test-utils", + "reth-consensus/test-utils", + "reth-evm/test-utils", + "reth-downloaders/test-utils", + "reth-primitives/test-utils", + "reth-primitives-traits/test-utils", + "reth-revm/test-utils", + "reth-codecs/test-utils", + "reth-db-api/test-utils", + "reth-trie-db/test-utils", + "reth-trie/test-utils" ] [[bench]] diff --git a/crates/storage/codecs/Cargo.toml b/crates/storage/codecs/Cargo.toml index 21a1897f1c78..2525b4e8d7f8 100644 --- a/crates/storage/codecs/Cargo.toml +++ b/crates/storage/codecs/Cargo.toml @@ -49,7 +49,15 @@ serde.workspace = true [features] default = ["std", "alloy"] -std = ["alloy-primitives/std", "bytes/std"] +std = [ + "alloy-primitives/std", + "bytes/std", + "alloy-consensus?/std", + "alloy-eips?/std", + "alloy-genesis?/std", + "alloy-trie?/std", + "serde/std" +] alloy = [ "dep:alloy-consensus", "dep:alloy-eips", diff --git a/crates/storage/db-api/Cargo.toml b/crates/storage/db-api/Cargo.toml index d674f9d7b685..932a94b98ebc 100644 --- a/crates/storage/db-api/Cargo.toml +++ b/crates/storage/db-api/Cargo.toml @@ -56,11 +56,25 @@ proptest.workspace = true proptest-arbitrary-interop.workspace = true [features] -test-utils = ["arbitrary"] +test-utils = [ + "arbitrary", + "reth-primitives/test-utils", + "reth-primitives-traits/test-utils", + "reth-codecs/test-utils", + "reth-db-models/test-utils", + "reth-trie-common/test-utils" +] arbitrary = [ - "reth-primitives/arbitrary", - "reth-db-models/arbitrary", - "dep:arbitrary", - "dep:proptest", + "reth-primitives/arbitrary", + "reth-db-models/arbitrary", + "dep:arbitrary", + "dep:proptest", + "reth-primitives-traits/arbitrary", + "reth-trie-common/arbitrary", + "alloy-primitives/arbitrary", + "parity-scale-codec/arbitrary" +] +optimism = [ + "reth-primitives/optimism", + "reth-codecs/optimism" ] -optimism = ["reth-primitives/optimism"] diff --git a/crates/storage/db-models/Cargo.toml b/crates/storage/db-models/Cargo.toml index 492178775b64..31741207cad2 100644 --- a/crates/storage/db-models/Cargo.toml +++ b/crates/storage/db-models/Cargo.toml @@ -39,5 +39,14 @@ proptest-arbitrary-interop.workspace = true test-fuzz.workspace = true [features] -test-utils = ["arbitrary"] -arbitrary = ["reth-primitives/arbitrary", "dep:arbitrary", "dep:proptest"] +test-utils = [ + "arbitrary", + "reth-primitives/test-utils", + "reth-codecs/test-utils" +] +arbitrary = [ + "reth-primitives/arbitrary", + "dep:arbitrary", + "dep:proptest", + "alloy-primitives/arbitrary" +] diff --git a/crates/storage/db/Cargo.toml b/crates/storage/db/Cargo.toml index 356672f2548d..2f437e631095 100644 --- a/crates/storage/db/Cargo.toml +++ b/crates/storage/db/Cargo.toml @@ -89,10 +89,28 @@ mdbx = [ "dep:strum", "dep:rustc-hash", ] -test-utils = ["dep:tempfile", "arbitrary", "parking_lot"] +test-utils = [ + "dep:tempfile", + "arbitrary", + "parking_lot", + "reth-primitives/test-utils", + "reth-primitives-traits/test-utils", + "reth-db-api/test-utils", + "reth-nippy-jar/test-utils", + "reth-trie-common/test-utils" +] bench = [] -arbitrary = ["reth-primitives/arbitrary", "reth-db-api/arbitrary"] -optimism = [] +arbitrary = [ + "reth-primitives/arbitrary", + "reth-db-api/arbitrary", + "reth-primitives-traits/arbitrary", + "reth-trie-common/arbitrary", + "alloy-primitives/arbitrary" +] +optimism = [ + "reth-primitives/optimism", + "reth-db-api/optimism" +] disable-lock = [] [[bench]] diff --git a/crates/storage/errors/Cargo.toml b/crates/storage/errors/Cargo.toml index 52c93ae4ef06..ecefa5f6aca7 100644 --- a/crates/storage/errors/Cargo.toml +++ b/crates/storage/errors/Cargo.toml @@ -25,4 +25,8 @@ derive_more.workspace = true [features] default = ["std"] -std = [] +std = [ + "reth-primitives/std", + "alloy-eips/std", + "alloy-primitives/std" +] diff --git a/crates/storage/provider/Cargo.toml b/crates/storage/provider/Cargo.toml index 00e1c9f098df..b93c22cdf671 100644 --- a/crates/storage/provider/Cargo.toml +++ b/crates/storage/provider/Cargo.toml @@ -88,16 +88,41 @@ alloy-consensus.workspace = true [features] optimism = [ - "reth-primitives/optimism", - "reth-execution-types/optimism", - "reth-optimism-primitives", + "reth-primitives/optimism", + "reth-execution-types/optimism", + "reth-optimism-primitives", + "reth-codecs/optimism", + "reth-db/optimism", + "reth-db-api/optimism", + "revm/optimism" +] +serde = [ + "reth-execution-types/serde", + "reth-trie-db/serde", + "reth-trie/serde", + "alloy-consensus?/serde", + "alloy-eips/serde", + "alloy-primitives/serde", + "alloy-rpc-types-engine/serde", + "dashmap/serde", + "notify/serde", + "parking_lot/serde", + "rand/serde", + "revm/serde" ] -serde = ["reth-execution-types/serde"] test-utils = [ - "reth-db/test-utils", - "reth-nippy-jar/test-utils", - "reth-trie/test-utils", - "reth-chain-state/test-utils", - "reth-ethereum-engine-primitives", - "alloy-consensus", + "reth-db/test-utils", + "reth-nippy-jar/test-utils", + "reth-trie/test-utils", + "reth-chain-state/test-utils", + "reth-ethereum-engine-primitives", + "alloy-consensus", + "reth-chainspec/test-utils", + "reth-evm/test-utils", + "reth-network-p2p/test-utils", + "reth-primitives/test-utils", + "reth-codecs/test-utils", + "reth-db-api/test-utils", + "reth-trie-db/test-utils", + "revm/test-utils" ] diff --git a/crates/transaction-pool/Cargo.toml b/crates/transaction-pool/Cargo.toml index cdac6a1aae6d..1bfb10d86d77 100644 --- a/crates/transaction-pool/Cargo.toml +++ b/crates/transaction-pool/Cargo.toml @@ -72,12 +72,42 @@ serde_json.workspace = true [features] default = ["serde"] -serde = ["dep:serde"] -test-utils = ["rand", "paste", "serde"] +serde = [ + "dep:serde", + "reth-execution-types/serde", + "reth-eth-wire-types/serde", + "reth-provider/serde", + "alloy-consensus/serde", + "alloy-eips/serde", + "alloy-primitives/serde", + "bitflags/serde", + "parking_lot/serde", + "rand?/serde", + "revm/serde", + "smallvec/serde" +] +test-utils = [ + "rand", + "paste", + "serde", + "reth-chain-state/test-utils", + "reth-chainspec/test-utils", + "reth-primitives/test-utils", + "reth-provider/test-utils", + "revm/test-utils" +] arbitrary = [ - "proptest", - "reth-primitives/arbitrary", - "proptest-arbitrary-interop", + "proptest", + "reth-primitives/arbitrary", + "proptest-arbitrary-interop", + "reth-chainspec/arbitrary", + "reth-eth-wire-types/arbitrary", + "alloy-consensus/arbitrary", + "alloy-eips/arbitrary", + "alloy-primitives/arbitrary", + "bitflags/arbitrary", + "revm/arbitrary", + "smallvec/arbitrary" ] [[bench]] diff --git a/crates/trie/common/Cargo.toml b/crates/trie/common/Cargo.toml index 0bd28140f447..2c6ccbfe689b 100644 --- a/crates/trie/common/Cargo.toml +++ b/crates/trie/common/Cargo.toml @@ -41,8 +41,19 @@ hash-db = "=0.15.2" plain_hasher = "0.2" [features] -test-utils = ["dep:plain_hasher", "dep:hash-db", "arbitrary"] +test-utils = [ + "dep:plain_hasher", + "dep:hash-db", + "arbitrary", + "reth-primitives-traits/test-utils", + "reth-codecs/test-utils" +] arbitrary = [ - "alloy-trie/arbitrary", - "dep:arbitrary", + "alloy-trie/arbitrary", + "dep:arbitrary", + "reth-primitives-traits/arbitrary", + "alloy-consensus/arbitrary", + "alloy-primitives/arbitrary", + "nybbles/arbitrary", + "revm-primitives/arbitrary" ] diff --git a/crates/trie/db/Cargo.toml b/crates/trie/db/Cargo.toml index e75b0456eb9b..55fa9a851b17 100644 --- a/crates/trie/db/Cargo.toml +++ b/crates/trie/db/Cargo.toml @@ -66,5 +66,23 @@ similar-asserts.workspace = true [features] metrics = ["reth-metrics", "reth-trie/metrics", "dep:metrics"] -serde = ["dep:serde"] -test-utils = ["triehash", "reth-trie-common/test-utils"] +serde = [ + "dep:serde", + "reth-provider/serde", + "reth-trie/serde", + "alloy-consensus/serde", + "alloy-primitives/serde", + "revm/serde", + "similar-asserts/serde" +] +test-utils = [ + "triehash", + "reth-trie-common/test-utils", + "reth-chainspec/test-utils", + "reth-primitives/test-utils", + "reth-db/test-utils", + "reth-db-api/test-utils", + "reth-provider/test-utils", + "reth-trie/test-utils", + "revm/test-utils" +] diff --git a/crates/trie/trie/Cargo.toml b/crates/trie/trie/Cargo.toml index 77fc57397700..112e661c0278 100644 --- a/crates/trie/trie/Cargo.toml +++ b/crates/trie/trie/Cargo.toml @@ -64,9 +64,23 @@ bincode.workspace = true [features] metrics = ["reth-metrics", "dep:metrics"] -serde = ["dep:serde"] -serde-bincode-compat = ["serde_with"] -test-utils = ["triehash", "reth-trie-common/test-utils"] +serde = [ + "dep:serde", + "alloy-consensus/serde", + "alloy-primitives/serde", + "revm/serde" +] +serde-bincode-compat = [ + "serde_with", + "reth-primitives/serde-bincode-compat", + "alloy-consensus/serde-bincode-compat" +] +test-utils = [ + "triehash", + "reth-trie-common/test-utils", + "reth-primitives/test-utils", + "revm/test-utils" +] [[bench]] name = "prefix_set" diff --git a/testing/ef-tests/Cargo.toml b/testing/ef-tests/Cargo.toml index df68f5154fc4..a56c44ec3db5 100644 --- a/testing/ef-tests/Cargo.toml +++ b/testing/ef-tests/Cargo.toml @@ -13,7 +13,11 @@ workspace = true [features] ef-tests = [] -asm-keccak = ["reth-primitives/asm-keccak"] +asm-keccak = [ + "reth-primitives/asm-keccak", + "alloy-primitives/asm-keccak", + "revm/asm-keccak" +] [dependencies] reth-chainspec.workspace = true From 422ab1735407c8e9de8ffa24adb416132d41f351 Mon Sep 17 00:00:00 2001 From: caglarkaya Date: Sun, 20 Oct 2024 01:14:52 +0300 Subject: [PATCH 099/113] feat: use next free nonce in eth_sendTransaction (#11873) --- crates/rpc/rpc-eth-api/src/helpers/state.rs | 36 +++++++++++++++++++ .../rpc-eth-api/src/helpers/transaction.rs | 5 ++- 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/crates/rpc/rpc-eth-api/src/helpers/state.rs b/crates/rpc/rpc-eth-api/src/helpers/state.rs index f2fc13f5d03e..080d90dc3b00 100644 --- a/crates/rpc/rpc-eth-api/src/helpers/state.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/state.rs @@ -272,6 +272,42 @@ pub trait LoadState: EthApiTypes { } } + /// Returns the next available nonce without gaps for the given address + /// Next available nonce is either the on chain nonce of the account or the highest consecutive + /// nonce in the pool + 1 + fn next_available_nonce( + &self, + address: Address, + ) -> impl Future> + Send + where + Self: SpawnBlocking, + { + self.spawn_blocking_io(move |this| { + // first fetch the on chain nonce of the account + let on_chain_account_nonce = this + .latest_state()? + .account_nonce(address) + .map_err(Self::Error::from_eth_err)? + .unwrap_or_default(); + + let mut next_nonce = on_chain_account_nonce; + // Retrieve the highest consecutive transaction for the sender from the transaction pool + if let Some(highest_tx) = this + .pool() + .get_highest_consecutive_transaction_by_sender(address, on_chain_account_nonce) + { + // Return the nonce of the highest consecutive transaction + 1 + next_nonce = highest_tx.nonce().checked_add(1).ok_or_else(|| { + Self::Error::from(EthApiError::InvalidTransaction( + RpcInvalidTransactionError::NonceMaxValue, + )) + })?; + } + + Ok(next_nonce) + }) + } + /// Returns the number of transactions sent from an address at the given block identifier. /// /// If this is [`BlockNumberOrTag::Pending`](reth_primitives::BlockNumberOrTag) then this will diff --git a/crates/rpc/rpc-eth-api/src/helpers/transaction.rs b/crates/rpc/rpc-eth-api/src/helpers/transaction.rs index 54d60cb7abdf..d29787d7a23b 100644 --- a/crates/rpc/rpc-eth-api/src/helpers/transaction.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/transaction.rs @@ -365,9 +365,8 @@ pub trait EthTransactions: LoadTransaction { // set nonce if not already set before if request.nonce.is_none() { - let nonce = self.transaction_count(from, Some(BlockId::pending())).await?; - // note: `.to()` can't panic because the nonce is constructed from a `u64` - request.nonce = Some(nonce.to()); + let nonce = self.next_available_nonce(from).await?; + request.nonce = Some(nonce); } let chain_id = self.chain_id(); From 453ba2d9accc2b85d6495c51306843899755810f Mon Sep 17 00:00:00 2001 From: Federico Gimenez Date: Sun, 20 Oct 2024 10:46:18 +0200 Subject: [PATCH 100/113] feat: switch to composable executor for Optimism (#11846) --- crates/optimism/evm/src/execute.rs | 497 ++++++++-------------------- crates/optimism/evm/src/lib.rs | 2 - crates/optimism/evm/src/strategy.rs | 494 --------------------------- crates/optimism/node/src/node.rs | 10 +- 4 files changed, 150 insertions(+), 853 deletions(-) delete mode 100644 crates/optimism/evm/src/strategy.rs diff --git a/crates/optimism/evm/src/execute.rs b/crates/optimism/evm/src/execute.rs index d15cdee13d66..77f670668517 100644 --- a/crates/optimism/evm/src/execute.rs +++ b/crates/optimism/evm/src/execute.rs @@ -1,146 +1,134 @@ -//! Optimism block executor. +//! Optimism block execution strategy. -use crate::{ - l1::ensure_create2_deployer, OpChainSpec, OptimismBlockExecutionError, OptimismEvmConfig, -}; +use crate::{l1::ensure_create2_deployer, OptimismBlockExecutionError, OptimismEvmConfig}; use alloc::{boxed::Box, sync::Arc, vec::Vec}; use alloy_consensus::Transaction as _; use alloy_eips::eip7685::Requests; -use alloy_primitives::{BlockNumber, U256}; use core::fmt::Display; -use reth_chainspec::{ChainSpec, EthereumHardforks}; +use reth_chainspec::EthereumHardforks; +use reth_consensus::ConsensusError; use reth_evm::{ execute::{ - BatchExecutor, BlockExecutionError, BlockExecutionInput, BlockExecutionOutput, - BlockExecutorProvider, BlockValidationError, Executor, ProviderError, + BasicBlockExecutorProvider, BlockExecutionError, BlockExecutionStrategy, + BlockExecutionStrategyFactory, BlockValidationError, ProviderError, }, state_change::post_block_balance_increments, - system_calls::{NoopHook, OnStateHook, SystemCaller}, - ConfigureEvm, + system_calls::{OnStateHook, SystemCaller}, + ConfigureEvm, ConfigureEvmEnv, }; -use reth_execution_types::ExecutionOutcome; +use reth_optimism_chainspec::OpChainSpec; use reth_optimism_consensus::validate_block_post_execution; use reth_optimism_forks::OptimismHardfork; -use reth_primitives::{BlockWithSenders, Header, Receipt, Receipts, TxType}; -use reth_prune_types::PruneModes; -use reth_revm::{batch::BlockBatchRecord, db::states::bundle_state::BundleRetention, Evm, State}; +use reth_primitives::{BlockWithSenders, Header, Receipt, TxType}; +use reth_revm::{ + db::{states::bundle_state::BundleRetention, BundleState}, + Database, State, +}; use revm_primitives::{ - db::{Database, DatabaseCommit}, - BlockEnv, CfgEnvWithHandlerCfg, EnvWithHandlerCfg, ResultAndState, + db::DatabaseCommit, BlockEnv, CfgEnvWithHandlerCfg, EnvWithHandlerCfg, ResultAndState, U256, }; use tracing::trace; -/// Provides executors to execute regular optimism blocks +/// Factory for [`OpExecutionStrategy`]. #[derive(Debug, Clone)] -pub struct OpExecutorProvider { +pub struct OpExecutionStrategyFactory { + /// The chainspec chain_spec: Arc, + /// How to create an EVM. evm_config: EvmConfig, } -impl OpExecutorProvider { - /// Creates a new default optimism executor provider. +impl OpExecutionStrategyFactory { + /// Creates a new default optimism executor strategy factory. pub fn optimism(chain_spec: Arc) -> Self { Self::new(chain_spec.clone(), OptimismEvmConfig::new(chain_spec)) } } -impl OpExecutorProvider { - /// Creates a new executor provider. +impl OpExecutionStrategyFactory { + /// Creates a new executor strategy factory. pub const fn new(chain_spec: Arc, evm_config: EvmConfig) -> Self { Self { chain_spec, evm_config } } } -impl OpExecutorProvider -where - EvmConfig: ConfigureEvm
, -{ - fn op_executor(&self, db: DB) -> OpBlockExecutor - where - DB: Database + Display>, - { - OpBlockExecutor::new( - self.chain_spec.clone(), - self.evm_config.clone(), - State::builder().with_database(db).with_bundle_update().without_state_clear().build(), - ) - } -} +impl BlockExecutionStrategyFactory for OpExecutionStrategyFactory { + type Strategy + Display>> = OpExecutionStrategy; -impl BlockExecutorProvider for OpExecutorProvider -where - EvmConfig: ConfigureEvm
, -{ - type Executor + Display>> = - OpBlockExecutor; - - type BatchExecutor + Display>> = - OpBatchExecutor; - fn executor(&self, db: DB) -> Self::Executor + fn create_strategy(&self, db: DB) -> Self::Strategy where DB: Database + Display>, { - self.op_executor(db) - } - - fn batch_executor(&self, db: DB) -> Self::BatchExecutor - where - DB: Database + Display>, - { - let executor = self.op_executor(db); - OpBatchExecutor { executor, batch_record: BlockBatchRecord::default() } + let state = + State::builder().with_database(db).with_bundle_update().without_state_clear().build(); + OpExecutionStrategy::new(state, self.chain_spec.clone(), self.evm_config.clone()) } } -/// Helper container type for EVM with chain spec. -#[derive(Debug, Clone)] -pub struct OpEvmExecutor { +/// Block execution strategy for Optimism. +#[allow(missing_debug_implementations)] +pub struct OpExecutionStrategy { /// The chainspec chain_spec: Arc, /// How to create an EVM. evm_config: EvmConfig, + /// Current state for block execution. + state: State, + /// Utility to call system smart contracts. + system_caller: SystemCaller, } -impl OpEvmExecutor +impl OpExecutionStrategy { + /// Creates a new [`OpExecutionStrategy`] + pub fn new( + state: State, + chain_spec: Arc, + evm_config: OptimismEvmConfig, + ) -> Self { + let system_caller = SystemCaller::new(evm_config.clone(), (*chain_spec).clone()); + Self { state, chain_spec, evm_config, system_caller } + } +} + +impl OpExecutionStrategy { + /// Configures a new evm configuration and block environment for the given block. + /// + /// Caution: this does not initialize the tx environment. + fn evm_env_for_block(&self, header: &Header, total_difficulty: U256) -> EnvWithHandlerCfg { + let mut cfg = CfgEnvWithHandlerCfg::new(Default::default(), Default::default()); + let mut block_env = BlockEnv::default(); + self.evm_config.fill_cfg_and_block_env(&mut cfg, &mut block_env, header, total_difficulty); + + EnvWithHandlerCfg::new_with_cfg_env(cfg, block_env, Default::default()) + } +} + +impl BlockExecutionStrategy for OpExecutionStrategy where - EvmConfig: ConfigureEvm
, + DB: Database + Display>, { - /// Executes the transactions in the block and returns the receipts. - /// - /// This applies the pre-execution changes, and executes the transactions. - /// - /// The optional `state_hook` will be executed with the state changes if present. - /// - /// # Note - /// - /// It does __not__ apply post-execution changes. - fn execute_pre_and_transactions( - &self, + type Error = BlockExecutionError; + + fn apply_pre_execution_changes( + &mut self, block: &BlockWithSenders, - mut evm: Evm<'_, Ext, &mut State>, - state_hook: Option, - ) -> Result<(Vec, u64), BlockExecutionError> - where - DB: Database + Display>, - F: OnStateHook + 'static, - { - let mut system_caller = SystemCaller::new(self.evm_config.clone(), &self.chain_spec); - if let Some(hook) = state_hook { - system_caller.with_state_hook(Some(Box::new(hook) as Box)); - } + total_difficulty: U256, + ) -> Result<(), Self::Error> { + // Set state clear flag if the block is after the Spurious Dragon hardfork. + let state_clear_flag = + (*self.chain_spec).is_spurious_dragon_active_at_block(block.header.number); + self.state.set_state_clear_flag(state_clear_flag); + + let env = self.evm_env_for_block(&block.header, total_difficulty); + let mut evm = self.evm_config.evm_with_env(&mut self.state, env); - // apply pre execution changes - system_caller.apply_beacon_root_contract_call( + self.system_caller.apply_beacon_root_contract_call( block.timestamp, block.number, block.parent_beacon_block_root, &mut evm, )?; - // execute transactions - let is_regolith = - self.chain_spec.fork(OptimismHardfork::Regolith).active_at_timestamp(block.timestamp); - // Ensure that the create2deployer is force-deployed at the canyon transition. Optimism // blocks will always have at least a single transaction in them (the L1 info transaction), // so we can safely assume that this will always be triggered upon the transition and that @@ -148,6 +136,20 @@ where ensure_create2_deployer(self.chain_spec.clone(), block.timestamp, evm.db_mut()) .map_err(|_| OptimismBlockExecutionError::ForceCreate2DeployerFail)?; + Ok(()) + } + + fn execute_transactions( + &mut self, + block: &BlockWithSenders, + total_difficulty: U256, + ) -> Result<(Vec, u64), Self::Error> { + let env = self.evm_env_for_block(&block.header, total_difficulty); + let mut evm = self.evm_config.evm_with_env(&mut self.state, env); + + let is_regolith = + self.chain_spec.fork(OptimismHardfork::Regolith).active_at_timestamp(block.timestamp); + let mut cumulative_gas_used = 0; let mut receipts = Vec::with_capacity(block.body.transactions.len()); for (sender, transaction) in block.transactions_with_sender() { @@ -200,7 +202,7 @@ where ?transaction, "Executed transaction" ); - system_caller.on_state(&result_and_state); + self.system_caller.on_state(&result_and_state); let ResultAndState { result, state } = result_and_state; evm.db_mut().commit(state); @@ -225,288 +227,63 @@ where .then_some(1), }); } - drop(evm); Ok((receipts, cumulative_gas_used)) } -} - -/// A basic Optimism block executor. -/// -/// Expected usage: -/// - Create a new instance of the executor. -/// - Execute the block. -#[derive(Debug)] -pub struct OpBlockExecutor { - /// Chain specific evm config that's used to execute a block. - executor: OpEvmExecutor, - /// The state to use for execution - state: State, -} - -impl OpBlockExecutor { - /// Creates a new Optimism block executor. - pub const fn new( - chain_spec: Arc, - evm_config: EvmConfig, - state: State, - ) -> Self { - Self { executor: OpEvmExecutor { chain_spec, evm_config }, state } - } - - /// Returns the chain spec. - #[inline] - pub fn chain_spec(&self) -> &ChainSpec { - &self.executor.chain_spec - } - - /// Returns mutable reference to the state that wraps the underlying database. - pub fn state_mut(&mut self) -> &mut State { - &mut self.state - } -} - -impl OpBlockExecutor -where - EvmConfig: ConfigureEvm
, - DB: Database + Display>, -{ - /// Configures a new evm configuration and block environment for the given block. - /// - /// Caution: this does not initialize the tx environment. - fn evm_env_for_block(&self, header: &Header, total_difficulty: U256) -> EnvWithHandlerCfg { - let mut cfg = CfgEnvWithHandlerCfg::new(Default::default(), Default::default()); - let mut block_env = BlockEnv::default(); - self.executor.evm_config.fill_cfg_and_block_env( - &mut cfg, - &mut block_env, - header, - total_difficulty, - ); - - EnvWithHandlerCfg::new_with_cfg_env(cfg, block_env, Default::default()) - } - /// Convenience method to invoke `execute_without_verification_with_state_hook` setting the - /// state hook as `None`. - fn execute_without_verification( + fn apply_post_execution_changes( &mut self, block: &BlockWithSenders, total_difficulty: U256, - ) -> Result<(Vec, u64), BlockExecutionError> { - self.execute_without_verification_with_state_hook(block, total_difficulty, None::) - } - - /// Execute a single block and apply the state changes to the internal state. - /// - /// Returns the receipts of the transactions in the block and the total gas used. - /// - /// Returns an error if execution fails. - fn execute_without_verification_with_state_hook( - &mut self, - block: &BlockWithSenders, - total_difficulty: U256, - state_hook: Option, - ) -> Result<(Vec, u64), BlockExecutionError> - where - F: OnStateHook + 'static, - { - // 1. prepare state on new block - self.on_new_block(&block.header); - - // 2. configure the evm and execute - let env = self.evm_env_for_block(&block.header, total_difficulty); - - let (receipts, gas_used) = { - let evm = self.executor.evm_config.evm_with_env(&mut self.state, env); - self.executor.execute_pre_and_transactions(block, evm, state_hook) - }?; - - // 3. apply post execution changes - self.post_execution(block, total_difficulty)?; - - Ok((receipts, gas_used)) - } - - /// Apply settings before a new block is executed. - pub(crate) fn on_new_block(&mut self, header: &Header) { - // Set state clear flag if the block is after the Spurious Dragon hardfork. - let state_clear_flag = self.chain_spec().is_spurious_dragon_active_at_block(header.number); - self.state.set_state_clear_flag(state_clear_flag); - } - - /// Apply post execution state changes, including block rewards, withdrawals, and irregular DAO - /// hardfork state change. - pub fn post_execution( - &mut self, - block: &BlockWithSenders, - total_difficulty: U256, - ) -> Result<(), BlockExecutionError> { + _receipts: &[Receipt], + ) -> Result { let balance_increments = - post_block_balance_increments(self.chain_spec(), block, total_difficulty); + post_block_balance_increments(&self.chain_spec.clone(), block, total_difficulty); // increment balances self.state .increment_balances(balance_increments) .map_err(|_| BlockValidationError::IncrementBalanceFailed)?; - Ok(()) + Ok(Requests::default()) } -} - -impl Executor for OpBlockExecutor -where - EvmConfig: ConfigureEvm
, - DB: Database + Display>, -{ - type Input<'a> = BlockExecutionInput<'a, BlockWithSenders>; - type Output = BlockExecutionOutput; - type Error = BlockExecutionError; - - /// Executes the block and commits the state changes. - /// - /// Returns the receipts of the transactions in the block. - /// - /// Returns an error if the block could not be executed or failed verification. - /// - /// State changes are committed to the database. - fn execute(mut self, input: Self::Input<'_>) -> Result { - let BlockExecutionInput { block, total_difficulty } = input; - 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); - - Ok(BlockExecutionOutput { - state: self.state.take_bundle(), - receipts, - requests: Requests::default(), - gas_used, - }) + fn state_ref(&self) -> &State { + &self.state } - fn execute_with_state_closure( - mut self, - input: Self::Input<'_>, - mut witness: F, - ) -> Result - where - F: FnMut(&State), - { - let BlockExecutionInput { block, total_difficulty } = input; - 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); - witness(&self.state); - - Ok(BlockExecutionOutput { - state: self.state.take_bundle(), - receipts, - requests: Requests::default(), - gas_used, - }) + fn state_mut(&mut self) -> &mut State { + &mut self.state } - fn execute_with_state_hook( - mut self, - input: Self::Input<'_>, - state_hook: F, - ) -> Result - where - F: OnStateHook + 'static, - { - let BlockExecutionInput { block, total_difficulty } = input; - let (receipts, gas_used) = self.execute_without_verification_with_state_hook( - block, - total_difficulty, - Some(state_hook), - )?; - - // NOTE: we need to merge keep the reverts for the bundle retention - self.state.merge_transitions(BundleRetention::Reverts); - - Ok(BlockExecutionOutput { - state: self.state.take_bundle(), - receipts, - requests: Requests::default(), - gas_used, - }) + fn with_state_hook(&mut self, hook: Option>) { + self.system_caller.with_state_hook(hook); } -} - -/// An executor for a batch of blocks. -/// -/// State changes are tracked until the executor is finalized. -#[derive(Debug)] -pub struct OpBatchExecutor { - /// The executor used to execute blocks. - executor: OpBlockExecutor, - /// Keeps track of the batch and record receipts based on the configured prune mode - batch_record: BlockBatchRecord, -} -impl OpBatchExecutor { - /// Returns the receipts of the executed blocks. - pub const fn receipts(&self) -> &Receipts { - self.batch_record.receipts() + fn finish(&mut self) -> BundleState { + self.state.merge_transitions(BundleRetention::Reverts); + self.state.take_bundle() } - /// Returns mutable reference to the state that wraps the underlying database. - pub fn state_mut(&mut self) -> &mut State { - self.executor.state_mut() + fn validate_block_post_execution( + &self, + block: &BlockWithSenders, + receipts: &[Receipt], + _requests: &Requests, + ) -> Result<(), ConsensusError> { + validate_block_post_execution(block, &self.chain_spec.clone(), receipts) } } -impl BatchExecutor for OpBatchExecutor -where - EvmConfig: ConfigureEvm
, - DB: Database + Display>, -{ - type Input<'a> = BlockExecutionInput<'a, BlockWithSenders>; - type Output = ExecutionOutcome; - type Error = BlockExecutionError; - - fn execute_and_verify_one(&mut self, input: Self::Input<'_>) -> Result<(), Self::Error> { - let BlockExecutionInput { block, total_difficulty } = input; - - if self.batch_record.first_block().is_none() { - self.batch_record.set_first_block(block.number); - } - - 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); - self.executor.state.merge_transitions(retention); - - // store receipts in the set - self.batch_record.save_receipts(receipts)?; - - Ok(()) - } - - fn finalize(mut self) -> Self::Output { - ExecutionOutcome::new( - self.executor.state.take_bundle(), - self.batch_record.take_receipts(), - self.batch_record.first_block().unwrap_or_default(), - self.batch_record.take_requests(), - ) - } - - fn set_tip(&mut self, tip: BlockNumber) { - self.batch_record.set_tip(tip); - } - - fn set_prune_modes(&mut self, prune_modes: PruneModes) { - self.batch_record.set_prune_modes(prune_modes); - } +/// Helper type with backwards compatible methods to obtain executor providers. +#[derive(Debug)] +pub struct OpExecutorProvider; - fn size_hint(&self) -> Option { - Some(self.executor.state.bundle_state.size_hint()) +impl OpExecutorProvider { + /// Creates a new default optimism executor strategy factory. + pub fn optimism( + chain_spec: Arc, + ) -> BasicBlockExecutorProvider { + BasicBlockExecutorProvider::new(OpExecutionStrategyFactory::optimism(chain_spec)) } } @@ -517,6 +294,7 @@ mod tests { use alloy_consensus::TxEip1559; use alloy_primitives::{b256, Address, StorageKey, StorageValue}; use reth_chainspec::MIN_TRANSACTION_GAS; + use reth_evm::execute::{BasicBlockExecutorProvider, BatchExecutor, BlockExecutorProvider}; use reth_optimism_chainspec::{optimism_deposit_tx_signature, OpChainSpecBuilder}; use reth_primitives::{Account, Block, BlockBody, Signature, Transaction, TransactionSigned}; use reth_revm::{ @@ -551,8 +329,13 @@ mod tests { db } - fn executor_provider(chain_spec: Arc) -> OpExecutorProvider { - OpExecutorProvider { evm_config: OptimismEvmConfig::new(chain_spec.clone()), chain_spec } + fn executor_provider( + chain_spec: Arc, + ) -> BasicBlockExecutorProvider { + let strategy_factory = + OpExecutionStrategyFactory::new(chain_spec.clone(), OptimismEvmConfig::new(chain_spec)); + + BasicBlockExecutorProvider::new(strategy_factory) } #[test] @@ -600,7 +383,10 @@ mod tests { let provider = executor_provider(chain_spec); let mut executor = provider.batch_executor(StateProviderDatabase::new(&db)); - executor.state_mut().load_cache_account(L1_BLOCK_CONTRACT).unwrap(); + // make sure the L1 block contract state is preloaded. + executor.with_state_mut(|state| { + state.load_cache_account(L1_BLOCK_CONTRACT).unwrap(); + }); // Attempt to execute a block with one deposit and one non-deposit transaction executor @@ -622,8 +408,9 @@ mod tests { ) .unwrap(); - let tx_receipt = executor.receipts()[0][0].as_ref().unwrap(); - let deposit_receipt = executor.receipts()[0][1].as_ref().unwrap(); + let receipts = executor.receipts(); + let tx_receipt = receipts[0][0].as_ref().unwrap(); + let deposit_receipt = receipts[0][1].as_ref().unwrap(); // deposit_receipt_version is not present in pre canyon transactions assert!(deposit_receipt.deposit_receipt_version.is_none()); @@ -680,7 +467,10 @@ mod tests { let provider = executor_provider(chain_spec); let mut executor = provider.batch_executor(StateProviderDatabase::new(&db)); - executor.state_mut().load_cache_account(L1_BLOCK_CONTRACT).unwrap(); + // make sure the L1 block contract state is preloaded. + executor.with_state_mut(|state| { + state.load_cache_account(L1_BLOCK_CONTRACT).unwrap(); + }); // attempt to execute an empty block with parent beacon block root, this should not fail executor @@ -702,8 +492,9 @@ mod tests { ) .expect("Executing a block while canyon is active should not fail"); - let tx_receipt = executor.receipts()[0][0].as_ref().unwrap(); - let deposit_receipt = executor.receipts()[0][1].as_ref().unwrap(); + let receipts = executor.receipts(); + let tx_receipt = receipts[0][0].as_ref().unwrap(); + let deposit_receipt = receipts[0][1].as_ref().unwrap(); // deposit_receipt_version is set to 1 for post canyon deposit transactions assert_eq!(deposit_receipt.deposit_receipt_version, Some(1)); diff --git a/crates/optimism/evm/src/lib.rs b/crates/optimism/evm/src/lib.rs index ffc82fde43cb..60aa9f7db083 100644 --- a/crates/optimism/evm/src/lib.rs +++ b/crates/optimism/evm/src/lib.rs @@ -36,8 +36,6 @@ use revm_primitives::{ BlobExcessGasAndPrice, BlockEnv, Bytes, CfgEnv, Env, HandlerCfg, OptimismFields, SpecId, TxKind, }; -pub mod strategy; - /// Optimism-related EVM configuration. #[derive(Debug, Clone)] pub struct OptimismEvmConfig { diff --git a/crates/optimism/evm/src/strategy.rs b/crates/optimism/evm/src/strategy.rs deleted file mode 100644 index c626bb66587c..000000000000 --- a/crates/optimism/evm/src/strategy.rs +++ /dev/null @@ -1,494 +0,0 @@ -//! Optimism block execution strategy, - -use crate::{l1::ensure_create2_deployer, OptimismBlockExecutionError, OptimismEvmConfig}; -use alloc::{boxed::Box, sync::Arc, vec::Vec}; -use alloy_consensus::Transaction as _; -use alloy_eips::eip7685::Requests; -use core::fmt::Display; -use reth_chainspec::EthereumHardforks; -use reth_consensus::ConsensusError; -use reth_evm::{ - execute::{ - BlockExecutionError, BlockExecutionStrategy, BlockExecutionStrategyFactory, - BlockValidationError, ProviderError, - }, - state_change::post_block_balance_increments, - system_calls::{OnStateHook, SystemCaller}, - ConfigureEvm, ConfigureEvmEnv, -}; -use reth_optimism_chainspec::OpChainSpec; -use reth_optimism_consensus::validate_block_post_execution; -use reth_optimism_forks::OptimismHardfork; -use reth_primitives::{BlockWithSenders, Header, Receipt, TxType}; -use reth_revm::{ - db::{states::bundle_state::BundleRetention, BundleState}, - Database, State, -}; -use revm_primitives::{ - db::DatabaseCommit, BlockEnv, CfgEnvWithHandlerCfg, EnvWithHandlerCfg, ResultAndState, U256, -}; -use tracing::trace; - -/// Factory for [`OpExecutionStrategy`]. -#[derive(Debug, Clone)] -pub struct OpExecutionStrategyFactory { - /// The chainspec - chain_spec: Arc, - /// How to create an EVM. - evm_config: EvmConfig, -} - -impl OpExecutionStrategyFactory { - /// Creates a new default optimism executor strategy factory. - pub fn optimism(chain_spec: Arc) -> Self { - Self::new(chain_spec.clone(), OptimismEvmConfig::new(chain_spec)) - } -} - -impl OpExecutionStrategyFactory { - /// Creates a new executor strategy factory. - pub const fn new(chain_spec: Arc, evm_config: EvmConfig) -> Self { - Self { chain_spec, evm_config } - } -} - -impl BlockExecutionStrategyFactory for OpExecutionStrategyFactory { - type Strategy + Display>> = OpExecutionStrategy; - - fn create_strategy(&self, db: DB) -> Self::Strategy - where - DB: Database + Display>, - { - let state = - State::builder().with_database(db).with_bundle_update().without_state_clear().build(); - OpExecutionStrategy::new(state, self.chain_spec.clone(), self.evm_config.clone()) - } -} - -/// Block execution strategy for Optimism. -#[allow(missing_debug_implementations)] -pub struct OpExecutionStrategy { - /// The chainspec - chain_spec: Arc, - /// How to create an EVM. - evm_config: EvmConfig, - /// Current state for block execution. - state: State, - /// Utility to call system smart contracts. - system_caller: SystemCaller, -} - -impl OpExecutionStrategy { - /// Creates a new [`OpExecutionStrategy`] - pub fn new( - state: State, - chain_spec: Arc, - evm_config: OptimismEvmConfig, - ) -> Self { - let system_caller = SystemCaller::new(evm_config.clone(), (*chain_spec).clone()); - Self { state, chain_spec, evm_config, system_caller } - } -} - -impl OpExecutionStrategy { - /// Configures a new evm configuration and block environment for the given block. - /// - /// Caution: this does not initialize the tx environment. - fn evm_env_for_block(&self, header: &Header, total_difficulty: U256) -> EnvWithHandlerCfg { - let mut cfg = CfgEnvWithHandlerCfg::new(Default::default(), Default::default()); - let mut block_env = BlockEnv::default(); - self.evm_config.fill_cfg_and_block_env(&mut cfg, &mut block_env, header, total_difficulty); - - EnvWithHandlerCfg::new_with_cfg_env(cfg, block_env, Default::default()) - } -} - -impl BlockExecutionStrategy for OpExecutionStrategy -where - DB: Database + Display>, -{ - type Error = BlockExecutionError; - - fn apply_pre_execution_changes( - &mut self, - block: &BlockWithSenders, - total_difficulty: U256, - ) -> Result<(), Self::Error> { - // Set state clear flag if the block is after the Spurious Dragon hardfork. - let state_clear_flag = - (*self.chain_spec).is_spurious_dragon_active_at_block(block.header.number); - self.state.set_state_clear_flag(state_clear_flag); - - let env = self.evm_env_for_block(&block.header, total_difficulty); - let mut evm = self.evm_config.evm_with_env(&mut self.state, env); - - self.system_caller.apply_beacon_root_contract_call( - block.timestamp, - block.number, - block.parent_beacon_block_root, - &mut evm, - )?; - - // Ensure that the create2deployer is force-deployed at the canyon transition. Optimism - // blocks will always have at least a single transaction in them (the L1 info transaction), - // so we can safely assume that this will always be triggered upon the transition and that - // the above check for empty blocks will never be hit on OP chains. - ensure_create2_deployer(self.chain_spec.clone(), block.timestamp, evm.db_mut()) - .map_err(|_| OptimismBlockExecutionError::ForceCreate2DeployerFail)?; - - Ok(()) - } - - fn execute_transactions( - &mut self, - block: &BlockWithSenders, - total_difficulty: U256, - ) -> Result<(Vec, u64), Self::Error> { - let env = self.evm_env_for_block(&block.header, total_difficulty); - let mut evm = self.evm_config.evm_with_env(&mut self.state, env); - - let is_regolith = - self.chain_spec.fork(OptimismHardfork::Regolith).active_at_timestamp(block.timestamp); - - let mut cumulative_gas_used = 0; - let mut receipts = Vec::with_capacity(block.body.transactions.len()); - for (sender, transaction) in block.transactions_with_sender() { - // The sum of the transaction’s gas limit, Tg, and the gas utilized in this block prior, - // must be no greater than the block’s gasLimit. - let block_available_gas = block.header.gas_limit - cumulative_gas_used; - if transaction.gas_limit() > block_available_gas && - (is_regolith || !transaction.is_system_transaction()) - { - return Err(BlockValidationError::TransactionGasLimitMoreThanAvailableBlockGas { - transaction_gas_limit: transaction.gas_limit(), - block_available_gas, - } - .into()) - } - - // An optimism block should never contain blob transactions. - if matches!(transaction.tx_type(), TxType::Eip4844) { - return Err(OptimismBlockExecutionError::BlobTransactionRejected.into()) - } - - // Cache the depositor account prior to the state transition for the deposit nonce. - // - // Note that this *only* needs to be done post-regolith hardfork, as deposit nonces - // were not introduced in Bedrock. In addition, regular transactions don't have deposit - // nonces, so we don't need to touch the DB for those. - let depositor = (is_regolith && transaction.is_deposit()) - .then(|| { - evm.db_mut() - .load_cache_account(*sender) - .map(|acc| acc.account_info().unwrap_or_default()) - }) - .transpose() - .map_err(|_| OptimismBlockExecutionError::AccountLoadFailed(*sender))?; - - self.evm_config.fill_tx_env(evm.tx_mut(), transaction, *sender); - - // Execute transaction. - let result_and_state = evm.transact().map_err(move |err| { - let new_err = err.map_db_err(|e| e.into()); - // Ensure hash is calculated for error log, if not already done - BlockValidationError::EVM { - hash: transaction.recalculate_hash(), - error: Box::new(new_err), - } - })?; - - trace!( - target: "evm", - ?transaction, - "Executed transaction" - ); - self.system_caller.on_state(&result_and_state); - let ResultAndState { result, state } = result_and_state; - evm.db_mut().commit(state); - - // append gas used - cumulative_gas_used += result.gas_used(); - - // Push transaction changeset and calculate header bloom filter for receipt. - receipts.push(Receipt { - tx_type: transaction.tx_type(), - // Success flag was added in `EIP-658: Embedding transaction status code in - // receipts`. - success: result.is_success(), - cumulative_gas_used, - logs: result.into_logs(), - deposit_nonce: depositor.map(|account| account.nonce), - // The deposit receipt version was introduced in Canyon to indicate an update to how - // receipt hashes should be computed when set. The state transition process ensures - // this is only set for post-Canyon deposit transactions. - deposit_receipt_version: (transaction.is_deposit() && - self.chain_spec - .is_fork_active_at_timestamp(OptimismHardfork::Canyon, block.timestamp)) - .then_some(1), - }); - } - - Ok((receipts, cumulative_gas_used)) - } - - fn apply_post_execution_changes( - &mut self, - block: &BlockWithSenders, - total_difficulty: U256, - _receipts: &[Receipt], - ) -> Result { - let balance_increments = - post_block_balance_increments(&self.chain_spec.clone(), block, total_difficulty); - // increment balances - self.state - .increment_balances(balance_increments) - .map_err(|_| BlockValidationError::IncrementBalanceFailed)?; - - Ok(Requests::default()) - } - - fn state_ref(&self) -> &State { - &self.state - } - - fn state_mut(&mut self) -> &mut State { - &mut self.state - } - - fn with_state_hook(&mut self, hook: Option>) { - self.system_caller.with_state_hook(hook); - } - - fn finish(&mut self) -> BundleState { - self.state.merge_transitions(BundleRetention::Reverts); - self.state.take_bundle() - } - - fn validate_block_post_execution( - &self, - block: &BlockWithSenders, - receipts: &[Receipt], - _requests: &Requests, - ) -> Result<(), ConsensusError> { - validate_block_post_execution(block, &self.chain_spec.clone(), receipts) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::OpChainSpec; - use alloy_consensus::TxEip1559; - use alloy_primitives::{b256, Address, StorageKey, StorageValue}; - use reth_chainspec::MIN_TRANSACTION_GAS; - use reth_evm::execute::{BasicBlockExecutorProvider, BatchExecutor, BlockExecutorProvider}; - use reth_optimism_chainspec::{optimism_deposit_tx_signature, OpChainSpecBuilder}; - use reth_primitives::{Account, Block, BlockBody, Signature, Transaction, TransactionSigned}; - use reth_revm::{ - database::StateProviderDatabase, test_utils::StateProviderTest, L1_BLOCK_CONTRACT, - }; - use std::{collections::HashMap, str::FromStr}; - - fn create_op_state_provider() -> StateProviderTest { - let mut db = StateProviderTest::default(); - - let l1_block_contract_account = - Account { balance: U256::ZERO, bytecode_hash: None, nonce: 1 }; - - let mut l1_block_storage = HashMap::default(); - // base fee - l1_block_storage.insert(StorageKey::with_last_byte(1), StorageValue::from(1000000000)); - // l1 fee overhead - l1_block_storage.insert(StorageKey::with_last_byte(5), StorageValue::from(188)); - // l1 fee scalar - l1_block_storage.insert(StorageKey::with_last_byte(6), StorageValue::from(684000)); - // l1 free scalars post ecotone - l1_block_storage.insert( - StorageKey::with_last_byte(3), - StorageValue::from_str( - "0x0000000000000000000000000000000000001db0000d27300000000000000005", - ) - .unwrap(), - ); - - db.insert_account(L1_BLOCK_CONTRACT, l1_block_contract_account, None, l1_block_storage); - - db - } - - fn executor_provider( - chain_spec: Arc, - ) -> BasicBlockExecutorProvider { - let strategy_factory = - OpExecutionStrategyFactory::new(chain_spec.clone(), OptimismEvmConfig::new(chain_spec)); - - BasicBlockExecutorProvider::new(strategy_factory) - } - - #[test] - fn op_deposit_fields_pre_canyon() { - let header = Header { - timestamp: 1, - number: 1, - gas_limit: 1_000_000, - gas_used: 42_000, - receipts_root: b256!( - "83465d1e7d01578c0d609be33570f91242f013e9e295b0879905346abbd63731" - ), - ..Default::default() - }; - - let mut db = create_op_state_provider(); - - let addr = Address::ZERO; - let account = Account { balance: U256::MAX, ..Account::default() }; - db.insert_account(addr, account, None, HashMap::default()); - - let chain_spec = Arc::new(OpChainSpecBuilder::base_mainnet().regolith_activated().build()); - - let tx = TransactionSigned::from_transaction_and_signature( - Transaction::Eip1559(TxEip1559 { - chain_id: chain_spec.chain.id(), - nonce: 0, - gas_limit: MIN_TRANSACTION_GAS, - to: addr.into(), - ..Default::default() - }), - Signature::test_signature(), - ); - - let tx_deposit = TransactionSigned::from_transaction_and_signature( - Transaction::Deposit(op_alloy_consensus::TxDeposit { - from: addr, - to: addr.into(), - gas_limit: MIN_TRANSACTION_GAS, - ..Default::default() - }), - Signature::test_signature(), - ); - - let provider = executor_provider(chain_spec); - let mut executor = provider.batch_executor(StateProviderDatabase::new(&db)); - - // make sure the L1 block contract state is preloaded. - executor.with_state_mut(|state| { - state.load_cache_account(L1_BLOCK_CONTRACT).unwrap(); - }); - - // Attempt to execute a block with one deposit and one non-deposit transaction - executor - .execute_and_verify_one( - ( - &BlockWithSenders { - block: Block { - header, - body: BlockBody { - transactions: vec![tx, tx_deposit], - ..Default::default() - }, - }, - senders: vec![addr, addr], - }, - U256::ZERO, - ) - .into(), - ) - .unwrap(); - - let receipts = executor.receipts(); - let tx_receipt = receipts[0][0].as_ref().unwrap(); - let deposit_receipt = receipts[0][1].as_ref().unwrap(); - - // deposit_receipt_version is not present in pre canyon transactions - assert!(deposit_receipt.deposit_receipt_version.is_none()); - assert!(tx_receipt.deposit_receipt_version.is_none()); - - // deposit_nonce is present only in deposit transactions - assert!(deposit_receipt.deposit_nonce.is_some()); - assert!(tx_receipt.deposit_nonce.is_none()); - } - - #[test] - fn op_deposit_fields_post_canyon() { - // ensure_create2_deployer will fail if timestamp is set to less then 2 - let header = Header { - timestamp: 2, - number: 1, - gas_limit: 1_000_000, - gas_used: 42_000, - receipts_root: b256!( - "fffc85c4004fd03c7bfbe5491fae98a7473126c099ac11e8286fd0013f15f908" - ), - ..Default::default() - }; - - let mut db = create_op_state_provider(); - let addr = Address::ZERO; - let account = Account { balance: U256::MAX, ..Account::default() }; - - db.insert_account(addr, account, None, HashMap::default()); - - let chain_spec = Arc::new(OpChainSpecBuilder::base_mainnet().canyon_activated().build()); - - let tx = TransactionSigned::from_transaction_and_signature( - Transaction::Eip1559(TxEip1559 { - chain_id: chain_spec.chain.id(), - nonce: 0, - gas_limit: MIN_TRANSACTION_GAS, - to: addr.into(), - ..Default::default() - }), - Signature::test_signature(), - ); - - let tx_deposit = TransactionSigned::from_transaction_and_signature( - Transaction::Deposit(op_alloy_consensus::TxDeposit { - from: addr, - to: addr.into(), - gas_limit: MIN_TRANSACTION_GAS, - ..Default::default() - }), - optimism_deposit_tx_signature(), - ); - - let provider = executor_provider(chain_spec); - let mut executor = provider.batch_executor(StateProviderDatabase::new(&db)); - - // make sure the L1 block contract state is preloaded. - executor.with_state_mut(|state| { - state.load_cache_account(L1_BLOCK_CONTRACT).unwrap(); - }); - - // attempt to execute an empty block with parent beacon block root, this should not fail - executor - .execute_and_verify_one( - ( - &BlockWithSenders { - block: Block { - header, - body: BlockBody { - transactions: vec![tx, tx_deposit], - ..Default::default() - }, - }, - senders: vec![addr, addr], - }, - U256::ZERO, - ) - .into(), - ) - .expect("Executing a block while canyon is active should not fail"); - - let receipts = executor.receipts(); - let tx_receipt = receipts[0][0].as_ref().unwrap(); - let deposit_receipt = receipts[0][1].as_ref().unwrap(); - - // deposit_receipt_version is set to 1 for post canyon deposit transactions - assert_eq!(deposit_receipt.deposit_receipt_version, Some(1)); - assert!(tx_receipt.deposit_receipt_version.is_none()); - - // deposit_nonce is present only in deposit transactions - assert!(deposit_receipt.deposit_nonce.is_some()); - assert!(tx_receipt.deposit_nonce.is_none()); - } -} diff --git a/crates/optimism/node/src/node.rs b/crates/optimism/node/src/node.rs index 175b2d4bf413..22fc1a88ff73 100644 --- a/crates/optimism/node/src/node.rs +++ b/crates/optimism/node/src/node.rs @@ -4,7 +4,7 @@ use std::sync::Arc; use reth_basic_payload_builder::{BasicPayloadJobGenerator, BasicPayloadJobGeneratorConfig}; use reth_chainspec::{EthChainSpec, Hardforks}; -use reth_evm::ConfigureEvm; +use reth_evm::{execute::BasicBlockExecutorProvider, ConfigureEvm}; use reth_network::{NetworkConfig, NetworkHandle, NetworkManager}; use reth_node_api::{ AddOnsContext, EngineValidator, FullNodeComponents, NodeAddOns, NodePrimitives, @@ -20,7 +20,7 @@ use reth_node_builder::{ }; use reth_optimism_chainspec::OpChainSpec; use reth_optimism_consensus::OptimismBeaconConsensus; -use reth_optimism_evm::{OpExecutorProvider, OptimismEvmConfig}; +use reth_optimism_evm::{OpExecutionStrategyFactory, OptimismEvmConfig}; use reth_optimism_rpc::OpEthApi; use reth_payload_builder::{PayloadBuilderHandle, PayloadBuilderService}; use reth_primitives::{Block, Header}; @@ -184,14 +184,16 @@ where Node: FullNodeTypes>, { type EVM = OptimismEvmConfig; - type Executor = OpExecutorProvider; + type Executor = BasicBlockExecutorProvider; async fn build_evm( self, ctx: &BuilderContext, ) -> eyre::Result<(Self::EVM, Self::Executor)> { let evm_config = OptimismEvmConfig::new(ctx.chain_spec()); - let executor = OpExecutorProvider::new(ctx.chain_spec(), evm_config.clone()); + let strategy_factory = + OpExecutionStrategyFactory::new(ctx.chain_spec(), evm_config.clone()); + let executor = BasicBlockExecutorProvider::new(strategy_factory); Ok((evm_config, executor)) } From de07436f0e5d534873cd4670f75df8918abf2bec Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 20 Oct 2024 12:43:31 +0000 Subject: [PATCH 101/113] chore(deps): weekly `cargo update` (#11902) Co-authored-by: github-merge-queue <118344674+github-merge-queue@users.noreply.github.com> --- Cargo.lock | 213 ++++++++++++++++++++++++++--------------------------- 1 file changed, 105 insertions(+), 108 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4def3dcabed7..19287e6669a5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -97,9 +97,9 @@ checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" [[package]] name = "alloy-chains" -version = "0.1.38" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "156bfc5dcd52ef9a5f33381701fa03310317e14c65093a9430d3e3557b08dcd3" +checksum = "d4932d790c723181807738cf1ac68198ab581cd699545b155601332541ee47bd" dependencies = [ "alloy-primitives", "alloy-rlp", @@ -394,7 +394,7 @@ checksum = "4d0f2d905ebd295e7effec65e5f6868d153936130ae718352771de3e7d03c75c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.80", ] [[package]] @@ -618,7 +618,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.80", ] [[package]] @@ -634,7 +634,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.80", "syn-solidity", "tiny-keccak", ] @@ -650,7 +650,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.80", "syn-solidity", ] @@ -841,9 +841,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.89" +version = "1.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" +checksum = "37bf3594c4c988a53154954629820791dde498571819ae4ca50ca811e060cc95" [[package]] name = "aquamarine" @@ -856,7 +856,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.80", ] [[package]] @@ -1032,9 +1032,9 @@ dependencies = [ [[package]] name = "async-compression" -version = "0.4.15" +version = "0.4.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e26a9844c659a2a293d239c7910b752f8487fe122c6c8bd1659bf85a6507c302" +checksum = "103db485efc3e41214fe4fda9f3dbeae2eb9082f48fd236e6095627a9422066e" dependencies = [ "brotli", "flate2", @@ -1079,7 +1079,7 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.80", ] [[package]] @@ -1090,7 +1090,7 @@ checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.80", ] [[package]] @@ -1128,7 +1128,7 @@ checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.80", ] [[package]] @@ -1234,7 +1234,7 @@ dependencies = [ "regex", "rustc-hash 1.1.0", "shlex", - "syn 2.0.79", + "syn 2.0.80", ] [[package]] @@ -1416,7 +1416,7 @@ checksum = "240f4126219a83519bad05c9a40bfc0303921eeb571fc2d7e44c17ffac99d3f1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.80", "synstructure", ] @@ -1538,7 +1538,7 @@ checksum = "bcfcc3cd946cb52f0bbfdbbcfa2f4e24f75ebb6c0e1002f7c25904fada18b9ec" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.80", ] [[package]] @@ -1626,9 +1626,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.30" +version = "1.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b16803a61b81d9eabb7eae2588776c4c1e584b738ede45fdbb4c972cec1e9945" +checksum = "c2e7962b54006dcfcc61cb72735f4d89bb97061dd6a7ed882ec6b8ee53714c6f" dependencies = [ "jobserver", "libc", @@ -1750,7 +1750,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.80", ] [[package]] @@ -2038,9 +2038,9 @@ dependencies = [ [[package]] name = "critical-section" -version = "1.1.3" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f64009896348fc5af4222e9cf7d7d82a95a256c634ebcf61c53e4ea461422242" +checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" [[package]] name = "crossbeam-channel" @@ -2207,7 +2207,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.80", ] [[package]] @@ -2231,7 +2231,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.79", + "syn 2.0.80", ] [[package]] @@ -2242,7 +2242,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.79", + "syn 2.0.80", ] [[package]] @@ -2363,7 +2363,7 @@ checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.80", ] [[package]] @@ -2374,7 +2374,7 @@ checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.80", ] [[package]] @@ -2395,7 +2395,7 @@ dependencies = [ "convert_case", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.80", "unicode-xid", ] @@ -2509,7 +2509,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.80", ] [[package]] @@ -2657,7 +2657,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.80", ] [[package]] @@ -2668,7 +2668,7 @@ checksum = "2f9ed6b3789237c8a0c1c505af1c7eb2c560df6186f01b098c3a1064ea532f38" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.80", ] [[package]] @@ -2725,7 +2725,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.80", ] [[package]] @@ -3263,7 +3263,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.80", ] [[package]] @@ -3707,9 +3707,9 @@ dependencies = [ [[package]] name = "hyper" -version = "1.4.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" +checksum = "bbbff0a806a4728c99295b254c8838933b5b082d75e3cb70c8dab21fdfbcfa9a" dependencies = [ "bytes", "futures-channel", @@ -3789,7 +3789,7 @@ dependencies = [ "quote", "serde", "serde_json", - "syn 2.0.79", + "syn 2.0.80", ] [[package]] @@ -3939,7 +3939,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.80", ] [[package]] @@ -4107,7 +4107,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b23a0c8dfe501baac4adf6ebbfa6eddf8f0c07f56b058cc1288017e32397846c" dependencies = [ "quote", - "syn 2.0.79", + "syn 2.0.80", ] [[package]] @@ -4252,9 +4252,9 @@ dependencies = [ [[package]] name = "jsonrpsee" -version = "0.24.6" +version = "0.24.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02f01f48e04e0d7da72280ab787c9943695699c9b32b99158ece105e8ad0afea" +checksum = "c5c71d8c1a731cc4227c2f698d377e7848ca12c8a48866fc5e6951c43a4db843" dependencies = [ "jsonrpsee-client-transport", "jsonrpsee-core", @@ -4270,9 +4270,9 @@ dependencies = [ [[package]] name = "jsonrpsee-client-transport" -version = "0.24.6" +version = "0.24.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d80eccbd47a7b9f1e67663fd846928e941cb49c65236e297dd11c9ea3c5e3387" +checksum = "548125b159ba1314104f5bb5f38519e03a41862786aa3925cf349aae9cdd546e" dependencies = [ "base64 0.22.1", "futures-channel", @@ -4295,9 +4295,9 @@ dependencies = [ [[package]] name = "jsonrpsee-core" -version = "0.24.6" +version = "0.24.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c2709a32915d816a6e8f625bf72cf74523ebe5d8829f895d6b041b1d3137818" +checksum = "f2882f6f8acb9fdaec7cefc4fd607119a9bd709831df7d7672a1d3b644628280" dependencies = [ "async-trait", "bytes", @@ -4322,9 +4322,9 @@ dependencies = [ [[package]] name = "jsonrpsee-http-client" -version = "0.24.6" +version = "0.24.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc54db939002b030e794fbfc9d5a925aa2854889c5a2f0352b0bffa54681707e" +checksum = "b3638bc4617f96675973253b3a45006933bde93c2fd8a6170b33c777cc389e5b" dependencies = [ "async-trait", "base64 0.22.1", @@ -4347,22 +4347,22 @@ dependencies = [ [[package]] name = "jsonrpsee-proc-macros" -version = "0.24.6" +version = "0.24.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a9a4b2eaba8cc928f49c4ccf4fcfa65b690a73997682da99ed08f3393b51f07" +checksum = "c06c01ae0007548e73412c08e2285ffe5d723195bf268bce67b1b77c3bb2a14d" dependencies = [ "heck", "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.80", ] [[package]] name = "jsonrpsee-server" -version = "0.24.6" +version = "0.24.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e30110d0f2d7866c8cc6c86483bdab2eb9f4d2f0e20db55518b2bca84651ba8e" +checksum = "82ad8ddc14be1d4290cd68046e7d1d37acd408efed6d3ca08aefcc3ad6da069c" dependencies = [ "futures-util", "http", @@ -4387,9 +4387,9 @@ dependencies = [ [[package]] name = "jsonrpsee-types" -version = "0.24.6" +version = "0.24.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ca331cd7b3fe95b33432825c2d4c9f5a43963e207fdc01ae67f9fd80ab0930f" +checksum = "a178c60086f24cc35bb82f57c651d0d25d99c4742b4d335de04e97fa1f08a8a1" dependencies = [ "http", "serde", @@ -4399,9 +4399,9 @@ dependencies = [ [[package]] name = "jsonrpsee-wasm-client" -version = "0.24.6" +version = "0.24.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c603d97578071dc44d79d3cfaf0775437638fd5adc33c6b622dfe4fa2ec812d" +checksum = "1a01cd500915d24ab28ca17527e23901ef1be6d659a2322451e1045532516c25" dependencies = [ "jsonrpsee-client-transport", "jsonrpsee-core", @@ -4410,9 +4410,9 @@ dependencies = [ [[package]] name = "jsonrpsee-ws-client" -version = "0.24.6" +version = "0.24.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "755ca3da1c67671f1fae01cd1a47f41dfb2233a8f19a643e587ab0a663942044" +checksum = "0fe322e0896d0955a3ebdd5bf813571c53fea29edd713bc315b76620b327e86d" dependencies = [ "http", "jsonrpsee-client-transport", @@ -4515,9 +4515,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.159" +version = "0.2.161" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" +checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" [[package]] name = "libloading" @@ -4526,7 +4526,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" dependencies = [ "cfg-if", - "windows-targets 0.48.5", + "windows-targets 0.52.6", ] [[package]] @@ -4773,7 +4773,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "syn 2.0.79", + "syn 2.0.80", ] [[package]] @@ -4920,7 +4920,7 @@ dependencies = [ "cfg-if", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.80", ] [[package]] @@ -5168,7 +5168,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.80", ] [[package]] @@ -5547,7 +5547,7 @@ dependencies = [ "phf_shared", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.80", ] [[package]] @@ -5576,7 +5576,7 @@ checksum = "a4502d8515ca9f32f1fb543d987f63d95a14934883db45bdb48060b6b69257f8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.80", ] [[package]] @@ -5743,12 +5743,12 @@ dependencies = [ [[package]] name = "prettyplease" -version = "0.2.22" +version = "0.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479cf940fbbb3426c32c5d5176f62ad57549a0bb84773423ba8be9d089f5faba" +checksum = "904afd36257cdb6ce0bee88b7981847bd7b955e5e216bb32f466b302923ad446" dependencies = [ "proc-macro2", - "syn 2.0.79", + "syn 2.0.80", ] [[package]] @@ -5823,14 +5823,14 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.80", ] [[package]] name = "proc-macro2" -version = "1.0.87" +version = "1.0.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a" +checksum = "7c3a7fc5db1e57d5a779a352c8cdb57b29aa4c40cc69c3a68a7fedc815fbf2f9" dependencies = [ "unicode-ident", ] @@ -5921,7 +5921,7 @@ checksum = "6ff7ff745a347b87471d859a377a9a404361e7efc2a971d73424a6d183c0fc77" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.80", ] [[package]] @@ -6744,7 +6744,7 @@ dependencies = [ "proc-macro2", "quote", "similar-asserts", - "syn 2.0.79", + "syn 2.0.80", ] [[package]] @@ -9589,9 +9589,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.14" +version = "0.23.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "415d9944693cb90382053259f89fbb077ea730ad7273047ec63b19bc9b160ba8" +checksum = "5fbb44d7acc4e873d613422379f69f237a1b141928c02f6bc6ccfddddc2d7993" dependencies = [ "log", "once_cell", @@ -9881,14 +9881,14 @@ checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.80", ] [[package]] name = "serde_json" -version = "1.0.128" +version = "1.0.132" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" +checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" dependencies = [ "indexmap 2.6.0", "itoa", @@ -9916,7 +9916,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.80", ] [[package]] @@ -9967,7 +9967,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.80", ] [[package]] @@ -9990,7 +9990,7 @@ checksum = "82fe9db325bcef1fbcde82e078a5cc4efdf787e96b3b9cf45b50b529f2083d67" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.80", ] [[package]] @@ -10286,7 +10286,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.79", + "syn 2.0.80", ] [[package]] @@ -10344,9 +10344,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.79" +version = "2.0.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" +checksum = "e6e185e337f816bc8da115b8afcb3324006ccc82eeaddf35113888d3bd8e44ac" dependencies = [ "proc-macro2", "quote", @@ -10362,7 +10362,7 @@ dependencies = [ "paste", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.80", ] [[package]] @@ -10388,7 +10388,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.80", ] [[package]] @@ -10465,7 +10465,7 @@ dependencies = [ "prettyplease", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.80", ] [[package]] @@ -10504,7 +10504,7 @@ checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.80", ] [[package]] @@ -10681,7 +10681,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.80", ] [[package]] @@ -10882,7 +10882,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.80", ] [[package]] @@ -11106,12 +11106,9 @@ checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" [[package]] name = "unicase" -version = "2.7.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" -dependencies = [ - "version_check", -] +checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df" [[package]] name = "unicode-bidi" @@ -11229,9 +11226,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" +checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" dependencies = [ "getrandom 0.2.15", ] @@ -11330,7 +11327,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.80", "wasm-bindgen-shared", ] @@ -11364,7 +11361,7 @@ checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.80", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -11520,7 +11517,7 @@ checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.80", ] [[package]] @@ -11531,7 +11528,7 @@ checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.80", ] [[package]] @@ -11542,7 +11539,7 @@ checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.80", ] [[package]] @@ -11553,7 +11550,7 @@ checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.80", ] [[package]] @@ -11828,7 +11825,7 @@ checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.80", "synstructure", ] @@ -11850,7 +11847,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.80", ] [[package]] @@ -11870,7 +11867,7 @@ checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.80", "synstructure", ] @@ -11891,7 +11888,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.80", ] [[package]] @@ -11913,7 +11910,7 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.80", ] [[package]] From e9c09723edf7b75a8dcdc5f3d458307120713356 Mon Sep 17 00:00:00 2001 From: nk_ysg Date: Sun, 20 Oct 2024 22:39:42 +0800 Subject: [PATCH 102/113] docs(blockchain-tree): rm comment (#11903) --- crates/blockchain-tree/src/blockchain_tree.rs | 3 --- crates/blockchain-tree/src/externals.rs | 1 - 2 files changed, 4 deletions(-) diff --git a/crates/blockchain-tree/src/blockchain_tree.rs b/crates/blockchain-tree/src/blockchain_tree.rs index 1e2ed2a4a2ed..95c0361f31f5 100644 --- a/crates/blockchain-tree/src/blockchain_tree.rs +++ b/crates/blockchain-tree/src/blockchain_tree.rs @@ -113,9 +113,6 @@ where /// is crucial for the correct execution of transactions. /// - `tree_config`: Configuration for the blockchain tree, including any parameters that affect /// its structure or performance. - /// - `prune_modes`: Configuration for pruning old blockchain data. This helps in managing the - /// storage space efficiently. It's important to validate this configuration to ensure it does - /// not lead to unintended data loss. pub fn new( externals: TreeExternals, config: BlockchainTreeConfig, diff --git a/crates/blockchain-tree/src/externals.rs b/crates/blockchain-tree/src/externals.rs index 719852c12ac0..4e22fcb78b6b 100644 --- a/crates/blockchain-tree/src/externals.rs +++ b/crates/blockchain-tree/src/externals.rs @@ -21,7 +21,6 @@ use std::{collections::BTreeMap, sync::Arc}; /// - A handle to the database /// - A handle to the consensus engine /// - The executor factory to execute blocks with -/// - The chain spec #[derive(Debug)] pub struct TreeExternals { /// The provider factory, used to commit the canonical chain, or unwind it. From 5fca07ca8752163aecfe1334fa8474565db20b66 Mon Sep 17 00:00:00 2001 From: Federico Gimenez Date: Sun, 20 Oct 2024 21:23:31 +0200 Subject: [PATCH 103/113] fix: impl BlockExecutionStrategy for OpExecutionStrategy generic over EvmConfig (#11910) --- crates/optimism/evm/src/execute.rs | 36 ++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/crates/optimism/evm/src/execute.rs b/crates/optimism/evm/src/execute.rs index 77f670668517..10ac5c5250a8 100644 --- a/crates/optimism/evm/src/execute.rs +++ b/crates/optimism/evm/src/execute.rs @@ -14,7 +14,7 @@ use reth_evm::{ }, state_change::post_block_balance_increments, system_calls::{OnStateHook, SystemCaller}, - ConfigureEvm, ConfigureEvmEnv, + ConfigureEvm, }; use reth_optimism_chainspec::OpChainSpec; use reth_optimism_consensus::validate_block_post_execution; @@ -52,8 +52,13 @@ impl OpExecutionStrategyFactory { } } -impl BlockExecutionStrategyFactory for OpExecutionStrategyFactory { - type Strategy + Display>> = OpExecutionStrategy; +impl BlockExecutionStrategyFactory for OpExecutionStrategyFactory +where + EvmConfig: + Clone + Unpin + Sync + Send + 'static + ConfigureEvm
, +{ + type Strategy + Display>> = + OpExecutionStrategy; fn create_strategy(&self, db: DB) -> Self::Strategy where @@ -67,7 +72,10 @@ impl BlockExecutionStrategyFactory for OpExecutionStrategyFactory { /// Block execution strategy for Optimism. #[allow(missing_debug_implementations)] -pub struct OpExecutionStrategy { +pub struct OpExecutionStrategy +where + EvmConfig: Clone, +{ /// The chainspec chain_spec: Arc, /// How to create an EVM. @@ -78,19 +86,22 @@ pub struct OpExecutionStrategy { system_caller: SystemCaller, } -impl OpExecutionStrategy { +impl OpExecutionStrategy +where + EvmConfig: Clone, +{ /// Creates a new [`OpExecutionStrategy`] - pub fn new( - state: State, - chain_spec: Arc, - evm_config: OptimismEvmConfig, - ) -> Self { + pub fn new(state: State, chain_spec: Arc, evm_config: EvmConfig) -> Self { let system_caller = SystemCaller::new(evm_config.clone(), (*chain_spec).clone()); Self { state, chain_spec, evm_config, system_caller } } } -impl OpExecutionStrategy { +impl OpExecutionStrategy +where + DB: Database + Display>, + EvmConfig: ConfigureEvm
, +{ /// Configures a new evm configuration and block environment for the given block. /// /// Caution: this does not initialize the tx environment. @@ -103,9 +114,10 @@ impl OpExecutionStrategy { } } -impl BlockExecutionStrategy for OpExecutionStrategy +impl BlockExecutionStrategy for OpExecutionStrategy where DB: Database + Display>, + EvmConfig: ConfigureEvm
, { type Error = BlockExecutionError; From a188597a3c6a9590ab54cfc9e02c18e7e0760be3 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sun, 20 Oct 2024 22:55:14 +0200 Subject: [PATCH 104/113] ci: merge sync jobs (#11909) --- .github/workflows/eth-sync.yml | 53 ---------------------------- .github/workflows/op-sync.yml | 55 ----------------------------- .github/workflows/sync.yml | 63 ++++++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 108 deletions(-) delete mode 100644 .github/workflows/eth-sync.yml delete mode 100644 .github/workflows/op-sync.yml create mode 100644 .github/workflows/sync.yml diff --git a/.github/workflows/eth-sync.yml b/.github/workflows/eth-sync.yml deleted file mode 100644 index f473e29a57c6..000000000000 --- a/.github/workflows/eth-sync.yml +++ /dev/null @@ -1,53 +0,0 @@ -# Runs an ethereum mainnet sync test. - -name: eth-sync-test - -on: - pull_request: - merge_group: - push: - branches: [ main ] - -env: - CARGO_TERM_COLOR: always - -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} - cancel-in-progress: true - -jobs: - sync: - name: sync / 100k blocks - # Only run sync tests in merge groups - if: github.event_name == 'merge_group' - runs-on: - group: Reth - env: - RUST_LOG: info,sync=error - RUST_BACKTRACE: 1 - timeout-minutes: 60 - steps: - - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@stable - - uses: Swatinem/rust-cache@v2 - with: - cache-on-failure: true - - name: Build reth - run: | - cargo install --features asm-keccak,jemalloc --path bin/reth - - name: Run sync - run: | - reth node \ - --debug.tip 0x91c90676cab257a59cd956d7cb0bceb9b1a71d79755c23c7277a0697ccfaf8c4 \ - --debug.max-block 100000 \ - --debug.terminate - - name: Verify the target block hash - run: | - reth db get static-file headers 100000 \ - | grep 0x91c90676cab257a59cd956d7cb0bceb9b1a71d79755c23c7277a0697ccfaf8c4 - - name: Run stage unwind for 100 blocks - run: | - reth stage unwind num-blocks 100 - - name: Run stage unwind to block hash - run: | - reth stage unwind to-block 0x52e0509d33a988ef807058e2980099ee3070187f7333aae12b64d4d675f34c5a diff --git a/.github/workflows/op-sync.yml b/.github/workflows/op-sync.yml deleted file mode 100644 index 2a223391d711..000000000000 --- a/.github/workflows/op-sync.yml +++ /dev/null @@ -1,55 +0,0 @@ -# Runs a base mainnet sync test. - -name: op-sync-test - -on: - pull_request: - merge_group: - push: - branches: [ main ] - -env: - CARGO_TERM_COLOR: always - -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} - cancel-in-progress: true - -jobs: - sync: - name: op sync / 10k blocks - # Only run sync tests in merge groups - if: github.event_name == 'merge_group' - runs-on: - group: Reth - env: - RUST_LOG: info,sync=error - RUST_BACKTRACE: 1 - timeout-minutes: 60 - steps: - - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@stable - - uses: Swatinem/rust-cache@v2 - with: - cache-on-failure: true - - name: Build op-reth - run: make install-op - - name: Run sync - # https://basescan.org/block/10000 - run: | - op-reth node \ - --chain base \ - --debug.tip 0xbb9b85352c7ebca6ba8efc63bd66cecd038c92ec8ebd02e153a3e0b197e672b7 \ - --debug.max-block 10000 \ - --debug.terminate - - name: Verify the target block hash - run: | - op-reth db --chain base get static-file headers 10000 \ - | grep 0xbb9b85352c7ebca6ba8efc63bd66cecd038c92ec8ebd02e153a3e0b197e672b7 - - name: Run stage unwind for 100 blocks - run: | - op-reth stage --chain base unwind num-blocks 100 - - name: Run stage unwind to block hash - run: | - op-reth stage --chain base unwind to-block 0x118a6e922a8c6cab221fc5adfe5056d2b72d58c6580e9c5629de55299e2cf8de - diff --git a/.github/workflows/sync.yml b/.github/workflows/sync.yml new file mode 100644 index 000000000000..531d04b2e489 --- /dev/null +++ b/.github/workflows/sync.yml @@ -0,0 +1,63 @@ +# Runs sync tests. + +name: sync test + +on: + merge_group: + +env: + CARGO_TERM_COLOR: always + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +jobs: + sync: + name: sync (${{ matrix.chain.bin }}) + runs-on: + group: Reth + env: + RUST_LOG: info,sync=error + RUST_BACKTRACE: 1 + timeout-minutes: 60 + strategy: + matrix: + chain: + - build: install + bin: reth + chain: mainnet + tip: "0x91c90676cab257a59cd956d7cb0bceb9b1a71d79755c23c7277a0697ccfaf8c4" + block: 100000 + unwind-target: "0x52e0509d33a988ef807058e2980099ee3070187f7333aae12b64d4d675f34c5a" + - build: install-op + bin: op-reth + chain: base + tip: "0xbb9b85352c7ebca6ba8efc63bd66cecd038c92ec8ebd02e153a3e0b197e672b7" + block: 10000 + unwind-target: "0x118a6e922a8c6cab221fc5adfe5056d2b72d58c6580e9c5629de55299e2cf8de" + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + - uses: Swatinem/rust-cache@v2 + with: + cache-on-failure: true + - name: Build ${{ matrix.chain.bin }} + run: make ${{ matrix.chain.build }} + - name: Run sync + run: | + ${{ matrix.chain.bin }} node \ + --chain ${{ matrix.chain.chain }} \ + --debug.tip ${{ matrix.chain.tip }} \ + --debug.max-block ${{ matrix.chain.block }} \ + --debug.terminate + - name: Verify the target block hash + run: | + ${{ matrix.chain.bin }} db --chain ${{ matrix.chain.chain }} get static-file headers ${{ matrix.chain.block }} \ + | grep ${{ matrix.chain.tip }} + - name: Run stage unwind for 100 blocks + run: | + ${{ matrix.chain.bin }} stage --chain ${{ matrix.chain.chain }} unwind num-blocks 100 + - name: Run stage unwind to block hash + run: | + ${{ matrix.chain.bin }} stage --chain ${{ matrix.chain.chain }} unwind to-block ${{ matrix.chain.unwind-target }} From 0270128d4f7a9f6fad27dff69273095abdfa7452 Mon Sep 17 00:00:00 2001 From: Thomas Coratger <60488569+tcoratger@users.noreply.github.com> Date: Sun, 20 Oct 2024 23:42:45 +0200 Subject: [PATCH 105/113] refactor(txpool): small refactor in `DiskFileBlobStoreInner` `get_exact` (#11911) --- crates/transaction-pool/src/blobstore/disk.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/crates/transaction-pool/src/blobstore/disk.rs b/crates/transaction-pool/src/blobstore/disk.rs index 96119a0f8170..e168a1c11116 100644 --- a/crates/transaction-pool/src/blobstore/disk.rs +++ b/crates/transaction-pool/src/blobstore/disk.rs @@ -409,13 +409,9 @@ impl DiskFileBlobStoreInner { /// Returns an error if there are any missing blobs. #[inline] fn get_exact(&self, txs: Vec) -> Result, BlobStoreError> { - let mut res = Vec::with_capacity(txs.len()); - for tx in txs { - let blob = self.get_one(tx)?.ok_or_else(|| BlobStoreError::MissingSidecar(tx))?; - res.push(blob) - } - - Ok(res) + txs.into_iter() + .map(|tx| self.get_one(tx)?.ok_or(BlobStoreError::MissingSidecar(tx))) + .collect() } } From 2e8a8fe6f6147123ecb2892692ed09ef7e95d0ff Mon Sep 17 00:00:00 2001 From: Thomas Coratger <60488569+tcoratger@users.noreply.github.com> Date: Mon, 21 Oct 2024 01:10:36 +0200 Subject: [PATCH 106/113] doc(storage): add missing documentation for `nippy-jar` (#11913) --- .../storage/nippy-jar/src/compression/mod.rs | 2 + .../storage/nippy-jar/src/compression/zstd.rs | 4 ++ crates/storage/nippy-jar/src/consistency.rs | 5 +++ crates/storage/nippy-jar/src/cursor.rs | 7 +++- crates/storage/nippy-jar/src/error.rs | 39 +++++++++++++++++++ crates/storage/nippy-jar/src/lib.rs | 7 +++- crates/storage/nippy-jar/src/writer.rs | 12 ++++++ 7 files changed, 72 insertions(+), 4 deletions(-) diff --git a/crates/storage/nippy-jar/src/compression/mod.rs b/crates/storage/nippy-jar/src/compression/mod.rs index 28a92fe909f2..f9bf8110eebb 100644 --- a/crates/storage/nippy-jar/src/compression/mod.rs +++ b/crates/storage/nippy-jar/src/compression/mod.rs @@ -44,7 +44,9 @@ pub trait Compression: Serialize + for<'a> Deserialize<'a> { #[derive(Debug, Serialize, Deserialize)] #[cfg_attr(test, derive(PartialEq))] pub enum Compressors { + /// Zstandard compression algorithm with custom settings. Zstd(Zstd), + /// LZ4 compression algorithm with custom settings. Lz4(Lz4), } diff --git a/crates/storage/nippy-jar/src/compression/zstd.rs b/crates/storage/nippy-jar/src/compression/zstd.rs index 500247d17677..7685941dfbe3 100644 --- a/crates/storage/nippy-jar/src/compression/zstd.rs +++ b/crates/storage/nippy-jar/src/compression/zstd.rs @@ -12,10 +12,13 @@ pub use zstd::{bulk::Decompressor, dict::DecoderDictionary}; type RawDictionary = Vec; +/// Represents the state of a Zstandard compression operation. #[derive(Debug, Default, PartialEq, Eq, Serialize, Deserialize)] pub enum ZstdState { + /// The compressor is pending a dictionary. #[default] PendingDictionary, + /// The compressor is ready to perform compression. Ready, } @@ -51,6 +54,7 @@ impl Zstd { } } + /// Sets the compression level for the Zstd compression instance. pub const fn with_level(mut self, level: i32) -> Self { self.level = level; self diff --git a/crates/storage/nippy-jar/src/consistency.rs b/crates/storage/nippy-jar/src/consistency.rs index 1093fb5546ac..952980ef6eff 100644 --- a/crates/storage/nippy-jar/src/consistency.rs +++ b/crates/storage/nippy-jar/src/consistency.rs @@ -28,6 +28,11 @@ pub struct NippyJarChecker { } impl NippyJarChecker { + /// Creates a new instance of [`NippyJarChecker`] with the provided [`NippyJar`]. + /// + /// This method initializes the checker without any associated file handles for + /// the data or offsets files. The [`NippyJar`] passed in contains all necessary + /// configurations for handling data. pub const fn new(jar: NippyJar) -> Self { Self { jar, data_file: None, offsets_file: None } } diff --git a/crates/storage/nippy-jar/src/cursor.rs b/crates/storage/nippy-jar/src/cursor.rs index 267764827299..376411ac2656 100644 --- a/crates/storage/nippy-jar/src/cursor.rs +++ b/crates/storage/nippy-jar/src/cursor.rs @@ -25,9 +25,10 @@ impl std::fmt::Debug for NippyJarCursor<'_, H> { } impl<'a, H: NippyJarHeader> NippyJarCursor<'a, H> { + /// Creates a new instance of [`NippyJarCursor`] for the given [`NippyJar`]. pub fn new(jar: &'a NippyJar) -> Result { let max_row_size = jar.max_row_size; - Ok(NippyJarCursor { + Ok(Self { jar, reader: Arc::new(jar.open_data_reader()?), // Makes sure that we have enough buffer capacity to decompress any row of data. @@ -36,12 +37,14 @@ impl<'a, H: NippyJarHeader> NippyJarCursor<'a, H> { }) } + /// Creates a new instance of [`NippyJarCursor`] with the specified [`NippyJar`] and data + /// reader. pub fn with_reader( jar: &'a NippyJar, reader: Arc, ) -> Result { let max_row_size = jar.max_row_size; - Ok(NippyJarCursor { + Ok(Self { jar, reader, // Makes sure that we have enough buffer capacity to decompress any row of data. diff --git a/crates/storage/nippy-jar/src/error.rs b/crates/storage/nippy-jar/src/error.rs index fc096cf848c6..f69bb44a068b 100644 --- a/crates/storage/nippy-jar/src/error.rs +++ b/crates/storage/nippy-jar/src/error.rs @@ -4,53 +4,92 @@ use thiserror::Error; /// Errors associated with [`crate::NippyJar`]. #[derive(Error, Debug)] pub enum NippyJarError { + /// An internal error occurred, wrapping any type of error. #[error(transparent)] Internal(#[from] Box), + + /// An error occurred while disconnecting, wrapping a standard I/O error. #[error(transparent)] Disconnect(#[from] std::io::Error), + + /// An error related to the file system occurred, wrapping a file system path error. #[error(transparent)] FileSystem(#[from] reth_fs_util::FsPathError), + + /// A custom error message provided by the user. #[error("{0}")] Custom(String), + + /// An error occurred during serialization/deserialization with Bincode. #[error(transparent)] Bincode(#[from] Box), + + /// An error occurred with the Elias-Fano encoding/decoding process. #[error(transparent)] EliasFano(#[from] anyhow::Error), + + /// Compression was enabled, but the compressor is not ready yet. #[error("compression was enabled, but it's not ready yet")] CompressorNotReady, + + /// Decompression was enabled, but the decompressor is not ready yet. #[error("decompression was enabled, but it's not ready yet")] DecompressorNotReady, + + /// The number of columns does not match the expected length. #[error("number of columns does not match: {0} != {1}")] ColumnLenMismatch(usize, usize), + + /// An unexpected missing value was encountered at a specific row and column. #[error("unexpected missing value: row:col {0}:{1}")] UnexpectedMissingValue(u64, u64), + + /// The size of an offset exceeds the maximum allowed size of 8 bytes. #[error("the size of an offset must be at most 8 bytes, got {offset_size}")] OffsetSizeTooBig { /// The read offset size in number of bytes. offset_size: u8, }, + + /// The size of an offset is less than the minimum allowed size of 1 byte. #[error("the size of an offset must be at least 1 byte, got {offset_size}")] OffsetSizeTooSmall { /// The read offset size in number of bytes. offset_size: u8, }, + + /// An attempt was made to read an offset that is out of bounds. #[error("attempted to read an out of bounds offset: {index}")] OffsetOutOfBounds { /// The index of the offset that was being read. index: usize, }, + + /// The output buffer is too small for the compression or decompression operation. #[error("compression or decompression requires a bigger destination output")] OutputTooSmall, + + /// A dictionary is not loaded when it is required for operations. #[error("dictionary is not loaded.")] DictionaryNotLoaded, + + /// It's not possible to generate a compressor after loading a dictionary. #[error("it's not possible to generate a compressor after loading a dictionary.")] CompressorNotAllowed, + + /// The number of offsets is smaller than the requested prune size. #[error("number of offsets ({0}) is smaller than prune request ({1}).")] InvalidPruning(u64, u64), + + /// The jar has been frozen and cannot be modified. #[error("jar has been frozen and cannot be modified.")] FrozenJar, + + /// The file is in an inconsistent state. #[error("File is in an inconsistent state.")] InconsistentState, + + /// A specified file is missing. #[error("Missing file: {0}.")] MissingFile(PathBuf), } diff --git a/crates/storage/nippy-jar/src/lib.rs b/crates/storage/nippy-jar/src/lib.rs index bdc950aa38a7..b1d174feb2c3 100644 --- a/crates/storage/nippy-jar/src/lib.rs +++ b/crates/storage/nippy-jar/src/lib.rs @@ -10,7 +10,6 @@ issue_tracker_base_url = "https://github.com/paradigmxyz/reth/issues/" )] #![cfg_attr(not(test), warn(unused_crate_dependencies))] -#![allow(missing_docs)] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] use memmap2::Mmap; @@ -28,6 +27,7 @@ use std::os::windows::prelude::OpenOptionsExt; use tracing::*; +/// Compression algorithms supported by `NippyJar`. pub mod compression; #[cfg(test)] use compression::Compression; @@ -55,10 +55,13 @@ pub use writer::NippyJarWriter; mod consistency; pub use consistency::NippyJarChecker; +/// The version number of the Nippy Jar format. const NIPPY_JAR_VERSION: usize = 1; - +/// The file extension used for index files. const INDEX_FILE_EXTENSION: &str = "idx"; +/// The file extension used for offsets files. const OFFSETS_FILE_EXTENSION: &str = "off"; +/// The file extension used for configuration files. pub const CONFIG_FILE_EXTENSION: &str = "conf"; /// A [`RefRow`] is a list of column value slices pointing to either an internal buffer or a diff --git a/crates/storage/nippy-jar/src/writer.rs b/crates/storage/nippy-jar/src/writer.rs index 9bf9bf526448..3a1003bee764 100644 --- a/crates/storage/nippy-jar/src/writer.rs +++ b/crates/storage/nippy-jar/src/writer.rs @@ -354,6 +354,10 @@ impl NippyJarWriter { Ok(()) } + /// Commits changes to the data file and offsets without synchronizing all data to disk. + /// + /// This function flushes the buffered data to the data file and commits the offsets, + /// but it does not guarantee that all data is synchronized to persistent storage. #[cfg(feature = "test-utils")] pub fn commit_without_sync_all(&mut self) -> Result<(), NippyJarError> { self.data_file.flush()?; @@ -412,41 +416,49 @@ impl NippyJarWriter { Ok(()) } + /// Returns the maximum row size for the associated [`NippyJar`]. #[cfg(test)] pub const fn max_row_size(&self) -> usize { self.jar.max_row_size } + /// Returns the column index of the current checker instance. #[cfg(test)] pub const fn column(&self) -> usize { self.column } + /// Returns a reference to the offsets vector. #[cfg(test)] pub fn offsets(&self) -> &[u64] { &self.offsets } + /// Returns a mutable reference to the offsets vector. #[cfg(test)] pub fn offsets_mut(&mut self) -> &mut Vec { &mut self.offsets } + /// Returns the path to the offsets file for the associated [`NippyJar`]. #[cfg(test)] pub fn offsets_path(&self) -> std::path::PathBuf { self.jar.offsets_path() } + /// Returns the path to the data file for the associated [`NippyJar`]. #[cfg(test)] pub fn data_path(&self) -> &Path { self.jar.data_path() } + /// Returns a mutable reference to the buffered writer for the data file. #[cfg(any(test, feature = "test-utils"))] pub fn data_file(&mut self) -> &mut BufWriter { &mut self.data_file } + /// Returns a reference to the associated [`NippyJar`] instance. #[cfg(any(test, feature = "test-utils"))] pub const fn jar(&self) -> &NippyJar { &self.jar From ddc82e2645b584719996f3824596e4721174aeba Mon Sep 17 00:00:00 2001 From: Thomas Coratger <60488569+tcoratger@users.noreply.github.com> Date: Mon, 21 Oct 2024 08:31:29 +0200 Subject: [PATCH 107/113] test(static-file): add unit tests for `HighestStaticFiles` implementation (#11912) --- crates/static-file/types/src/lib.rs | 78 +++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/crates/static-file/types/src/lib.rs b/crates/static-file/types/src/lib.rs index 380931138869..6e954a781b71 100644 --- a/crates/static-file/types/src/lib.rs +++ b/crates/static-file/types/src/lib.rs @@ -71,3 +71,81 @@ pub const fn find_fixed_range( let start = (block / blocks_per_static_file) * blocks_per_static_file; SegmentRangeInclusive::new(start, start + blocks_per_static_file - 1) } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_highest_static_files_highest() { + let files = + HighestStaticFiles { headers: Some(100), receipts: Some(200), transactions: None }; + + // Test for headers segment + assert_eq!(files.highest(StaticFileSegment::Headers), Some(100)); + + // Test for receipts segment + assert_eq!(files.highest(StaticFileSegment::Receipts), Some(200)); + + // Test for transactions segment + assert_eq!(files.highest(StaticFileSegment::Transactions), None); + } + + #[test] + fn test_highest_static_files_as_mut() { + let mut files = HighestStaticFiles::default(); + + // Modify headers value + *files.as_mut(StaticFileSegment::Headers) = Some(150); + assert_eq!(files.headers, Some(150)); + + // Modify receipts value + *files.as_mut(StaticFileSegment::Receipts) = Some(250); + assert_eq!(files.receipts, Some(250)); + + // Modify transactions value + *files.as_mut(StaticFileSegment::Transactions) = Some(350); + assert_eq!(files.transactions, Some(350)); + } + + #[test] + fn test_highest_static_files_min() { + let files = + HighestStaticFiles { headers: Some(300), receipts: Some(100), transactions: None }; + + // Minimum value among the available segments + assert_eq!(files.min(), Some(100)); + + let empty_files = HighestStaticFiles::default(); + // No values, should return None + assert_eq!(empty_files.min(), None); + } + + #[test] + fn test_highest_static_files_max() { + let files = + HighestStaticFiles { headers: Some(300), receipts: Some(100), transactions: Some(500) }; + + // Maximum value among the available segments + assert_eq!(files.max(), Some(500)); + + let empty_files = HighestStaticFiles::default(); + // No values, should return None + assert_eq!(empty_files.max(), None); + } + + #[test] + fn test_find_fixed_range() { + // Test with default block size + let block: BlockNumber = 600_000; + let range = find_fixed_range(block, DEFAULT_BLOCKS_PER_STATIC_FILE); + assert_eq!(range.start(), 500_000); + assert_eq!(range.end(), 999_999); + + // Test with a custom block size + let block: BlockNumber = 1_200_000; + let range = find_fixed_range(block, 1_000_000); + assert_eq!(range.start(), 1_000_000); + assert_eq!(range.end(), 1_999_999); + } +} From fbb27ebdad01780a2068399a01e7337bc0bb514f Mon Sep 17 00:00:00 2001 From: Federico Gimenez Date: Mon, 21 Oct 2024 10:24:36 +0200 Subject: [PATCH 108/113] chore(ci): update excluded crates in wasm checker (#11915) --- .github/assets/check_wasm.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/assets/check_wasm.sh b/.github/assets/check_wasm.sh index 52d7009412c5..3b2f2d6b7e6c 100755 --- a/.github/assets/check_wasm.sh +++ b/.github/assets/check_wasm.sh @@ -36,7 +36,6 @@ exclude_crates=( reth-ethereum-engine-primitives reth-ethereum-payload-builder reth-etl - reth-evm-ethereum reth-exex reth-exex-test-utils reth-ipc From bdad91b7002913a8bb6ec08982752685b2c5b604 Mon Sep 17 00:00:00 2001 From: greged93 <82421016+greged93@users.noreply.github.com> Date: Mon, 21 Oct 2024 11:42:46 +0200 Subject: [PATCH 109/113] docs: update grafana docs (#11908) --- etc/README.md | 41 +++++++++++++++-------------------------- 1 file changed, 15 insertions(+), 26 deletions(-) diff --git a/etc/README.md b/etc/README.md index 28c71b04688b..4f4ce7f20e45 100644 --- a/etc/README.md +++ b/etc/README.md @@ -19,55 +19,41 @@ the [docker docs](/book/installation/docker.md#using-docker-compose). #### Adding a new metric to Grafana -To set up a new metric in Reth and its Grafana dashboard: +To set up a new metric in Reth and its Grafana dashboard (this assumes running Reth and Grafana instances): 1. Add the metric to the codebase following the [metrics section](../docs/design/metrics.md#creating-metrics) documentation. -2. Build the Reth image: - - ```bash - docker build . -t reth:local - ``` - - Modify the [docker-compose](./docker-compose.yml) file to use your locally built image for the Reth service. - -3. Run Docker Compose: - - ```bash - docker compose -f etc/docker-compose.yml -f etc/lighthouse.yml up -d - ``` - -4. Access Grafana: +1. Access Grafana: - Open `http://localhost:3000/` in a browser - Log in with username and password `admin` - Navigate to the `Dashboards` tab -5. Create or modify a dashboard: +1. Create or modify a dashboard: - Select an existing dashboard or create a new one - Click `Add` > `Visualization` to create a new panel -6. Configure your metric panel: +1. Configure your metric panel: - Set a panel title and description - Select metric(s) from the `Metrics browser` or use the `PromQL` terminal - Document your metric(s) by setting units, legends, etc. - When adding multiple metrics, use field overwrites if needed -7. Save and arrange: +1. Save and arrange: - Click `Apply` to save the panel - Drag the panel to desired position on the dashboard -8. Export the dashboard: +1. Export the dashboard: - Click `Share` > `Export` - Toggle `Export for sharing externally` - Click `Save to file` -9. Update dashboard file: +1. Update dashboard file: - Replace the content of the corresponding file in the [dashboards folder](./grafana/dashboards) with the exported JSON @@ -75,15 +61,18 @@ Your new metric is now integrated into the Reth Grafana dashboard. #### Import Grafana dashboards -In order to import new Grafana dashboards or update a dashboard: +If you are running Reth and Grafana outside of docker, and wish to import new Grafana dashboards or update a dashboard: 1. Go to `Home` > `Dashboards` -2. Click `New` > `Import` +1. Click `New` > `Import` -3. Drag the JSON dashboard file to import it +1. Drag the JSON dashboard file to import it -4. If updating an existing dashboard, you will need to change the name and UID of the imported dashboard in order to +1. If updating an existing dashboard, you will need to change the name and UID of the imported dashboard in order to avoid conflict -5. Delete the old dashboard +1. Delete the old dashboard + +If you are running Reth and Grafana using docker, after having pulled the updated dashboards from `main`, restart the +Grafana service. This will update all dashboards. \ No newline at end of file From aba4991d0acb514190399c607fbcf56657789718 Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Mon, 21 Oct 2024 12:31:29 +0200 Subject: [PATCH 110/113] docs: note about type changes (#11925) --- crates/storage/codecs/src/lib.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/crates/storage/codecs/src/lib.rs b/crates/storage/codecs/src/lib.rs index 54ca046cb71a..58a7db8c10c9 100644 --- a/crates/storage/codecs/src/lib.rs +++ b/crates/storage/codecs/src/lib.rs @@ -48,6 +48,12 @@ pub mod test_utils; /// Regarding the `specialized_to/from_compact` methods: Mainly used as a workaround for not being /// able to specialize an impl over certain types like `Vec`/`Option` where `T` is a fixed /// size array like `Vec`. +/// +/// ## Caution +/// +/// Due to the bitfields, every type change on the rust type (e.g. `U256` to `u64`) is a breaking +/// change and will lead to a new, incompatible [`Compact`] implementation. Implementers must take +/// special care when changing or rearranging fields. pub trait Compact: Sized { /// Takes a buffer which can be written to. *Ideally*, it returns the length written to. fn to_compact(&self, buf: &mut B) -> usize From f25cceb9f93fcceaae59a030f81f088e29a5f0c1 Mon Sep 17 00:00:00 2001 From: nk_ysg Date: Mon, 21 Oct 2024 19:59:09 +0800 Subject: [PATCH 111/113] perf: use Vec::with_capacity and reserve_exact (#11904) --- crates/evm/execution-types/src/chain.rs | 4 ++-- crates/net/discv4/src/lib.rs | 4 ++-- crates/rpc/rpc-eth-types/src/fee_history.rs | 2 +- crates/rpc/rpc-eth-types/src/simulate.rs | 2 +- crates/rpc/rpc/src/eth/core.rs | 9 +++++---- crates/rpc/rpc/src/eth/helpers/signer.rs | 2 +- crates/stages/api/src/pipeline/builder.rs | 4 +++- crates/stages/stages/src/stages/bodies.rs | 3 ++- crates/storage/codecs/src/lib.rs | 2 +- crates/storage/nippy-jar/src/compression/zstd.rs | 2 +- .../provider/src/providers/static_file/manager.rs | 2 +- crates/transaction-pool/benches/truncate.rs | 2 +- examples/beacon-api-sidecar-fetcher/src/mined_sidecar.rs | 1 + 13 files changed, 22 insertions(+), 17 deletions(-) diff --git a/crates/evm/execution-types/src/chain.rs b/crates/evm/execution-types/src/chain.rs index d3ed2913ea3b..65f96ff56387 100644 --- a/crates/evm/execution-types/src/chain.rs +++ b/crates/evm/execution-types/src/chain.rs @@ -228,11 +228,11 @@ impl Chain { /// /// Attachment includes block number, block hash, transaction hash and transaction index. pub fn receipts_with_attachment(&self) -> Vec { - let mut receipt_attach = Vec::new(); + let mut receipt_attach = Vec::with_capacity(self.blocks().len()); for ((block_num, block), receipts) in self.blocks().iter().zip(self.execution_outcome.receipts().iter()) { - let mut tx_receipts = Vec::new(); + let mut tx_receipts = Vec::with_capacity(receipts.len()); for (tx, receipt) in block.body.transactions().zip(receipts.iter()) { tx_receipts.push(( tx.hash(), diff --git a/crates/net/discv4/src/lib.rs b/crates/net/discv4/src/lib.rs index 7c14eac9b653..7963c6e6fd65 100644 --- a/crates/net/discv4/src/lib.rs +++ b/crates/net/discv4/src/lib.rs @@ -2324,9 +2324,9 @@ mod tests { let original = EnrForkIdEntry { fork_id: ForkId { hash: ForkHash([0xdc, 0xe9, 0x6c, 0x2d]), next: 0 }, }; - let mut encoded = Vec::new(); - original.encode(&mut encoded); let expected: [u8; 8] = [0xc7, 0xc6, 0x84, 0xdc, 0xe9, 0x6c, 0x2d, 0x80]; + let mut encoded = Vec::with_capacity(expected.len()); + original.encode(&mut encoded); assert_eq!(&expected[..], encoded.as_slice()); } diff --git a/crates/rpc/rpc-eth-types/src/fee_history.rs b/crates/rpc/rpc-eth-types/src/fee_history.rs index 57dd276e5cf4..c845d9683870 100644 --- a/crates/rpc/rpc-eth-types/src/fee_history.rs +++ b/crates/rpc/rpc-eth-types/src/fee_history.rs @@ -305,7 +305,7 @@ pub fn calculate_reward_percentiles_for_block( // the percentiles are monotonically increasing. let mut tx_index = 0; let mut cumulative_gas_used = transactions.first().map(|tx| tx.gas_used).unwrap_or_default(); - let mut rewards_in_block = Vec::new(); + let mut rewards_in_block = Vec::with_capacity(percentiles.len()); for percentile in percentiles { // Empty blocks should return in a zero row if transactions.is_empty() { diff --git a/crates/rpc/rpc-eth-types/src/simulate.rs b/crates/rpc/rpc-eth-types/src/simulate.rs index a673da967202..77db511e6251 100644 --- a/crates/rpc/rpc-eth-types/src/simulate.rs +++ b/crates/rpc/rpc-eth-types/src/simulate.rs @@ -183,7 +183,7 @@ pub fn build_block( ) -> Result>, EthApiError> { let mut calls: Vec = Vec::with_capacity(results.len()); let mut senders = Vec::with_capacity(results.len()); - let mut receipts = Vec::new(); + let mut receipts = Vec::with_capacity(results.len()); let mut log_index = 0; for (transaction_index, ((sender, result), tx)) in diff --git a/crates/rpc/rpc/src/eth/core.rs b/crates/rpc/rpc/src/eth/core.rs index 6da46804005c..5c7fbbd00239 100644 --- a/crates/rpc/rpc/src/eth/core.rs +++ b/crates/rpc/rpc/src/eth/core.rs @@ -421,8 +421,8 @@ mod tests { let mut rng = generators::rng(); // Build mock data - let mut gas_used_ratios = Vec::new(); - let mut base_fees_per_gas = Vec::new(); + let mut gas_used_ratios = Vec::with_capacity(block_count as usize); + let mut base_fees_per_gas = Vec::with_capacity(block_count as usize); let mut last_header = None; let mut parent_hash = B256::default(); @@ -444,8 +444,9 @@ mod tests { last_header = Some(header.clone()); parent_hash = hash; - let mut transactions = vec![]; - for _ in 0..100 { + const TOTAL_TRANSACTIONS: usize = 100; + let mut transactions = Vec::with_capacity(TOTAL_TRANSACTIONS); + for _ in 0..TOTAL_TRANSACTIONS { let random_fee: u128 = rng.gen(); if let Some(base_fee_per_gas) = header.base_fee_per_gas { diff --git a/crates/rpc/rpc/src/eth/helpers/signer.rs b/crates/rpc/rpc/src/eth/helpers/signer.rs index a5818aa494fd..e59be0ac2838 100644 --- a/crates/rpc/rpc/src/eth/helpers/signer.rs +++ b/crates/rpc/rpc/src/eth/helpers/signer.rs @@ -40,7 +40,7 @@ impl DevSigner { /// Generates provided number of random dev signers /// which satisfy [`EthSigner`] trait pub fn random_signers(num: u32) -> Vec> { - let mut signers = Vec::new(); + let mut signers = Vec::with_capacity(num as usize); for _ in 0..num { let sk = PrivateKeySigner::random_with(&mut rand::thread_rng()); diff --git a/crates/stages/api/src/pipeline/builder.rs b/crates/stages/api/src/pipeline/builder.rs index 68ca887fe790..79a4c477ee6c 100644 --- a/crates/stages/api/src/pipeline/builder.rs +++ b/crates/stages/api/src/pipeline/builder.rs @@ -34,7 +34,9 @@ impl PipelineBuilder { /// [`builder`][StageSet::builder] on the set which will convert it to a /// [`StageSetBuilder`][crate::StageSetBuilder]. pub fn add_stages>(mut self, set: Set) -> Self { - for stage in set.builder().build() { + let states = set.builder().build(); + self.stages.reserve_exact(states.len()); + for stage in states { self.stages.push(stage); } self diff --git a/crates/stages/stages/src/stages/bodies.rs b/crates/stages/stages/src/stages/bodies.rs index 93d8a1229921..06a5250913ed 100644 --- a/crates/stages/stages/src/stages/bodies.rs +++ b/crates/stages/stages/src/stages/bodies.rs @@ -917,7 +917,8 @@ mod tests { return Poll::Ready(None) } - let mut response = Vec::default(); + let mut response = + Vec::with_capacity(std::cmp::min(this.headers.len(), this.batch_size as usize)); while let Some(header) = this.headers.pop_front() { if header.is_empty() { response.push(BlockResponse::Empty(header)) diff --git a/crates/storage/codecs/src/lib.rs b/crates/storage/codecs/src/lib.rs index 58a7db8c10c9..c432400a5766 100644 --- a/crates/storage/codecs/src/lib.rs +++ b/crates/storage/codecs/src/lib.rs @@ -505,7 +505,7 @@ mod tests { #[test] fn compact_address() { - let mut buf = vec![]; + let mut buf = Vec::with_capacity(21); assert_eq!(Address::ZERO.to_compact(&mut buf), 20); assert_eq!(buf, vec![0; 20]); diff --git a/crates/storage/nippy-jar/src/compression/zstd.rs b/crates/storage/nippy-jar/src/compression/zstd.rs index 7685941dfbe3..896a65bd7080 100644 --- a/crates/storage/nippy-jar/src/compression/zstd.rs +++ b/crates/storage/nippy-jar/src/compression/zstd.rs @@ -213,7 +213,7 @@ impl Compression for Zstd { return Err(NippyJarError::ColumnLenMismatch(self.columns, columns.len())) } - let mut dictionaries = vec![]; + let mut dictionaries = Vec::with_capacity(columns.len()); for column in columns { // ZSTD requires all training data to be continuous in memory, alongside the size of // each entry diff --git a/crates/storage/provider/src/providers/static_file/manager.rs b/crates/storage/provider/src/providers/static_file/manager.rs index 20d6a1b184b2..e81dc01f722c 100644 --- a/crates/storage/provider/src/providers/static_file/manager.rs +++ b/crates/storage/provider/src/providers/static_file/manager.rs @@ -1364,13 +1364,13 @@ impl TransactionsProviderExt for StaticFileProvider { // chunks are too big, there will be idle threads waiting for work. Choosing an // arbitrary smaller value to make sure it doesn't happen. let chunk_size = 100; - let mut channels = Vec::new(); // iterator over the chunks let chunks = tx_range .clone() .step_by(chunk_size) .map(|start| start..std::cmp::min(start + chunk_size as u64, tx_range.end)); + let mut channels = Vec::with_capacity(tx_range_size.div_ceil(chunk_size)); for chunk_range in chunks { let (channel_tx, channel_rx) = mpsc::channel(); diff --git a/crates/transaction-pool/benches/truncate.rs b/crates/transaction-pool/benches/truncate.rs index 22e457630540..1ca6f98499cd 100644 --- a/crates/transaction-pool/benches/truncate.rs +++ b/crates/transaction-pool/benches/truncate.rs @@ -66,7 +66,7 @@ fn generate_many_transactions(senders: usize, max_depth: usize) -> Vec().new_tree(&mut runner).unwrap().current() % max_depth + 1; diff --git a/examples/beacon-api-sidecar-fetcher/src/mined_sidecar.rs b/examples/beacon-api-sidecar-fetcher/src/mined_sidecar.rs index cc761aa98a61..1c53e4f41051 100644 --- a/examples/beacon-api-sidecar-fetcher/src/mined_sidecar.rs +++ b/examples/beacon-api-sidecar-fetcher/src/mined_sidecar.rs @@ -109,6 +109,7 @@ where match self.pool.get_all_blobs_exact(txs.iter().map(|(tx, _)| tx.hash()).collect()) { Ok(blobs) => { + actions_to_queue.reserve_exact(txs.len()); for ((tx, _), sidecar) in txs.iter().zip(blobs.iter()) { let transaction = BlobTransaction::try_from_signed(tx.clone(), sidecar.clone()) .expect("should not fail to convert blob tx if it is already eip4844"); From 7119bb1fe000dbd7cb58e0fcd5a66c549538e9a2 Mon Sep 17 00:00:00 2001 From: Federico Gimenez Date: Mon, 21 Oct 2024 14:34:23 +0200 Subject: [PATCH 112/113] chore: introduce ExecuteOutput (#11929) --- crates/ethereum/evm/src/execute.rs | 6 +++--- crates/evm/src/execute.rs | 32 +++++++++++++++++++++--------- crates/optimism/evm/src/execute.rs | 6 +++--- 3 files changed, 29 insertions(+), 15 deletions(-) diff --git a/crates/ethereum/evm/src/execute.rs b/crates/ethereum/evm/src/execute.rs index 185f351dd9f3..e8b238c6a7cb 100644 --- a/crates/ethereum/evm/src/execute.rs +++ b/crates/ethereum/evm/src/execute.rs @@ -14,7 +14,7 @@ use reth_ethereum_consensus::validate_block_post_execution; use reth_evm::{ execute::{ BasicBlockExecutorProvider, BlockExecutionError, BlockExecutionStrategy, - BlockExecutionStrategyFactory, BlockValidationError, ProviderError, + BlockExecutionStrategyFactory, BlockValidationError, ExecuteOutput, ProviderError, }, state_change::post_block_balance_increments, system_calls::{OnStateHook, SystemCaller}, @@ -152,7 +152,7 @@ where &mut self, block: &BlockWithSenders, total_difficulty: U256, - ) -> Result<(Vec, u64), Self::Error> { + ) -> Result { let env = self.evm_env_for_block(&block.header, total_difficulty); let mut evm = self.evm_config.evm_with_env(&mut self.state, env); @@ -203,7 +203,7 @@ where }, ); } - Ok((receipts, cumulative_gas_used)) + Ok(ExecuteOutput { receipts, gas_used: cumulative_gas_used }) } fn apply_post_execution_changes( diff --git a/crates/evm/src/execute.rs b/crates/evm/src/execute.rs index d7c8590eea85..2b3ce85e9b94 100644 --- a/crates/evm/src/execute.rs +++ b/crates/evm/src/execute.rs @@ -166,6 +166,15 @@ pub trait BlockExecutorProvider: Send + Sync + Clone + Unpin + 'static { DB: Database + Display>; } +/// Helper type for the output of executing a block. +#[derive(Debug, Clone)] +pub struct ExecuteOutput { + /// Receipts obtained after executing a block. + pub receipts: Vec, + /// Cumulative gas used in the block execution. + pub gas_used: u64, +} + /// Defines the strategy for executing a single block. pub trait BlockExecutionStrategy { /// The error type returned by this strategy's methods. @@ -183,7 +192,7 @@ pub trait BlockExecutionStrategy { &mut self, block: &BlockWithSenders, total_difficulty: U256, - ) -> Result<(Vec, u64), Self::Error>; + ) -> Result; /// Applies any necessary changes after executing the block's transactions. fn apply_post_execution_changes( @@ -313,7 +322,8 @@ where let BlockExecutionInput { block, total_difficulty } = input; self.strategy.apply_pre_execution_changes(block, total_difficulty)?; - let (receipts, gas_used) = self.strategy.execute_transactions(block, total_difficulty)?; + let ExecuteOutput { receipts, gas_used } = + self.strategy.execute_transactions(block, total_difficulty)?; let requests = self.strategy.apply_post_execution_changes(block, total_difficulty, &receipts)?; let state = self.strategy.finish(); @@ -332,7 +342,8 @@ where let BlockExecutionInput { block, total_difficulty } = input; self.strategy.apply_pre_execution_changes(block, total_difficulty)?; - let (receipts, gas_used) = self.strategy.execute_transactions(block, total_difficulty)?; + let ExecuteOutput { receipts, gas_used } = + self.strategy.execute_transactions(block, total_difficulty)?; let requests = self.strategy.apply_post_execution_changes(block, total_difficulty, &receipts)?; @@ -356,7 +367,8 @@ where self.strategy.with_state_hook(Some(Box::new(state_hook))); self.strategy.apply_pre_execution_changes(block, total_difficulty)?; - let (receipts, gas_used) = self.strategy.execute_transactions(block, total_difficulty)?; + let ExecuteOutput { receipts, gas_used } = + self.strategy.execute_transactions(block, total_difficulty)?; let requests = self.strategy.apply_post_execution_changes(block, total_difficulty, &receipts)?; @@ -407,7 +419,8 @@ where } self.strategy.apply_pre_execution_changes(block, total_difficulty)?; - let (receipts, _gas_used) = self.strategy.execute_transactions(block, total_difficulty)?; + let ExecuteOutput { receipts, .. } = + self.strategy.execute_transactions(block, total_difficulty)?; let requests = self.strategy.apply_post_execution_changes(block, total_difficulty, &receipts)?; @@ -545,14 +558,14 @@ mod tests { _chain_spec: Arc, _evm_config: EvmConfig, state: State, - execute_transactions_result: (Vec, u64), + execute_transactions_result: ExecuteOutput, apply_post_execution_changes_result: Requests, finish_result: BundleState, } #[derive(Clone)] struct TestExecutorStrategyFactory { - execute_transactions_result: (Vec, u64), + execute_transactions_result: ExecuteOutput, apply_post_execution_changes_result: Requests, finish_result: BundleState, } @@ -599,7 +612,7 @@ mod tests { &mut self, _block: &BlockWithSenders, _total_difficulty: U256, - ) -> Result<(Vec, u64), Self::Error> { + ) -> Result { Ok(self.execute_transactions_result.clone()) } @@ -651,7 +664,8 @@ mod tests { fn test_strategy() { let expected_gas_used = 10; let expected_receipts = vec![Receipt::default()]; - let expected_execute_transactions_result = (expected_receipts.clone(), expected_gas_used); + let expected_execute_transactions_result = + ExecuteOutput { receipts: expected_receipts.clone(), gas_used: expected_gas_used }; let expected_apply_post_execution_changes_result = Requests::new(vec![bytes!("deadbeef")]); let expected_finish_result = BundleState::default(); diff --git a/crates/optimism/evm/src/execute.rs b/crates/optimism/evm/src/execute.rs index 10ac5c5250a8..20ef64457bb7 100644 --- a/crates/optimism/evm/src/execute.rs +++ b/crates/optimism/evm/src/execute.rs @@ -10,7 +10,7 @@ use reth_consensus::ConsensusError; use reth_evm::{ execute::{ BasicBlockExecutorProvider, BlockExecutionError, BlockExecutionStrategy, - BlockExecutionStrategyFactory, BlockValidationError, ProviderError, + BlockExecutionStrategyFactory, BlockValidationError, ExecuteOutput, ProviderError, }, state_change::post_block_balance_increments, system_calls::{OnStateHook, SystemCaller}, @@ -155,7 +155,7 @@ where &mut self, block: &BlockWithSenders, total_difficulty: U256, - ) -> Result<(Vec, u64), Self::Error> { + ) -> Result { let env = self.evm_env_for_block(&block.header, total_difficulty); let mut evm = self.evm_config.evm_with_env(&mut self.state, env); @@ -240,7 +240,7 @@ where }); } - Ok((receipts, cumulative_gas_used)) + Ok(ExecuteOutput { receipts, gas_used: cumulative_gas_used }) } fn apply_post_execution_changes( From 7270aaf2668fc9618b5954df13401b16a28cf1b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Garamv=C3=B6lgyi?= Date: Mon, 21 Oct 2024 16:03:24 +0200 Subject: [PATCH 113/113] update fork base commit --- fork.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fork.yaml b/fork.yaml index 93920105fe2a..707a313ffda8 100644 --- a/fork.yaml +++ b/fork.yaml @@ -4,7 +4,7 @@ footer: | base: name: reth url: https://github.com/paradigmxyz/reth - hash: 161605313a567a081ea2eaf23ab1f6eeba29d19f + hash: 7119bb1fe000dbd7cb58e0fcd5a66c549538e9a2 fork: name: scroll-reth url: https://github.com/scroll-tech/reth